deepcut works with pyGhida

This commit is contained in:
Maloney, Vivian
2025-09-12 14:07:48 -04:00
parent 22c0a93da4
commit 2a77c349b8
17 changed files with 458 additions and 213 deletions

View File

@@ -84,6 +84,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ChangeManager;
import ghidra.program.util.DefinedDataIterator;
import ghidra.program.util.DefinedStringIterator;
import ghidra.program.util.GhidraProgramUtilities;
import ghidra.program.util.ProgramChangeRecord;
import ghidra.program.util.ProgramLocation;
@@ -1069,7 +1070,8 @@ public class CodeCutGUIPlugin extends ProgramPlugin implements DomainObjectListe
Accumulator<ProgramLocation> accumulator = new ListAccumulator<>();
Swing.allowSwingToProcessEvents();
for (Data stringInstance : DefinedDataIterator.definedStrings(currentProgram)) {
// 09032025 Vivian, changed to accommodate updated ghidra api
for (Data stringInstance : DefinedStringIterator.forProgram(currentProgram)) {
Address strAddr = stringInstance.getAddress();
ReferenceIterator refIterator = refManager.getReferencesTo(strAddr);
while (refIterator.hasNext()) {

View File

@@ -65,7 +65,6 @@ public class GraphCutLayout extends AbstractVisualGraphLayout<GraphCutVertex, Gr
return newLayout;
}
@Override
protected Point2D getVertexLocation(GraphCutVertex v, Column col, Row<GraphCutVertex> row, Rectangle bounds) {
return getCenteredVertexLocation(v, col, row, bounds);
}

BIN
deepcut-ghidra/ghidra_scripts/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,77 @@
# @category CodeCut
# @menupath CodeCut.DeepCut (Run)
# @toolbar codecut.png
# @runtime PyGhidra
# (C) 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (JHU/APL). All Rights Reserved.
#
# This material may be only be used, modified, or reproduced by or for
# the U.S. Government pursuant to the license rights granted under the
# clauses at DFARS 252.227-7013/7014 or FAR 52.227-14. For any other
# permission, please contact the Office of Technology Transfer at
# 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.
#
# HAVE A NICE DAY.
# 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.
import sys
import json
print("started DeepCutRun")
from dependency_bootstrap import DependencyManager
# list the packages you need
# dictionary of "import name" : "pip name"
# for when they differ, e.g. "sklearn": "scikit-learn"
deps = DependencyManager(
{"networkx": "networkx",
"scipy": "scipy",
"torch": "torch",
"torch_geometric": "torch-geometric"})
# make sure they're installed
if not deps.ensure_or_prompt():
println("[DeepCut] Required Python packages not available, exiting.")
exit(1)
from deepcut import Deepcut
# Pass Ghidra context + args into your package entry point
# run(currentProgram, state, monitor, *args)
def main():
args = list(getScriptArgs())
with open(args[0], "r") as f:
fcg = json.load(f)
model_path = args[2]
d = Deepcut(fcg, model_path)
with open(args[1], "w") as f:
json.dump(d.module_list(), f)
print("Successfully exported module boundaries")
if __name__ == "__main__":
main()

View File

@@ -1,4 +1,4 @@
# © 2021 The Johns Hopkins University Applied Physics Laboratory LLC
# (C) 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (JHU/APL). All Rights Reserved.
#
# This material may be only be used, modified, or reproduced by or for
@@ -7,7 +7,7 @@
# permission, please contact the Office of Technology Transfer at
# JHU/APL.
#
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED AS IS. 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
@@ -88,12 +88,6 @@ class Net(torch.nn.Module):
self.out2 = torch.nn.Linear(dim, 4)
def forward(self, x, edge_attr, edge_index, batch):
# x, edge_attr, edge_index, batch = (
# data.x,
# data.edge_attr,
# data.edge_index,
# data.batch,
# )
x = F.relu(self.init_mlp(x))
x = self.init_bn(x)
@@ -118,20 +112,14 @@ class Net(torch.nn.Module):
edge_attr = self.e_mlp3(edge_attr)
edge_attr = self.ebn2(edge_attr) # oops typo this should be a 3
#x = x[edge_index[0]] + x[edge_index[1]] + edge_attr
#x = F.softmax(x, dim=1)
#edge_attr = F.softmax(edge_attr, dim=1)
x = torch.cat([x[edge_index[0]], x[edge_index[1]], edge_attr], dim=1)
x = F.relu(self.out1(x))
x = self.out_bn(x)
x = self.out2(x)
#ret = torch.max(x, dim=1)[0]
ret = torch.mean(x, dim=1)
#ret = torch.max(x[edge_index[0]] + x[edge_index[1]], dim=1)[0]
#ret = torch.mean(x[edge_index[0]] + x[edge_index[1]], dim=1)
return ret
def load_gnn(model_file):

View File

@@ -1,6 +1,4 @@
#!/usr/bin/env python
#
# © 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (C) 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (JHU/APL). All Rights Reserved.
#
# This material may be only be used, modified, or reproduced by or for
@@ -9,7 +7,7 @@
# permission, please contact the Office of Technology Transfer at
# JHU/APL.
#
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED AS IS. 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
@@ -29,7 +27,6 @@
# Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
# under Contract Number N66001-20-C-4024.
import json
import sys
import numpy as np
@@ -188,7 +185,7 @@ def main():
if len(sys.argv) == 2:
model_file = sys.argv[1]
else:
model_file = "model_weights_1.p"
model_file = "model_weights.p"
d = Deepcut(fcg, model_file)

View File

@@ -0,0 +1,96 @@
from __future__ import annotations
import sys, os, io, importlib, subprocess
from typing import Dict, List, Tuple
class DependencyManager:
"""
Minimal dependency manager for Ghidra Python (PyGhidra/CPython).
- Takes a dict {import_name: pip_name}.
- Prompts the user to install missing ones via a Swing/Ghidra popup.
- Reloads site/import caches so new installs are importable immediately.
"""
def __init__(self, packages: Dict[str, str], *, title: str = "Missing Python Packages"):
self.packages = packages
self.title = title
# -------- public API --------
def ensure_or_prompt(self) -> bool:
_, missing = self._try_imports(list(self.packages.keys()))
if not missing:
return True
if not self._ask_to_install(missing):
return False
pip_names = [self.packages[name] for name in missing]
if not self._pip_install(pip_names):
return False
self._reload_paths()
_, still = self._try_imports(missing)
if still:
print("[deps] Still missing after install:", still)
return False
return True
# -------- internals --------
def _try_imports(self, names: List[str]) -> Tuple[List[str], List[str]]:
ok, missing = [], []
for n in names:
try:
importlib.import_module(n)
ok.append(n)
except Exception:
missing.append(n)
return ok, missing
def _ask_to_install(self, missing: List[str]) -> bool:
# Prefer Ghidra OptionDialog (GUI-safe)
try:
from docking.widgets import OptionDialog
lines = ["The following Python packages are required and missing:\n"]
lines += [f" • import '{name}' (pip install {self.packages[name]})" for name in missing]
lines += ["", "Install them now with pip?"]
msg = "\n".join(lines)
return OptionDialog.showYesNoDialog(None, self.title, msg) == OptionDialog.YES_OPTION
except Exception:
# Headless fallback is unlikely in-tool, but just in case:
print(f"{self.title}: will install {', '.join(self.packages[n] for n in missing)}")
return True
def _pip_install(self, pip_names: List[str]) -> bool:
args = ["install", "--upgrade", "--no-input"] + pip_names
print(f"[deps] pip {' '.join(args)}")
# Suppress pips version check and ensure no interactive prompts
env = dict(os.environ)
env.setdefault("PIP_DISABLE_PIP_VERSION_CHECK", "1")
env.setdefault("PYTHONWARNINGS", "ignore") # optional: quiet noisy warnings
# pip 20+: use cli.main
from pip._internal.cli.main import main as pip_main # type: ignore
try:
code = pip_main(args)
except SystemExit as e: # pip may call sys.exit()
code = int(e.code) if e.code is not None else 0
if int(code) == 0:
return True
print(f"[deps] pip (in-process) failed with code {code}")
def _reload_paths(self) -> None:
importlib.invalidate_caches()
try:
import site
importlib.reload(site) # process site-packages & .pth files
except Exception:
pass
try:
import pkg_resources # type: ignore
pkg_resources.working_set.__init__() # rebuild dist cache
except Exception:
pass

View File

@@ -0,0 +1,14 @@
# @category Diagnostics
# @menupath Diagnostics.Test askYesNo
# @runtime PyGhidra
def main():
try:
# Ghidra injects askYesNo into the script's globals
result = askYesNo("askYesNo Test", "Does askYesNo() work in this environment?")
println(f"[test] askYesNo returned: {result!r}")
except Exception as e:
println(f"[test] askYesNo failed: {e}")
if __name__ == "__main__":
main()

View File

@@ -25,11 +25,16 @@
package deepcut;
import java.io.FileNotFoundException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
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.app.util.opinion.ElfLoader;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
@@ -40,34 +45,32 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
import com.google.gson.GsonBuilder;
/**
* TODO: Provide class-level documentation that describes what this analyzer does.
* Uses the DeepCut algorithm to find module boundaries.
*/
public class DeepCutAnalyzer extends AbstractAnalyzer {
private final static String NAME = "Deepcut";
private final static String DESCRIPTION = "Uses the deepcut algorithm to find module boundaries.";
private final static String OPTION_NAME_PYTHON_EXEC = "Python Executable";
private final static String OPTION_DESCRIPTION_PYTHON_EXEC = "";
private final static String OPTION_DEFAULT_PYTHON_EXEC = "/usr/bin/python3";
private String pythonExec = OPTION_DEFAULT_PYTHON_EXEC;
private static final String NAME = "Deepcut";
private static final String DESCRIPTION = "Uses the deepcut algorithm to find module boundaries.";
public DeepCutAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
setDefaultEnablement(false);
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.after());
setPrototype();
setSupportsOneTimeAnalysis();
}
private final Gson gson = new GsonBuilder().create();
@Override
public DeepCutAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
setDefaultEnablement(false);
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.after());
setPrototype();
setSupportsOneTimeAnalysis();
Msg.info(this, "DeepCutAnalyzer loaded");
}
@Override
public boolean getDefaultEnablement(Program program) {
// Only supports one-time analysis.
return false;
@@ -80,86 +83,79 @@ public class DeepCutAnalyzer extends AbstractAnalyzer {
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_PYTHON_EXEC, pythonExec,
null, OPTION_DESCRIPTION_PYTHON_EXEC);
// no options
}
@Override
public void optionsChanged(Options options, Program program) {
pythonExec = options.getString(OPTION_NAME_PYTHON_EXEC, pythonExec);
// no options
}
private boolean checkError(DeepCutPython deepcut, MessageLog log)
{
String error = deepcut.readProcessError();
if (!error.isEmpty()) {
log.appendMsg(error);
return true;
}
return false;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
DeepCutPython deepcut = new DeepCutPython(pythonExec);
FunctionCallGraph fcg = new FunctionCallGraph(program, monitor);
try {
deepcut.startProcess();
if (checkError(deepcut, log)) {
return false;
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
// 1) Build input JSON from the program
FunctionCallGraph fcg = new FunctionCallGraph(program, monitor);
String inputJson = fcg.toJson();
// 2) Run DeepCut via the launcher (blocking, file-IO args under the hood)
String cutsJson="";
try {
cutsJson = DeepCutLauncher.runDeepCutFileMode(program, set, inputJson, monitor);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GhidraScriptLoadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
deepcut.writeProcess(fcg.toJson() + "\n");
deepcut.waitFor();
if (cutsJson == null || cutsJson.isEmpty()) {
log.appendMsg("DeepCut returned no output.");
return false;
}
try {
if (checkError(deepcut, log)) {
return false;
}
String cuts_json = deepcut.readProcessOutput();
// 3) Parse result and apply namespaces
Cut[] cuts = gson.fromJson(cutsJson, Cut[].class);
int i = 0;
Cut[] cuts = new GsonBuilder().create().fromJson(cuts_json, Cut[].class);
for (FunctionInfo fi : fcg.getFunctionInfos()) {
AddressFactory af = program.getAddressFactory();
Address cutAddress = af.getAddress(cuts[i].address);
int i = 0;
for (FunctionInfo fi : fcg.getFunctionInfos()) {
AddressFactory af = program.getAddressFactory();
Address cutAddress = af.getAddress(cuts[i].address);
if (fi.getAddress().compareTo(cutAddress) == -1) {
addNamespace(program, "object" + i, fi.getFunction());
} else {
i++;
addNamespace(program, "object" + i, fi.getFunction());
}
}
} catch (Exception e) {
log.appendException(e);
return false;
}
return true;
}
public void addNamespace(Program program, String name, Function function)
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
SymbolTable symbolTable = program.getSymbolTable();
Namespace namespace = null;
namespace = symbolTable.getNamespace(name, null);
if(namespace == null) {
namespace = symbolTable.createNameSpace(null, name,
SourceType.USER_DEFINED);
if (fi.getAddress().compareTo(cutAddress) < 0) {
addNamespace(program, "object" + i, fi.getFunction());
} else {
i++;
addNamespace(program, "object" + i, fi.getFunction());
if (i >= cuts.length) {
// no more cuts; remaining functions go into the last bucket
// (optional: break; if you prefer to stop assigning)
i = cuts.length - 1;
}
}
}
return true;
} catch (Exception e) {
log.appendException(e);
return false;
}
function.setParentNamespace(namespace);
}
}
private void addNamespace(Program program, String name, Function function)
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
SymbolTable symbolTable = program.getSymbolTable();
Namespace ns = symbolTable.getNamespace(name, null);
if (ns == null) {
ns = symbolTable.createNameSpace(null, name, SourceType.USER_DEFINED);
}
function.setParentNamespace(ns);
}
}

View File

@@ -0,0 +1,178 @@
/* ###
* © 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 ghidra.util.Msg;
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;
import ghidra.framework.Application;
public class DeepCutLauncher {
/**
* Runs DeepCutRun.py synchronously with two args: infile and outfile.
* 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 runDeepCutFileMode(Program program,
AddressSetView set,
String inputJson,
TaskMonitor monitor) throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
final String scriptName = "DeepCutRun.py"; // must be on Ghidra script path
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)
"PyGhidra Required", // 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;
}
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);
}
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);
}
}

View File

@@ -1,102 +0,0 @@
/* ###
* © 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.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.stream.Collectors;
import ghidra.framework.Application;
public class DeepCutPython {
public Runtime runtime;
public String pythonExec;
public Process process;
public OutputStream stdin;
public InputStream stdout;
public InputStream stderr;
public DeepCutPython(String pythonExec) {
this.pythonExec = pythonExec;
this.runtime = Runtime.getRuntime();
}
public void startProcess() throws IOException {
String pythonFile = Application.getModuleDataFile("deepcut.py").toString();
String modelFile = Application.getModuleDataFile("model_weights_1.p").toString();
//pythonFile = "/Users/desteaj1/Programs/AMP/deepcut/src/deepcut";
String[] exec = {pythonExec, pythonFile, modelFile};
process = runtime.exec(exec);
// Yes this is confusing. stdin is a Java OutputStream, stdout is an InputStream
stdin = process.getOutputStream();
stdout = process.getInputStream();
stderr = process.getErrorStream();
}
public void waitFor() throws InterruptedException {
process.waitFor();
}
public void writeProcess(String data) throws IOException {
writeProcess(data.getBytes());
}
public void writeProcess(byte[] data) throws IOException {
stdin.write(data);
}
public String readProcessOutput() {
return readProcess(stdout);
}
public String readProcessError() {
return readProcess(stderr);
}
private String readProcess(InputStream stream) {
String result = "";
try {
if (stream.available() > 0 ) {
result = new BufferedReader(new InputStreamReader(stream))
.lines().collect(Collectors.joining("\n"));
}
} catch (IOException e) {
return result;
}
return result;
}
}