mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-07 20:43:54 -05:00
Fixed extra directories
This commit is contained in:
0
deepcut-ghidra/Module.manifest
Normal file
0
deepcut-ghidra/Module.manifest
Normal file
75
deepcut-ghidra/README.md
Normal file
75
deepcut-ghidra/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
Ghidra Deepcut Analyzer
|
||||
=======================
|
||||
|
||||
Implementation of the deepcut as a Ghidra one-shot analyzer.
|
||||
|
||||
## Building and Installation
|
||||
JDK 11 (or newer) and Ghidra 9.1.0 (or newer) are required.
|
||||
|
||||
Ghidra's standard Gradle build system is used. Set the
|
||||
`GHIDRA_INSTALL_DIR` environment variable before building, or set it as
|
||||
a Gradle property (useful for building in an IDE):
|
||||
|
||||
### Environment variable
|
||||
```bash
|
||||
$ export GHIDRA_INSTALL_DIR="/path/to/ghidra"
|
||||
$ ./gradlew
|
||||
```
|
||||
|
||||
### Gradle property
|
||||
```bash
|
||||
echo GHIDRA_INSTALL_DIR=/path/to/ghidra > gradle.properties
|
||||
```
|
||||
|
||||
The module ZIP will be output to `dist/`. Use **File > Install
|
||||
Extensions** and select the green plus to browse to the
|
||||
extension. Restart Ghidra when prompted.
|
||||
|
||||
For proper functionality, the plugin should be built with the same JRE
|
||||
used by your Ghidra installation. If you have multiple Java runtime
|
||||
environments installed, select the correct JRE by setting the
|
||||
`JAVA_HOME` environment variable before building.
|
||||
|
||||
### Python 3
|
||||
The deepcut graph based machine learning model needs Python 3 to
|
||||
execute. The analyzer calls and external python process to execute the
|
||||
model on a graph representation of the binary. There are no GPU
|
||||
requirements since the model converge quickly even running in CPU mode.
|
||||
|
||||
#### Python 3 Path
|
||||
By default the analyzer use the command `/usr/local/bin/python3` to
|
||||
execute the deepcut python script. This setting can be changed in the
|
||||
Analysis Options menu **Analysis -> Analyze All Open...** To change the
|
||||
setting you need to click the checkbox next to **Deepcut (Prototype)**
|
||||
first.
|
||||
|
||||
#### Dependencies
|
||||
Deepcut has the following Python 3 dependencies:
|
||||
|
||||
- torch 1.7.1
|
||||
- torch-geometric 1.6.3
|
||||
- torch-cluster 1.5.8
|
||||
- torch-sparse 0.6.8
|
||||
- torch-scatter 2.0.5
|
||||
- torch-spline-conv 1.2.0
|
||||
|
||||
To install the dependencies:
|
||||
|
||||
```bash
|
||||
pip install torch==1.7.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
|
||||
pip install -r requirements-torch_geometric.txt
|
||||
```
|
||||
|
||||
The torch-cluster dependency can take a significant amount of time to
|
||||
build and install.
|
||||
|
||||
## Running the Analyzer
|
||||
The Deepcut analyzer will not run during auto-analysis. Once the binary
|
||||
is loaded and the auto-analyzer is finish use the menu item **Analysis
|
||||
-> One Shot -> Deepcut**
|
||||
|
||||
Once complete each function will include a `moduleX` value in the
|
||||
Namespace field.
|
||||
|
||||
If there are any errors please make sure you are using the proper path
|
||||
to Python 3 and the requirement dependencies installed.
|
||||
33
deepcut-ghidra/build.gradle
Normal file
33
deepcut-ghidra/build.gradle
Normal file
@@ -0,0 +1,33 @@
|
||||
// Builds a Ghidra Extension for a given Ghidra installation.
|
||||
//
|
||||
// An absolute path to the Ghidra installation directory must be supplied either by setting the
|
||||
// GHIDRA_INSTALL_DIR environment variable or Gradle project property:
|
||||
//
|
||||
// > export GHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
|
||||
// > gradle
|
||||
//
|
||||
// or
|
||||
//
|
||||
// > gradle -PGHIDRA_INSTALL_DIR=<Absolute path to Ghidra>
|
||||
//
|
||||
// Gradle should be invoked from the directory of the project to build. Please see the
|
||||
// application.gradle.version property in <GHIDRA_INSTALL_DIR>/Ghidra/application.properties
|
||||
// for the correction version of Gradle to use for the Ghidra installation you specify.
|
||||
|
||||
//----------------------START "DO NOT MODIFY" SECTION------------------------------
|
||||
def ghidraInstallDir
|
||||
|
||||
if (System.env.GHIDRA_INSTALL_DIR) {
|
||||
ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
|
||||
}
|
||||
else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
|
||||
ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
|
||||
}
|
||||
|
||||
if (ghidraInstallDir) {
|
||||
apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
|
||||
}
|
||||
else {
|
||||
throw new GradleException("GHIDRA_INSTALL_DIR is not defined!")
|
||||
}
|
||||
//----------------------END "DO NOT MODIFY" SECTION-------------------------------
|
||||
148
deepcut-ghidra/data/GNN_Net.py
Normal file
148
deepcut-ghidra/data/GNN_Net.py
Normal file
@@ -0,0 +1,148 @@
|
||||
# © 2021 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 torch
|
||||
import torch.nn.functional as F
|
||||
from torch.nn import Sequential, Linear, ReLU
|
||||
from torch_geometric import nn
|
||||
|
||||
|
||||
class Net(torch.nn.Module):
|
||||
def __init__(self, num_features, num_edge_features, dim=32):
|
||||
super(Net, self).__init__()
|
||||
|
||||
self.init_mlp = Sequential(Linear(num_features, num_edge_features),
|
||||
ReLU(),
|
||||
Linear(num_edge_features, num_edge_features))
|
||||
self.init_bn = torch.nn.LayerNorm(num_edge_features)
|
||||
|
||||
self.init_emlp = Sequential(Linear(num_edge_features, num_edge_features),
|
||||
ReLU(),
|
||||
Linear(num_edge_features, num_edge_features))
|
||||
self.init_ebn = torch.nn.LayerNorm(num_edge_features)
|
||||
|
||||
mlp1 = Sequential(Linear(num_edge_features, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim), ReLU(), Linear(dim, dim))
|
||||
self.e_mlp1 = Sequential(Linear(num_edge_features, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim), ReLU(), Linear(dim, dim))
|
||||
self.e_bn1 = torch.nn.LayerNorm(dim)
|
||||
self.gin1 = nn.GINEConv(mlp1, train_eps=True).jittable()
|
||||
self.bn1 = nn.PairNorm() # nn.LayerNorm(dim) #torch.nn.BatchNorm1d(dim)
|
||||
|
||||
mlp2 = Sequential(Linear(dim, dim), ReLU(), Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.gin2 = nn.GINEConv(mlp2, train_eps=True).jittable()
|
||||
self.bn2 = nn.PairNorm() # nn.LayerNorm(dim) #torch.nn.BatchNorm1d(dim)
|
||||
self.e_mlp2 = Sequential(Linear(3*dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.ebn2 = torch.nn.LayerNorm(dim)
|
||||
|
||||
mlp3 = Sequential(Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.gin3 = nn.GINEConv(mlp3, train_eps=True).jittable()
|
||||
self.bn3 = nn.PairNorm() # nn.LayerNorm(dim)
|
||||
self.e_mlp3 = Sequential(Linear(3*dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.ebn3 = torch.nn.LayerNorm(dim)
|
||||
|
||||
self.out1 = torch.nn.Linear(3*dim, dim)
|
||||
self.out_bn = torch.nn.LayerNorm(dim)
|
||||
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)
|
||||
edge_attr = self.init_emlp(edge_attr)
|
||||
edge_attr = self.init_ebn(edge_attr)
|
||||
|
||||
x = F.relu(self.gin1(x, edge_index, edge_attr))
|
||||
x = self.bn1(x, batch)
|
||||
edge_attr = F.relu(self.e_mlp1(edge_attr))
|
||||
edge_attr = self.e_bn1(edge_attr)
|
||||
|
||||
x = F.relu(self.gin2(x, edge_index, edge_attr))
|
||||
x = self.bn2(x, batch)
|
||||
edge_attr = torch.cat([x[edge_index[0]], x[edge_index[1]], edge_attr],
|
||||
dim=1)
|
||||
edge_attr = self.e_mlp2(edge_attr)
|
||||
edge_attr = self.ebn2(edge_attr)
|
||||
|
||||
x = F.relu(self.gin3(x, edge_index, edge_attr))
|
||||
x = self.bn3(x, batch)
|
||||
edge_attr = torch.cat([x[edge_index[0]], x[edge_index[1]], edge_attr], dim=1)
|
||||
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):
|
||||
model = Net(
|
||||
num_features=2,
|
||||
num_edge_features=4,
|
||||
dim=64,
|
||||
)
|
||||
|
||||
loaded_weights = torch.load(model_file,
|
||||
map_location=torch.device('cpu'))
|
||||
model.load_state_dict(loaded_weights)
|
||||
|
||||
return model
|
||||
15
deepcut-ghidra/data/README.txt
Normal file
15
deepcut-ghidra/data/README.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
The "data" directory is intended to hold data files that will be used by this module and will
|
||||
not end up in the .jar file, but will be present in the zip or tar file. Typically, data
|
||||
files are placed here rather than in the resources directory if the user may need to edit them.
|
||||
|
||||
An optional data/languages directory can exist for the purpose of containing various Sleigh language
|
||||
specification files and importer opinion files.
|
||||
|
||||
The data/buildLanguage.xml is used for building the contents of the data/languages directory.
|
||||
|
||||
The skel language definition has been commented-out within the skel.ldefs file so that the
|
||||
skeleton language does not show-up within Ghidra.
|
||||
|
||||
See the Sleigh language documentation (docs/languages/index.html) for details Sleigh language
|
||||
specification syntax.
|
||||
|
||||
199
deepcut-ghidra/data/deepcut.py
Normal file
199
deepcut-ghidra/data/deepcut.py
Normal file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# © 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 json
|
||||
import sys
|
||||
import numpy as np
|
||||
|
||||
import torch
|
||||
|
||||
from math import log2, copysign
|
||||
from networkx import DiGraph
|
||||
from scipy.linalg import toeplitz
|
||||
|
||||
import GNN_Net
|
||||
|
||||
|
||||
class Deepcut:
|
||||
def __init__(self, fcg_data, model_file):
|
||||
self.fcg_data = fcg_data
|
||||
self.model_file = model_file
|
||||
|
||||
self.graph = DiGraph()
|
||||
self.functions = {}
|
||||
self.graph_connectivity = []
|
||||
self.node_features = []
|
||||
self.edge_features = []
|
||||
|
||||
self._generate_graph()
|
||||
self._generate_features()
|
||||
self._predicte_labels()
|
||||
|
||||
def _generate_graph(self):
|
||||
for f in self.fcg_data['functions']:
|
||||
self.graph.add_node(f['index'],
|
||||
num_inc=log2(2 + f['num_incoming_edges']),
|
||||
num_out=log2(2 + f['num_outgoing_edges']))
|
||||
self.functions[f['index']] = {
|
||||
'address': f['addr'],
|
||||
'name': f['name'],
|
||||
}
|
||||
|
||||
for e in self.fcg_data['edges']:
|
||||
index_dist_weight = copysign(log2(2 + abs(e['index_distance'])),
|
||||
e['index_distance'])
|
||||
address_dist_weight = copysign(log2(2 + abs(e['addr_distance'])),
|
||||
e['addr_distance']) / 4
|
||||
multiplicity_weight = log2(2 + abs(e['multiplicity']))
|
||||
|
||||
# The weight attribute is a 4-tuple. The multiplicity value
|
||||
# is 0.0 for the "opposite" direction
|
||||
self.graph.add_edge(e['src_index'], e['dst_index'],
|
||||
weights=(index_dist_weight,
|
||||
address_dist_weight,
|
||||
multiplicity_weight,
|
||||
0.0))
|
||||
|
||||
self.graph.add_edge(e['dst_index'], e['src_index'],
|
||||
weights=(-index_dist_weight,
|
||||
-address_dist_weight,
|
||||
0.0,
|
||||
multiplicity_weight))
|
||||
|
||||
def _generate_features(self):
|
||||
for n in sorted(list(self.graph.nodes)):
|
||||
self.node_features.append([self.graph.nodes[n]['num_out'],
|
||||
self.graph.nodes[n]['num_inc']])
|
||||
|
||||
for (n1, n2, d) in self.graph.edges(data=True):
|
||||
self.graph_connectivity.append([n1, n2])
|
||||
self.edge_features.append(list(d["weights"]))
|
||||
|
||||
def _predicte_labels(self):
|
||||
model = GNN_Net.load_gnn(self.model_file)
|
||||
m = model(x=torch.Tensor(self.node_features),
|
||||
edge_index=torch.LongTensor(self.graph_connectivity).t().contiguous(),
|
||||
edge_attr=torch.Tensor(self.edge_features),
|
||||
batch=torch.tensor([0] * len(self.graph)))
|
||||
|
||||
self.predicted_labels = torch.sigmoid(m).detach().numpy()
|
||||
|
||||
def _adjacency_matrix(self):
|
||||
num_funcs = len(self.graph.nodes)
|
||||
A = np.zeros((num_funcs, num_funcs))
|
||||
|
||||
for e, v in zip(self.graph_connectivity, self.predicted_labels):
|
||||
e0, e1 = e
|
||||
A[e0, e1] = v
|
||||
|
||||
A += A.T
|
||||
A *= 0.5
|
||||
|
||||
"""
|
||||
add a small connection between adjacent nodes,
|
||||
essentially to break ties in favor of merging communities
|
||||
"""
|
||||
x = np.zeros(num_funcs)
|
||||
x[1] = 0.05
|
||||
A += toeplitz(x)
|
||||
|
||||
return A
|
||||
|
||||
def _modularity(self):
|
||||
adj_matrix = self._adjacency_matrix()
|
||||
# node degrees
|
||||
k = np.sum(adj_matrix, axis=0)
|
||||
|
||||
k2 = np.array([k])
|
||||
B = k2.T @ k2
|
||||
B /= 2 * np.sum(k2)
|
||||
|
||||
Q = adj_matrix - B
|
||||
|
||||
def compute_partial_modularity(start, stop):
|
||||
return np.sum(Q[start:stop, start:stop])
|
||||
|
||||
scores = [0.0]
|
||||
scores = np.array(scores)
|
||||
cuts = [[0]]
|
||||
|
||||
# speedup so it runs in linear time
|
||||
max_cluster_size = 100
|
||||
|
||||
for index in range(1, len(self.graph.nodes)):
|
||||
update = [compute_partial_modularity(i, index) for i in
|
||||
range(max(0, index-max_cluster_size), index)]
|
||||
if index > max_cluster_size:
|
||||
update = [0]*(index-max_cluster_size) + update
|
||||
updated_scores = scores + update
|
||||
|
||||
i = np.argmax(updated_scores)
|
||||
|
||||
if index > max_cluster_size:
|
||||
i = np.argmax(updated_scores[index-max_cluster_size:])+ (index - max_cluster_size)
|
||||
|
||||
s = updated_scores[i]
|
||||
c = cuts[i] + [index]
|
||||
|
||||
scores = np.append(scores, s)
|
||||
cuts.append(c)
|
||||
|
||||
final_cut = cuts[-1]
|
||||
return final_cut
|
||||
|
||||
def module_list(self):
|
||||
cuts = self._modularity()
|
||||
return [self.functions[x] for x in cuts]
|
||||
|
||||
|
||||
def read_input():
|
||||
# Yes this expects the json to have no newlines
|
||||
inp = sys.stdin.readline()
|
||||
ret = json.loads(inp)
|
||||
return ret
|
||||
|
||||
|
||||
def main():
|
||||
fcg = read_input()
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
model_file = sys.argv[1]
|
||||
else:
|
||||
model_file = "model_weights_1.p"
|
||||
|
||||
d = Deepcut(fcg, model_file)
|
||||
|
||||
print(json.dumps(d.module_list()))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
deepcut-ghidra/data/model_weights_1.p
Normal file
BIN
deepcut-ghidra/data/model_weights_1.p
Normal file
Binary file not shown.
5
deepcut-ghidra/extension.properties
Normal file
5
deepcut-ghidra/extension.properties
Normal file
@@ -0,0 +1,5 @@
|
||||
name=@extname@
|
||||
description=Use the deepcut algorithm to find module boundaries.
|
||||
author=JHU/APL
|
||||
createdOn=
|
||||
version=@extversion@
|
||||
1
deepcut-ghidra/ghidra_scripts/README.txt
Normal file
1
deepcut-ghidra/ghidra_scripts/README.txt
Normal file
@@ -0,0 +1 @@
|
||||
Java source directory to hold module-specific Ghidra scripts.
|
||||
5
deepcut-ghidra/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
deepcut-ghidra/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
185
deepcut-ghidra/gradlew
vendored
Normal file
185
deepcut-ghidra/gradlew
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
deepcut-ghidra/gradlew.bat
vendored
Normal file
89
deepcut-ghidra/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
3
deepcut-ghidra/os/linux64/README.txt
Normal file
3
deepcut-ghidra/os/linux64/README.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The "os/linux64" directory is intended to hold Linux native binaries
|
||||
which this module is dependent upon. This directory may be eliminated for a specific
|
||||
module if native binaries are not provided for the corresponding platform.
|
||||
3
deepcut-ghidra/os/osx64/README.txt
Normal file
3
deepcut-ghidra/os/osx64/README.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The "os/osx64" directory is intended to hold macOS (OS X) native binaries
|
||||
which this module is dependent upon. This directory may be eliminated for a specific
|
||||
module if native binaries are not provided for the corresponding platform.
|
||||
3
deepcut-ghidra/os/win64/README.txt
Normal file
3
deepcut-ghidra/os/win64/README.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
The "os/win64" directory is intended to hold MS Windows native binaries (.exe)
|
||||
which this module is dependent upon. This directory may be eliminated for a specific
|
||||
module if native binaries are not provided for the corresponding platform.
|
||||
7
deepcut-ghidra/requirements-torch_geometric.txt
Normal file
7
deepcut-ghidra/requirements-torch_geometric.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
torch-geometric==1.6.3
|
||||
|
||||
--find-links https://pytorch-geometric.com/whl/torch-1.7.0+cpu.html
|
||||
torch-sparse==0.6.8
|
||||
torch-scatter==2.0.5
|
||||
torch-cluster==1.5.8
|
||||
torch-spline-conv==1.2.0
|
||||
57
deepcut-ghidra/src/main/help/help/TOC_Source.xml
Normal file
57
deepcut-ghidra/src/main/help/help/TOC_Source.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<?xml version='1.0' encoding='ISO-8859-1' ?>
|
||||
<!--
|
||||
|
||||
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
|
||||
upon the JavaHelp table of contents document format. The Ghidra help system uses a
|
||||
TOC_Source.xml file to allow a module with help to define how its contents appear in the
|
||||
Ghidra help viewer's table of contents. The main document (in the Base module)
|
||||
defines a basic structure for the
|
||||
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
|
||||
their files directly into this structure (and optionally define a substructure).
|
||||
|
||||
|
||||
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
|
||||
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
|
||||
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
|
||||
appropriate id attribute value. Using these two tags allows any module to define a place
|
||||
in the table of contents system (<tocdef>), which also provides a place for
|
||||
other TOC_Source.xml files to insert content (<tocref>).
|
||||
|
||||
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
|
||||
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
|
||||
<module name>_TOC.xml files, which are table of contents files written in the format
|
||||
desired by the JavaHelp system. Additionally, the genated files will be merged together
|
||||
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
|
||||
help GUI, there will be on table of contents that has been created from the definitions in
|
||||
all of the modules' TOC_Source.xml files.
|
||||
|
||||
|
||||
Tags and Attributes
|
||||
|
||||
<tocdef>
|
||||
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
|
||||
-text - the display text of the node, as seen in the help GUI
|
||||
-target** - the file to display when the node is clicked in the GUI
|
||||
-sortgroup - this is a string that defines where a given node should appear under a given
|
||||
parent. The string values will be sorted by the JavaHelp system using
|
||||
a javax.text.RulesBasedCollator. If this attribute is not specified, then
|
||||
the text of attribute will be used.
|
||||
|
||||
<tocref>
|
||||
-id - The id of the <tocdef> that this reference points to
|
||||
|
||||
**The URL for the target is relative and should start with 'help/topics'. This text is
|
||||
used by the Ghidra help system to provide a universal starting point for all links so that
|
||||
they can be resolved at runtime, across modules.
|
||||
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<tocroot>
|
||||
<!-- Uncomment and adjust fields to add help topic to help system's Table of Contents
|
||||
<tocref id="Ghidra Functionality">
|
||||
<tocdef id="HelpAnchor" text="My Feature" target="help/topics/my_topic/help.html" />
|
||||
</tocref>
|
||||
-->
|
||||
</tocroot>
|
||||
64
deepcut-ghidra/src/main/help/help/shared/Frontpage.css
Normal file
64
deepcut-ghidra/src/main/help/help/shared/Frontpage.css
Normal file
@@ -0,0 +1,64 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
WARNING!
|
||||
This file is copied to all help directories. If you change this file, you must copy it
|
||||
to each src/main/help/help/shared directory.
|
||||
|
||||
|
||||
Java Help Note: JavaHelp does not accept sizes (like in 'margin-top') in anything but
|
||||
px (pixel) or with no type marking.
|
||||
|
||||
*/
|
||||
|
||||
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
|
||||
li { font-family:times new roman; font-size:14pt; }
|
||||
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
|
||||
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
|
||||
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
|
||||
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
|
||||
|
||||
/*
|
||||
P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
|
||||
way it had been done in the beginning). The net effect is that the text is indented. In
|
||||
modern HTML we would use CSS to do this. We need to support the Ghidra P tags, nested in
|
||||
blockquote tags, as well as naked P tags. The following two lines accomplish this. Note
|
||||
that the 'blockquote p' definition will inherit from the first 'p' definition.
|
||||
*/
|
||||
p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
|
||||
blockquote p { margin-left: 10px; }
|
||||
|
||||
p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
|
||||
p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
|
||||
|
||||
/*
|
||||
We wish for a tables to have space between it and the preceding element, so that text
|
||||
is not too close to the top of the table. Also, nest the table a bit so that it is clear
|
||||
the table relates to the preceding text.
|
||||
*/
|
||||
table { margin-left: 20px; margin-top: 10px; width: 80%;}
|
||||
td { font-family:times new roman; font-size:14pt; vertical-align: top; }
|
||||
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
|
||||
|
||||
/*
|
||||
Code-like formatting for things such as file system paths and proper names of classes,
|
||||
methods, etc. To apply this to a file path, use this syntax:
|
||||
<CODE CLASS="path">...</CODE>
|
||||
*/
|
||||
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
|
||||
23
deepcut-ghidra/src/main/help/help/topics/deepcut/help.html
Normal file
23
deepcut-ghidra/src/main/help/help/topics/deepcut/help.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
<META http-equiv="Content-Language" content="en-us">
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<META name="ProgId" content="FrontPage.Editor.Document">
|
||||
|
||||
<TITLE>Skeleton Help File for a Module</TITLE>
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<H1><a name="HelpAnchor"></a>Skeleton Help File for a Module</H1>
|
||||
|
||||
<P>This is a simple skeleton help topic. For a better description of what should and should not
|
||||
go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
|
||||
favorite help topic. In general, language modules do not have their own help topics.</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
43
deepcut-ghidra/src/main/java/deepcut/Cut.java
Normal file
43
deepcut-ghidra/src/main/java/deepcut/Cut.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ###
|
||||
* © 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 ghidra.program.model.listing.Program;
|
||||
|
||||
class Cut {
|
||||
public String address;
|
||||
public String name;
|
||||
|
||||
public Cut(Program program, String address, String name) {
|
||||
this.address = address;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.address.toString() + ":" + this.name;
|
||||
}
|
||||
}
|
||||
165
deepcut-ghidra/src/main/java/deepcut/DeepCutAnalyzer.java
Normal file
165
deepcut-ghidra/src/main/java/deepcut/DeepCutAnalyzer.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/* ###
|
||||
* © 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 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;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.CircularDependencyException;
|
||||
import ghidra.program.model.listing.Function;
|
||||
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.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.
|
||||
*/
|
||||
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 = "/projects/venv/bin/python3";
|
||||
private String pythonExec = OPTION_DEFAULT_PYTHON_EXEC;
|
||||
|
||||
public DeepCutAnalyzer() {
|
||||
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
|
||||
setDefaultEnablement(false);
|
||||
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.after());
|
||||
setPrototype();
|
||||
setSupportsOneTimeAnalysis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDefaultEnablement(Program program) {
|
||||
// Only supports one-time analysis.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAnalyze(Program program) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
options.registerOption(OPTION_NAME_PYTHON_EXEC, pythonExec,
|
||||
null, OPTION_DESCRIPTION_PYTHON_EXEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
pythonExec = options.getString(OPTION_NAME_PYTHON_EXEC, pythonExec);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
deepcut.writeProcess(fcg.toJson() + "\n");
|
||||
deepcut.waitFor();
|
||||
|
||||
if (checkError(deepcut, log)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String cuts_json = deepcut.readProcessOutput();
|
||||
|
||||
|
||||
Cut[] cuts = new GsonBuilder().create().fromJson(cuts_json, Cut[].class);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function.setParentNamespace(namespace);
|
||||
}
|
||||
|
||||
}
|
||||
102
deepcut-ghidra/src/main/java/deepcut/DeepCutPython.java
Normal file
102
deepcut-ghidra/src/main/java/deepcut/DeepCutPython.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/* ###
|
||||
* © 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, stdin 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;
|
||||
}
|
||||
}
|
||||
91
deepcut-ghidra/src/main/java/deepcut/EdgeInfo.java
Normal file
91
deepcut-ghidra/src/main/java/deepcut/EdgeInfo.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/* ###
|
||||
* © 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;
|
||||
|
||||
class EdgeInfo {
|
||||
private FunctionInfo src;
|
||||
private FunctionInfo dst;
|
||||
|
||||
private int multiplicity;
|
||||
|
||||
/*
|
||||
distance between the two functions,
|
||||
either in terms of address
|
||||
or number of functions in between.
|
||||
*/
|
||||
private double addressDistance;
|
||||
private double indexDistance;
|
||||
|
||||
private boolean isSelfCall;
|
||||
|
||||
public EdgeInfo(FunctionInfo src, FunctionInfo dst, int multiplicity) {
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
|
||||
this.multiplicity = multiplicity;
|
||||
|
||||
this.addressDistance = (double) dst.getAddress().subtract(src.getAddress());
|
||||
this.indexDistance = (double) dst.getAddressIndex() - src.getAddressIndex();
|
||||
}
|
||||
|
||||
public FunctionInfo getSrc() {
|
||||
return src;
|
||||
}
|
||||
|
||||
public FunctionInfo getDst() {
|
||||
return dst;
|
||||
}
|
||||
|
||||
public int getMultiplicity() {
|
||||
return multiplicity;
|
||||
}
|
||||
|
||||
public double getAddressDistance() {
|
||||
return addressDistance;
|
||||
}
|
||||
|
||||
public double getIndexDistance() {
|
||||
return indexDistance;
|
||||
}
|
||||
|
||||
public boolean getisSelfCall() {
|
||||
return isSelfCall;
|
||||
}
|
||||
|
||||
public long getSrcAddressIndex() {
|
||||
return src.getAddressIndex();
|
||||
}
|
||||
|
||||
public long getDstAddressIndex() {
|
||||
return dst.getAddressIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%-20s -> %20-s\t#%d", src.getName(),
|
||||
dst.getName(), multiplicity);
|
||||
}
|
||||
}
|
||||
48
deepcut-ghidra/src/main/java/deepcut/EdgeInfoSerializer.java
Normal file
48
deepcut-ghidra/src/main/java/deepcut/EdgeInfoSerializer.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ###
|
||||
* © 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.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
class EdgeInfoSerializer implements JsonSerializer<EdgeInfo> {
|
||||
@Override
|
||||
public JsonElement serialize(EdgeInfo src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
|
||||
obj.addProperty("src_index", src.getSrcAddressIndex());
|
||||
obj.addProperty("dst_index", src.getDstAddressIndex());
|
||||
obj.addProperty("multiplicity", src.getMultiplicity());
|
||||
obj.addProperty("addr_distance", src.getAddressDistance());
|
||||
obj.addProperty("index_distance", src.getIndexDistance());
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
211
deepcut-ghidra/src/main/java/deepcut/FunctionCallGraph.java
Normal file
211
deepcut-ghidra/src/main/java/deepcut/FunctionCallGraph.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/* ###
|
||||
* © 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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.annotations.*;
|
||||
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.program.flatapi.FlatProgramAPI;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.FunctionIterator;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
|
||||
class FunctionCallGraph {
|
||||
private TaskMonitor monitor;
|
||||
private Program program;
|
||||
private FlatProgramAPI api;
|
||||
|
||||
// map from ghidra functions to my function class.
|
||||
public Map<Function, FunctionInfo> functionMap;
|
||||
|
||||
// list of functions, sorted by address
|
||||
@Expose(serialize = true)
|
||||
@SerializedName(value="functions")
|
||||
public List<FunctionInfo> functionList;
|
||||
|
||||
// Adjacency list of edges
|
||||
@Expose(serialize = true)
|
||||
@SerializedName(value="edges")
|
||||
public List<EdgeInfo> edgeList;
|
||||
|
||||
|
||||
public FunctionCallGraph(Program program, TaskMonitor monitor) {
|
||||
this.program = program;
|
||||
this.monitor = monitor;
|
||||
api = new FlatProgramAPI(program);
|
||||
|
||||
functionList = new ArrayList<FunctionInfo>();
|
||||
functionMap = new HashMap<Function, FunctionInfo>();
|
||||
edgeList = new ArrayList<EdgeInfo>();
|
||||
|
||||
createListOfFunctions();
|
||||
createListOfEdges();
|
||||
}
|
||||
|
||||
private void createListOfFunctions() {
|
||||
// Returns an iterator over all non-external functions in address (entry point) order.
|
||||
FunctionIterator iter = program.getFunctionManager().getFunctions(true);
|
||||
|
||||
int index = 0;
|
||||
while (iter.hasNext()) {
|
||||
Function function = iter.next();
|
||||
|
||||
FunctionInfo func_info = new FunctionInfo(function);
|
||||
func_info.setAddressIndex(index++);
|
||||
|
||||
functionList.add(func_info);
|
||||
functionMap.put(function, func_info);
|
||||
}
|
||||
}
|
||||
|
||||
private void createListOfEdges() {
|
||||
for (FunctionInfo func_info : functionList) {
|
||||
Function function = func_info.getFunction();
|
||||
|
||||
Map<Function, Integer> hm = getCountCallingFunctions(function);
|
||||
|
||||
for (Map.Entry<Function, Integer> val : hm.entrySet()) {
|
||||
Function src = val.getKey();
|
||||
int multiplicity = val.getValue();
|
||||
|
||||
// no idea why, but sometimes `src` is null.
|
||||
if (src == null) continue;
|
||||
|
||||
// set the `is_recursive` flag if the function calls itself
|
||||
if(function.equals(src)) {
|
||||
func_info.setIsRecursive(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// create the edge and add it to each list.
|
||||
FunctionInfo src_func_info = functionMap.get(src);
|
||||
EdgeInfo edge_info = new EdgeInfo(src_func_info, func_info, multiplicity);
|
||||
edgeList.add(edge_info);
|
||||
func_info.addIncomingEdge(edge_info);
|
||||
src_func_info.addOutgoingEdge(edge_info);
|
||||
}
|
||||
// remove the recursive call, if applicable.
|
||||
// Note: does nothing if `function` not in `hm`
|
||||
hm.remove(function);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
return a hashmap of the number of times each function calls this function.
|
||||
*/
|
||||
private Map<Function, Integer> getCountCallingFunctions(Function function) {
|
||||
|
||||
// hashmap to store the frequency of element
|
||||
Map<Function, Integer> hm = new HashMap<Function, Integer>();
|
||||
|
||||
/*
|
||||
first populate the hashmap with all the calling functions.
|
||||
this is needed b/c `getCallingFunctions` returns some functions which
|
||||
`getReferencesTo` doesn't pick up on.
|
||||
|
||||
I think this is b/c `getCallingFunctions` just tracks any xref.
|
||||
*/
|
||||
Set<Function> calling_funcs = function.getCallingFunctions(monitor);
|
||||
|
||||
for (Function f : calling_funcs) {
|
||||
hm.put(f, 0);
|
||||
}
|
||||
|
||||
// then populate the counts
|
||||
Address entryPoint = function.getEntryPoint();
|
||||
Reference[] references = api.getReferencesTo(entryPoint);
|
||||
|
||||
ArrayList<Function> func_list = new ArrayList<Function>();
|
||||
|
||||
for(Reference r : references) {
|
||||
RefType rt = r.getReferenceType();
|
||||
boolean xref_is_call = rt.isCall() || rt.isJump();
|
||||
if (xref_is_call) {
|
||||
Address toAddress = r.getFromAddress();
|
||||
Function func = api.getFunctionContaining(toAddress);
|
||||
func_list.add(func);
|
||||
}
|
||||
}
|
||||
|
||||
for (Function f : func_list) {
|
||||
Integer j = hm.get(f);
|
||||
hm.put(f, (j == null) ? 1 : j + 1);
|
||||
}
|
||||
|
||||
return hm;
|
||||
}
|
||||
|
||||
public List<FunctionInfo> getFunctionInfos() {
|
||||
return functionList;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.registerTypeAdapter(FunctionInfo.class, new FunctionInfoSerializer())
|
||||
.registerTypeAdapter(EdgeInfo.class, new EdgeInfoSerializer())
|
||||
.create();
|
||||
|
||||
return gson.toJson(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("Function List:\n");
|
||||
|
||||
for(FunctionInfo fi : functionList) {
|
||||
str.append("{\"name\": \"" + fi.getName() +
|
||||
"\", \"addr\": \"0x" + fi.getAddress() +
|
||||
"\", \"idx\": " + fi.getAddressIndex() +
|
||||
", \"num_incoming_edges\": " + fi.getIncomingEdges().size() +
|
||||
", \"num_outgoing_edges\": " + fi.getOutgoingEdges().size() + "}\n");
|
||||
}
|
||||
|
||||
str.append("\nEdge List:\n");
|
||||
for(EdgeInfo ei : edgeList) {
|
||||
str.append("{\"src_idx\": " + ei.getSrc().getAddressIndex() +
|
||||
", \"dst_idx\": " + ei.getDst().getAddressIndex() +
|
||||
", \"multiplicity\": " + ei.getMultiplicity() +
|
||||
", \"addr_dst\": " + ei.getAddressDistance() +
|
||||
", \"idx_dst\": " + ei.getIndexDistance() + "}\n");
|
||||
}
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
129
deepcut-ghidra/src/main/java/deepcut/FunctionInfo.java
Normal file
129
deepcut-ghidra/src/main/java/deepcut/FunctionInfo.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/* ###
|
||||
* © 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.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
||||
class FunctionInfo {
|
||||
private Function function;
|
||||
|
||||
private Address address;
|
||||
private long addressIndex;
|
||||
|
||||
private String name;
|
||||
|
||||
// `true` if the function is either external or a thunk function.
|
||||
private boolean isExternalThunk;
|
||||
|
||||
private List<EdgeInfo> incomingEdges;
|
||||
private List<EdgeInfo> outgoingEdges;
|
||||
|
||||
// `true` if the function ever calls itself
|
||||
private boolean isRecursive;
|
||||
|
||||
public FunctionInfo(Function function) {
|
||||
this.function = function;
|
||||
address = function.getEntryPoint();
|
||||
name = function.getName();
|
||||
|
||||
// will be set in a later pass
|
||||
addressIndex = -1;
|
||||
isRecursive = false;
|
||||
|
||||
isExternalThunk = function.isThunk() || function.isExternal() ||
|
||||
(!function.getParentNamespace().isGlobal());
|
||||
|
||||
incomingEdges = new ArrayList<EdgeInfo>();
|
||||
outgoingEdges = new ArrayList<EdgeInfo>();
|
||||
}
|
||||
|
||||
public void addIncomingEdge(EdgeInfo edge) {
|
||||
incomingEdges.add(edge);
|
||||
}
|
||||
|
||||
public List<EdgeInfo> getIncomingEdges() {
|
||||
return incomingEdges;
|
||||
}
|
||||
|
||||
public int getIncomingEdgeSize() {
|
||||
return incomingEdges.size();
|
||||
}
|
||||
|
||||
public void addOutgoingEdge(EdgeInfo edge) {
|
||||
outgoingEdges.add(edge);
|
||||
}
|
||||
|
||||
public List<EdgeInfo> getOutgoingEdges() {
|
||||
return outgoingEdges;
|
||||
}
|
||||
|
||||
public int getOutgoingEdgeSize() {
|
||||
return outgoingEdges.size();
|
||||
}
|
||||
|
||||
public Function getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
public void setIsRecursive(boolean val) {
|
||||
isRecursive = val;
|
||||
}
|
||||
|
||||
public boolean getIsRecursive() {
|
||||
return isRecursive;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddressIndex(int index) {
|
||||
this.addressIndex = index;
|
||||
}
|
||||
|
||||
public long getAddressIndex() {
|
||||
return addressIndex;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getFunction().getName() + " " + address +
|
||||
" (" + addressIndex + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +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.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
class FunctionInfoSerializer implements JsonSerializer<FunctionInfo> {
|
||||
@Override
|
||||
public JsonElement serialize(FunctionInfo src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("name", src.getName());
|
||||
obj.addProperty("addr", src.getAddress().toString());
|
||||
obj.addProperty("index", src.getAddressIndex());
|
||||
obj.addProperty("num_incoming_edges", src.getIncomingEdges().size());
|
||||
obj.addProperty("num_outgoing_edges", src.getOutgoingEdges().size());
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
2
deepcut-ghidra/src/main/resources/images/README.txt
Normal file
2
deepcut-ghidra/src/main/resources/images/README.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
The "src/resources/images" directory is intended to hold all image/icon files used by
|
||||
this module.
|
||||
2
deepcut-ghidra/src/test/java/README.test.txt
Normal file
2
deepcut-ghidra/src/test/java/README.test.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
The "test" directory is intended to hold unit test cases. The package structure within
|
||||
this folder should correspond to that found in the "src" folder.
|
||||
Reference in New Issue
Block a user