GP-693: Simplifying GhidraJarBuilder

This commit is contained in:
Ryan Kurtz 2021-03-12 11:39:03 -05:00
parent 2a8afd5296
commit 415a27ccc7
2 changed files with 44 additions and 125 deletions

View file

@ -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;
}
} }

View file

@ -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;
}
} }