mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-693: Simplifying GhidraJarBuilder
This commit is contained in:
parent
2a8afd5296
commit
415a27ccc7
2 changed files with 44 additions and 125 deletions
|
@ -17,10 +17,9 @@
|
||||||
//@category Examples
|
//@category Examples
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
import generic.jar.ApplicationModule;
|
import generic.jar.ApplicationModule;
|
||||||
import generic.jar.ResourceFile;
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.util.GhidraJarBuilder;
|
import ghidra.util.GhidraJarBuilder;
|
||||||
|
@ -32,8 +31,7 @@ public class BuildGhidraJarScript extends GhidraScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
GhidraJarBuilder builder =
|
GhidraJarBuilder builder = new GhidraJarBuilder(Application.getApplicationLayout());
|
||||||
new GhidraJarBuilder(toFiles(Application.getApplicationRootDirectories()));
|
|
||||||
|
|
||||||
builder.setMainClass("ghidra.JarRun"); // default is ghidra.JarRun, only here if you want
|
builder.setMainClass("ghidra.JarRun"); // default is ghidra.JarRun, only here if you want
|
||||||
// to change it to something else.
|
// to change it to something else.
|
||||||
|
@ -69,12 +67,4 @@ public class BuildGhidraJarScript extends GhidraScript {
|
||||||
// uncomment the following line to create a src zip for debugging.
|
// uncomment the following line to create a src zip for debugging.
|
||||||
// builder.buildSrcZip(new File(installDir, "GhidraSrc.zip"), monitor);
|
// builder.buildSrcZip(new File(installDir, "GhidraSrc.zip"), monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<File> toFiles(Collection<ResourceFile> resourceFiles) {
|
|
||||||
List<File> fileList = new ArrayList<>();
|
|
||||||
for (ResourceFile resourceFile : resourceFiles) {
|
|
||||||
fileList.add(resourceFile.getFile(true));
|
|
||||||
}
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,33 +20,29 @@ import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
|
|
||||||
import generic.jar.*;
|
import generic.jar.*;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.GhidraLaunchable;
|
import ghidra.GhidraLaunchable;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.*;
|
||||||
import ghidra.framework.HeadlessGhidraApplicationConfiguration;
|
|
||||||
import ghidra.framework.plugintool.dialog.ExtensionUtils;
|
import ghidra.framework.plugintool.dialog.ExtensionUtils;
|
||||||
import ghidra.util.classfinder.ClassFinder;
|
import ghidra.util.classfinder.ClassFinder;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
import utility.application.ApplicationLayout;
|
||||||
import utility.module.ModuleUtilities;
|
import utility.module.ModuleUtilities;
|
||||||
|
|
||||||
public class GhidraJarBuilder implements GhidraLaunchable {
|
public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
|
|
||||||
private static final String ROOT = "_Root/";
|
private static final String ROOT = "_Root/";
|
||||||
private static final String ROOT_GHIDRA = "_Root/Ghidra/";
|
private static final String ROOT_GHIDRA = "_Root/Ghidra/";
|
||||||
private static final String LIBS_FILE_MODULE_KEY = "Module: ";
|
|
||||||
|
|
||||||
// this is set in the buildGhidraJar batch/script files
|
// this is set in the buildGhidraJar batch/script files
|
||||||
private static final String INVOCATION_NAME_PROPERTY = "GhidraJarBuilder.Name";
|
private static final String INVOCATION_NAME_PROPERTY = "GhidraJarBuilder.Name";
|
||||||
private static HashMap<String, List<String>> libsMap = new HashMap<>();
|
|
||||||
private List<File> rootGhidraDirs = new ArrayList<>();
|
private List<File> rootGhidraDirs = new ArrayList<>();
|
||||||
private List<ApplicationModule> allModules;
|
private List<ApplicationModule> allModules;
|
||||||
private Set<ApplicationModule> includedModules = new HashSet<>();
|
private Set<ApplicationModule> includedModules = new HashSet<>();
|
||||||
|
@ -57,19 +53,18 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
private Pattern extensionPointSuffixPattern;
|
private Pattern extensionPointSuffixPattern;
|
||||||
private List<String> extensionPointClasses = new ArrayList<>();
|
private List<String> extensionPointClasses = new ArrayList<>();
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
private boolean inGradleMode = false;
|
|
||||||
private Set<File> processedJars = new HashSet<>();
|
private Set<File> processedJars = new HashSet<>();
|
||||||
|
|
||||||
public GhidraJarBuilder() {
|
public GhidraJarBuilder() {
|
||||||
// Required for GhidraLaunchable
|
// Required for GhidraLaunchable
|
||||||
}
|
}
|
||||||
|
|
||||||
public GhidraJarBuilder(List<File> rootDirs) throws IOException {
|
public GhidraJarBuilder(ApplicationLayout layout) throws IOException {
|
||||||
for (File file : rootDirs) {
|
for (ResourceFile file : layout.getApplicationRootDirs()) {
|
||||||
File rgd = file.getCanonicalFile();
|
File rgd = file.getFile(false).getCanonicalFile();
|
||||||
rootGhidraDirs.add(rgd);
|
rootGhidraDirs.add(rgd);
|
||||||
}
|
}
|
||||||
allModules = findAllModules();
|
allModules = findAllModules(layout);
|
||||||
Collections.sort(allModules);
|
Collections.sort(allModules);
|
||||||
for (ApplicationModule module : allModules) {
|
for (ApplicationModule module : allModules) {
|
||||||
if (includeByDefault(module)) {
|
if (includeByDefault(module)) {
|
||||||
|
@ -203,7 +198,7 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
|
|
||||||
for (ApplicationModule module : moduleList) {
|
for (ApplicationModule module : moduleList) {
|
||||||
writeModuleClassesAndResources(jar, module);
|
writeModuleClassesAndResources(jar, module);
|
||||||
if (!excludeHelp && !inGradleMode) {
|
if (!excludeHelp) {
|
||||||
writeModuleHelp(jar, module);
|
writeModuleHelp(jar, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,16 +355,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
private void writeModuleClassesAndResources(Jar jar, ApplicationModule module)
|
private void writeModuleClassesAndResources(Jar jar, ApplicationModule module)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
|
||||||
if (inGradleMode) {
|
|
||||||
File gradleBuildFileForModule =
|
|
||||||
new File(module.getModuleDir(), "build/libs/" + module.getName() + ".jar");
|
|
||||||
processJarFile(jar, gradleBuildFileForModule, module);
|
|
||||||
File gradleBuildFileForGPLModule =
|
|
||||||
new File(module.getModuleDir(), "build/data/lib/" + module.getName() + ".jar");
|
|
||||||
processJarFile(jar, gradleBuildFileForGPLModule, module);
|
|
||||||
processExternalLibs(jar, module);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// NOTE: This only works in a distribution where the 3rd party jars live in each
|
// NOTE: This only works in a distribution where the 3rd party jars live in each
|
||||||
// module's libs directory
|
// module's libs directory
|
||||||
File binDir = new File(module.getModuleDir(), "bin/main");
|
File binDir = new File(module.getModuleDir(), "bin/main");
|
||||||
|
@ -380,18 +365,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
processLibDir(jar, module);
|
processLibDir(jar, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processExternalLibs(Jar jar, ApplicationModule module)
|
|
||||||
throws CancelledException, IOException {
|
|
||||||
List<String> list = libsMap.get(module.getName());
|
|
||||||
if (list == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String libPath : list) {
|
|
||||||
File file = new File(libPath);
|
|
||||||
processJarFile(jar, file, module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processLibDir(Jar jar, ApplicationModule module)
|
private void processLibDir(Jar jar, ApplicationModule module)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
File libDir = new File(module.getModuleDir(), "lib");
|
File libDir = new File(module.getModuleDir(), "lib");
|
||||||
|
@ -586,16 +559,40 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ApplicationModule> findAllModules() {
|
private List<ApplicationModule> findAllModules(ApplicationLayout layout) throws IOException {
|
||||||
List<ApplicationModule> modules = new ArrayList<>();
|
List<ApplicationModule> modules = new ArrayList<>();
|
||||||
for (File appRoot : rootGhidraDirs) {
|
|
||||||
findModules(appRoot, appRoot, modules);
|
|
||||||
findModules(appRoot, new File(appRoot, "../GPL"), modules);
|
|
||||||
|
|
||||||
|
// Add GPL root directories
|
||||||
|
List<File> rootDirs = new ArrayList<>(rootGhidraDirs);
|
||||||
|
for (File rootDir : rootGhidraDirs) {
|
||||||
|
rootDirs.add(new File(rootDir.getParentFile(), "GPL"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (GModule module : layout.getModules().values()) {
|
||||||
|
File moduleDir = module.getModuleRoot().getFile(false).getCanonicalFile();
|
||||||
|
File rootDir = getModuleRootDir(moduleDir);
|
||||||
|
modules.add(new ApplicationModule(rootDir, moduleDir));
|
||||||
|
}
|
||||||
|
|
||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getModuleRootDir(File moduleDir) {
|
||||||
|
// Add GPL directories
|
||||||
|
List<File> rootDirs = new ArrayList<>(rootGhidraDirs);
|
||||||
|
for (File rootDir : rootGhidraDirs) {
|
||||||
|
rootDirs.add(new File(rootDir.getParentFile(), "GPL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each root directory to see if it contains the module
|
||||||
|
for (File rootDir : rootDirs) {
|
||||||
|
if (FileUtilities.isPathContainedWithin(rootDir, moduleDir)) {
|
||||||
|
return rootDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AssertException("Module root directory could not be determined: " + moduleDir);
|
||||||
|
}
|
||||||
|
|
||||||
private String getPathFromRoot(String rootPath, File file) {
|
private String getPathFromRoot(String rootPath, File file) {
|
||||||
String filePath = file.getAbsolutePath();
|
String filePath = file.getAbsolutePath();
|
||||||
if (!filePath.startsWith(rootPath)) {
|
if (!filePath.startsWith(rootPath)) {
|
||||||
|
@ -604,23 +601,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return filePath.substring(rootPath.length() + 1);
|
return filePath.substring(rootPath.length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findModules(File rootAppDir, File dir, List<ApplicationModule> modules) {
|
|
||||||
File moduleManifest = new File(dir, "Module.manifest");
|
|
||||||
if (moduleManifest.exists()) {
|
|
||||||
ApplicationModule module = new ApplicationModule(rootAppDir, dir);
|
|
||||||
modules.add(module);
|
|
||||||
return; // modules can't live in other modules;
|
|
||||||
}
|
|
||||||
File[] listFiles = dir.listFiles();
|
|
||||||
if (listFiles != null) {
|
|
||||||
for (File file : listFiles) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
findModules(rootAppDir, file, modules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkExtensionPointClass(String path, InputStream inputStream) {
|
private void checkExtensionPointClass(String path, InputStream inputStream) {
|
||||||
// remove .class
|
// remove .class
|
||||||
path = path.substring(0, path.length() - 6);
|
path = path.substring(0, path.length() - 6);
|
||||||
|
@ -931,31 +911,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseLibsFile(String libsFilePath) {
|
|
||||||
try {
|
|
||||||
List<String> lines = FileUtilities.getLines(new File(libsFilePath));
|
|
||||||
|
|
||||||
List<String> libPaths = new ArrayList<>();
|
|
||||||
String currentModule = null;
|
|
||||||
for (String line : lines) {
|
|
||||||
if (line.startsWith(LIBS_FILE_MODULE_KEY)) {
|
|
||||||
if (currentModule != null) {
|
|
||||||
libsMap.put(currentModule, libPaths);
|
|
||||||
libPaths = new ArrayList<>();
|
|
||||||
}
|
|
||||||
currentModule = line.substring(LIBS_FILE_MODULE_KEY.length()).trim();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
libPaths.add(line.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
System.err.println("Could not read lib paths file: " + libsFilePath);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void usage(String[] args) {
|
private static void usage(String[] args) {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
System.err.println("arg " + i + ": " + args[i]);
|
System.err.println("arg " + i + ": " + args[i]);
|
||||||
|
@ -964,7 +919,7 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
|
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append("\nUsage: ");
|
buf.append("\nUsage: ");
|
||||||
buf.append(invocationName != null ? invocationName : "GhidraJarBuilder ");
|
buf.append(invocationName != null ? invocationName : "GhidraJarBuilder");
|
||||||
buf.append(
|
buf.append(
|
||||||
" [-output <output file>] [-srczip <src zip output file>] [-bin <compiled classes dir>] [-main <main-class>]\n");
|
" [-output <output file>] [-srczip <src zip output file>] [-bin <compiled classes dir>] [-main <main-class>]\n");
|
||||||
System.err.println(buf.toString());
|
System.err.println(buf.toString());
|
||||||
|
@ -988,15 +943,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
usage(args);
|
usage(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<File> ghidraDirs = layout.getApplicationRootDirs()
|
|
||||||
.stream()
|
|
||||||
.map(f -> f.getFile(false))
|
|
||||||
.collect(Collectors.toCollection(ArrayList::new));
|
|
||||||
File outputFile = null;
|
File outputFile = null;
|
||||||
File srczip = null;
|
File srczip = null;
|
||||||
File extraBinDir = null;
|
File extraBinDir = null;
|
||||||
String mainClassArg = null;
|
String mainClassArg = null;
|
||||||
boolean usingGradle = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
String arg = args[i];
|
String arg = args[i];
|
||||||
|
@ -1024,28 +974,14 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
mainClassArg = args[++i];
|
mainClassArg = args[++i];
|
||||||
}
|
}
|
||||||
else if (arg.equals("-gradle")) {
|
|
||||||
if (i == args.length - 1) {
|
|
||||||
usage(args);
|
|
||||||
}
|
|
||||||
usingGradle = true;
|
|
||||||
parseLibsFile(args[++i]);
|
|
||||||
}
|
|
||||||
else if (arg.startsWith("-")) {
|
|
||||||
usage(args);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
ghidraDirs.add(new File(arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ghidraDirs.isEmpty()) {
|
|
||||||
usage(args);
|
usage(args);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (outputFile == null) {
|
if (outputFile == null) {
|
||||||
outputFile = new File("ghidra.jar");
|
outputFile = new File("ghidra.jar");
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Ghidra dirs = " + ghidraDirs);
|
|
||||||
System.out.println("Output file = " + outputFile);
|
System.out.println("Output file = " + outputFile);
|
||||||
if (srczip != null) {
|
if (srczip != null) {
|
||||||
System.out.println("Source Zip File = " + srczip);
|
System.out.println("Source Zip File = " + srczip);
|
||||||
|
@ -1055,13 +991,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GhidraJarBuilder builder = new GhidraJarBuilder(ghidraDirs);
|
GhidraJarBuilder builder = new GhidraJarBuilder(layout);
|
||||||
if (mainClassArg != null) {
|
if (mainClassArg != null) {
|
||||||
builder.setMainClass(mainClassArg);
|
builder.setMainClass(mainClassArg);
|
||||||
}
|
}
|
||||||
if (usingGradle) {
|
|
||||||
builder.setGradleMode();
|
|
||||||
}
|
|
||||||
builder.addExcludedFileExtension(".pdf");
|
builder.addExcludedFileExtension(".pdf");
|
||||||
|
|
||||||
// builder.addExcludedFileExtension(".htm");
|
// builder.addExcludedFileExtension(".htm");
|
||||||
|
@ -1076,10 +1009,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
System.out.println("Exclude " + module.getName());
|
System.out.println("Exclude " + module.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.buildJar(outputFile, extraBinDir, TaskMonitorAdapter.DUMMY_MONITOR);
|
builder.buildJar(outputFile, extraBinDir, TaskMonitor.DUMMY);
|
||||||
|
|
||||||
if (srczip != null) {
|
if (srczip != null) {
|
||||||
builder.buildSrcZip(srczip, TaskMonitorAdapter.DUMMY_MONITOR);
|
builder.buildSrcZip(srczip, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
@ -1093,8 +1026,4 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return new File(ghidraRootDir, "application.properties");
|
return new File(ghidraRootDir, "application.properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGradleMode() {
|
|
||||||
inGradleMode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue