mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-10 05:48:01 -05:00
deepcut works with pyGhida
This commit is contained in:
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Binary file not shown.
BIN
deepcut-ghidra/ghidra_scripts/.DS_Store
vendored
Normal file
BIN
deepcut-ghidra/ghidra_scripts/.DS_Store
vendored
Normal file
Binary file not shown.
77
deepcut-ghidra/ghidra_scripts/DeepCutRun.py
Normal file
77
deepcut-ghidra/ghidra_scripts/DeepCutRun.py
Normal 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()
|
||||
@@ -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):
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
|
||||
96
deepcut-ghidra/ghidra_scripts/dependency_bootstrap.py
Normal file
96
deepcut-ghidra/ghidra_scripts/dependency_bootstrap.py
Normal 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 pip’s 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
|
||||
14
deepcut-ghidra/ghidra_scripts/vivvy_test.py
Normal file
14
deepcut-ghidra/ghidra_scripts/vivvy_test.py
Normal 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()
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
178
deepcut-ghidra/src/main/java/deepcut/DeepCutLauncher.java
Normal file
178
deepcut-ghidra/src/main/java/deepcut/DeepCutLauncher.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user