mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-09 14:58:02 -05:00
changed everything to use pyGhidra
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -30,11 +30,13 @@ import java.io.FileNotFoundException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.script.GhidraScriptLoadException;
|
||||
import ghidra.app.services.AbstractAnalyzer;
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.app.services.AnalyzerType;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
@@ -104,7 +106,7 @@ public class DeepCutAnalyzer extends AbstractAnalyzer {
|
||||
// 2) Run DeepCut via the launcher (blocking, file-IO args under the hood)
|
||||
String cutsJson="";
|
||||
try {
|
||||
cutsJson = DeepCutLauncher.runFileMode(program, set, inputJson, monitor);
|
||||
cutsJson = DeepCutLauncher.execute(program, set, inputJson, monitor);
|
||||
} catch (IllegalAccessException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@@ -158,4 +160,7 @@ public class DeepCutAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
function.setParentNamespace(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,176 +1,47 @@
|
||||
/* ###
|
||||
* © 2022 The Johns Hopkins University Applied Physics Laboratory LLC
|
||||
* (JHU/APL).
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL
|
||||
* MAKES NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF
|
||||
* THE MATERIALS, INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL
|
||||
* VIABILITY, AND DISCLAIMS ALL WARRANTIES IN THE MATERIAL, WHETHER
|
||||
* EXPRESS OR IMPLIED, INCLUDING (BUT NOT LIMITED TO) ANY AND ALL IMPLIED
|
||||
* WARRANTIES OF PERFORMANCE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, AND NON-INFRINGEMENT OF INTELLECTUAL PROPERTY OR OTHER THIRD
|
||||
* PARTY RIGHTS. ANY USER OF THE MATERIAL ASSUMES THE ENTIRE RISK AND
|
||||
* LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL JHU/APL BE LIABLE
|
||||
* TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT, CONSEQUENTIAL,
|
||||
* SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO USE,
|
||||
* THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST
|
||||
* PROFITS.
|
||||
*
|
||||
* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
package deepcut;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.script.GhidraScriptLoadException;
|
||||
import ghidra.app.script.GhidraScriptProvider;
|
||||
import ghidra.app.script.GhidraScriptUtil;
|
||||
import ghidra.app.script.GhidraState;
|
||||
import ghidra.app.services.ConsoleService;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DeepCutLauncher {
|
||||
public class DeepCutLauncher extends PyGhidraFileLauncher {
|
||||
|
||||
/**
|
||||
* Runs DeepCutRun.py synchronously with three args: infile, outfile, modelfile.
|
||||
* Writes the provided JSON string to a temp infile, runs the script, reads the temp outfile,
|
||||
* and returns its contents. Best-effort temp cleanup.
|
||||
* @throws IllegalAccessException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static String runFileMode(Program program,
|
||||
AddressSetView set,
|
||||
String inputJson,
|
||||
TaskMonitor monitor) throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
|
||||
final String scriptName = "DeepCutRun.py"; // must be on Ghidra script path
|
||||
@Override protected String getScriptName() { return "DeepCutRun.py"; }
|
||||
@Override protected String getInfilePrefix() { return "deepcut_in"; }
|
||||
@Override protected String getOutfilePrefix() { return "deepcut_out"; }
|
||||
@Override protected String getInfileSuffix() { return ".json"; }
|
||||
@Override protected String getOutfileSuffix() { return ".json"; }
|
||||
|
||||
AutoAnalysisManager aam = AutoAnalysisManager.getAnalysisManager(program);
|
||||
PluginTool tool = aam.getAnalysisTool();
|
||||
Project project = tool != null ? tool.getProject() : null;
|
||||
|
||||
GhidraState state = new GhidraState(
|
||||
tool,
|
||||
project,
|
||||
program,
|
||||
new ProgramLocation(program, set.getMinAddress()),
|
||||
new ProgramSelection(set),
|
||||
null
|
||||
);
|
||||
|
||||
PrintWriter out = getOut(tool);
|
||||
PrintWriter err = getErr(tool);
|
||||
|
||||
Path inFile = null, outFile = null;
|
||||
// 1) Locate script
|
||||
ResourceFile sourceFile = GhidraScriptUtil.findScriptByName(scriptName);
|
||||
if (sourceFile == null) {
|
||||
throw new IllegalAccessException("Couldn't find script: " + scriptName);
|
||||
}
|
||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(sourceFile);
|
||||
if (provider == null) {
|
||||
throw new IllegalAccessException("Couldn't find script provider for: " + scriptName);
|
||||
}
|
||||
ResourceFile pythonFile = Application.getModuleDataFile("model_weights.p");
|
||||
if (pythonFile == null) {
|
||||
throw new IllegalAccessException("Couldn't find weights file for: " + scriptName);
|
||||
}
|
||||
|
||||
|
||||
Msg.info(DeepCutLauncher.class, "Chosen provider: " + provider.getClass().getName() + " (runtime=" + provider.getRuntimeEnvironmentName() + ")");
|
||||
|
||||
GhidraScript script;
|
||||
try {
|
||||
script = provider.getScriptInstance(sourceFile, err);
|
||||
}
|
||||
catch(GhidraScriptLoadException e) {
|
||||
Msg.showError(
|
||||
null, // parent object (your plugin/analyzer/launcher)
|
||||
null, // parent component (null = center on tool)
|
||||
"DeepCut Failed to Launch", // dialog title
|
||||
"DeepCut requires the PyGhidra extension.\n\nDetails: " + e.getMessage()
|
||||
);
|
||||
throw new GhidraScriptLoadException("DeepCut requires PyGhidra", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
// 2) Prep temp files
|
||||
inFile = Files.createTempFile("deepcut_in", ".json");
|
||||
outFile = Files.createTempFile("deepcut_out", ".json");
|
||||
// ensure delete on JVM exit as a fallback
|
||||
inFile.toFile().deleteOnExit();
|
||||
outFile.toFile().deleteOnExit();
|
||||
|
||||
// write input JSON
|
||||
Files.writeString(inFile, (inputJson == null ? "" : inputJson) + "\n", StandardCharsets.UTF_8);
|
||||
|
||||
// 3) Pass args: [infile, outfile, modelfile]
|
||||
script.setScriptArgs(new String[] {
|
||||
inFile.toString(),
|
||||
outFile.toString(),
|
||||
pythonFile.toString() });
|
||||
|
||||
|
||||
|
||||
// 4) Run blocking
|
||||
script.execute(state, monitor, out);
|
||||
|
||||
// 5) Read result JSON
|
||||
String result = Files.readString(outFile, StandardCharsets.UTF_8).trim();
|
||||
return result;
|
||||
@Override
|
||||
protected String[] getExtraArgs(ghidra.framework.plugintool.PluginTool tool) throws Exception {
|
||||
|
||||
// derive the correct module name at runtime
|
||||
String moduleName = Application.getMyModuleRootDirectory().getName();
|
||||
|
||||
// Locate model weights packaged with the extension/module
|
||||
ResourceFile weights = Application.getModuleDataFile(moduleName, "model_weights.p");
|
||||
if (weights == null) {
|
||||
throw new IllegalAccessException("Couldn't find weights file for: " + getScriptName());
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// user cancelled; return null or empty to signal no result
|
||||
return null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.warn(DeepCutLauncher.class, "Error running script " + scriptName + ": " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
// best-effort cleanup
|
||||
try { if (inFile != null) Files.deleteIfExists(inFile); } catch (IOException ignored) {}
|
||||
try { if (outFile != null) Files.deleteIfExists(outFile); } catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private static PrintWriter getOut(PluginTool tool) {
|
||||
if (tool != null) {
|
||||
ConsoleService console = tool.getService(ConsoleService.class);
|
||||
if (console != null) return console.getStdOut();
|
||||
}
|
||||
return new PrintWriter(System.out);
|
||||
return new String[] { weights.toString() };
|
||||
}
|
||||
|
||||
private static PrintWriter getErr(PluginTool tool) {
|
||||
if (tool != null) {
|
||||
ConsoleService console = tool.getService(ConsoleService.class);
|
||||
if (console != null) return console.getStdErr();
|
||||
}
|
||||
return new PrintWriter(System.err);
|
||||
// Convenience static method to preserve your old call-site signature
|
||||
public static String execute(Program program,
|
||||
AddressSetView set,
|
||||
String inputPayload,
|
||||
TaskMonitor monitor)
|
||||
throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
|
||||
return new DeepCutLauncher().runFileMode(program, set, inputPayload, monitor);
|
||||
}
|
||||
|
||||
@Override protected String getLaunchFailDialogTitle() { return "DeepCut Failed to Launch"; }
|
||||
@Override protected String getLaunchFailDialogBodyPrefix() {
|
||||
return "DeepCut requires the PyGhidra extension.\n\nDetails: ";
|
||||
}
|
||||
}
|
||||
|
||||
174
deepcut-ghidra/src/main/java/deepcut/PyGhidraFileLauncher.java
Normal file
174
deepcut-ghidra/src/main/java/deepcut/PyGhidraFileLauncher.java
Normal file
@@ -0,0 +1,174 @@
|
||||
package deepcut;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.script.GhidraScriptLoadException;
|
||||
import ghidra.app.script.GhidraScriptProvider;
|
||||
import ghidra.app.script.GhidraScriptUtil;
|
||||
import ghidra.app.script.GhidraState;
|
||||
import ghidra.app.services.ConsoleService;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Base class for launching PyGhidra scripts in "file mode":
|
||||
* - writes input payload to a temp infile
|
||||
* - runs a named script with args [infile, outfile, ...extraArgs]
|
||||
* - reads output payload from the outfile
|
||||
*
|
||||
* Subclasses override:
|
||||
* - script name
|
||||
* - temp file prefixes/suffixes (optional)
|
||||
* - extra args (optional)
|
||||
* - UI strings for error dialogs (optional)
|
||||
*/
|
||||
public abstract class PyGhidraFileLauncher {
|
||||
|
||||
/** Provide the script file name that must be on the Ghidra script path. */
|
||||
protected abstract String getScriptName();
|
||||
|
||||
/** Prefix for the temp input file (default: "in_"). */
|
||||
protected String getInfilePrefix() { return "in_"; }
|
||||
/** Suffix/extension for the temp input file (default: ".json"). */
|
||||
protected String getInfileSuffix() { return ".json"; }
|
||||
|
||||
/** Prefix for the temp output file (default: "out_"). */
|
||||
protected String getOutfilePrefix() { return "out_"; }
|
||||
/** Suffix/extension for the temp output file (default: ".json"). */
|
||||
protected String getOutfileSuffix() { return ".json"; }
|
||||
|
||||
/**
|
||||
* Return any extra script args after [infile, outfile]. Default: none.
|
||||
* If this is used, the subclass must be defined in its own .java file
|
||||
* in order for Ghidra the correctly find the module data file
|
||||
* (yes this is strange)
|
||||
*/
|
||||
protected String[] getExtraArgs(PluginTool tool) throws Exception { return new String[0]; }
|
||||
|
||||
/** Title and message for the “PyGhidra required” dialog. */
|
||||
protected String getLaunchFailDialogTitle() { return "Script Failed to Launch"; }
|
||||
protected String getLaunchFailDialogBodyPrefix() { return "This feature requires the PyGhidra extension.\n\nDetails: "; }
|
||||
|
||||
/**
|
||||
* Run the script synchronously and return the outfile contents (trimmed), or null on cancel/error.
|
||||
*/
|
||||
public String runFileMode(Program program,
|
||||
AddressSetView set,
|
||||
String inputPayload,
|
||||
TaskMonitor monitor)
|
||||
throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
|
||||
|
||||
final String scriptName = getScriptName();
|
||||
|
||||
AutoAnalysisManager aam = AutoAnalysisManager.getAnalysisManager(program);
|
||||
PluginTool tool = aam.getAnalysisTool();
|
||||
Project project = tool != null ? tool.getProject() : null;
|
||||
|
||||
GhidraState state = new GhidraState(
|
||||
tool,
|
||||
project,
|
||||
program,
|
||||
new ProgramLocation(program, set.getMinAddress()),
|
||||
new ProgramSelection(set),
|
||||
null
|
||||
);
|
||||
|
||||
PrintWriter out = getOut(tool);
|
||||
PrintWriter err = getErr(tool);
|
||||
|
||||
Path inFile = null, outFile = null;
|
||||
|
||||
// 1) Locate script
|
||||
ResourceFile sourceFile = GhidraScriptUtil.findScriptByName(scriptName);
|
||||
if (sourceFile == null) {
|
||||
throw new IllegalAccessException("Couldn't find script: " + scriptName);
|
||||
}
|
||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(sourceFile);
|
||||
if (provider == null) {
|
||||
throw new IllegalAccessException("Couldn't find script provider for: " + scriptName);
|
||||
}
|
||||
|
||||
Msg.info(getClass(), "Chosen provider: " + provider.getClass().getName() +
|
||||
" (runtime=" + provider.getRuntimeEnvironmentName() + ")");
|
||||
|
||||
GhidraScript script;
|
||||
try {
|
||||
script = provider.getScriptInstance(sourceFile, err);
|
||||
} catch (GhidraScriptLoadException e) {
|
||||
ghidra.util.Msg.showError(
|
||||
null, null,
|
||||
getLaunchFailDialogTitle(),
|
||||
getLaunchFailDialogBodyPrefix() + e.getMessage()
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
|
||||
try {
|
||||
// 2) Prep temp files
|
||||
inFile = Files.createTempFile(getInfilePrefix(), getInfileSuffix());
|
||||
outFile = Files.createTempFile(getOutfilePrefix(), getOutfileSuffix());
|
||||
inFile.toFile().deleteOnExit();
|
||||
outFile.toFile().deleteOnExit();
|
||||
|
||||
// write input payload
|
||||
Files.writeString(inFile, (inputPayload == null ? "" : inputPayload) + "\n", StandardCharsets.UTF_8);
|
||||
|
||||
// 3) Assemble args: [infile, outfile, ...extra]
|
||||
String[] extras = getExtraArgs(tool);
|
||||
String[] args = new String[2 + extras.length];
|
||||
args[0] = inFile.toString();
|
||||
args[1] = outFile.toString();
|
||||
System.arraycopy(extras, 0, args, 2, extras.length);
|
||||
script.setScriptArgs(args);
|
||||
|
||||
// 4) Run blocking
|
||||
script.execute(state, monitor, out);
|
||||
|
||||
// 5) Read result payload
|
||||
return Files.readString(outFile, StandardCharsets.UTF_8).trim();
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.warn(getClass(), "Error running script " + scriptName + ": " + e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
try { if (inFile != null) Files.deleteIfExists(inFile); } catch (IOException ignored) {}
|
||||
try { if (outFile != null) Files.deleteIfExists(outFile); } catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
// ----- console helpers -----
|
||||
protected static PrintWriter getOut(PluginTool tool) {
|
||||
if (tool != null) {
|
||||
ConsoleService console = tool.getService(ConsoleService.class);
|
||||
if (console != null) return console.getStdOut();
|
||||
}
|
||||
return new PrintWriter(System.out);
|
||||
}
|
||||
|
||||
protected static PrintWriter getErr(PluginTool tool) {
|
||||
if (tool != null) {
|
||||
ConsoleService console = tool.getService(ConsoleService.class);
|
||||
if (console != null) return console.getStdErr();
|
||||
}
|
||||
return new PrintWriter(System.err);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user