22 Commits
v1.0 ... master

Author SHA1 Message Date
Vivian M
5207d70934 updated troubleshooting 2025-10-08 12:04:41 -04:00
Vivian M
d9bfeff6b7 removed debugging print statement 2025-10-08 11:59:43 -04:00
Vivian M
04181bce35 updated Readme with PyGhidra changes 2025-10-08 11:58:56 -04:00
evm
8fbf5c8cf7 Add copyright statements 2025-09-30 12:46:20 -04:00
evm-sec
20c9025d24 Merge pull request #4 from JHUAPL/pyghidra_sept25
Pyghidra sept25
2025-09-27 11:49:38 -04:00
Vivian M
8d26ba6e0b pyghidra changes, not including modnaming refactor 2025-09-26 13:24:50 -04:00
Vivian M
bbc19924e3 changed everything to use pyGhidra 2025-09-18 16:00:39 -04:00
Vivian M
b657cf2782 mod naming direct port runs with pyghidra 2025-09-16 20:13:02 -04:00
Maloney, Vivian
2a77c349b8 deepcut works with pyGhida 2025-09-12 14:07:48 -04:00
evm
22c0a93da4 For Ghidra 11.2 - old "Python" API now moved to "Jython" 2024-12-04 14:11:34 -05:00
evm
3953e9d357 tweak Readme 2024-09-25 15:15:44 -04:00
evm
046f4706d2 Modernize DeepCut script's torch usage, update README 2024-09-25 15:07:47 -04:00
evm-sec
f2901905ea Merge pull request #3 from AndreQuimper/dev
fixed to use eventType enum class and addition of graphing module
2024-09-10 11:13:00 -04:00
AndreQuimper
bec42aa376 addition of graphcut module
Addition of GraphCut module allows graphing of Namespaces and their relationships. Also allows for filtering through the CodeCut table.
2024-06-24 15:26:59 -04:00
AndreQuimper
9400cc6c69 updated to use of eventType enum
Since eventType objects changed from constant integers to enum classes we can no longer do switch statements with them (their IDs are not constant).
2024-05-29 14:35:26 -04:00
evm
44dbcdce55 Final minor tweaks for CodeCut 1.1 release 2023-11-22 15:37:45 -05:00
evm
b1a348bc48 Adding recompilable C scripts - staging changes for next release 2023-11-12 19:00:10 -05:00
evm
cab7f1774c Added updated OutputObjFile.py (still doesn't kick off quite right from GUI) - other minor fixes 2023-04-05 16:59:49 -04:00
evm
a7dd1a2916 Minor cleanup stuff in recomp C 2023-02-23 15:26:15 -05:00
evm
1b169e834f recomp C bugfixes from hackathon 2023-02-23 15:12:50 -05:00
evm
4829f1c12b Adding latest on filtering and decompiling a range 2023-02-23 11:10:17 -05:00
evm
b56b6e583c Updating legal comments 2023-02-23 11:04:21 -05:00
114 changed files with 9554 additions and 61356 deletions

View File

@@ -1,848 +0,0 @@
#-------------------------------------------------------------------------------
#
# IDAPython script to show many features extracted from debugging strings. It's
# also able to rename functions based on the guessed function name & rename
# functions based on the source code file they belong to.
#
# Copyright (c) 2018-2019, Joxean Koret
# Licensed under the GNU Affero General Public License v3.
#
#-------------------------------------------------------------------------------
from __future__ import print_function
import os
import re
from collections import Counter
import idaapi
from idc import *
from idaapi import *
from idautils import *
from PyQt5 import QtCore, QtGui, QtWidgets
try:
import nltk
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
has_nltk = True
except ImportError:
has_nltk = False
#-------------------------------------------------------------------------------
PROGRAM_NAME = "IMS"
#-------------------------------------------------------------------------------
SOURCE_FILES_REGEXP = r"([a-z_\/\\][a-z0-9_/\\:\-\.@]+\.(c|cc|cxx|c\+\+|cpp|h|hpp|m|rs|go|ml))($|:| )"
LANGS = {}
LANGS["C/C++"] = ["c", "cc", "cxx", "cpp", "h", "hpp"]
LANGS["C"] = ["c"]
LANGS["C++"] = ["cc", "cxx", "cpp", "hpp", "c++"]
LANGS["Obj-C"] = ["m"]
LANGS["Rust"] = ["rs"]
LANGS["Golang"] = ["go"]
LANGS["OCaml"] = ["ml"]
#-------------------------------------------------------------------------------
FUNCTION_NAMES_REGEXP = r"([a-z_][a-z0-9_]+((::)+[a-z_][a-z0-9_]+)*)"
CLASS_NAMES_REGEXP = r"([a-z_][a-z0-9_]+(::(<[a-z0-9_]+>|~{0,1}[a-z0-9_]+))+)\({0,1}"
NOT_FUNCTION_NAMES = ["copyright", "char", "bool", "int", "unsigned", "long",
"double", "float", "signed", "license", "version", "cannot", "error",
"invalid", "null", "warning", "general", "argument", "written", "report",
"failed", "assert", "object", "integer", "unknown", "localhost", "native",
"memory", "system", "write", "read", "open", "close", "help", "exit", "test",
"return", "libs", "home", "ambiguous", "internal", "request", "inserting",
"deleting", "removing", "updating", "adding", "assertion", "flags",
"overflow", "enabled", "disabled", "enable", "disable", "virtual", "client",
"server", "switch", "while", "offset", "abort", "panic", "static", "updated",
"pointer", "reason", "month", "year", "week", "hour", "minute", "second",
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august',
'september', 'october', 'november', 'december', "arguments", "corrupt",
"corrupted", "default", "success", "expecting", "missing", "phrase",
"unrecognized", "undefined",
]
#-------------------------------------------------------------------------------
FOUND_TOKENS = {}
TOKEN_TYPES = ["NN", "NNS", "NNP", "JJ", "VB", "VBD", "VBG", "VBN", "VBP", "VBZ"]
def nltk_preprocess(strings):
if not has_nltk:
return
strings = "\n".join(map(str, list(strings)))
tokens = re.findall(FUNCTION_NAMES_REGEXP, strings)
l = []
for token in tokens:
l.append(token[0])
word_tags = nltk.pos_tag(l)
for word, tag in word_tags:
try:
FOUND_TOKENS[word.lower()].add(tag)
except:
FOUND_TOKENS[word.lower()] = set([tag])
#-------------------------------------------------------------------------------
def get_strings(strtypes = [0, 1]):
strings = Strings()
strings.setup(strtypes = strtypes)
return strings
#-------------------------------------------------------------------------------
def get_lang(full_path):
_, file_ext = os.path.splitext(full_path.lower())
file_ext = file_ext.strip(".")
for key in LANGS:
if file_ext in LANGS[key]:
return key
return None
#-------------------------------------------------------------------------------
def add_source_file_to(d, src_langs, refs, full_path, s):
if full_path not in d:
d[full_path] = []
lang = get_lang(full_path)
if lang is not None:
src_langs[lang] += 1
for ref in refs:
d[full_path].append([ref, get_func_name(ref), str(s)])
return d, src_langs
#-------------------------------------------------------------------------------
def get_source_strings(min_len = 4, strtypes = [0, 1]):
strings = get_strings(strtypes)
# Search string references to source files
src_langs = Counter()
total_files = 0
d = {}
for s in strings:
if s and s.length > min_len:
ret = re.findall(SOURCE_FILES_REGEXP, str(s), re.IGNORECASE)
if ret and len(ret) > 0:
refs = list(DataRefsTo(s.ea))
if len(refs) > 0:
total_files += 1
full_path = ret[0][0]
d, src_langs = add_source_file_to(d, src_langs, refs, full_path, s)
# Use the loaded debugging information (if any) to find source files
for f in list(Functions()):
done = False
func = idaapi.get_func(f)
if func is not None:
cfg = idaapi.FlowChart(func)
for block in cfg:
if done:
break
for head in list(Heads(block.start_ea, block.end_ea)):
full_path = get_sourcefile(head)
if full_path is not None:
total_files += 1
d, src_langs = add_source_file_to(d, src_langs, [head], full_path, "Symbol: %s" % full_path)
nltk_preprocess(strings)
if len(d) > 0 and total_files > 0:
print("Programming languages found:\n")
for key in src_langs:
print(" %s %f%%" % (key.ljust(10), src_langs[key] * 100. / total_files))
print("\n")
return d, strings
#-------------------------------------------------------------------------------
def handler(item, column_no):
ea = item.ea
if is_mapped(ea):
jumpto(ea)
#-------------------------------------------------------------------------------
class CBaseTreeViewer(PluginForm):
def populate_tree(self, d):
# Clear previous items
self.tree.clear()
# Build the tree
for key in d:
src_file_item = QtWidgets.QTreeWidgetItem(self.tree)
src_file_item.setText(0, key)
src_file_item.ea = BADADDR
for ea, name, str_data in d[key]:
item = QtWidgets.QTreeWidgetItem(src_file_item)
item.setText(0, "%s [0x%08x] %s" % (name, ea, str_data))
item.ea = ea
self.tree.itemDoubleClicked.connect(handler)
def OnCreate(self, form):
# Get parent widget
self.parent = idaapi.PluginForm.FormToPyQtWidget(form)
# Create tree control
self.tree = QtWidgets.QTreeWidget()
self.tree.setHeaderLabels(("Names",))
self.tree.setColumnWidth(0, 100)
if self.d is None:
self.d, self.s = get_source_strings()
d = self.d
# Create layout
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tree)
self.populate_tree(d)
# Populate PluginForm
self.parent.setLayout(layout)
def Show(self, title, d = None):
self.d = d
return PluginForm.Show(self, title, options = PluginForm.WOPN_PERSIST)
#-------------------------------------------------------------------------------
def basename(path):
pos1 = path[::-1].find("\\")
pos2 = path[::-1].find("/")
if pos1 == -1: pos1 = len(path)
if pos2 == -1: pos2 = len(path)
pos = min(pos1, pos2)
return path[len(path)-pos:]
#-------------------------------------------------------------------------------
class command_handler_t(ida_kernwin.action_handler_t):
def __init__(self, obj, cmd_id, num_args = 1):
self.obj = obj
self.cmd_id = cmd_id
self.num_args = num_args
ida_kernwin.action_handler_t.__init__(self)
def activate(self, ctx):
if self.num_args == 1:
return self.obj.OnCommand(self.cmd_id)
return self.obj.OnCommand(self.obj, self.cmd_id)
def update(self, ctx):
return idaapi.AST_ENABLE_ALWAYS
#-------------------------------------------------------------------------------
class CIDAMagicStringsChooser(Choose):
def __init__(self, title, columns, options):
Choose.__init__(self, title, columns, options)
self.actions = []
def AddCommand(self, menu_name, shortcut=None):
action_name = "IDAMagicStrings:%s" % menu_name.replace(" ", "")
self.actions.append([len(self.actions), action_name, menu_name, shortcut])
return len(self.actions)-1
def OnPopup(self, form, popup_handle):
for num, action_name, menu_name, shortcut in self.actions:
handler = command_handler_t(self, num, 2)
desc = ida_kernwin.action_desc_t(action_name, menu_name, handler, shortcut)
ida_kernwin.attach_dynamic_action_to_popup(form, popup_handle, desc)
#-------------------------------------------------------------------------------
class CSourceFilesChooser(CIDAMagicStringsChooser):
def __init__(self, title):
columns = [ ["Line", 4], ["Full path", 20], ["Filename", 15], ["EA", 16], ["Function Name", 18], ["String data", 40], ]
CIDAMagicStringsChooser.__init__(self, title, columns, Choose.CH_MULTI)
self.n = 0
self.icon = -1
self.selcount = 0
self.modal = False
self.items = []
self.selected_items = []
d, s = get_source_strings()
keys = list(d.keys())
keys.sort()
i = 0
for key in keys:
for ea, name, str_data in d[key]:
line = ["%03d" % i, key, basename(key), "0x%08x" % ea, name, str_data]
self.items.append(line)
i += 1
self.d = d
self.s = s
def show(self):
ret = self.Show(False)
if ret < 0:
return False
self.cmd_all = self.AddCommand("Rename all to filename_EA")
self.cmd_all_sub = self.AddCommand("Rename all sub_* to filename_EA")
self.cmd_selected = self.AddCommand("Rename selected to filename_EA")
self.cmd_selected_sub = self.AddCommand("Rename selected sub_* to filename_EA")
return self.d
def OnCommand(self, n, cmd_id):
# Aditional right-click-menu commands handles
if cmd_id == self.cmd_all:
l = list(range(len(self.items)))
elif cmd_id == self.cmd_all_sub:
l = []
for i, item in enumerate(self.items):
if item[4] is not None and item[4].startswith("sub_"):
l.append(i)
elif cmd_id == self.cmd_selected:
l = list(self.selected_items)
elif cmd_id == self.cmd_selected_sub:
l = []
for i, item in enumerate(self.items):
if item[4].startswith("sub_"):
if i in self.selected_items:
l.append(i)
self.rename_items(l)
def rename_items(self, items):
for i in items:
item = self.items[i]
ea = int(item[3], 16)
candidate, _ = os.path.splitext(item[2])
name = "%s_%08x" % (candidate, ea)
func = idaapi.get_func(ea)
if func is not None:
ea = func.start_ea
set_name(ea, name, SN_CHECK)
else:
line = "WARNING: Cannot rename 0x%08x to %s because there is no function associated."
print(line % (ea, name))
def OnGetLine(self, n):
return self.items[n]
def OnGetSize(self):
n = len(self.items)
return n
def OnDeleteLine(self, n):
del self.items[n]
return n
def OnRefresh(self, n):
return n
def OnSelectLine(self, n):
self.selcount += 1
row = self.items[n[0]]
ea = int(row[3], 16)
if is_mapped(ea):
jumpto(ea)
def OnSelectionChange(self, sel_list):
self.selected_items = sel_list
#-------------------------------------------------------------------------------
class CCandidateFunctionNames(CIDAMagicStringsChooser):
def __init__(self, title, l):
columns = [ ["Line", 4], ["EA", 16], ["Function Name", 25], ["Candidate", 25], ["FP?", 2], ["Strings", 50], ]
CIDAMagicStringsChooser.__init__(self, title, columns, Choose.CH_MULTI)
self.n = 0
self.icon = -1
self.selcount = 0
self.modal = False
self.items = []
self.selected_items = []
i = 0
for item in l:
bin_func = item[1]
candidate = item[2]
seems_false = str(int(self.looks_false(bin_func, candidate)))
line = ["%03d" % i, "0x%08x" % item[0], item[1], item[2], seems_false, ", ".join(item[3]) ]
self.items.append(line)
i += 1
self.items = sorted(self.items, key=lambda x: x[4])
def show(self):
ret = self.Show(False)
if ret < 0:
return False
self.cmd_rename_all = self.AddCommand("Rename all functions")
self.cmd_rename_sub = self.AddCommand("Rename all sub_* functions")
self.cmd_rename_selected = self.AddCommand("Rename selected function(s)")
self.cmd_rename_sub_sel = self.AddCommand("Rename selected sub_* function(s)")
def OnCommand(self, n, cmd_id):
# Aditional right-click-menu commands handles
if cmd_id == self.cmd_rename_all:
l = list(range(len(self.items)))
elif cmd_id == self.cmd_rename_selected:
l = list(self.selected_items)
elif cmd_id == self.cmd_rename_sub:
l = []
for i, item in enumerate(self.items):
if item[2].startswith("sub_"):
l.append(i)
elif cmd_id == self.cmd_rename_sub_sel:
l = []
for i, item in enumerate(self.items):
if item[2].startswith("sub_"):
if i in self.selected_items:
l.append(i)
else:
raise Exception("Unknown menu command!")
self.rename_items(l)
def rename_items(self, items):
for i in items:
item = self.items[i]
ea = int(item[1], 16)
candidate = item[3]
set_name(ea, candidate, SN_CHECK)
def OnGetLine(self, n):
return self.items[n]
def OnGetSize(self):
n = len(self.items)
return n
def OnDeleteLine(self, n):
del self.items[n]
return n
def OnRefresh(self, n):
return n
def OnSelectLine(self, n):
self.selcount += 1
row = self.items[n[0]]
ea = int(row[1], 16)
if is_mapped(ea):
jumpto(ea)
def OnSelectionChange(self, sel_list):
self.selected_items = sel_list
def looks_false(self, bin_func, candidate):
bin_func = bin_func.lower()
candidate = candidate.lower()
if not bin_func.startswith("sub_"):
if bin_func.find(candidate) == -1 and candidate.find(bin_func) == -1:
return True
return False
def OnGetLineAttr(self, n):
item = self.items[n]
bin_func = item[2]
candidate = item[3]
if self.looks_false(bin_func, candidate):
return [0x026AFD, 0]
return [0xFFFFFF, 0]
#-------------------------------------------------------------------------------
class CClassXRefsChooser(idaapi.Choose):
def __init__(self, title, items):
idaapi.Choose.__init__(self,
title,
[ ["Address", 8], ["String", 80] ])
self.items = items
def OnGetLine(self, n):
return self.items[n]
def OnGetSize(self):
return len(self.items)
#-------------------------------------------------------------------------------
def get_string(ea):
tmp = idc.get_strlit_contents(ea, strtype=0)
if tmp is None or len(tmp) == 1:
unicode_tmp = idc.get_strlit_contents(ea, strtype=1)
if unicode_tmp is not None and len(unicode_tmp) > len(tmp):
tmp = unicode_tmp
if tmp is None:
tmp = ""
elif type(tmp) != str:
tmp = tmp.decode("utf-8")
return tmp
#-------------------------------------------------------------------------------
def classes_handler(item, column_no):
if item.childCount() == 0:
ea = item.ea
if is_mapped(ea):
jumpto(ea)
#-------------------------------------------------------------------------------
class CClassesTreeViewer(PluginForm):
def populate_tree(self):
# Clear previous items
self.tree.clear()
self.nodes = {}
self.classes = sorted(self.classes, key=lambda x: x[1][0])
for ea, tokens in self.classes:
for i, node_name in enumerate(tokens):
full_name = "::".join(tokens[:tokens.index(node_name)+1])
if full_name not in self.nodes:
if full_name.find("::") == -1:
parent = self.tree
else:
parent_name = "::".join(tokens[:tokens.index(node_name)])
try:
parent = self.nodes[parent_name]
except:
print("Error adding node?", self.nodes, parent_name, str(sys.exc_info()[1]))
node = QtWidgets.QTreeWidgetItem(parent)
node.setText(0, full_name)
node.ea = ea
self.nodes[full_name] = node
self.tree.itemDoubleClicked.connect(classes_handler)
def OnCreate(self, form):
# Get parent widget
self.parent = idaapi.PluginForm.FormToPyQtWidget(form)
# Create tree control
self.tree = QtWidgets.QTreeWidget()
self.tree.setHeaderLabels(("Classes",))
self.tree.setColumnWidth(0, 100)
# Create layout
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tree)
self.populate_tree()
# Populate PluginForm
self.parent.setLayout(layout)
def Show(self, title, classes):
self.classes = classes
return PluginForm.Show(self, title, options = PluginForm.WOPN_PERSIST)
#-------------------------------------------------------------------------------
class CClassesGraph(idaapi.GraphViewer):
def __init__(self, title, classes, final_list):
idaapi.GraphViewer.__init__(self, title)
self.selected = None
self.classes = classes
self.final_list = final_list
self.nodes = {}
self.nodes_ea = {}
self.graph = {}
self.last_cmd = 0
dones = set()
for ea, tokens in self.classes:
refs = DataRefsTo(ea)
refs_funcs = set()
for ref in refs:
func = idaapi.get_func(ref)
if func is not None:
refs_funcs.add(func.start_ea)
if len(refs_funcs) == 1:
func_ea = list(refs_funcs)[0]
if func_ea in dones:
continue
dones.add(func_ea)
func_name = get_func_name(func_ea)
tmp = demangle_name(func_name, INF_SHORT_DN)
if tmp is not None:
func_name = tmp
element = [func_ea, func_name, "::".join(tokens), [get_string(ea)]]
self.final_list.append(element)
def OnRefresh(self):
self.Clear()
self.graph = {}
for ea, tokens in self.classes:
for node_name in tokens:
full_name = "::".join(tokens[:tokens.index(node_name)+1])
if full_name not in self.nodes:
node_id = self.AddNode(node_name)
self.nodes[full_name] = node_id
self.graph[node_id] = []
else:
node_id = self.nodes[full_name]
try:
self.nodes_ea[node_id].add(ea)
except KeyError:
self.nodes_ea[node_id] = set([ea])
parent_name = "::".join(tokens[:tokens.index(node_name)])
if parent_name != "" and parent_name in self.nodes:
parent_id = self.nodes[parent_name]
self.AddEdge(parent_id, node_id)
self.graph[parent_id].append(node_id)
return True
def OnGetText(self, node_id):
return str(self[node_id])
def OnDblClick(self, node_id):
eas = self.nodes_ea[node_id]
if len(eas) == 1:
jumpto(list(eas)[0])
else:
items = []
for ea in eas:
func = idaapi.get_func(ea)
if func is None:
s = get_strlit_contents(ea)
s = s.decode("utf-8")
if s is not None and s.find(str(self[node_id])) == -1:
s = get_strlit_contents(ea, strtype=1)
else:
s = GetDisasm(ea)
else:
s = get_func_name(func.start_ea)
items.append(["0x%08x" % ea, repr(s)])
chooser = CClassXRefsChooser("XRefs to %s" % str(self[node_id]), items)
idx = chooser.Show(1)
if idx > -1:
jumpto(list(eas)[idx])
def OnCommand(self, cmd_id):
if self.cmd_dot == cmd_id:
fname = ask_file(1, "*.dot", "Dot file name")
if fname:
f = open(fname, "w")
buf = 'digraph G {\n graph [overlap=scale]; node [fontname=Courier]; \n\n'
for n in self.graph:
name = str(self[n])
buf += ' a%s [shape=box, label = "%s", color="blue"]\n' % (n, name)
buf += '\n'
dones = set()
for node_id in self.graph:
for child_id in self.graph[node_id]:
s = str([node_id, child_id])
if s in dones:
continue
dones.add(s)
buf += " a%s -> a%s [style = bold]\n" % (node_id, child_id)
buf += '\n'
buf += '}'
f.write(buf)
f.close()
elif self.cmd_gml == cmd_id:
fname = ask_file(1, "*.gml", "GML file name")
if fname:
f = open(fname, "w")
buf = 'graph [ \n'
for n in self.graph:
name = str(self[n])
buf += 'node [ id %s \n label "%s"\n fill "blue" \n type "oval"\n LabelGraphics [ type "text" ] ] \n' % (n, name)
buf += '\n'
dones = set()
for node_id in self.graph:
for child_id in self.graph[node_id]:
s = str([node_id, child_id])
if s in dones:
continue
dones.add(s)
buf += " edge [ source %s \n target %s ]\n" % (node_id, child_id)
buf += '\n'
buf += ']'
f.write(buf)
f.close()
def OnPopup(self, form, popup_handle):
self.cmd_dot = 0
cmd_handler = command_handler_t(self, self.cmd_dot)
desc = ida_kernwin.action_desc_t("IDAMagicStrings:GraphvizExport", "Export to Graphviz",
cmd_handler, "F2")
ida_kernwin.attach_dynamic_action_to_popup(form, popup_handle, desc)
self.cmd_gml = 1
cmd_handler = command_handler_t(self, self.cmd_gml)
desc = ida_kernwin.action_desc_t("IDAMagicStrings:GmlExport","Export to GML",
cmd_handler, "F3")
ida_kernwin.attach_dynamic_action_to_popup(form, popup_handle, desc)
def OnClick(self, item):
self.selected = item
return True
def Show(self):
if not idaapi.GraphViewer.Show(self):
return False
return True
#-------------------------------------------------------------------------------
def show_tree(d = None):
tree_frm = CBaseTreeViewer()
tree_frm.Show(PROGRAM_NAME + ": Source code tree", d)
#-------------------------------------------------------------------------------
def seems_function_name(candidate):
if len(candidate) >= 6 and candidate.lower() not in NOT_FUNCTION_NAMES:
if candidate.upper() != candidate:
return True
return False
#-------------------------------------------------------------------------------
class CFakeString:
def __init__(self, ea, s):
self.ea = ea
self.s = s
def __str__(self):
return str(self.s)
def __repr__(self):
return self.__str__()
#-------------------------------------------------------------------------------
def find_function_names(strings_list):
rarity = {}
func_names = {}
raw_func_strings = {}
class_objects = []
class_tmp_names = []
for ea, name in Names():
func = idaapi.get_func(ea)
if func is None:
continue
true_name = name
if name.find("::") == -1:
name = demangle_name(name, INF_SHORT_DN)
if name is not None and name != "" and name.find("::") > -1:
true_name = name
if true_name.find("::") > -1:
s = CFakeString(ea, true_name)
class_tmp_names.append(s)
class_tmp_names.extend(strings_list)
for s in class_tmp_names:
# Find class members
class_ret = re.findall(CLASS_NAMES_REGEXP, str(s), re.IGNORECASE)
if len(class_ret) > 0:
for element in class_ret:
candidate = element[0]
if candidate.find("::") > 0:
tokens = candidate.split("::")
if tokens not in class_objects:
class_objects.append([s.ea, tokens])
# Find just function names
ret = re.findall(FUNCTION_NAMES_REGEXP, str(s), re.IGNORECASE)
if len(ret) > 0:
candidate = ret[0][0]
if seems_function_name(candidate):
ea = s.ea
refs = DataRefsTo(ea)
found = False
for ref in refs:
func = idaapi.get_func(ref)
if func is not None:
found = True
key = func.start_ea
if has_nltk:
if candidate not in FOUND_TOKENS:
continue
found = False
for tkn_type in TOKEN_TYPES:
if tkn_type in FOUND_TOKENS[candidate]:
found = True
break
if not found:
continue
try:
rarity[candidate].add(key)
except KeyError:
rarity[candidate] = set([key])
try:
func_names[key].add(candidate)
except KeyError:
func_names[key] = set([candidate])
try:
raw_func_strings[key].add(str(s))
except:
raw_func_strings[key] = set([str(s)])
return func_names, raw_func_strings, rarity, class_objects
#-------------------------------------------------------------------------------
def show_function_names(strings_list):
l = find_function_names(strings_list)
func_names, raw_func_strings, rarity, classes = l
final_list = []
for key in func_names:
candidates = set()
for candidate in func_names[key]:
if len(rarity[candidate]) == 1:
candidates.add(candidate)
if len(candidates) == 1:
raw_strings = list(raw_func_strings[key])
raw_strings = list(map(repr, raw_strings))
func_name = get_func_name(key)
tmp = demangle_name(func_name, INF_SHORT_DN)
if tmp is not None:
func_name = tmp
final_list.append([key, func_name, list(candidates)[0], raw_strings])
if len(classes) > 0:
class_graph = CClassesGraph(PROGRAM_NAME + ": Classes Hierarchy", classes, final_list)
class_graph.Show()
class_tree = CClassesTreeViewer()
class_tree.Show(PROGRAM_NAME + ": Classes Tree", classes)
final_list = class_graph.final_list
if len(final_list) > 0:
cfn = CCandidateFunctionNames(PROGRAM_NAME + ": Candidate Function Names", final_list)
cfn.show()
#-------------------------------------------------------------------------------
def main():
ch = CSourceFilesChooser(PROGRAM_NAME + ": Source code files")
if len(ch.items) > 0:
ch.show()
d = ch.d
if len(d) > 0:
show_tree(d)
show_function_names(ch.s)
if __name__ == "__main__":
main()

View File

@@ -1,153 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
#################################################################
#### CodeCut - Detecting Object File Boundaries in IDA Pro ####
#################################################################
**** Terminology ****
I tend to use the term "module" for a set of related functions within a binary
that came from a single object file. So you will see the terms "module" and
"object file" used interchangeabley in the CC source and documentation.
**** Dependencies ****
CodeCut relies on:
Natural Language Toolkit (NLTK) - https://www.nltk.org
Snap.py - https://snap.stanford.edu/snappy/
**** Source Files ****
cc_main.py - Main entry point - simply load this up with the
"File -> Script file..." option in IDA.
lfa.py - Analysis engine for LFA.
mc.py - Analysis engine for MaxCut.
basicutils_7x.py - Provides an API to IDA - maybe one day we'll get this
ported to Ghidra!
map_read.py - For research purposes - compares a ground truth .map
file (from ld) to a .map file from CC and produces
a score. See RECON slides or the code itself for more
info. You need to add the option -Map=<target>.map to
the linker options in a Makefile to get a .map file.
The syntax to map_read is:
python map_read.py <ground truth file> <CC map file>
**** MaxCut Parameters ****
- Right now there is only one parameter for MaxCut, a value for the maximum
module size (currently set to 16K).
**** LFA Parameters & Interpolation ****
A couple areas for research:
- The idea behind LFA is that we throw out "external" calls - we can't
determine this exactly in a binary so we throw out calls that are above a
certain threshold. This is set to 4K in the code but it could be tweaked.
- There is a threshold set for edge detection - plus a little bit of extra
logic (value has to be positive and 2 of last 3 values were negative). You
can either vary this threshold or write your own edge_detect() function.
- Currently "calls to" affinity and "calls from" affinity are treated as
separate scores. If one of these scores is zero an interpolation from
the previous score is used - just a simple linear equation assuming
decreasing scores. This could be improved a number of ways but could
be replaced with an actual interpolation between scores.
- If both "calls to" affinity and "calls from" affinity for a function are 0
the function is skipped and is essentially treated like it's not there.
This happens for functions with no references or where all references are
above the "external" threshold. This means there can be gaps between the
modules in the output list.
- The portion of code that tries to name object files based on common strings
is completely researchy and open ended. Lots of things to play with there.
**** MaxCut Parameters & Interpolation ****
- The only real parameter for MaxCut is a THRESHOLD variable that corresponds to the size at which the algorithm will stop subdividing modules. A threshold of 4K (0x1000) seems to provide similar sized modules to LFA. A threshold of 8K (0x2000) seems to be a good upper bound. A good area of research would be making this not a static cutoff but maybe deciding to stop subdividing based on a connectedness measurement or something along those lines.
**** Output Files ****
CodeCut produces 7 files:
<target>_cc_results.csv - Raw score output from LFA and MaxCut, including where
edges are detected. Graphs can fairly easily be
generated in your favorite spreadsheet program.
<target>_{lfa,mc}_labels.py - Script that can be used to label your DB with CC's
output. After determining module boundaries, CC
attempts to guess the name (fun!) by looking at
common strings used by the module, for both the
LFA and MaxCut module lists. You can use this
script as a scratchpad to name unnamed modules as you
determine what they are, or you can also use other
functions in basicutils to change module names later.
<target>_{lfa,mc}_map.map - A .map file similar to the output from the ld. This is
for the purposes of comparing to a ground truth .map
file to test CC when you have source code.
<target>_{lfa,mc}_mod_graph.gv - a Graphviz graph file of the module relationships
This is a directed graph where a -> b indicates
that a function in module a calls a function in
module b. This may take a long time to render if
you have a large binary (more than a couple
hundred modules detected). For smaller binaries
this can pretty clearly communicate the software
architecture immediately. For larger binaries
this will show you graphically the most heavily
used modules in the binary.
You can use sfdp to render the graph into a PNG file with a command line like:
sfdp -x -Goverlap=scale -Tpng -Goutputorder=edgesfirst -Nstyle=filled -Nfillcolor=white <target>_lfa_mod_graph.gv > <target>.png
A really nice hierarchical graph can be obtained by adding:
ranksep=0
nodesep=0
to the .gv file and running:
dot -x -Goverlap=scale -Tpng -Goutputorder=edgesfirst -Nstyle=filled -Nfillcolor=white <target>.gv > <target>.png
**** "Canonical" Names ****
NOTE on IDA and Canonical Names:
AFAICT IDA doesn't really have a concept of source file / object files in
the database (it does with source-level debugging but that's it I think).
In my ideal world, I'd write a nice GUI plugin to manage the object file
names and regions, and then you'd be able to select how to display object/
function names in the disassembly. For now though I have to save both the
object name and function name in the filename.
For now, my hacky workaround is to name modules and functions in camel case
(e.g. ReadNetworkString, or HtmlParsingEngine), and then combine them together
in a nasty snake case "canonical" format, that looks like:
<ObjectName>_<FunctionName>_<Address>
That way I can parse out function and object names to be able to rename
objects. I am open to suggestions on better ways to do this.

View File

@@ -1,366 +0,0 @@
##############################################################################################
# Copyright 2018 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
# basicutils - a version-agnostic API for IDA Pro with some (slightly) higher level functionality
# This is the 7.x version - see basicutils_6x for the 7.x version
import os
import ida_bytes
import ida_funcs
import ida_nalt
import ida_ua
import ida_name
import idc
import struct
import idautils
import ida_idaapi
import ida_segment
import re
BADADDR = ida_idaapi.BADADDR
def SegByName(n):
t = ida_segment.get_segm_by_name(n)
if (t and t.start_ea != ida_idaapi.BADADDR):
start = t.start_ea
end = t.end_ea
else:
start = ida_idaapi.BADADDR
end = ida_idaapi.BADADDR
return (start,end)
def GetFunctionName(x):
return idc.get_func_name(x)
def GetInputFile():
return idc.get_root_filename()
def GetIdbFile():
return idc.get_idb_path()
def GetRootName():
return os.path.join(os.path.dirname(GetIdbFile()), os.path.basename(GetInputFile()))
def NextFunction(x):
return idc.get_next_func(x)
def PrevFunction(x):
return idc.get_prev_func(x)
MAX_OPCODE_LEN = 15
def PrevInstr(ea):
# TODO this will return an inst_t type. Need to figure out how to populate it/make workflow happy
out=ida_ua.insn_t()
ida_ua.decode_prev_insn(out, ea)
return out.ea
def CodeRefsTo(target):
return idautils.CodeRefsTo(target,0)
def ForEveryUniqXrefTo( target, fun ):
a = 0
for xref in idautils.CodeRefsTo(target,0):
if idc.get_func_attr(xref,idc.FUNCATTR_START) != a :
fun(xref)
a = idc.get_func_attr(xref, idc.FUNCATTR_START);
def ForEveryXrefTo( target, fun ):
for xref in idautils.CodeRefsTo(target,0):
fun(xref)
def ForEveryUniqXrefToD( target, fun ):
a = 0
for xref in idautils.CodeRefsTo(target,0):
if idc.get_func_attr(xref,idc.FUNCATTR_START) != a :
fun(xref, target)
a = idc.get_func_attr(xref, idc.FUNCATTR_START);
def ForEveryXrefToD( target, fun ):
for xref in idautils.CodeRefsTo(target,0):
fun(xref, target)
def ForEveryFuncInDb( fun ):
f = NextFunction(0)
while (f != ida_idaapi.BADADDR):
"""print "ev: %#x" % f"""
fun(f)
f=NextFunction(f)
def ForEveryFuncInSeg( seg, fun ):
start,end = SegByName(".text")
if (start == BADADDR):
start = NextFunction(0)
end = BADADDR
f = start
while (f < end):
"""print "ev: %#x" % f"""
print(f)
fun(f)
f=NextFunction(f)
def NFuncUp( fun, n ) :
i=0
f=fun
while ((i<n) and (f!=ida_idaapi.BADADDR)):
f=PrevFunction(f)
i=i+1
return f
def NFuncDown( fun, n ) :
i=0
f=fun
while ((i<n) and (f!=ida_idaapi.BADADDR)):
f=NextFunction(f)
i=i+1
return f
def FuncMidPt( fun ):
fstart = idc.get_func_attr(fun, idc.FUNCATTR_START)
fend = idc.get_func_attr(fun, idc.FUNCATTR_END)
return fstart+((fend-fstart)/2)
def FuncXrefsFrom ( fun ) :
f = set()
for item in idautils.FuncItems(fun):
for x in idautils.CodeRefsFrom(item,0):
s = idc.get_func_attr(x, idc.FUNCATTR_START)
if (x == s):
f.add(x)
#print "func xrefs from"
#print f
return f
def XrefFromRange ( fun ) :
f = FuncXrefsFrom(fun)
if f:
return (min(f),max(f))
else:
return (0,0)
def ProgramAddrRange() :
return ida_funcs.get_prev_func(ida_idaapi.BADADDR) - ida_funcs.get_next_func(0)
def MemCopy( dest, src, length ) :
for i in range(0, length):
#if (i < 20):
# print "set byte at %#x to %#x" % (dest+i, idc.Byte(src+i))
ida_bytes.patch_byte(dest+i,ida_bytes.get_byte(src+i))
def PrefixRange(start, end, prefix) :
x = start
while x < end:
n = idc.get_func_name(x)
if n.startswith("sub_"):
nn = prefix + n
print("Renaming %s to %s\n" % (n, nn))
ida_name.set_name(x,nn)
x = NextFunction(x)
def snakeToCamelCase(s):
f = s.lstrip("_")
nf = ""
nx = 0
x=0
while (x<len(f)):
#print "%s" % (f[x])
if f[x] == '_':
nf+=(f[x+1].upper())
x+=2
else:
nf+=f[x]
x+=1
nx+=1
return nf
def isSnakeCase(s) :
p = re.compile("[a-zA-Z0-9]+(_[a-zA-Z0-9]+)+\Z")
if p.match(s):
return True
return False
#Todo - right now this is going to miss something like FooBARFunction
def isCamelCase(s) :
p = re.compile("([A-Z][a-z0-9]+)([A-Z][a-z0-9]+)+\Z")
if p.match(s):
return True
return False
#Todo - weed out if it's all uppercase or all uppercase and _, etc.
def isUCSnakeCase(s):
p = re.compile("[A-Z0-9]+(_[A-Z0-9]+)+\Z")
if p.match(s):
return True
return False
def isPlausibleFunction(s):
if isSnakeCase(s):
if isUCSnakeCase(s):
return False
return True
if isCamelCase(s):
return True
return False
def PrependStrToFuncName(f,s):
n = idc.get_func_name(f)
n = s + n
ida_name.set_name(f,n)
#The "canonical" name format (for now) is <module name>_<func name>_<address>
#where <module_name> and <func_name> are in camel case.
#This is not ideal for a number of reasons but this is a workaround for now
#Return just the "function name" part of the canonical name
def GetCanonicalName(f):
n = idc.get_func_name(f)
parts = n.split("_")
if len(parts) == 3:
return parts[1]
else:
return None
#Put function in canonical format, given the function name and module name
def NameCanonical(f,mod_name,func_name):
n = "%s_%s_%08x" % (mod_name,func_name,f)
print("Renaming %s to %s\n" % (idc.get_func_name(f),n))
ida_name.force_name(f,n)
#Put function in canonical format when it doesn't have a name, but you know the module name
def RenameFuncWithAddr(f,s):
func_name = "unk"
NameCanonical(f,s,func_name)
#Use this if you have pre-existing named functions in the DB that are in non-canonical format
def RenameRangeWithAddr(start,end,s):
x = start
while (x<=end):
n = idc.get_func_name(x)
if (n.startswith("sub_")):
RenameFuncWithAddr(x,s)
else:
NameCanonical(x,s,n)
x = NextFunction(x)
#Rename a function in canonical format without changing the module name
def CanonicalFuncRename(f,name):
n = idc.get_func_name(f)
parts = n.split("_")
new_name = "%s_%s_%08x" % (parts[0],name,f)
print("Renaming %s to %s\n" % (n, new_name))
ida_name.set_name(f,new_name)
#Rename the module name without changing the function name
def RenameFuncWithNewMod(f,mod):
n = idc.get_func_name(f)
parts = n.split("_")
new_name = "%s_%s_%08x" % (mod,parts[1],f)
print("Renaming %s to %s\n" % (n, new_name))
ida_name.set_name(f,new_name)
#Rename a module (all functions that start with <mod>_)
def RenameMod(orig, new):
i = idc.get_next_func(0)
while (i != BADADDR):
n = idc.get_func_name(i)
if n.startswith(orig+"_"):
RenameFuncWithNewMod(i,new)
i = NextFunction(i)
#Just rename the module over a given range (can be used to split a module and give part a new name)
def RenameModRange(start, end, new):
x = start
while (x<=end):
n = idc.get_func_name(x)
RenameFuncWithNewMod(x,new)
x = NextFunction(x)
#Given a range of functions, some of which may have names and module names
# and a module name, put names in canonical format
def CanonicalizeRange(start,end,mod):
x = start
while (x<=end):
n = idc.get_func_name(x)
#if it already starts with mod name, assume it's canonical
if (not n.startswith(mod+"_")):
if (n.startswith("sub_")):
RenameFuncWithAddr(x,mod)
#this should be contains "_"
elif ("_" in n):
n = snakeToCamelCase(n)
NameCanonical(x,mod,n)
else:
NameCanonical(x,mod,n)
x = NextFunction(x)
#Returns a string that is the concatenation of all of the string references from a function, separated by <sep>
#Iterates through every item in function and looks for data references that are strings
def CompileTextFromFunction(f,sep):
s=""
faddr = list(idautils.FuncItems(f))
for c in range(len(faddr)):
for d in idautils.DataRefsFrom(faddr[c]):
t = ida_nalt.get_str_type(d)
if ((t==0) or (t==3)):
s += " "+ sep + " " + idc.GetStrLitContents(d)
return s
#Returns a string which is the concatenation all of the string references
# for an address range in the program, separated by <sep>
#Similar to above, but iterates over the whole set of functions in the given range
def CompileTextFromRange(start,end,sep):
x = start
s = ""
while (x<=end):
faddr = list(idautils.FuncItems(x))
#print "items list: %d" % len(faddr)
for c in range(len(faddr)):
for d in idautils.DataRefsFrom(faddr[c]):
#print "Found ref at %x: %x " % (faddr[c],d)
t = ida_nalt.get_str_type(d)
if ((t==0) or (t==3)):
s += " " + sep + " " + GetStrLitContents(d).decode("utf-8")
x = NextFunction(x)
return s
#Returns a string which is a concatenation of all the function names in the given range
# separated by <sep>
def CompileFuncNamesFromRangeAsText(start,end,sep):
x = start
s = ""
while (x<=end):
n = idc.get_func_name(x)
if (not n.startswith("sub_")):
s += " " + sep + " " + n
x = NextFunction(x)
return s
#helper function which checks for both ASCII and Unicode strings at the given ea
def GetStrLitContents(ea):
potential_len = ida_bytes.get_max_strlit_length(ea, ida_nalt.STRTYPE_C_16)
if(potential_len > 0):
# If we get a non zero length, this is likely our string
return ida_bytes.get_strlit_contents(ea, potential_len, ida_nalt.STRTYPE_C_16)
# If we didn't get a good length out of C_16, try 8 bit strings
potential_len = ida_bytes.get_max_strlit_length(ea, ida_nalt.STRTYPE_C)
if(potential_len > 0):
return ida_bytes.get_strlit_contents(ea, potential_len, ida_nalt.STRTYPE_C)
#print("Error! %lu not a string" % (ea))
return ""

View File

@@ -1,161 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
import basicutils_7x as basicutils
import json
import os
import modnaming
## Utilities
#escape_for_graphviz()
#Return the string escaped for usage in a GraphViz file
def escape_for_graphviz(string):
return json.dumps(string)
## CodeCut Basics
## A couple of functions for working with function and module lists and outputting results
#locate_module()
#Return the module information for a given function
#This assumes that the module list is in order, but not necessarily contiguous
def locate_module(module_list, f):
found=0
c=0
#print "Finding %08x in module list length: %d" % (f,len(module_list))
while ( (found != 1) and (c < len(module_list))):
m = module_list[c]
#print "\t%x - %x: %s" % (m.start,m.end,m.name)
#this is the case where a function falls in the cracks between modules (because it wasn't cool enough to get a score)
if (f < m.start):
found = 1
ret = None
elif ((f >= m.start) and (f <= m.end)):
found = 1
ret = m
c+=1
return m
#gen_mod_graph()
#Output a module-to-module call graph in GraphViz format
#For each module m_1
# For each function <f> in the module
# For each function that <f> calls
# Lookup the module info for <f> m_2
# If it's been assigned a module, add edge m_1 -> m_2 to the graph
def gen_mod_graph(module_list, suffix):
c=0
g=set()
while (c < len(module_list)):
m = module_list[c]
f = m.start
while (f <= m.end):
for xref in basicutils.FuncXrefsFrom(f):
target = locate_module(module_list,xref)
if (target):
g.add((m.name,target.name))
f = basicutils.NextFunction(f)
c+=1
root_name = basicutils.GetRootName()
file = open(root_name + "_" + suffix + "_mod_graph.gv", "w")
file.write("digraph g {\n")
for (node1,node2) in g:
line = "%s -> %s\n" % (escape_for_graphviz(node1),escape_for_graphviz(node2))
file.write(line)
file.write("}\n")
file.close()
#gen_rename_script()
#Output the module list with names as a Python script
#This script can then be run on the database if in the same directory as the basicutils libraries
#Look at basicutils.RenameRangeWithAddr to see the "canonical" name format -
# you can also tweak that function to use a different naming convention
def gen_rename_script(module_list, suffix):
c=0
root_name = basicutils.GetRootName()
file = open(root_name + "_" + suffix + "_labels.py", "w")
#if (IDA_VERSION < 7):
# file.write("import basicutils_6x as basicutils\n");
#else:
file.write("import basicutils_7x as basicutils\n");
file.write("\ndef go():\n");
while (c<len(module_list)):
m=module_list[c]
file.write("\tbasicutils.RenameRangeWithAddr(0x%x,0x%x,%r)\n"%(m.start,m.end,m.name))
c+=1
file.write("\n")
file.write("if __name__ == \"__main__\":\n")
file.write("\treload(basicutils)\n")
file.write("\tgo()\n")
file.close()
#gen_map_file()
#Produce a .map file similar to that produced by the ld option -Map=foo.map
#Use map_read.py to test accuracy when a ground truth map file is available
def gen_map_file(module_list, suffix):
c=0
root_name = basicutils.GetRootName()
file = open(root_name + "_" + suffix + "_map.map", "w")
while (c<len(module_list)):
m=module_list[c]
#mlen = basicutils.NextFunction(m.end) - m.start
mlen = m.end - m.start
mlen_str = "0x%x" % mlen
file.write("%s0x%016x%s %s\n" % (" .text".ljust(16),m.start,mlen_str.rjust(11),m.name))
c+=1
file.close()
#print_results():
#Write all of the results to <target>.csv - which can be opened in your favorite spreadsheet program
def print_results(function_list, module_list1, module_list2):
c=0
root_name = basicutils.GetRootName()
file = open(root_name + "_cc_results.csv", "w")
#write header
file.write("Function,Function #,LFA Score 1,LFA Score 2,LFA Total,LFA Edge,MC Edge,Function Name,Suggested Mod Name (LFA), Suggested Mod Name(MC),Source Str Ref\n");
while (c<len(function_list)):
f = function_list[c]
fname = basicutils.GetFunctionName(f.loc)
m1 = locate_module(module_list1, f.loc)
m2 = locate_module(module_list2, f.loc)
mname1 = m1.name
mname2 = m2.name
#hacky - should actually find the extent of the function
#for now we'll just skip the last one
if (c < (len(function_list) - 1)):
nf = basicutils.NextFunction(f.loc)
func_str_ref, score = modnaming.source_file_strings(f.loc, nf-1)
else:
func_str_ref=""
line = "0x%08x, %d , %f, %f, %f, %d, %d, %s, %s, %s, %s\n" % (f.loc,c+1,f.score1, f.score2, f.total_score,f.edge[0],f.edge[1],fname, mname1, mname2, func_str_ref)
file.write(line)
c+=1

View File

@@ -1,63 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
import maxcut
import lfa
import module
import modnaming
import cc_base
import basicutils_7x as basicutils
import snap_cg
import imp
def go():
#Do LFA and MaxCut Analysis to find module boundaries
lfa_funclist, lfa_modlist = lfa.analyze()
merge_flist,maxcut_modlist = maxcut.analyze(lfa_funclist)
#Guess names for the modules using NLP
lfa_modlist = modnaming.guess_module_names(lfa_modlist)
maxcut_modlist = modnaming.guess_module_names(maxcut_modlist)
#Output all results as .csv
cc_base.print_results(merge_flist, lfa_modlist, maxcut_modlist)
#Output module-to-module call graph as a Graphviz .gv file
cc_base.gen_mod_graph(lfa_modlist, "lfa")
cc_base.gen_mod_graph(maxcut_modlist, "mc")
#Output a Python script that will rename modules
cc_base.gen_rename_script(lfa_modlist, "lfa")
cc_base.gen_rename_script(maxcut_modlist, "mc")
#Output .map file (for comparison against ground truth, when available)
cc_base.gen_map_file(lfa_modlist, "lfa")
cc_base.gen_map_file(maxcut_modlist, "mc")
return True
if __name__ == "__main__":
imp.reload(modnaming)
imp.reload(module)
imp.reload(cc_base)
imp.reload(lfa)
imp.reload(maxcut)
imp.reload(snap_cg)
imp.reload(basicutils)
go()

View File

@@ -1,103 +0,0 @@
import idc
import ida_kernwin
import imp
import snap_cg
import lfa
import maxcut
import module
import cc_base
import modnaming
import basicutils_7x as basicutils
from PyQt5 import QtCore, QtGui, QtWidgets
from IDAMagicStrings import get_source_strings
#-------------------------------------------------------------------------------
def handler(item, column_no):
if item.ignore:
return
ea = item.ea
if is_mapped(ea):
jumpto(ea)
#-------------------------------------------------------------------------------
class CBaseTreeViewer(ida_kernwin.PluginForm):
def populate_tree(self):
# Clear previous items
self.tree.clear()
# Get source file names
self.dict, _ = get_source_strings()
module_names = {}
for key in self.dict:
for values in self.dict[key]:
ea, module_name = values[0], values[2]
module_names[ea] = module_name
self.modules_cache = {}
#Do LFA and MaxCut Analysis to find module boundaries
_, lfa_modlist = lfa.analyze()
for module_data in lfa_modlist:
module_name = "Module 0x%08x:0x%08x" % (module_data.start, module_data.end)
for ea in module_names:
if ea >= module_data.start and ea <= module_data.end:
module_name = module_names[ea]
break
if module_name in self.modules_cache:
item = self.modules_cache[module_name]
else:
item = QtWidgets.QTreeWidgetItem(self.tree)
item.setText(0, module_name)
item.ea = module_data.start
item.ignore = True
self.modules_cache[module_name] = item
for func in Functions(module_data.start, module_data.end):
node = QtWidgets.QTreeWidgetItem(item)
node.setText(0, "0x%08x: %s" % (func, idc.get_func_name(func)))
node.ea = func
node.ignore = False
self.tree.itemDoubleClicked.connect(handler)
def OnCreate(self, form):
# Get parent widget
self.parent = ida_kernwin.PluginForm.FormToPyQtWidget(form)
# Create tree control
self.tree = QtWidgets.QTreeWidget()
self.tree.setHeaderLabels(("Names",))
self.tree.setColumnWidth(0, 100)
# Create layout
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tree)
self.populate_tree()
# Populate PluginForm
self.parent.setLayout(layout)
def Show(self, title):
return ida_kernwin.PluginForm.Show(self, title, options = ida_kernwin.PluginForm.WOPN_PERSIST)
#-------------------------------------------------------------------------------
def main():
tree_frm = CBaseTreeViewer()
tree_frm.Show("Object Files")
if __name__ == "__main__":
imp.reload(modnaming)
imp.reload(module)
imp.reload(cc_base)
imp.reload(lfa)
imp.reload(maxcut)
imp.reload(snap_cg)
imp.reload(basicutils)
main()

View File

@@ -1,26 +0,0 @@
This is a dataset for exploring other solutions to the CodeCut problem or
improving LFA.
Each of the targets is an ELF file with DWARF debug information, as well as
a .map file that was produced by ld at link time (showing object file
boundaries). Some of the larger targets have a trimmed .map file
(with "_trim") in the filename - this is basically just the object file
boundaries to make parsing faster.
You can use map_read.py to test LFA output (or any other solution to the
CodeCut problem)
Syntax:
map_read.py <ground truth map file> <CodeCut/LFA map file>
This will output a 3 part score: match %, gap %, and underlap %
Expected results for LFA:
Gnuchess - Linux binary (x86) 76.1 3.2 20.7
PX4 Firmware / NuttX (ARM) 82.2 13.6 4.2
GoodFET 41 Firmware (msp430) 76.1 0 23.9
Tmote Sky Firmware / Contiki (msp430) 93.3 0 6.7
NXP Httpd Demo / FreeRTOS (ARM) 86.7 1.4 11.9
A perfect result would be 100% match with no gap and no underlap.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,907 +0,0 @@
.text 0x0000000000402470 0x2e012
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
.text.unlikely
0x0000000000402470 0x0 /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o
.text.unlikely
0x0000000000402470 0x0 main.o
.text.unlikely
0x0000000000402470 0x0 components.o
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(cmd.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(debug.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(epd.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(genmove.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(init.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(move.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(output.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(players.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(pgn.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(solve.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(swap.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(util.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(engine.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(lexpgn.o)
.text.unlikely
0x0000000000402470 0x0 frontend/libfrontend.a(atak.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(main.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(option.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(piece.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(square.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(uci.o)
.text.unlikely
0x0000000000402470 0x0 adapter/libadapter.a(util.o)
.text.unlikely
0x0000000000402470 0xd4 adapter/libadapter.a(adapter.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(attack.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(board.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(book.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(book_make.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(book_merge.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(colour.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(engine.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(epd.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(fen.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(game.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(hash.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(io.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(line.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(list.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(move.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(move_do.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(move_gen.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(move_legal.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(parse.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(pgn.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(posix.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(random.o)
.text.unlikely
0x0000000000402544 0x0 adapter/libadapter.a(san.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(main.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(move_do.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(option.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(pawn.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(piece.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(protocol.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(pst.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(random.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(search.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(search_full.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(see.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(sort.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(square.o)
.text.unlikely
0x0000000000402544 0x0 engine/libengine.a(trans.o)
.text.unlikely
0x0000000000402544 0x1c engine/libengine.a(util.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(value.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(vector.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(attack.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(board.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(book.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(eval.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(fen.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(hash.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(list.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(material.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(move.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(move_check.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(move_evasion.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(move_gen.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(move_legal.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(posix.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(pv.o)
.text.unlikely
0x0000000000402560 0x0 engine/libengine.a(recog.o)
.text.unlikely
0x0000000000402560 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
.text.startup 0x0000000000402560 0x79b main.o
0x0000000000402560 main
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
*fill* 0x0000000000402cfb 0x5
.text 0x0000000000402d00 0x2a /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o
0x0000000000402d00 _start
.text 0x0000000000402d2a 0x0 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o
*fill* 0x0000000000402d2a 0x6
.text 0x0000000000402d30 0xc6 /usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o
.text 0x0000000000402df6 0x0 main.o
*fill* 0x0000000000402df6 0xa
.text 0x0000000000402e00 0x1ab components.o
0x0000000000402e00 engine_func(void*)
0x0000000000402e20 InitAdapter()
0x0000000000402eb0 InitEngine()
0x0000000000402f10 adapter_func(void*)
0x0000000000402f30 TerminateAdapterEngine()
*fill* 0x0000000000402fab 0x5
.text 0x0000000000402fb0 0x2863 frontend/libfrontend.a(cmd.o)
0x0000000000402fb0 cmd_variant()
0x0000000000402fc0 cmd_bk()
0x0000000000402fd0 cmd_movenow()
0x0000000000402fe0 cmd_protover()
0x0000000000402ff0 cmd_otim()
0x0000000000403000 cmd_ics()
0x0000000000403010 cmd_hint()
0x0000000000403020 cmd_hard()
0x0000000000403030 cmd_easy()
0x0000000000403040 cmd_accepted()
0x0000000000403050 cmd_activate()
0x0000000000403080 cmd_black()
0x00000000004030b0 cmd_graphic()
0x00000000004030e0 cmd_nographic()
0x0000000000403110 cmd_random()
0x0000000000403140 cmd_switch()
0x0000000000403170 cmd_white()
0x00000000004031a0 cmd_test()
0x00000000004031d0 cmd_analyze()
0x0000000000403200 cmd_force()
0x0000000000403230 cmd_manual()
0x0000000000403260 cmd_nopost()
0x0000000000403290 cmd_quit()
0x0000000000403370 cmd_hash()
0x0000000000403420 cmd_null()
0x00000000004034d0 cmd_time()
0x00000000004035b0 cmd_depth()
0x0000000000403660 cmd_ping()
0x00000000004036a0 cmd_post()
0x00000000004036e0 cmd_go()
0x0000000000403780 cmd_level()
0x00000000004038d0 cmd_st()
0x0000000000403990 cmd_rating()
0x0000000000403a10 cmd_new()
0x0000000000403a90 cmd_undo()
0x0000000000403b60 cmd_remove()
0x0000000000403c40 cmd_result()
0x0000000000403cf0 cmd_solve()
0x0000000000403d00 cmd_usage()
0x0000000000403f60 cmd_usermove()
0x0000000000404110 cmd_help()
0x0000000000404270 cmd_version()
0x00000000004042b0 cmd_exit()
0x00000000004042f0 cmd_xboard()
0x0000000000404390 cmd_book()
0x00000000004045f0 cmd_pgnload()
0x0000000000404760 cmd_edit()
0x0000000000404790 cmd_memory()
0x0000000000404860 cmd_list()
0x00000000004048f0 cmd_name()
0x0000000000404a20 cmd_next()
0x0000000000404af0 cmd_previous()
0x0000000000404bc0 cmd_last()
0x0000000000404d30 cmd_first()
0x0000000000404d50 cmd_pgnreplay()
0x0000000000404fb0 cmd_save()
0x0000000000404fd0 cmd_pgnsave()
0x0000000000404ff0 cmd_show()
0x0000000000405270 cmd_rejected()
0x0000000000405280 parse_input()
0x0000000000405550 check_board()
0x00000000004055d0 cmd_load()
0x0000000000405780 cmd_setboard()
*fill* 0x0000000000405813 0xd
.text 0x0000000000405820 0x23 frontend/libfrontend.a(debug.o)
0x0000000000405820 dbg_open(char const*)
0x0000000000405830 dbg_printf(char const*, ...)
0x0000000000405840 dbg_close()
*fill* 0x0000000000405843 0xd
.text 0x0000000000405850 0xeee frontend/libfrontend.a(epd.o)
0x0000000000405850 ParseEPD(char*)
0x0000000000406210 ReadEPDFile(char const*, short)
0x00000000004063d0 LoadEPD(char*)
0x00000000004064a0 SaveEPD(char*)
*fill* 0x000000000040673e 0x2
.text 0x0000000000406740 0x3460 frontend/libfrontend.a(genmove.o)
0x0000000000406740 GenMoves(short)
0x0000000000407890 GenNonCaptures(short)
0x00000000004084a0 GenCaptures(short)
0x0000000000409290 GenCheckEscapes(short)
0x0000000000409ab0 FilterIllegalMoves(short)
.text 0x0000000000409ba0 0x1091 frontend/libfrontend.a(init.o)
0x0000000000409ba0 InitLzArray()
0x0000000000409be0 InitBitPosArray()
0x0000000000409c20 InitMoveArray()
0x0000000000409d30 InitRay()
0x0000000000409e80 InitFromToRay()
0x0000000000409fc0 InitRankFileBit()
0x000000000040a010 InitBitCount()
0x000000000040a080 InitRotAtak()
0x000000000040a720 InitVars()
0x000000000040aaa0 Initialize()
0x000000000040abd0 NewPosition()
*fill* 0x000000000040ac31 0xf
.text 0x000000000040ac40 0x1d9f frontend/libfrontend.a(move.o)
0x000000000040ac40 MakeMove(int, int*)
0x000000000040b600 UnmakeMove(int, int*)
0x000000000040bb20 SANMove(int, int)
0x000000000040be80 IsInMoveList(int, int, int, char)
0x000000000040bf10 AlgbrMove(int)
0x000000000040bfa0 ValidateMove(char*)
*fill* 0x000000000040c9df 0x1
.text 0x000000000040c9e0 0xd9a frontend/libfrontend.a(output.o)
0x000000000040c9e0 ShowTime()
0x000000000040c9f0 ShowMoveList(int)
0x000000000040cac0 ShowSmallBoard()
0x000000000040ce20 ShowBoard()
0x000000000040d560 ShowCBoard()
0x000000000040d5e0 ShowMvboard()
0x000000000040d650 ShowGame()
*fill* 0x000000000040d77a 0x6
.text 0x000000000040d780 0x572 frontend/libfrontend.a(players.o)
0x000000000040d870 DBSortPlayer(char const*)
0x000000000040d910 DBWritePlayer()
0x000000000040d9a0 DBReadPlayer()
0x000000000040da30 DBListPlayer(char const*)
0x000000000040db10 DBSearchPlayer(char const*)
0x000000000040db90 DBUpdatePlayer(char const*, char const*)
*fill* 0x000000000040dcf2 0xe
.text 0x000000000040dd00 0x6da frontend/libfrontend.a(pgn.o)
0x000000000040dd00 PGNSaveToFile(char const*, char const*)
0x000000000040e270 PGNReadFromFile(char const*, int)
0x000000000040e390 IsTrustedPlayer(char const*)
*fill* 0x000000000040e3da 0x6
.text 0x000000000040e3e0 0x205 frontend/libfrontend.a(solve.o)
0x000000000040e3e0 Solve(char*)
*fill* 0x000000000040e5e5 0xb
.text 0x000000000040e5f0 0x513 frontend/libfrontend.a(swap.o)
0x000000000040e5f0 AddXrayPiece(int, int, int, unsigned long*, unsigned long*)
0x000000000040e700 SwapOff(int)
*fill* 0x000000000040eb03 0xd
.text 0x000000000040eb10 0x371 frontend/libfrontend.a(util.o)
0x000000000040eb10 UpdateFriends()
0x000000000040eb90 UpdateCBoard()
0x000000000040ec70 UpdateMvboard()
0x000000000040ecc0 ValidateBoard()
*fill* 0x000000000040ee81 0xf
.text 0x000000000040ee90 0xf42 frontend/libfrontend.a(engine.o)
0x000000000040efa0 InitFrontend()
0x000000000040efc0 SendToEngine(char*)
0x000000000040f040 ReadFromEngine()
0x000000000040f1c0 ReadFromUser()
0x000000000040f310 SetDataToEngine(char const*)
0x000000000040f330 ExpectAnswerFromEngine(int)
0x000000000040f340 ShowPrompt()
0x000000000040f430 NextUserCmd()
0x000000000040f610 NextEngineCmd()
0x000000000040f8b0 SetUserInputValidMove(int)
0x000000000040f8c0 ChangeColor(int)
0x000000000040f8d0 SetAutoGo(int)
0x000000000040f8e0 GetAutoGo()
0x000000000040f8f0 SolvePosition(char*, char const*)
0x000000000040fae0 ForwardUserInputToEngine()
0x000000000040fc90 ForwardEngineOutputToUser()
*fill* 0x000000000040fdd2 0xe
.text 0x000000000040fde0 0x22f5 frontend/libfrontend.a(lexpgn.o)
0x000000000040ff80 return_append_str(char*, char const*)
0x0000000000410020 append_str(char**, char const*)
0x0000000000410040 append_comment(char const*)
0x00000000004100a0 yy_switch_to_buffer(yy_buffer_state*)
0x0000000000410150 yy_delete_buffer(yy_buffer_state*)
0x00000000004101c0 yy_flush_buffer(yy_buffer_state*)
0x00000000004102d0 yy_create_buffer(_IO_FILE*, int)
0x0000000000410330 yyrestart(_IO_FILE*)
0x0000000000410400 yylex()
0x0000000000411cd0 yypush_buffer_state(yy_buffer_state*)
0x0000000000411d90 yypop_buffer_state()
0x0000000000411e20 yy_scan_buffer(char*, unsigned long)
0x0000000000411ec0 yy_scan_bytes(char const*, unsigned long)
0x0000000000411f40 yy_scan_string(char const*)
0x0000000000411f60 yyget_lineno()
0x0000000000411f70 yyget_in()
0x0000000000411f80 yyget_out()
0x0000000000411f90 yyget_leng()
0x0000000000411fa0 yyget_text()
0x0000000000411fb0 yyset_lineno(int)
0x0000000000411fc0 yyset_in(_IO_FILE*)
0x0000000000411fd0 yyset_out(_IO_FILE*)
0x0000000000411fe0 yyget_debug()
0x0000000000411ff0 yyset_debug(int)
0x0000000000412000 yylex_destroy()
0x00000000004120b0 yyalloc(unsigned long)
0x00000000004120c0 yyrealloc(void*, unsigned long)
0x00000000004120d0 yyfree(void*)
*fill* 0x00000000004120d5 0xb
.text 0x00000000004120e0 0x4ff frontend/libfrontend.a(atak.o)
0x00000000004120e0 SqAtakd(short, short)
0x00000000004122c0 AttackTo(int, int)
0x0000000000412480 PinnedOnKing(int, int)
*fill* 0x00000000004125df 0x1
.text 0x00000000004125e0 0x5cc adapter/libadapter.a(main.o)
0x00000000004129c0 adapter::main_adapter(int, char**)
0x0000000000412b40 adapter::quit()
*fill* 0x0000000000412bac 0x4
.text 0x0000000000412bb0 0x3e5 adapter/libadapter.a(option.o)
0x0000000000412bb0 adapter::option_set(char const*, char const*)
0x0000000000412c20 adapter::option_init()
0x0000000000412e50 adapter::option_get(char const*)
0x0000000000412ec0 adapter::option_get_bool(char const*)
0x0000000000412f50 adapter::option_get_double(char const*)
0x0000000000412f70 adapter::option_get_int(char const*)
0x0000000000412f90 adapter::option_get_string(char const*)
*fill* 0x0000000000412f95 0xb
.text 0x0000000000412fa0 0x1bb adapter/libadapter.a(piece.o)
0x0000000000412fa0 adapter::piece_init()
0x0000000000412ff0 adapter::piece_is_ok(int)
0x0000000000413010 adapter::piece_make_pawn(int)
0x0000000000413020 adapter::piece_pawn_opp(int)
0x0000000000413030 adapter::piece_colour(int)
0x0000000000413040 adapter::piece_type(int)
0x0000000000413050 adapter::piece_is_pawn(int)
0x0000000000413060 adapter::piece_is_knight(int)
0x0000000000413070 adapter::piece_is_bishop(int)
0x0000000000413080 adapter::piece_is_rook(int)
0x0000000000413090 adapter::piece_is_queen(int)
0x00000000004130a0 adapter::piece_is_king(int)
0x00000000004130b0 adapter::piece_is_slider(int)
0x00000000004130c0 adapter::piece_to_12(int)
0x00000000004130d0 adapter::piece_from_12(int)
0x00000000004130e0 adapter::piece_to_char(int)
0x0000000000413100 adapter::piece_from_char(int)
0x0000000000413140 adapter::char_is_piece(int)
*fill* 0x000000000041315b 0x5
.text 0x0000000000413160 0x1f7 adapter/libadapter.a(square.o)
0x0000000000413160 adapter::square_init()
0x00000000004131b0 adapter::square_is_ok(int)
0x00000000004131d0 adapter::square_make(int, int)
0x00000000004131e0 adapter::square_file(int)
0x00000000004131f0 adapter::square_rank(int)
0x0000000000413200 adapter::square_side_rank(int, int)
0x0000000000413230 adapter::square_from_64(int)
0x0000000000413240 adapter::square_to_64(int)
0x0000000000413250 adapter::square_is_promote(int)
0x0000000000413270 adapter::square_ep_dual(int)
0x0000000000413280 adapter::square_colour(int)
0x0000000000413290 adapter::file_from_char(int)
0x00000000004132a0 adapter::rank_from_char(int)
0x00000000004132b0 adapter::file_to_char(int)
0x00000000004132c0 adapter::rank_to_char(int)
0x00000000004132d0 adapter::char_is_file(int)
0x00000000004132e0 adapter::char_is_rank(int)
0x00000000004132f0 adapter::square_to_string(int, char*, int)
0x0000000000413320 adapter::square_from_string(char const*)
*fill* 0x0000000000413357 0x9
.text 0x0000000000413360 0x1328 adapter/libadapter.a(uci.o)
0x0000000000413360 adapter::uci_close(adapter::uci_t*)
0x00000000004133d0 adapter::uci_clear(adapter::uci_t*)
0x00000000004134a0 adapter::uci_send_isready(adapter::uci_t*)
0x00000000004134c0 adapter::uci_send_stop(adapter::uci_t*)
0x00000000004134e0 adapter::uci_send_ucinewgame(adapter::uci_t*)
0x0000000000413510 adapter::uci_option_exist(adapter::uci_t*, char const*)
0x0000000000413570 adapter::uci_send_option(adapter::uci_t*, char const*, char const*, ...)
0x00000000004136e0 adapter::uci_parse(adapter::uci_t*, char const*)
0x00000000004144b0 adapter::uci_open(adapter::uci_t*, adapter::engine_t*)
0x0000000000414590 adapter::uci_send_isready_sync(adapter::uci_t*)
0x0000000000414610 adapter::uci_send_stop_sync(adapter::uci_t*)
*fill* 0x0000000000414688 0x8
.text 0x0000000000414690 0x81f adapter/libadapter.a(util.o)
0x0000000000414690 adapter::util_init()
0x00000000004146d0 adapter::my_random_init()
0x00000000004146f0 adapter::my_random_int(int)
0x0000000000414720 adapter::my_random_double()
0x0000000000414740 adapter::my_atoll(char const*)
0x0000000000414780 adapter::my_round(double)
0x00000000004147a0 adapter::my_free(void*)
0x00000000004147b0 adapter::my_log_open(char const*)
0x00000000004147f0 adapter::my_log_close()
0x0000000000414810 adapter::my_log(char const*, ...)
0x00000000004148e0 adapter::my_fatal(char const*, ...)
0x0000000000414a30 adapter::my_malloc(int)
0x0000000000414a60 adapter::my_realloc(void*, int)
0x0000000000414aa0 adapter::my_file_read_line(_IO_FILE*, char*, int)
0x0000000000414b30 adapter::my_string_empty(char const*)
0x0000000000414b50 adapter::my_string_equal(char const*, char const*)
0x0000000000414b70 adapter::my_string_case_equal(char const*, char const*)
0x0000000000414bd0 adapter::my_strdup(char const*)
0x0000000000414c20 adapter::my_string_clear(char const**)
0x0000000000414c40 adapter::my_string_set(char const**, char const*)
0x0000000000414c70 adapter::my_timer_reset(adapter::my_timer_t*)
0x0000000000414c90 adapter::my_timer_start(adapter::my_timer_t*)
0x0000000000414cb0 adapter::my_timer_stop(adapter::my_timer_t*)
0x0000000000414cf0 adapter::my_timer_elapsed_real(adapter::my_timer_t const*)
0x0000000000414d40 adapter::my_timer_elapsed_cpu(adapter::my_timer_t const*)
0x0000000000414d90 adapter::my_timer_cpu_usage(adapter::my_timer_t const*)
0x0000000000414e90 adapter::compute_pkgdatadir()
*fill* 0x0000000000414eaf 0x1
.text 0x0000000000414eb0 0x2a53 adapter/libadapter.a(adapter.o)
0x0000000000417620 adapter::adapter_loop()
*fill* 0x0000000000417903 0xd
.text 0x0000000000417910 0x32e adapter/libadapter.a(attack.o)
0x0000000000417910 adapter::attack_init()
0x0000000000417a50 adapter::piece_attack(adapter::board_t const*, int, int, int)
0x0000000000417ad0 adapter::is_attacked(adapter::board_t const*, int, int)
0x0000000000417b30 adapter::is_in_check(adapter::board_t const*, int)
0x0000000000417b60 adapter::is_pinned(adapter::board_t const*, int, int, int)
*fill* 0x0000000000417c3e 0x2
.text 0x0000000000417c40 0x70a adapter/libadapter.a(board.o)
0x0000000000417c40 adapter::board_is_ok(adapter::board_t const*)
0x0000000000417c50 adapter::board_clear(adapter::board_t*)
0x0000000000417d50 adapter::board_start(adapter::board_t*)
0x0000000000417d60 adapter::board_copy(adapter::board_t*, adapter::board_t const*)
0x0000000000417d70 adapter::board_equal(adapter::board_t const*, adapter::board_t const*)
0x0000000000417e40 adapter::board_init_list(adapter::board_t*)
0x00000000004180a0 adapter::board_flags(adapter::board_t const*)
0x00000000004180e0 adapter::board_can_play(adapter::board_t const*)
0x0000000000418160 adapter::board_mobility(adapter::board_t const*)
0x00000000004181b0 adapter::board_is_check(adapter::board_t const*)
0x00000000004181c0 adapter::board_is_mate(adapter::board_t const*)
0x00000000004181f0 adapter::board_is_stalemate(adapter::board_t const*)
0x0000000000418220 adapter::king_pos(adapter::board_t const*, int)
0x0000000000418230 adapter::board_disp(adapter::board_t const*)
*fill* 0x000000000041834a 0x6
.text 0x0000000000418350 0xa9f adapter/libadapter.a(book.o)
0x00000000004185b0 adapter::book_clear()
0x00000000004185d0 adapter::book_open(char const*, int)
0x00000000004187a0 adapter::book_close()
0x00000000004187e0 adapter::is_in_book(adapter::board_t const*)
0x0000000000418870 adapter::book_move(adapter::board_t const*, bool)
0x0000000000418980 adapter::book_move(adapter::board_t const*, bool, bool)
0x0000000000418ae0 adapter::book_disp(adapter::board_t const*)
0x0000000000418c50 adapter::book_learn_move(adapter::board_t const*, int, int)
0x0000000000418db0 adapter::book_flush()
*fill* 0x0000000000418def 0x1
.text 0x0000000000418df0 0xb1a adapter/libadapter.a(book_make.o)
0x00000000004192b0 adapter::book_make(int, char**)
*fill* 0x000000000041990a 0x6
.text 0x0000000000419910 0x6a1 adapter/libadapter.a(book_merge.o)
0x0000000000419c10 adapter::book_merge(int, char**)
*fill* 0x0000000000419fb1 0xf
.text 0x0000000000419fc0 0x46 adapter/libadapter.a(colour.o)
0x0000000000419fc0 adapter::colour_is_ok(int)
0x0000000000419fd0 adapter::colour_is_white(int)
0x0000000000419fe0 adapter::colour_is_black(int)
0x0000000000419ff0 adapter::colour_equal(int, int)
0x000000000041a000 adapter::colour_opp(int)
*fill* 0x000000000041a006 0xa
.text 0x000000000041a010 0x29d adapter/libadapter.a(engine.o)
0x000000000041a010 adapter::engine_is_ok(adapter::engine_t const*)
0x000000000041a030 adapter::engine_open(adapter::engine_t*)
0x000000000041a050 adapter::engine_close(adapter::engine_t*)
0x000000000041a060 adapter::engine_get(adapter::engine_t*, char*, int)
0x000000000041a0b0 adapter::engine_send(adapter::engine_t*, char const*, ...)
0x000000000041a1b0 adapter::engine_send_queue(adapter::engine_t*, char const*, ...)
*fill* 0x000000000041a2ad 0x3
.text 0x000000000041a2b0 0xb1c adapter/libadapter.a(epd.o)
0x000000000041a430 adapter::epd_get_op(char const*, char const*, char*, int)
0x000000000041aaf0 adapter::epd_test(int, char**)
*fill* 0x000000000041adcc 0x4
.text 0x000000000041add0 0xad0 adapter/libadapter.a(fen.o)
0x000000000041add0 adapter::fen_fatal(char const*, int, char const*)
0x000000000041af70 adapter::board_from_fen(adapter::board_t*, char const*)
0x000000000041b560 adapter::board_to_fen(adapter::board_t const*, char*, int)
.text 0x000000000041b8a0 0x518 adapter/libadapter.a(game.o)
0x000000000041ba30 adapter::game_is_ok(adapter::game_t const*)
0x000000000041ba70 adapter::game_init(adapter::game_t*, char const*)
0x000000000041bac0 adapter::game_clear(adapter::game_t*)
0x000000000041bad0 adapter::game_status(adapter::game_t const*)
0x000000000041bae0 adapter::game_size(adapter::game_t const*)
0x000000000041baf0 adapter::game_pos(adapter::game_t const*)
0x000000000041bb00 adapter::game_move(adapter::game_t const*, int)
0x000000000041bb10 adapter::game_get_board(adapter::game_t const*, adapter::board_t*, int)
0x000000000041bb90 adapter::game_turn(adapter::game_t const*)
0x000000000041bba0 adapter::game_move_nb(adapter::game_t const*)
0x000000000041bbb0 adapter::game_add_move(adapter::game_t*, int)
0x000000000041bc40 adapter::game_goto(adapter::game_t*, int)
0x000000000041bcd0 adapter::game_rem_move(adapter::game_t*)
0x000000000041bd00 adapter::game_disp(adapter::game_t const*)
*fill* 0x000000000041bdb8 0x8
.text 0x000000000041bdc0 0x1a6 adapter/libadapter.a(hash.o)
0x000000000041bdc0 adapter::hash_init()
0x000000000041be20 adapter::hash_piece_key(int, int)
0x000000000041be50 adapter::hash_key(adapter::board_t const*)
0x000000000041bf10 adapter::hash_castle_key(int)
0x000000000041bf20 adapter::hash_ep_key(int)
0x000000000041bf40 adapter::hash_turn_key(int)
*fill* 0x000000000041bf66 0xa
.text 0x000000000041bf70 0x65f adapter/libadapter.a(io.o)
0x000000000041bf70 adapter::io_is_ok(adapter::io_t const*)
0x000000000041bfb0 adapter::io_init(adapter::io_t*)
0x000000000041bfd0 adapter::io_close(adapter::io_t*)
0x000000000041c030 adapter::io_get_update(adapter::io_t*)
0x000000000041c0e0 adapter::io_line_ready(adapter::io_t const*)
0x000000000041c110 adapter::io_get_line(adapter::io_t*, char*, int)
0x000000000041c220 adapter::io_send(adapter::io_t*, char const*, ...)
0x000000000041c460 adapter::io_send_queue(adapter::io_t*, char const*, ...)
*fill* 0x000000000041c5cf 0x1
.text 0x000000000041c5d0 0x3cd adapter/libadapter.a(line.o)
0x000000000041c5d0 adapter::line_is_ok(unsigned short const*)
0x000000000041c610 adapter::line_clear(unsigned short*)
0x000000000041c620 adapter::line_copy(unsigned short*, unsigned short const*)
0x000000000041c640 adapter::line_from_can(unsigned short*, adapter::board_t const*, char const*, int)
0x000000000041c760 adapter::line_to_can(unsigned short const*, adapter::board_t const*, char*, int)
0x000000000041c870 adapter::line_to_san(unsigned short const*, adapter::board_t const*, char*, int)
*fill* 0x000000000041c99d 0x3
.text 0x000000000041c9a0 0x55a adapter/libadapter.a(list.o)
0x000000000041c9a0 adapter::list_is_ok(adapter::list_t const*)
0x000000000041c9c0 adapter::list_clear(adapter::list_t*)
0x000000000041c9d0 adapter::list_add(adapter::list_t*, int, int)
0x000000000041c9f0 adapter::list_remove(adapter::list_t*, int)
0x000000000041ca30 adapter::list_is_empty(adapter::list_t const*)
0x000000000041ca40 adapter::list_size(adapter::list_t const*)
0x000000000041ca50 adapter::list_move(adapter::list_t const*, int)
0x000000000041ca60 adapter::list_value(adapter::list_t const*, int)
0x000000000041ca70 adapter::list_copy(adapter::list_t*, adapter::list_t const*)
0x000000000041cad0 adapter::list_move_to_front(adapter::list_t*, int)
0x000000000041cb20 adapter::list_note(adapter::list_t*)
0x000000000041cb60 adapter::list_sort(adapter::list_t*)
0x000000000041cc10 adapter::list_contain(adapter::list_t const*, int)
0x000000000041cc50 adapter::list_equal(adapter::list_t*, adapter::list_t*)
0x000000000041ce40 adapter::list_disp(adapter::list_t const*, adapter::board_t const*)
*fill* 0x000000000041cefa 0x6
.text 0x000000000041cf00 0x661 adapter/libadapter.a(move.o)
0x000000000041cf00 adapter::move_is_ok(int)
0x000000000041cf10 adapter::move_make(int, int)
0x000000000041cf40 adapter::move_make_flags(int, int, int)
0x000000000041cf70 adapter::move_from(int)
0x000000000041cf80 adapter::move_to(int)
0x000000000041cf90 adapter::move_promote_hack(int)
0x000000000041cfa0 adapter::move_is_promote(int)
0x000000000041cfb0 adapter::move_is_en_passant(int, adapter::board_t const*)
0x000000000041d000 adapter::move_is_capture(int, adapter::board_t const*)
0x000000000041d030 adapter::move_is_castle(int, adapter::board_t const*)
0x000000000041d180 adapter::move_piece(int, adapter::board_t const*)
0x000000000041d1a0 adapter::move_capture(int, adapter::board_t const*)
0x000000000041d1f0 adapter::move_promote(int, adapter::board_t const*)
0x000000000041d220 adapter::move_is_check(int, adapter::board_t const*)
0x000000000041d280 adapter::move_is_mate(int, adapter::board_t const*)
0x000000000041d2e0 adapter::move_to_can(int, adapter::board_t const*, char*, int)
0x000000000041d300 adapter::move_from_can(char const*, adapter::board_t const*)
0x000000000041d500 adapter::move_order(int)
0x000000000041d510 adapter::move_disp(int, adapter::board_t const*)
*fill* 0x000000000041d561 0xf
.text 0x000000000041d570 0x649 adapter/libadapter.a(move_do.o)
0x000000000041d7c0 adapter::move_do(adapter::board_t*, int)
*fill* 0x000000000041dbb9 0x7
.text 0x000000000041dbc0 0x832 adapter/libadapter.a(move_gen.o)
0x000000000041dc30 adapter::gen_moves(adapter::list_t*, adapter::board_t const*)
0x000000000041e3d0 adapter::gen_legal_moves(adapter::list_t*, adapter::board_t const*)
*fill* 0x000000000041e3f2 0xe
.text 0x000000000041e400 0x175 adapter/libadapter.a(move_legal.o)
0x000000000041e400 adapter::move_is_pseudo(int, adapter::board_t const*)
0x000000000041e450 adapter::pseudo_is_legal(int, adapter::board_t const*)
0x000000000041e4c0 adapter::move_is_legal(int, adapter::board_t const*)
0x000000000041e4f0 adapter::filter_legal(adapter::list_t*, adapter::board_t const*)
*fill* 0x000000000041e575 0xb
.text 0x000000000041e580 0x5c7 adapter/libadapter.a(parse.o)
0x000000000041e680 adapter::match(char*, char const*)
0x000000000041e690 adapter::parse_is_ok(adapter::parse_t const*)
0x000000000041e6f0 adapter::parse_open(adapter::parse_t*, char const*)
0x000000000041e710 adapter::parse_close(adapter::parse_t*)
0x000000000041e760 adapter::parse_add_keyword(adapter::parse_t*, char const*)
0x000000000041e790 adapter::parse_get_word(adapter::parse_t*, char*, int)
0x000000000041e860 adapter::parse_get_string(adapter::parse_t*, char*, int)
*fill* 0x000000000041eb47 0x9
.text 0x000000000041eb50 0xb49 adapter/libadapter.a(pgn.o)
0x000000000041f1b0 adapter::pgn_open(adapter::pgn_t*, char const*)
0x000000000041f290 adapter::pgn_close(adapter::pgn_t*)
0x000000000041f2a0 adapter::pgn_next_game(adapter::pgn_t*)
0x000000000041f4f0 adapter::pgn_next_move(adapter::pgn_t*, char*, int)
*fill* 0x000000000041f699 0x7
.text 0x000000000041f6a0 0x1da adapter/libadapter.a(posix.o)
0x000000000041f6a0 adapter::input_available()
0x000000000041f750 adapter::now_real()
0x000000000041f7f0 adapter::now_cpu()
*fill* 0x000000000041f87a 0x6
.text 0x000000000041f880 0x1c adapter/libadapter.a(random.o)
0x000000000041f880 adapter::random_init()
0x000000000041f890 adapter::random_64(int)
*fill* 0x000000000041f89c 0x4
.text 0x000000000041f8a0 0xc99 adapter/libadapter.a(san.o)
0x000000000041fd50 adapter::move_to_san(int, adapter::board_t const*, char*, int)
0x000000000041fd70 adapter::move_from_san(char const*, adapter::board_t const*)
0x0000000000420490 adapter::move_from_san_debug(char const*, adapter::board_t const*)
*fill* 0x0000000000420539 0x7
.text 0x0000000000420540 0xae engine/libengine.a(main.o)
0x0000000000420540 engine::main_engine(int, char**)
*fill* 0x00000000004205ee 0x2
.text 0x00000000004205f0 0xc77 engine/libengine.a(move_do.o)
0x0000000000420b90 engine::move_do_init()
0x0000000000420bf0 engine::move_do(engine::board_t*, int, engine::undo_t*)
0x0000000000420fc0 engine::move_undo(engine::board_t*, int, engine::undo_t const*)
0x0000000000421190 engine::move_do_null(engine::board_t*, engine::undo_t*)
0x0000000000421230 engine::move_undo_null(engine::board_t*, engine::undo_t const*)
*fill* 0x0000000000421267 0x9
.text 0x0000000000421270 0x245 engine/libengine.a(option.o)
0x0000000000421270 engine::option_list()
0x00000000004212f0 engine::option_set(char const*, char const*)
0x0000000000421360 engine::option_init()
0x0000000000421390 engine::option_get(char const*)
0x0000000000421400 engine::option_get_bool(char const*)
0x0000000000421490 engine::option_get_int(char const*)
0x00000000004214b0 engine::option_get_string(char const*)
*fill* 0x00000000004214b5 0xb
.text 0x00000000004214c0 0x9e0 engine/libengine.a(pawn.o)
0x00000000004214c0 engine::pawn_init_bit()
0x0000000000421630 engine::pawn_init()
0x00000000004216c0 engine::pawn_clear()
0x0000000000421720 engine::pawn_alloc()
0x0000000000421760 engine::pawn_get_info(engine::pawn_info_t*, engine::board_t const*)
0x0000000000421e80 engine::quad(int, int, int)
.text 0x0000000000421ea0 0x1a7 engine/libengine.a(piece.o)
0x0000000000421ea0 engine::piece_init()
0x0000000000421fc0 engine::piece_is_ok(int)
0x0000000000421fe0 engine::piece_from_12(int)
0x0000000000421ff0 engine::piece_to_char(int)
0x0000000000422010 engine::piece_from_char(int)
*fill* 0x0000000000422047 0x9
.text 0x0000000000422050 0xeb0 engine/libengine.a(protocol.o)
0x00000000004220b0 engine::get(char*, int)
0x00000000004220e0 engine::send(char const*, ...)
0x0000000000422e70 engine::loop()
0x0000000000422ec0 engine::event()
.text 0x0000000000422f00 0x59b engine/libengine.a(pst.o)
0x0000000000422f00 engine::pst_init()
*fill* 0x000000000042349b 0x5
.text 0x00000000004234a0 0x2 engine/libengine.a(random.o)
0x00000000004234a0 engine::random_init()
*fill* 0x00000000004234a2 0xe
.text 0x00000000004234b0 0x8e3 engine/libengine.a(search.o)
0x00000000004234b0 engine::depth_is_ok(int)
0x00000000004234c0 engine::height_is_ok(int)
0x00000000004234d0 engine::search_clear()
0x00000000004235e0 engine::search_update_current()
0x0000000000423660 engine::search_update_best()
0x00000000004238e0 engine::search()
0x0000000000423bf0 engine::search_update_root()
0x0000000000423c70 engine::search_check()
*fill* 0x0000000000423d93 0xd
.text 0x0000000000423da0 0x18c5 engine/libengine.a(search_full.o)
0x00000000004253f0 engine::search_full_init(engine::list_t*, engine::board_t*)
0x0000000000425660 engine::search_full_root(engine::list_t*, engine::board_t*, int, int)
*fill* 0x0000000000425665 0xb
.text 0x0000000000425670 0x663 engine/libengine.a(see.o)
0x00000000004259b0 engine::see_move(int, engine::board_t const*)
0x0000000000425c20 engine::see_square(engine::board_t const*, int, int)
*fill* 0x0000000000425cd3 0xd
.text 0x0000000000425ce0 0xc87 engine/libengine.a(sort.o)
0x0000000000425e40 engine::sort_init()
0x0000000000425fa0 engine::sort_next(engine::sort_t*)
0x0000000000426340 engine::sort_init_qs(engine::sort_t*, engine::board_t*, engine::attack_t const*, bool)
0x00000000004263b0 engine::sort_next_qs(engine::sort_t*)
0x0000000000426590 engine::good_move(int, engine::board_t const*, int, int)
0x0000000000426650 engine::history_good(int, engine::board_t const*)
0x00000000004266f0 engine::history_bad(int, engine::board_t const*)
0x0000000000426780 engine::note_moves(engine::list_t*, engine::board_t const*, int, int)
0x00000000004268c0 engine::sort_init(engine::sort_t*, engine::board_t*, engine::attack_t const*, int, int, int)
*fill* 0x0000000000426967 0x9
.text 0x0000000000426970 0x120 engine/libengine.a(square.o)
0x0000000000426970 engine::square_init()
0x00000000004269f0 engine::file_from_char(int)
0x0000000000426a00 engine::rank_from_char(int)
0x0000000000426a10 engine::file_to_char(int)
0x0000000000426a20 engine::rank_to_char(int)
0x0000000000426a30 engine::square_to_string(int, char*, int)
0x0000000000426a60 engine::square_from_string(char const*)
.text 0x0000000000426a90 0x4a3 engine/libengine.a(trans.o)
0x0000000000426a90 engine::trans_is_ok(engine::trans const*)
0x0000000000426af0 engine::trans_free(engine::trans*)
0x0000000000426b20 engine::trans_clear(engine::trans*)
0x0000000000426bd0 engine::trans_init(engine::trans*)
0x0000000000426c50 engine::trans_alloc(engine::trans*)
0x0000000000426cd0 engine::trans_inc_date(engine::trans*)
0x0000000000426d40 engine::trans_store(engine::trans*, unsigned long long, int, int, int, int)
0x0000000000426e90 engine::trans_retrieve(engine::trans*, unsigned long long, int*, int*, int*, int*, int*)
0x0000000000426f00 engine::trans_stats(engine::trans const*)
*fill* 0x0000000000426f33 0xd
.text 0x0000000000426f40 0x586 engine/libengine.a(util.o)
0x0000000000426f40 engine::util_init()
0x0000000000426f80 engine::my_random_init()
0x0000000000426fa0 engine::my_random(int)
0x0000000000426fd0 engine::my_atoll(char const*)
0x0000000000427010 engine::my_round(double)
0x0000000000427030 engine::my_free(void*)
0x0000000000427040 engine::my_fatal(char const*, ...)
0x0000000000427100 engine::my_malloc(int)
0x0000000000427120 engine::my_file_read_line(_IO_FILE*, char*, int)
0x00000000004271a0 engine::my_string_empty(char const*)
0x00000000004271c0 engine::my_string_equal(char const*, char const*)
0x0000000000427220 engine::my_strdup(char const*)
0x0000000000427260 engine::my_string_clear(char const**)
0x0000000000427280 engine::my_string_set(char const**, char const*)
0x00000000004272b0 engine::my_timer_reset(engine::my_timer_t*)
0x00000000004272d0 engine::my_timer_start(engine::my_timer_t*)
0x00000000004272f0 engine::my_timer_stop(engine::my_timer_t*)
0x0000000000427330 engine::my_timer_elapsed_real(engine::my_timer_t const*)
0x0000000000427380 engine::my_timer_elapsed_cpu(engine::my_timer_t const*)
0x00000000004273d0 engine::my_timer_cpu_usage(engine::my_timer_t const*)
*fill* 0x00000000004274c6 0xa
.text 0x00000000004274d0 0x19a engine/libengine.a(value.o)
0x00000000004274d0 engine::value_init()
0x0000000000427580 engine::value_is_ok(int)
0x0000000000427590 engine::range_is_ok(int, int)
0x00000000004275c0 engine::value_is_mate(int)
0x00000000004275d0 engine::value_to_trans(int, int)
0x0000000000427600 engine::value_from_trans(int, int)
0x0000000000427630 engine::value_to_mate(int)
*fill* 0x000000000042766a 0x6
.text 0x0000000000427670 0xc6 engine/libengine.a(vector.o)
0x0000000000427670 engine::vector_init()
0x00000000004276f0 engine::delta_is_ok(int)
0x0000000000427710 engine::inc_is_ok(int)
*fill* 0x0000000000427736 0xa
.text 0x0000000000427740 0xae9 engine/libengine.a(attack.o)
0x0000000000427740 engine::attack_init()
0x0000000000427e00 engine::is_attacked(engine::board_t const*, int, int)
0x0000000000427ea0 engine::line_is_empty(engine::board_t const*, int, int)
0x0000000000427ee0 engine::is_pinned(engine::board_t const*, int, int)
0x0000000000427f60 engine::attack_is_ok(engine::attack_t const*)
0x0000000000428010 engine::attack_set(engine::attack_t*, engine::board_t const*)
0x0000000000428160 engine::piece_attack_king(engine::board_t const*, int, int, int)
*fill* 0x0000000000428229 0x7
.text 0x0000000000428230 0x8cb engine/libengine.a(board.o)
0x0000000000428230 engine::board_is_ok(engine::board_t const*)
0x0000000000428240 engine::board_clear(engine::board_t*)
0x00000000004282b0 engine::board_copy(engine::board_t*, engine::board_t const*)
0x00000000004282d0 engine::board_is_legal(engine::board_t const*)
0x0000000000428300 engine::board_is_check(engine::board_t const*)
0x0000000000428320 engine::board_is_mate(engine::board_t const*)
0x0000000000428380 engine::board_is_stalemate(engine::board_t*)
0x0000000000428440 engine::board_is_repetition(engine::board_t const*)
0x00000000004284e0 engine::board_opening(engine::board_t const*)
0x0000000000428590 engine::board_endgame(engine::board_t const*)
0x0000000000428640 engine::board_init_list(engine::board_t*)
*fill* 0x0000000000428afb 0x5
.text 0x0000000000428b00 0x586 engine/libengine.a(book.o)
0x0000000000428c40 engine::book_init()
0x0000000000428c60 engine::book_open(char const*)
0x0000000000428db0 engine::book_close()
0x0000000000428df0 engine::book_move(engine::board_t*)
*fill* 0x0000000000429086 0xa
.text 0x0000000000429090 0x2012 engine/libengine.a(eval.o)
0x0000000000429890 engine::eval_init()
0x0000000000429ab0 engine::eval(engine::board_t const*)
*fill* 0x000000000042b0a2 0xe
.text 0x000000000042b0b0 0x639 engine/libengine.a(fen.o)
0x000000000042b0b0 engine::board_from_fen(engine::board_t*, char const*)
0x000000000042b4e0 engine::board_to_fen(engine::board_t const*, char*, int)
*fill* 0x000000000042b6e9 0x7
.text 0x000000000042b6f0 0x260 engine/libengine.a(hash.o)
0x000000000042b6f0 engine::hash_init()
0x000000000042b730 engine::hash_key(engine::board_t const*)
0x000000000042b830 engine::hash_pawn_key(engine::board_t const*)
0x000000000042b890 engine::hash_material_key(engine::board_t const*)
0x000000000042b8e0 engine::hash_piece_key(int, int)
0x000000000042b910 engine::hash_castle_key(int)
0x000000000042b930 engine::hash_ep_key(int)
0x000000000042b940 engine::hash_turn_key(int)
.text 0x000000000042b950 0x287 engine/libengine.a(list.o)
0x000000000042b950 engine::list_is_ok(engine::list_t const*)
0x000000000042b970 engine::list_remove(engine::list_t*, int)
0x000000000042b9b0 engine::list_copy(engine::list_t*, engine::list_t const*)
0x000000000042ba00 engine::list_sort(engine::list_t*)
0x000000000042baa0 engine::list_contain(engine::list_t const*, int)
0x000000000042bae0 engine::list_note(engine::list_t*)
0x000000000042bb20 engine::list_filter(engine::list_t*, engine::board_t*, bool (*)(int, engine::board_t*), bool)
*fill* 0x000000000042bbd7 0x9
.text 0x000000000042bbe0 0xdac engine/libengine.a(material.o)
0x000000000042bbe0 engine::material_init()
0x000000000042bc30 engine::material_clear()
0x000000000042bc90 engine::material_alloc()
0x000000000042bcd0 engine::material_get_info(engine::material_info_t*, engine::board_t const*)
*fill* 0x000000000042c98c 0x4
.text 0x000000000042c990 0x34a engine/libengine.a(move.o)
0x000000000042c990 engine::move_is_ok(int)
0x000000000042c9b0 engine::move_promote(int)
0x000000000042c9e0 engine::move_order(int)
0x000000000042ca00 engine::move_is_capture(int, engine::board_t const*)
0x000000000042ca30 engine::move_is_under_promote(int)
0x000000000042ca60 engine::move_is_tactical(int, engine::board_t const*)
0x000000000042ca90 engine::move_capture(int, engine::board_t const*)
0x000000000042cad0 engine::move_to_string(int, char*, int)
0x000000000042cbc0 engine::move_from_string(char const*, engine::board_t const*)
*fill* 0x000000000042ccda 0x6
.text 0x000000000042cce0 0xa96 engine/libengine.a(move_check.o)
0x000000000042cd70 engine::gen_quiet_checks(engine::list_t*, engine::board_t*)
0x000000000042d640 engine::move_is_check(int, engine::board_t*)
*fill* 0x000000000042d776 0xa
.text 0x000000000042d780 0x7c3 engine/libengine.a(move_evasion.o)
0x000000000042ded0 engine::gen_legal_evasions(engine::list_t*, engine::board_t const*, engine::attack_t const*)
0x000000000042dee0 engine::gen_pseudo_evasions(engine::list_t*, engine::board_t const*, engine::attack_t const*)
0x000000000042def0 engine::legal_evasion_exist(engine::board_t const*, engine::attack_t const*)
*fill* 0x000000000042df43 0xd
.text 0x000000000042df50 0x1a8a engine/libengine.a(move_gen.o)
0x000000000042e1f0 engine::gen_quiet_moves(engine::list_t*, engine::board_t const*)
0x000000000042ebd0 engine::add_pawn_move(engine::list_t*, int, int)
0x000000000042ec40 engine::gen_moves(engine::list_t*, engine::board_t const*)
0x000000000042ef00 engine::gen_legal_moves(engine::list_t*, engine::board_t*)
0x000000000042ef80 engine::gen_captures(engine::list_t*, engine::board_t const*)
0x000000000042f9a0 engine::add_promote(engine::list_t*, int)
*fill* 0x000000000042f9da 0x6
.text 0x000000000042f9e0 0x3a3 engine/libengine.a(move_legal.o)
0x000000000042fa30 engine::move_is_pseudo(int, engine::board_t*)
0x000000000042fb50 engine::quiet_is_pseudo(int, engine::board_t*)
0x000000000042fc50 engine::pseudo_is_legal(int, engine::board_t*)
*fill* 0x000000000042fd83 0xd
.text 0x000000000042fd90 0x20a engine/libengine.a(posix.o)
0x000000000042fd90 engine::input_available()
0x000000000042fe70 engine::now_real()
0x000000000042ff10 engine::now_cpu()
*fill* 0x000000000042ff9a 0x6
.text 0x000000000042ffa0 0x127 engine/libengine.a(pv.o)
0x000000000042ffa0 engine::pv_is_ok(unsigned short const*)
0x0000000000430000 engine::pv_copy(unsigned short*, unsigned short const*)
0x0000000000430020 engine::pv_cat(unsigned short*, unsigned short const*, int)
0x0000000000430040 engine::pv_to_string(unsigned short const*, char*, int)
*fill* 0x00000000004300c7 0x9
.text 0x00000000004300d0 0x340 engine/libengine.a(recog.o)
0x00000000004301f0 engine::recog_draw(engine::board_t const*)
.text 0x0000000000430410 0x72 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
0x0000000000430410 __libc_csu_init
0x0000000000430480 __libc_csu_fini
.text 0x0000000000430482 0x0 /usr/lib/gcc/x86_64-linux-gnu/5/crtend.o
.text 0x0000000000430482 0x0 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o
*(.gnu.warning)
.fini 0x0000000000430484 0x9
*(SORT(.fini))
.fini 0x0000000000430484 0x4 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o
0x0000000000430484 _fini

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,78 +0,0 @@
import idc
import ida_kernwin
import imp
import snap_cg
import lfa
import maxcut
import module
import cc_base
import modnaming
import basicutils_7x as basicutils
from PyQt5 import QtCore, QtGui, QtWidgets
#-------------------------------------------------------------------------------
def handler(item, column_no):
ea = item.ea
if is_mapped(ea):
jumpto(ea)
#-------------------------------------------------------------------------------
class CBaseTreeViewer(ida_kernwin.PluginForm):
def populate_tree(self):
# Clear previous items
self.tree.clear()
#Do LFA and MaxCut Analysis to find module boundaries
_, lfa_modlist = lfa.analyze()
for module_data in lfa_modlist:
module_name = "Module 0x%08x:0x%08x" % (module_data.start, module_data.end)
item = QtWidgets.QTreeWidgetItem(self.tree)
item.setText(0, module_name)
item.ea = module_data.start
for func in Functions(module_data.start, module_data.end):
node = QtWidgets.QTreeWidgetItem(item)
node.setText(0, "0x%08x: %s" % (func, idc.get_func_name(func)))
node.ea = func
self.tree.itemDoubleClicked.connect(handler)
def OnCreate(self, form):
# Get parent widget
self.parent = ida_kernwin.PluginForm.FormToPyQtWidget(form)
# Create tree control
self.tree = QtWidgets.QTreeWidget()
self.tree.setHeaderLabels(("Names",))
self.tree.setColumnWidth(0, 100)
# Create layout
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tree)
self.populate_tree()
# Populate PluginForm
self.parent.setLayout(layout)
def Show(self, title):
return ida_kernwin.PluginForm.Show(self, title, options = ida_kernwin.PluginForm.WOPN_PERSIST)
#-------------------------------------------------------------------------------
def main():
tree_frm = CBaseTreeViewer()
tree_frm.Show("Object Files")
if __name__ == "__main__":
imp.reload(modnaming)
imp.reload(module)
imp.reload(cc_base)
imp.reload(lfa)
imp.reload(maxcut)
imp.reload(snap_cg)
imp.reload(basicutils)
main()

View File

@@ -1,292 +0,0 @@
##############################################################################################
# Copyright 2018 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
################################################################################
### Object File Boundary Detection in IDA Pro with Local Function Affinity ###
################################################################################
# LFA Metric
# Local Function Affinity (LFA) is a measurement of the direction a function
# is being "pulled" by the functions it calls and the functions that call it.
# By looking at an average of the log of the distance between these functions
# we get a measurement of whether the function is related to functions in the
# positive or negative direction.
# Edge Detection
# In a standard C/C++ development environment, the project is divided into
# multiple source files, which are compiled to object files, then linked into
# the final binary in order. If external references are eliminated (LFA does
# this imperfectly by just eliminating calls whose distance is above a chosen
# threshold) we would expect to see LFA starting positive, switching to
# negative over the course of a source file, then switching back to positive
# at the beginning of the next file. So object file boundaries
# What is code anyway?
# Don't get too hung up on "object file boundaries" - for LFA (or any other
# attempt to solve the problem) to be perfect, the design and implementation
# of the code would have to be perfect. What LFA is really finding is clusters
# of functionality, that should be more or less related to object files
# but it will often break up large object files into multiple clusters or
# detect 2 or 3 related object files as one file.
IDA_VERSION = 7
import basicutils_7x as basicutils
#External dependencies
import math
#CodeCut dependencies
import cc_base
import module
#Threshold above which a function call is considered "external"
#For published research - 0x1000 = 4K
MAX_CALL = 0x1000
#This is a list of the LFA scores for all functions
g_function_list = []
#This is a list of modules a.k.a. object files after the edge_detect()
#function is executed
g_module_list = []
#func_callers_weight(f):
#Return the LFA score for functions that this functions calls (i.e. the "calls from" score)
#If there are no references, return 0
def func_callers_weight(f):
fc = 0
fs = 0
for xref in basicutils.FuncXrefsFrom(f):
dist = abs(xref - f)
#print "%08x: %08x %d " % (f, xref, dist),
if dist > MAX_CALL:
continue
if (dist != 0):
logdist = math.log(dist)
else: #recursive function call
logdist = 0
if (xref - f < 0):
o = -logdist
else:
o = logdist
#print " %f " % o,
fs += o
fc += 1
if fc == 0:
score = 0
else:
score = fs / fc
return score
#func_callee_weight(f):
#Return the LFA score for calls where this function is the "callee" (i.e. the "calls to" score)
#If there are no references, return 0
def func_callee_weight(f):
fc = 0
fs = 0
a = 0
for xref in basicutils.CodeRefsTo(f):
dist = abs(xref - f)
#print "%08x: %08x %d " % (f, xref, dist),
if dist > MAX_CALL:
continue
if (dist != 0):
logdist = math.log(dist)
else: #recursive function call
logdist = 0
if (xref - f < 0):
o = -logdist
else:
o = logdist
#print " %f " % o,
fs += o
fc += 1
if fc == 0:
score = 0
else:
score = fs / fc
return score
#func_call_weight(start,end):
#Iterate over each function in the range and calculated the LFA scores
# If both scores are 0, skip the function altogether, exclude it from the list
# If one score is 0, interpolate that score from the previous score
def func_call_weight(f_start, f_end):
global g_function_list
c = 1
f = f_start
fe = f_end
if f==0:
f = basicutils.NextFunction(0)
f_end = basicutils.BADADDR
prevscore = 0
prevscore_1 = 0
prevscore_2 = 0
z1 = 0
z2 = 0
#for each function in range
while (f < fe):
#get both LFA scores for the function
score_1 = func_callers_weight(f)
score_2 = func_callee_weight(f)
#if both scores are 0 (i.e. no references for the function or all refs are above the threshold)
#then skip the function altogether
if (score_1 == 0) and (score_2 == 0):
#print("Skipping 0x%08x\n" % f)
prevscore_1 = 0
prevscore_2 = 0
z1 = 1
z2 = 1
finf = module.func_info(f,0,0)
finf.lfa_skip=1
g_function_list.append(finf)
f = basicutils.NextFunction(f)
continue
#if 1st or 2nd score is zero, interpolate using previous score and an assumed negative linear slope
#otherwise use the score
if (score_1 == 0):
score_1 = prevscore_1 - z1 * .4
z1 += 1
else:
prevscore_1 = score_1
z1 = 1
if (score_2 == 0):
score_2 = prevscore_2 - z2 * .4
z2 += 1
else:
prevscore_2 = score_2
z2 = 1
total_score = score_1 + score_2
#Output scores in log window
#print("0x%08x, %d , %f, %f, %f" % (f, c,score_1, score_2, total_score))
#Add scores to the global function score list
finf = module.func_info(f,score_1,score_2)
finf.lfa_skip=0
g_function_list.append(finf)
line = "0x%08x, %d , %f, %f, %f\n" % (f,c,score_1, score_2, total_score)
f=basicutils.NextFunction(f)
c+=1
#get_last _three and get_lfa_start:
#Previously LFA would just skip functions if they had no caller or callee score
#it would effectively drop them. This meant that when doing edge detection we
#knew every function in the function list had a score. Now we're putting all
#functions in the function list, and we have a "skip" field if LFA should skip it
#for scoring purposes. So these functions help parse that skip field, since for
#edge detection we look at the previous three scores.
def get_last_three(index):
c=0
i = index-1
p=[]
while ((c<3) and (i>0)):
#print "get_last_3: %d,%d" % (c,i)
if (g_function_list[i].lfa_skip == 0):
p.append(g_function_list[i])
c+=1
i-=1
if (c==3):
return p[0],p[1],p[2]
else:
print("Error: could not find 3 scored entries before index: %d (%d,%d)" % (index, i, c))
return 0,0,0
def get_lfa_start():
c=0;
i=0;
while (c < 4):
#print "get_lfa_start: %d,%d" % (c,i)
if (g_function_list[i].lfa_skip==0):
c+=1
i+=1
return i
#edge_detect():
# Determine boundaries between object files
# Edge condition is a delta of at least 2 where the current score is positive
# and 2 of the last 3 scores were negative (negative trend)
def edge_detect():
global g_function_list
global g_module_list
#For published research
EDGE_THRESHOLD = 2
c=get_lfa_start()
#do edge detection
while (c<len(g_function_list)):
if (g_function_list[c].lfa_skip == 0):
f_1,f_2,f_3 = get_last_three(c)
p_1 = f_1.total_score
p_2 = f_2.total_score
p_3 = f_3.total_score
s = g_function_list[c].total_score
#if score is positive and it is diff of at least 2 from previous
#and the previous function was not an edge
if ((not f_1.edge[0] == 1) and (s > 0) and ((s - p_1) > EDGE_THRESHOLD)):
#if 2 of last 3 were negative
m = sorted([p_1,p_2,p_3])
if (m[1] < 0):
g_function_list[c].edge[0]=1
c+=1
#assign modules based on where the edges are
c=0
mod_start = g_function_list[0].loc
while(c<len(g_function_list)):
f = g_function_list[c]
if (f.edge[0] == 1):
#change from previous code, this will make the modules contiguous
b_mod = module.bin_module(mod_start,f.loc-1,0,"")
mod_start = f.loc #set the start of the next module to this function (where edge was detected)
g_module_list.append(b_mod)
c+=1
#Main entry point - returns an LFA module list and a global function list (with the LFA module edges marked)
def analyze():
global g_function_list
global g_module_list
#Define range to analyze
#just do .text segment if we've got one
#otherwise just start from the first function in DB
start,end = basicutils.SegByName(".text")
if (start == basicutils.BADADDR):
start = basicutils.NextFunction(0)
end = basicutils.BADADDR
#Calculate LFA score for all functions
func_call_weight(start,end)
#Detect edges - object file boundaries
edge_detect()
return g_function_list, g_module_list

View File

@@ -1,343 +0,0 @@
#!/usr/bin/python
##############################################################################################
# Copyright 2018 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
import sys
#Syntax: map_read.py <ground truth .map file> <LFA produced .map file>
#Reads the two map files and outputs a score
#Score is % overlap, % underlap, and % gap (the sum of which should be 100%)
#Raw list of modules
g_mod_list1 = []
g_mod_list2 = []
#"Reconciled" module list - after modules have been combined to represent best alignment
g_rec_list1 = []
g_rec_list2 = []
#name
#offset - starting address of the module
#mlen - length of the module
#reach - end address of the module (offset + mlen)
#gap - when collapsing two modules,
class bin_mod:
def __init__(self, n, o, ml):
self.name = n
self.offset = o
self.mlen = ml
self.reach = o+ml
self.gap = 0
#map_parse(function, mlist):
#Parse a gcc/ld formatted .map file
# (mlist == 1): ground truth map, saved to g_mod_list1
# (mlist == 2): LFA map, saved to g_mod_list2
def map_parse(f,mlist):
global g_mod_list1
global g_mod_list2
line = f.readline()
prev_name = ""
while (line != ""):
#print "line %s" % line
if (not line.startswith(" .text") or (len(line) < 17)):
line = f.readline()
continue
#line wrap case
if not ((line[16] == '0') and (line[17] == 'x')):
seg = line.strip()
line = f.readline()
else:
seg = line[0:15].strip()
offset = int(line[16:34],16)
mlen = int(line[35:45].strip(),16)
name = line[46:].strip()
#print "%s\n%s\n%s\n%s\n"% (line[0:15],line[16:33],line[34:45],line[46:])
#print "Seg: %s Offset: %x Len: %x Name: %s" % (seg,offset,mlen,name)
if (offset == 0) or (mlen == 0):
line = f.readline()
continue
#print "Seg: %s Offset: %x Len: %x Name: %s" % (seg,offset,mlen,name)
if (name == prev_name):
#print "Combining"
if (mlist == 1):
new_reach = offset+mlen
begin = g_mod_list1[-1].offset
new_len = new_reach-begin
g_mod_list1[-1].mlen = new_len
g_mod_list1[-1].reach = new_reach
else:
new_reach = offset+mlen
begin = g_mod_list2[-1].offset
new_len = new_reach-begin
g_mod_list2[-1].mlen = new_len
g_mod_list2[-1].reach = new_reach
#print "Seg: %s Offset: %x Len: %x Name: %s" % (seg,begin,new_len,name)
else:
bm = bin_mod(name,offset,mlen)
if (mlist == 1):
g_mod_list1.append(bm)
else:
g_mod_list2.append(bm)
#read next line
line = f.readline()
prev_name = name
#map_print():
#Print both ground truth and LFA map output
def map_print(n):
if (n==1):
print("Map 1 (ground truth):")
mod_list = g_mod_list1
else:
print("Map 2:")
mod_list = g_mod_list2
print("# of modules: %d" % len(mod_list))
for x in range(len(mod_list)):
print("Name: %s Offset: %x Len: %x" % (mod_list[x].name,mod_list[x].offset,mod_list[x].mlen))
#score_underlap(module1,module2):
#opposite of overlap - actually "disjoint areas" might be more accurate
#For the purposes of scoring this is the area of m1 that m2 doesn't cover
#to ensure that the underlap does not get counted twice
def score_underlap(m1,m2):
#Assume that the m1s are contiguous (from .map files)
#Only measure the portion of this m1 that the m2 doesn't cover
#This ensures that disjoint areas don't get counted twice
m2_upper = max(m1.offset,m2.offset)
m2_lower = min(m1.reach, m2.reach)
ul = abs (m1.offset - m2_upper)
ul += abs (m1.reach - m2_lower)
return ul
#mod_underlap(m1,m2):
#Like score underlap but this is a simpler calculation for use with module list reconciliation
def mod_underlap(m1,m2):
ul = abs (m1.offset - m2.offset)
ul += abs (m1.reach - m2.reach)
return ul
#mod_collapse(module1,module2):
#Return a module object that is the combination of the two modules
#Does not update either of the global module lists
def mod_collapse(m1,m2):
nname = m1.name + "_and_" + m2.name
noffset = min(m1.offset,m2.offset)
nr = max(m1.reach,m2.reach)
nlen = nr - noffset
cm = bin_mod(nname, noffset, nlen)
cm.gap = m1.gap
cm.gap += m2.gap
#will work regardless of module order,
#the correct one will be positive, the wrong one negative
cm.gap += max(m2.offset - m1.reach, m1.offset - m2.reach)
return cm
#mod_print(m):
#Print a single module
def mod_print(m):
#print "%s: %08x - %08x" % (m.name,m.offset,m.reach),
print("%08x - %08x" % (m.offset,m.reach), end=' ')
if (m.gap != 0):
print(" gap: %x" % m.gap, end=' ')
#rec_list_print():
#Print side by side the reconciled module lists
def rec_list_print():
i1 = len(g_rec_list1)
i2 = len(g_rec_list2)
if (i1 != i2):
print("Error: List lengths don't match, not fully reconciled (%d and %d)." % (i1,i2))
return
for i in range(i1):
mod_print(g_rec_list1[i])
mod_print(g_rec_list2[i])
print("u: %x" % (score_underlap(g_rec_list1[i],g_rec_list2[i])))
#final_score():
#Determine the scores by iterating through the reconciled module lists
#and tallying underlap areas and gap areas
def final_score():
start = min(g_rec_list1[0].offset,g_rec_list2[0].offset)
end = max(g_rec_list1[-1].reach,g_rec_list2[-1].reach)
i1 = len(g_rec_list1)
i2 = len(g_rec_list2)
if (i1 != i2):
print("Error: List lengths don't match, not fully reconciled (%d and %d)." % (i1,i2))
return
s=0
g=0
for i in range(0,i1):
s+=score_underlap(g_rec_list1[i],g_rec_list2[i])
#only count gaps from the "compare" map file (the one we generate with LFA)
g+=g_rec_list2[i].gap
#Area of overlap - total area - (underlaps + gaps)
good_area = (end-start) - (s+g)
print("Length: 0x%x Good: 0x%x (%2f) Underlap: 0x%x (%2f) Gaps: 0x%x (%2f)" % (end-start,good_area, good_area*100.0/(end-start),s,s*100.0/(end-start),g,g*100.0/(end-start)))
return (s+g)/1.0/(end-start)
#map_reconcile():
#Attempt to combine modules in either list to make the maps more similar
#When combining modules, keep track of gaps between the modules so we can account for that in the overall score
#This might seem like cheating, but here's why it's not:
# - we want to give the algorithm credit if it finds a couple of clusters of functionality within a .o file
# (i.e. it says one .o file is really 2 or 3 .o files)
# - we want to give the algorithm credit if it says nearby .o files are so inter-related that they are essentially one
# (i.e. it says that 2 or 3 adjacent .o files are really one .o file
#
#I'm definitely open to suggestions on better ways to do this
def map_reconcile():
i1 = 0
i2 = 0
while (i1 < len(g_mod_list1)) and (i2 < len(g_mod_list2)):
m1 = g_mod_list1[i1]
m2 = g_mod_list2[i2]
#"reach" - aka the end of the current modules under consideration
m1r = m1.reach
m2r = m2.reach
#current underlap
po = mod_underlap(m1,m2)
pc = 0x10000000000
print(" m1 (%d): " % i1, end=' ')
mod_print(m1)
print(" m2 (%d): " % i2, end=' ')
mod_print(m2)
print(" underlap: %x" % (po))
d=0
#module 1 is longer than module 2, so attempt to collapse modules in list 2 to optimize
if (m1r > m2r):
nm2 = g_mod_list2[i2]
#add/collapse m2 modules, but check to see if makes it better
while (d == 0) and (i2+1 < len(g_mod_list2)):
pnm2 = nm2
nm2 = mod_collapse(nm2,g_mod_list2[i2+1])
pc = mod_underlap(m1, nm2)
print("nm2 (%d): (%x)" % (i2+1,pc), end=' ')
mod_print(nm2)
print("")
if (pc < po):
po = pc
i2+=1
else:
d=1
print("Collapsed m2 (%d): " % i2, end=' ')
mod_print(pnm2)
print("")
#add final collapsed modules to reconciled list
g_rec_list1.append(m1)
g_rec_list2.append(pnm2)
#module 2 is longer than module 1, so attempt to collapse modules in list 1 to optimize
else:
nm1 = g_mod_list1[i1]
while (d==0) and (i1+1 < len(g_mod_list1)):
pnm1 = nm1
nm1 = mod_collapse(nm1,g_mod_list1[i1+1])
pc = mod_underlap(nm1, m2)
print("nm1 (%d): (%x)" % (i1 + 1, pc), end=' ')
mod_print(nm1)
print("")
if (pc < po):
po = pc
i1 += 1
else:
d=1
print("Collapsed m1 (%d): " % i1, end=' ')
mod_print(pnm1)
print("")
g_rec_list1.append(pnm1)
g_rec_list2.append(m2)
i1+=1
i2+=1
print("")
#end case
#if we've got one module left on either side,
#collapse all the other modules on the other side to match
if (i1 == len(g_mod_list1)-1):
m1 = g_mod_list1[i1]
print("end m1 (%d):" % (i1), end=' ')
mod_print(m1)
print("")
nm2 = g_mod_list2[i2]
i2 += 1
while (i2 < len(g_mod_list2)):
nm2 = mod_collapse(nm2,g_mod_list2[i2])
print("end nm2 (%d):" % (i2), end=' ')
mod_print(nm2)
print("")
i2 += 1
g_rec_list1.append(m1)
g_rec_list2.append(nm2)
if (i2 == len(g_mod_list2)-1):
m2 = g_mod_list2[i2]
print("end m2 (%d):" % (i2), end=' ')
mod_print(m2)
print("")
nm1 = g_mod_list1[i1]
i1 += 1
while (i1 < len(g_mod_list1)):
nm1 = mod_collapse(nm1,g_mod_list1[i1])
print("end nm1 (%d):" % (i1), end=' ')
mod_print(nm1)
print("")
i1 += 1
g_rec_list1.append(nm1)
g_rec_list2.append(m2)
#"ground truth" map file
f = open(sys.argv[1], 'r')
map_parse(f,1)
#map file to compare
f2 = open(sys.argv[2], 'r')
map_parse(f2,2)
map_print(1)
map_print(2)
#"Reconcile" maps to make them more similar - see comment above for why we do this
map_reconcile()
#Print reconciled map
rec_list_print()
#Print score
print("Score: %f" % (final_score()))
f.close()
f2.close()

View File

@@ -1,180 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
###############################################################
### Object File Boundary Detection in IDA Pro with MaxCut ###
###############################################################
import snap
import sys
import snap_cg
import module
g_maxcut_modlist = []
#make_subgraph()
#returns a Snap subgraph for just the address region specified
#(i.e. the subgraph will not have any edges that originate outside the region
#or terminate outside the region)
def make_subgraph(region_start,region_end, graph):
print("make_subgraph: start: 0x%x and end: 0x%x" % (region_start,region_end))
NIdV = snap.TIntV()
#this would be much faster if we had a linear list of functions (nodes)
for Node in graph.Nodes():
start = Node.GetId()
if (start >= region_start) and (start <= region_end):
NIdV.Add(start)
if (start > region_end):
break
return snap.GetSubGraph(graph, NIdV)
#make_cut()
#This function analyzes the region specified and returns the cut address for the address with the
#maximum score, i.e. the address that has the highest average distance call length of function calls
#that go across the address. If multiple addresses with zero calls are found (inf. score) the one
#closest to the middle of the region is returned.
def make_cut(region_start, region_end, graph):
print("make_cut: start: 0x%x end: 0x%x" % (region_start,region_end))
weight = {}
z = 0
zeroes = []
for Node in graph.Nodes():
start = Node.GetId()
#iterate only over nodes in this region
cut_address = start - 1
if cut_address < region_start:
continue
weight[cut_address] = 0
edge_count = 0
for Edge in graph.Edges():
edge_start = Edge.GetSrcNId()
edge_end = Edge.GetDstNId()
#only look at edges that cross the possible cut address
#handle both cases for the directed graph
if (edge_start < cut_address and edge_end > cut_address) or (edge_end < cut_address and edge_start > cut_address):
#print " cut %x, %x to %x cross" % (cut_address,edge_start,edge_end)
weight[cut_address] += abs(edge_end - edge_start)
edge_count +=1
#If we have a place where we have no edges crossing - keep track of it
#We will pick the place closest to the center of the module
if edge_count == 0:
print(" returning 0 weight count at: 0x%0x" % cut_address)
z+=1
zeroes.append(cut_address)
weight[cut_address] = 0
else:
weight[cut_address] = weight[cut_address]/ edge_count
#print "w: %x: %x" % (cut_address, weight[cut_address])
#if we had edges with zero crossings, pick the one closest to the center
if (z > 0):
print(" total of %d zero weight counts" % (z))
center = region_start + ((region_end-region_start)/2)
min_dist = sys.maxsize
for i in range(z):
dist = abs(center - zeroes[i])
if dist < min_dist:
min_dist = dist
min_zero = zeroes[i]
print(" returning zero cut at addr: %x" % min_zero)
return min_zero
#otherwise pick the edge with the maximum weight score
max_weight=0
#print " weight table:"
for addr,w in weight.items():
#print " %x: %x" % (addr,w)
if w > max_weight:
max_addr = addr
max_weight = w
print(" returning max weight: %f at addr: 0x%x" % (max_weight,max_addr))
return max_addr
#do_cutting()
#This is the main recursive algorithm for MaxCut
#Find a cut address, split the graph into two subgraphs, and recurse on those subgraphs
#Stop if the area being cut is below a particular threshold
def do_cutting(start, end, graph):
nodes = graph.GetNodes()
print("do_cutting: start: 0x%x end: 0x%x nodes: 0x%x" % (start, end, nodes))
THRESHOLD = 0x1000
#THRESHOLD = 0x2000
if (end - start > THRESHOLD) and (nodes > 1):
cut_address = make_cut(start, end,graph)
graph1 = make_subgraph(start,cut_address,graph)
graph2 = make_subgraph(cut_address+1,end,graph)
do_cutting(start,cut_address,graph1)
do_cutting(cut_address+1,end,graph2)
else:
print("Module 0x%x to 0x%x" % (start, end))
b_mod = module.bin_module(start,end,0,"")
g_maxcut_modlist.append(b_mod)
#func_list_annotate()
#This function copies our list of modules into the function list
#This allows us to have a single function list with modules from multiple algorithms (LFA and MaxCut)
def func_list_annotate(flist):
c=0
m=0
while (m < len(g_maxcut_modlist)):
start = g_maxcut_modlist[m].start
while (flist[c].loc < start):
#print "F: %08x M: %08x" % (flist[c].loc, start)
c+=1
if (c == len(flist)):
print("Error: Maxcut module list does not reconcile with function list")
return None
flist[c].edge[1]=1
#print "MC: Set %08x func edge to 1" % flist[c].loc
m+=1
return flist
#Main entry point
#Returns a global function list (annotated with MaxCut edges) and a global module list
def analyze(flist):
sys.setrecursionlimit(5000)
UGraph = snap_cg.create_snap_cg()
g_min_node=sys.maxsize
g_max_node=0
for Node in UGraph.Nodes():
id = Node.GetId()
if id < g_min_node:
g_min_node = id
if id > g_max_node:
g_max_node = id
do_cutting(g_min_node,g_max_node, UGraph)
r_flist = func_list_annotate(flist)
return r_flist,g_maxcut_modlist

View File

@@ -1,309 +0,0 @@
##############################################################################################
# Copyright 2018 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
IDA_VERSION = 7
if (IDA_VERSION < 7):
import idc
import struct
import idautils
import basicutils_6x as basicutils
else:
import ida_idaapi
import ida_idc
import ida_funcs
import ida_nalt
import ida_segment
import idautils
import basicutils_7x as basicutils
import math
import nltk
import nltk.collocations
import re
### NLP Section ###
# This section of code attempts to name the modules based on common strings in the string references
# Not really based on any sound science or anything - your mileage may heavily vary. :-D
#string_range_tokenize(start,end,sep):
#Compile all string references between start and end as a list of strings (called "tokens")
# <sep> should be a nonsense word, and will show up in the list
def string_range_tokenize(start,end,sep):
# get all string references in this range concatenated into a single string
t = basicutils.CompileTextFromRange(start,end,sep)
#Enable this if you already have a bunch of function names and want to include that in the mix
#t+= basicutils.CompileFuncNamesFromRangeAsText(start,end,sep)
#print "string_range_tokenize: raw text:"
#print t
#remove printf/sprintf format strings
tc = re.sub("%[0-9A-Za-z]+"," ",t)
#convert dash to underscore
tc = re.sub("-","_",tc)
#replace _ and / with space - may want to turn this off sometimes
#this will break up snake case and paths
#problem is that if you have a path that is used throughout the binary it will probably dominate results
tc = re.sub("_"," ",tc)
#replace / and \\ with a space
tc = re.sub("[/\\\\]"," ",tc)
#remove anything except alphanumeric, spaces, . (for .c, .cpp, etc) and _
tc = re.sub("[^A-Za-z0-9_\.\s]"," ",tc)
#lowercase it - and store this as the original set of tokens to work with
tokens = [tk.lower() for tk in tc.split()]
#remove English stop words
#this is the list from the MIT *bow project
eng_stopw = {"about","all","am","an","and","are","as","at","be","been","but","by","can","cannot","did","do","does","doing","done","for","from","had","has","have","having","if","in","is","it","its","of","on","that","the","these","they","this","those","to","too","want","wants","was","what","which","will","with","would"}
#remove "code" stop words
#e.g. common words in debugging strings
code_sw = {"error","err","errlog","log","return","returned","byte","bytes","status","len","length","size","ok","0x","warning","fail","failed","failure","invalid","illegal","param","parameter","done","complete","assert","assertion","cant","didnt","class","foundation","cdecl","stdcall","thiscall"}
stopw = eng_stopw.union(code_sw)
c = 0
tokens_f = []
for t in tokens:
if t not in stopw:
tokens_f.append(t)
return tokens_f
#bracket_strings(start,end,b_brack,e_brack):
#Return the most common string in the range <star,end> that begins with b_brack and ends with e_brack
# The count of how many times this string appeared is also returned
#I find somewhat often people format debug strings like "[MOD_NAME] Function X did Y!"
#This function is called by guess_module_names() - if you see this format with different brackets
#you can edit that call
def bracket_strings(start,end,b_brack,e_brack):
sep = "tzvlw"
t = basicutils.CompileTextFromRange(start,end,sep)
tokens = [tk.lower() for tk in t.split(sep)]
b=[]
for tk in tokens:
tk = tk.strip()
if tk.startswith(b_brack) :
b_contents = tk[1:tk.find(e_brack)]
#Hack to get rid of [-],[+],[*] - could also try to remove non alpha
if (len(b_contents) > 3):
#Hack for debug prints that started with [0x%x]
if (b_contents != "0x%x"):
b.append(tk[1:tk.find(e_brack)])
print("bracket_strings tokens:")
print(tokens)
print(b)
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#source_file_strings(start,end):
#Return the most common string that looks like a source file name in the given range
# The count of how many times this string appeared is also returned
def source_file_strings(start,end):
sep = "tzvlw"
t = basicutils.CompileTextFromRange(start,end,sep)
#normally would do lower here to normalize but we lose camel case that way
tokens = [tk for tk in t.split(sep)]
#for each string, remove quotes and commas, then tokenize based on spaces to generate the final list
tokens2=[]
for tk in tokens:
tk = tk.strip()
#strip punctuation, need to leave in _ for filenames and / and \ for paths
tk = re.sub("[\"\'\,]"," ",tk)
for tk2 in tk.split(" "):
tokens2.append(tk2)
b=[]
for tk in tokens2:
tk = tk.strip()
if tk.endswith(".c") or tk.endswith(".cpp") or tk.endswith(".cc"):
#If there's a dir path, only use the end filename
#This could be tweaked if the directory structure is part of the software architecture
#e.g. if there are multiple source directories with meaningful names
if tk.rfind("/") != -1:
ntk = tk[tk.rfind("/")+1:]
elif tk.rfind("\\") != -1:
ntk = tk[tk.rfind("\\")+1:]
else:
ntk = tk
b.append(ntk)
print("source_file_strings tokens:")
#print tokens
print(b)
#a better way to do this (if there are multiple)
#would be to sort, uniquify, and then make the name foo.c_and_bar.c
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#common_strings(start,end):
#Return a list of the common strings in the given range
#Uses NLTK to generate a list of unigrams, bigrams, and trigrams (1 word, 2 word phrase, 3 word phrase)
#If the trigram score > 1/2 * bigram score, the most common trigram is used
#If the bigram score > 1/2 * unigram score, the most common bigram is used
#Otherwise the most common unigram (single word is used)
def common_strings(start,end):
CS_THRESHOLD = 6
sep = "tvlwz"
tokens = string_range_tokenize(start,end,sep)
#make a copy since we're going to edit it
u_tokens = tokens
c=0
while (c<len(u_tokens)):
if u_tokens[c] == sep:
del u_tokens[c]
else:
c+=1
print("common_strings tokens:")
print(tokens)
if len(u_tokens) < CS_THRESHOLD:
#print "%08x - %08x : %s" % (start,end,"no string")
return ("",0)
f = nltk.FreqDist(u_tokens)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
#print "Tokens:"
#print tokens
#print len(tokens)
bgs = list(nltk.bigrams(tokens))
c=0
while (c<len(bgs)):
if sep in bgs[c]:
del bgs[c]
else:
c+=1
#print "Bigrams:"
#print bgs
if (len(bgs) != 0):
fs = nltk.FreqDist(bgs)
b_gram = fs.most_common(1)[0][0]
#print "Most Common:"
#print b_gram
b_str = b_gram[0] + "_" + b_gram[1]
b_gram_score = fs.most_common(1)[0][1]
else:
b_str =""
b_gram_score = 0
tgs = list(nltk.trigrams(tokens))
c=0
while (c<len(tgs)):
if sep in tgs[c]:
del tgs[c]
else:
c+=1
#print "Trigrams:"
#print tgs
if (len(tgs) != 0):
ft = nltk.FreqDist(tgs)
t_gram = ft.most_common(1)[0][0]
t_str = t_gram[0] + "_" + t_gram[1] + "_" + t_gram[2]
t_gram_score = ft.most_common(1)[0][1]
else:
t_str = ""
t_gram_score = 0
#print "1: %s - %d 2: %s - %d 3: %s - %d\n" % (u_gram,u_gram_score,b_str,b_gram_score,t_str,t_gram_score)
if (b_gram_score * 2 >= u_gram_score):
if (t_gram_score * 2 >= b_gram_score):
ret = t_str
ret_s = t_gram_score
else:
ret = b_str
ret_s = b_gram_score
else:
ret = u_gram
ret_s = u_gram_score
#print "%08x - %08x : %s" % (start,end,ret)
return (ret,ret_s)
### End of NLP Section ###
#guess_module_names():
#Use the NLP section (above) to guess the names of modules and add them to the global module list
#Attempts to find common bracket strings (e.g. "[MOD_NAME] Debug print!")
#then source file names (most often left over from calls to assert())
#then common trigram/bigram/unigrams
#You can tweak the switchover thresholds below.
def guess_module_names(module_list):
#idea - make score threshold based on the size of the module
# (e.g. smaller modules should have a smaller threshold
C_SCORE_THRESHOLD = 3
S_SCORE_THRESHOLD = 1
B_SCORE_THRESHOLD = 1
c=0
unk_mod=0
while (c<len(module_list)):
m = module_list[c]
# first look for strings that start with [FOO], (bracket strings)
# then look for strings that contain source files (.c,.cpp,etc.)
# then try common strings
# above thresholds can be tweaked - they represent the number of strings that have to be repeated
# in order to use that string as the module name
(name,scr) = bracket_strings(m.start,m.end,"[","]")
if (scr < B_SCORE_THRESHOLD):
(name,scr) = source_file_strings(m.start,m.end)
if (scr < S_SCORE_THRESHOLD):
(name,scr) = common_strings(m.start,m.end)
if (scr < C_SCORE_THRESHOLD):
#Couldn't come up with a name so name it umod1, umod2, etc.
name = "umod%d" % (unk_mod)
#"word cloud" or something to get an idea of what the module is
#print basicutils.CompileTextFromRange(m.start,m.end," ")
unk_mod+=1
module_list[c].name = name
module_list[c].score = scr
print("%08x - %08x : %s (%d)" % (m.start,m.end,name,scr))
c+=1
return module_list

View File

@@ -1,52 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
#This represents the information we want to record about an individual function
#The function lists returned by LFA and MaxCut are made up of these
class func_info():
def __init__(self,loc,score1,score2):
self.loc = loc #the effective address of the function
self.score1=score1 #"Calls from" local function affinity score
self.score2=score2 #"Calls to" local function affinity score
self.total_score=score1+score2
self.lfa_skip=0 #Set to 1 if "skipped" (not scored) by LFA
self.edge=[0,0] #Set by edge_detect() - if 1, this is the start of a new module
#index 0 for LFA, 1 for MaxCut
def __repr__(self):
return "Function: 0x%08x" % (self.loc)
def __str__(self):
return self.__repr__()
#This represents the object files (aka modules) identified by LFA and MaxCut
class bin_module():
def __init__(self,start,end,score,name):
self.start=start
self.end=end
self.score=score #Currently unused
self.name=name
def __repr__(self):
line = "Module at 0x%08x:0x%08x" % (self.start, self.end)
if self.name != "" and self.name is not None:
line += " (name %s)" % self.name
return line
def __str__(self):
return self.__repr__()

View File

@@ -1,67 +0,0 @@
##############################################################################################
# Copyright 2019 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# HAVE A NICE DAY.
## This code creates a Snap PNGraph object that represents the call graph of a binary
## (the .text section)
import snap
import sys
import idc
import struct
import idautils
import basicutils_7x as basicutils
MAX_DIST = 0
UGraph = []
def add_edge(f, t):
global UGraph
n = basicutils.GetFunctionName(f)
if n != "":
#since we're only doing one edge for each xref, we'll do weight based on distance from the middle of the caller to the callee
f_start = idc.get_func_attr(f, idc.FUNCATTR_START)
if (not UGraph.IsNode(f_start)):
print("Error: had to add node (to): %08x" % f_start)
UGraph.AddNode(f_start)
print("%08x -> %08x" % (f_start, t))
UGraph.AddEdge(t,f_start)
#print "s_%#x -> s_%#x" % (f_start,t)," [len = ",get_weight(func_mid, t), "]"
def add_node(f):
basicutils.ForEveryXrefToD(f, add_edge)
def create_snap_cg():
global UGraph
UGraph= snap.PNGraph.New()
#Add every function linearly, this makes sure the nodes are in order
basicutils.ForEveryFuncInSeg(".text",UGraph.AddNode)
basicutils.ForEveryFuncInSeg(".text",add_node)
for NI in UGraph.Nodes():
print("node id 0x%x with out-degree %d and in-degree %d" %(
NI.GetId(), NI.GetOutDeg(), NI.GetInDeg()))
return UGraph

View File

@@ -1,48 +1,38 @@
# CodeCut Plugin for Ghidra
Ghidra Plugin for DeepCut / CodeCut GUI
## Theory of Operation
CodeCut allows a user to assign functions to object files in Ghidra, and then interact with the binary at the object file level. Functions are assigned to object files by setting the `Namespace` field in the Ghidra database. DeepCut attempts to establish initial object file boundaries which the user can then adjust using the CodeCut Table window.
CodeCut allows a user to assign functions to object files in Ghidra, and then interact with the binary at the object file level. Functions are assigned to object files by setting the `Namespace` field in the Ghidra database. DeepCut attempts to establish initial object file boundaries which the user can then adjust using the CodeCut Table window.
## Why Is This Useful?
Most binaries originate from multiple source code files. When reversing, RE analysts often develop a sense of which functions are related, and therefore likely belonged to the same source file. CodeCut allows the analyst to develop a hypothesis like "I think this block of functions are OS functions." Now if there are unexplored functions in that region, they will show up in disassembly and decompilation as OS::FUN_XXXXXXXX instead of just FUN_XXXXXXXX. This leads to a more rapid understanding of what functions might be used for when viewed in context.
## Plugin Installation
Follow normal Ghidra extension installation procedures. Copy the CodeCut and DeepCut extension zip into `$GHIDRA_INSTALL_DIR/Extensions` then in the main Ghidra window selection **File -> Install Extensions** and select the CodeCut and DeepCut boxes. Ghidra will tell you it needs to restart.
Follow normal Ghidra extension installation procedures. Copy the CodeCut and DeepCut extension zip into `$GHIDRA_INSTALL_DIR/Extensions` then in the main Ghidra window selection **File -> Install Extensions** and select the CodeCut and DeepCut boxes. Ghidra will tell you it needs to restart. Now that Ghidra only requires plugins to match the base version's major/minor and not patch versions, we expect to only release even major/minor versions.
**NOTE:** After restarting and loading a CodeBrowser window, Ghidra will tell you it has found new plugins and ask if you want to configure them. Only CodeCut shows up in this window. This is because DeepCut is a "one-shot" analyzer (it is still installed).
## Configuring Native Python Paths & Python Dependencies
Both CodeCut and DeepCut rely on native Python (outside of Ghidra) on your system. CodeCut uses native Python for guessing module names. DeepCut's model evaluation runs in native Python.
Both CodeCut and DeepCut rely on the native PyGhidra extension, and are not compatible with Jython. CodeCut uses native Python for guessing module names. DeepCut's model inference runs in native Python.
### Native Python Dependencies
CodeCut:
- nltk
DeepCut:
- 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 dependencies run:
- torch
- torch-geometric
- networkx
- scipy
To install dependencies, run:
```bash
pip install nltk
pip install torch torch-geometric networkx scipy
```
pip3 install nltk
pip3 install torch==1.7.1+cpu torch-geometric==1.6.3 torch-cluster==1.5.8 torch-spare==0.6.8 torch-scatter==2.0.5 torch-spline-conv==1.2.0
```
using the Python installation linked to your PyGhidra.
(assuming that pip3 points to the version of Python you plan to use below)
### Configuring CodeCut Python Path
![](img/codecut-config.png)
Configure the native Python path for CodeCut by choosing **Edit -> Tool Options** and selecting "Python Executable."
### Configuring DeepCut Python Path
![](img/deepcut-config.png)
Configure the native Python path for DeepCut by choosing **Analysis -> Analyze All Open...** and selecting **Deepcut (Prototype)**. After changing the path, click the **Apply** button.
## Running DeepCut Analysis
DeepCut is best run as a one-shot analyzer *after* initial auto-analysis. Select **Analysis -> One Shot -> Deepcut**. After DeepCut runs, you can view the results by looking at the **Namespace** field in the **Symbol Table** view.
@@ -50,7 +40,40 @@ DeepCut is best run as a one-shot analyzer *after* initial auto-analysis. Selec
## Using CodeCut
![](img/codecut-run.png)
After DeepCut runs, you can interact at an object file level with the **CodeCut Table** view. Select **Window -> CodeCut Table** You can have CodeCut guess the module names (based on string references) by choosing **Analysis -> Guess Module Names** in the CodeCut Table window. You can split/combine object files by right clicking on an object and choosing "Split Namespace Here" / "Combine Namespaces." You can move functions between object files (changing the boundaries of the object files) by dragging and dropping them.
After DeepCut runs, you can interact at an object file level with the **CodeCut Table** view. Select **Window -> CodeCut Table** to display the table. The CodeCut table is essentially a combined set of symbol tables, one for each module.
You can have CodeCut guess the module names (based on string references) by choosing **Analysis -> Guess Module Names** in the CodeCut Table window. This is helpful if your target executable has a lot of debug strings. The name guessing script attempts to find source file names first, then falls back to strings (including bigrams and trigrams) that are repeated multiple times.
You can split/combine object files by right clicking on an object and choosing **Split Namespace Here** / **Combine Namespaces.** You can move functions between object files (changing the boundaries of the object files) by dragging and dropping them.
## Exporting to Recompilable C
CodeCut contains two options for exporting a full module or a subrange of a module as recompilable C under the **Export** menu when you right click on a module in the CodeCut table. This feature is marked EXPERIMENTAL and is not well-tested.
## The CodeCut Graph
![](img/graph-pic.png)
CodeCut now has a graph option for viewing interactions / hierarchy of the modules within a binary. Add namespaces to the graph view by right clicking a function in the CodeCut Table and choosing **Add Namespace to Graph**. You can remove modules from the graph by right clicking and choosing **Show Namespaces in Graph Filter**.
## Limitations
### Careful Where You Click
While it looks like you can right click on the module names on the right side, CodeCut is actually paying attention to which function is highlighted in the table. So e.g. if you have a function in object3 highlighted and you right click on the grey object2 box to the left and click Combine/Split or Rename Namespaces, CodeCut will perform the operation from the function you have highlighted in object3.
### Address Range Peculiarities
CodeCut attempts to order the namespaces by their starting address. CodeCut may appear to list the modules out of order, however this is usually due to disassembly irregularities from Ghidra. E.g. let's say we have a memory map that looks like:
```
object2: 0x00010000 - 0x00018000
object3: 0x00018004 - 0x00020000
...
object50: 0x00480000 - 0x00480a00
```
Say the function at 0x00480000 makes a branch or jump to an address 0x00016008. This should be a new function entry point, but if only one function uses it, Ghidra might not label this as a function entry point, and just consider it part of FUN_00480000. This means that object50's actual range is 0x00016008 - 0x00480a00. And so object50 will show up in between object2 and object3 in the table. CodeCut outputs the module ranges into Ghidra's application log for help with debugging this. In this case defining 0x00016008 as a function will cause object50's bounds to be the right values and object50 will show up at the right place in the table.
### Defining Functions Later
Functions that get defined after DeepCut analysis has been run are by default added to the Global namespace. In the future we plan to add a feature that automatically adds them to the nearest namespace, or give a mechanism to more easily assign single functions directly to a specific namespace.
## Building
Specific build instructions are provided in the DeepCut and CodeCut subfolders.

View File

@@ -3,7 +3,7 @@
## Building and Installation
Requirements are the same as the Ghidra build requirements, currently JDK 17 (or newer) is required for Ghidra 10.2.
Requirements are the same as the Ghidra build requirements, currently JDK 21 (or newer) is required for Ghidra 11.
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).
@@ -20,13 +20,12 @@ gradle
echo GHIDRA_INSTALL_DIR="/path/to/ghidra" > gradle.properties
```
### Python 3
### PyGhidra and Dependencies
The CodeCut GUI's Module Name Guessing tool requires Python 3. Before running the tool, you may need to modify the Python Path of the tool. To do this, **Edit -> Tool Options -> Python Executable**. Insert path to your Python 3 executable. Click apply and ok.
CodeCut GUI requires the PyGhidra extension, and is not compatible with Jython.
### Install nltk
This module depends on the Python 3 dependency `nltk`. Run the following command to install:
```
The CodeCut GUI's Module Name Guessing tool requires the Python dependency [Natural Language ToolKit](https://www.nltk.org/). CodeCut attempts to automatically install the dependency when the tool is launched, but it can also be installed using the Python associated with PyGhidra by running:
```bash
pip install nltk
```

View File

@@ -1,15 +0,0 @@
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.

View File

@@ -1,348 +0,0 @@
##############################################################################################
# Copyright 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# 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 math
import nltk
import nltk.collocations
import re
#uncomment "print" to get debug prints
def debug_print(x):
#print(x)
return
### NLP Section ###
# This section of code attempts to name the modules based on common strings in the string references
# Not really based on any sound science or anything - your mileage may heavily vary. :-D
#string_range_tokenize(t):
#Take a long string and convert it into a list of tokens. If using a separator, this will appear in the token list
def string_range_tokenize(t):
#print "string_range_tokenize: raw text:"
#print t
#remove printf/sprintf format strings
#tc = re.sub("%[0-9A-Za-z]+"," ",t)
#convert dash to underscore
#tc = re.sub("-","_",tc)
#replace _ and / with space - may want to turn this off sometimes
#this will break up snake case and paths
#problem is that if you have a path that is used throughout the binary it will probably dominate results
#tc = re.sub("_"," ",tc)
#replace / and \\ with a space
#tc = re.sub("[/\\\\]"," ",tc)
#remove anything except alphanumeric, spaces, . (for .c, .cpp, etc) and _
#tc = re.sub("[^A-Za-z0-9_\.\s]"," ",tc)
#lowercase it - and store this as the original set of tokens to work with
tokens = [tk.lower() for tk in t.split()]
#remove English stop words
#this is the list from the MIT *bow project
eng_stopw = {"about","all","am","an","and","are","as","at","be","been","but","by","can","cannot","did","do","does","doing","done","for","from","had","has","have","having","if","in","is","it","its","of","on","that","the","these","they","this","those","to","too","want","wants","was","what","which","will","with","would"}
#remove "code" stop words
#e.g. common words in debugging strings
code_sw = {"error","err","errlog","log","return","returned","byte","bytes","status","len","length","size","ok","0x","warning","fail","failed","failure","invalid","illegal","param","parameter","done","complete","assert","assertion","cant","didnt","class","foundation","cdecl","stdcall","thiscall"}
#remove code stop words (from Joxean Koret's "IDAMagicStrings")
jk_sw = {"copyright", "char", "bool", "int", "unsigned", "long",
"double", "float", "signed", "license", "version", "cannot", "error",
"invalid", "null", "warning", "general", "argument", "written", "report",
"failed", "assert", "object", "integer", "unknown", "localhost", "native",
"memory", "system", "write", "read", "open", "close", "help", "exit", "test",
"return", "libs", "home", "ambiguous", "internal", "request", "inserting",
"deleting", "removing", "updating", "adding", "assertion", "flags",
"overflow", "enabled", "disabled", "enable", "disable", "virtual", "client",
"server", "switch", "while", "offset", "abort", "panic", "static", "updated",
"pointer", "reason", "month", "year", "week", "hour", "minute", "second",
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august',
'september', 'october', 'november', 'december', "arguments", "corrupt",
"corrupted", "default", "success", "expecting", "missing", "phrase",
"unrecognized", "undefined"}
stopw = eng_stopw.union(code_sw)
stopw = stopw.union(jk_sw)
c = 0
tokens_f = []
for t in tokens:
if t not in stopw:
tokens_f.append(t)
return tokens_f
#bracket_strings(t,b_brack,e_brack):
#Return the most common string in the text that begins with b_brack and ends with e_brack
# The count of how many times this string appeared is also returned
#I find somewhat often people format debug strings like "[MOD_NAME] Function X did Y!"
#This function is called by guess_module_names() - if you see this format with different brackets
#you can edit that call
def bracket_strings(t, b_brack,e_brack, sep):
#sep = "tzvlw"
#t = basicutils.CompileTextFromRange(start,end,sep)
tokens = [tk.lower() for tk in t.split(sep)]
#don't want to use tokenize here because it removes brackets
b=[]
for tk in tokens:
tk = tk.strip()
if tk.startswith(b_brack) :
b_contents = tk[1:tk.find(e_brack)]
#print("found bracket string, content: %s" % b_contents)
#Hack to get rid of [-],[+],[*] - could also try to remove non alpha
if (len(b_contents) > 3):
#Hack for debug prints that started with [0x%x]
if (b_contents != "0x%x"):
b.append(b_contents)
debug_print("bracket_strings tokens:")
debug_print(tokens)
debug_print(b)
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#is_source_file_str(f):
#return True if the file string ends with one of the source file extensions
#This uses structure borrowed from Joxean Koret's IDAMagicStrings
LANGS = {}
LANGS["C/C++"] = ["c", "cc", "cxx", "cpp", "h", "hpp"]
LANGS["C"] = ["c"]
LANGS["C++"] = ["cc", "cxx", "cpp", "hpp", "c++"]
LANGS["Obj-C"] = ["m"]
LANGS["Rust"] = ["rs"]
LANGS["Golang"] = ["go"]
LANGS["OCaml"] = ["ml"]
def is_source_file_str(f):
for key in LANGS:
for ext in LANGS[key]:
if f.endswith("." + ext):
return True
return False
#source_file_strings(start,end):
#Return the most common string that looks like a source file name in the given text string
# The count of how many times this string appeared is also returned
def source_file_strings(t,sep):
#sep = "tzvlw"
#t = basicutils.CompileTextFromRange(start,end,sep)
#normally would do lower here to normalize but we lose camel case that way
tokens = [tk for tk in t.split(sep)]
#for each string, remove quotes and commas, then tokenize based on spaces to generate the final list
tokens2=[]
for tk in tokens:
tk = tk.strip()
#strip punctuation, need to leave in _ for filenames and / and \ for paths
tk = re.sub("[\"\'\,]"," ",tk)
for tk2 in tk.split(" "):
tokens2.append(tk2)
debug_print("source_file_strings tokens2:")
debug_print(tokens2)
b=[]
for tk in tokens2:
tk = tk.strip()
if is_source_file_str(tk):
#If there's a dir path, only use the end filename
#This could be tweaked if the directory structure is part of the software architecture
#e.g. if there are multiple source directories with meaningful names
if tk.rfind("/") != -1:
ntk = tk[tk.rfind("/")+1:]
elif tk.rfind("\\") != -1:
ntk = tk[tk.rfind("\\")+1:]
else:
ntk = tk
b.append(ntk)
debug_print("source_file_strings tokens:")
debug_print(tokens)
debug_print(b)
#a better way to do this (if there are multiple)
#would be to sort, uniquify, and then make the name foo.c_and_bar.c
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#common_strings(t, sep):
#Return a list of the common strings in the string "t" - lines separated by "sep"
#Uses NLTK to generate a list of unigrams, bigrams, and trigrams (1 word, 2 word phrase, 3 word phrase)
#If the trigram score > 1/2 * bigram score, the most common trigram is used
#If the bigram score > 1/2 * unigram score, the most common bigram is used
#Otherwise the most common unigram (single word is used)
def common_strings(t,sep):
CS_THRESHOLD = 6
tokens = string_range_tokenize(t)
#make a copy since we're going to edit it
u_tokens = tokens
c=0
while (c<len(u_tokens)):
if u_tokens[c] == sep:
del u_tokens[c]
else:
c+=1
debug_print("common_strings tokens:")
debug_print(tokens)
if len(u_tokens) < CS_THRESHOLD:
#print("less than threshold")
return ("",0)
f = nltk.FreqDist(u_tokens)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
#print "Tokens:"
#print tokens
#print len(tokens)
bgs = list(nltk.bigrams(tokens))
c=0
while (c<len(bgs)):
if sep in bgs[c]:
del bgs[c]
else:
c+=1
debug_print("Bigrams:")
debug_print(bgs)
if (len(bgs) != 0):
fs = nltk.FreqDist(bgs)
b_gram = fs.most_common(1)[0][0]
#print "Most Common:"
#print b_gram
b_str = b_gram[0] + "_" + b_gram[1]
b_gram_score = fs.most_common(1)[0][1]
else:
b_str =""
b_gram_score = 0
tgs = list(nltk.trigrams(tokens))
c=0
while (c<len(tgs)):
if sep in tgs[c]:
del tgs[c]
else:
c+=1
debug_print("Trigrams:")
debug_print(tgs)
if (len(tgs) != 0):
ft = nltk.FreqDist(tgs)
t_gram = ft.most_common(1)[0][0]
t_str = t_gram[0] + "_" + t_gram[1] + "_" + t_gram[2]
t_gram_score = ft.most_common(1)[0][1]
else:
t_str = ""
t_gram_score = 0
debug_print("1: %s - %d 2: %s - %d 3: %s - %d\n" % (u_gram,u_gram_score,b_str,b_gram_score,t_str,t_gram_score))
if (b_gram_score > 1) and (b_gram_score * 2 >= u_gram_score):
if (t_gram_score > 1) and (t_gram_score * 2 >= b_gram_score):
ret = t_str
ret_s = t_gram_score
else:
ret = b_str
ret_s = b_gram_score
else:
ret = u_gram
ret_s = u_gram_score
return (ret,ret_s)
### End of NLP Section ###
#guess_module_names():
#Use the NLP section (above) to guess the names of modules and add them to the global module list
#Attempts to find common bracket strings (e.g. "[MOD_NAME] Debug print!")
#then source file names (most often left over from calls to assert())
#then common trigram/bigram/unigrams
#You can tweak the switchover thresholds below.
def guess_module_names(t,sep):
#idea - make score threshold based on the size of the module
# (e.g. smaller modules should have a smaller threshold
C_SCORE_THRESHOLD = 4 #we need to see at least <N> occurrences of a string set in order to pick that name
S_SCORE_THRESHOLD = 2 #if we see <N> occurrences of foo.c we'll pick "foo.c"
B_SCORE_THRESHOLD = 2 #if we see <N> occurrences of [foo] we'll pick "foo"
# first look for strings that start with [FOO], (bracket strings)
# then look for strings that contain source files (.c,.cpp,etc.)
# then try common strings
# above thresholds can be tweaked - they represent the number of strings that have to be repeated
# in order to use that string as the module name
(name,scr) = bracket_strings(t,"[","]",sep)
debug_print("bracket name: %s score: %d" %(name, scr))
#if (True):
if (scr < B_SCORE_THRESHOLD):
(name,scr) = source_file_strings(t,sep)
debug_print("source name: %s score: %d" % (name, scr))
#if (True):e
if (scr < S_SCORE_THRESHOLD):
(name,scr) = common_strings(t,sep)
debug_print("common name: %s score: %d" % (name, scr))
if (scr < C_SCORE_THRESHOLD):
#Couldn't come up with a name
name = "unknown"
return name
def main():
#t=""
sep = "tzvlw"
# java side handles adding sep between strings,
# read all in at once (no newlines between strings)
#t = sys.stdin.readline()
t = input()
#print ("text in: %s" % t)
name = guess_module_names(t,sep)
print(name)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,74 @@
# @category CodeCut
# @menupath CodeCut.ModNaming (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.
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(
{"nltk": "nltk"})
# make sure they're installed
if not deps.ensure_or_prompt():
println("[ModNaming] Required Python packages not available, exiting.")
exit(1)
from modnaming import *
import sys
import json
# 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:
t = f.read()
sep = "tzvlw"
name = guess_module_names(t, sep)
with open(args[1], "w") as f:
f.write(name)
print("Successfully guessed module name: ", name)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
from ghidra.app.decompiler import DecompInterface
from ghidra.util.task import ConsoleTaskMonitor
def decompile_user_functions_in_range(
current_program,
start_address_str,
end_address_str,
standard_library_namespaces=None,
):
if standard_library_namespaces is None:
standard_library_namespaces = ['libc', 'libm', 'libpthread',
'libdl', 'std']
def is_user_written_function(function):
namespace = function.getParentNamespace().getName()
return namespace not in standard_library_namespaces
#doesn't quite work right if you have overlapping functions
#we should rewrite to use FunctionManager/getFunctionsAt functionality
def getFunctions(start_address, end_address):
current_addr = start_address
while current_addr < end_address:
function = \
current_program.getFunctionManager().getFunctionContaining(current_addr)
if function is not None:
yield function
current_addr = function.getBody().getMaxAddress().add(1)
else:
current_addr = current_addr.add(1)
start_address = \
current_program.getAddressFactory().getAddress(start_address_str)
end_address = \
current_program.getAddressFactory().getAddress(end_address_str)
if start_address is None or end_address is None:
print('Invalid address range specified.')
return
if start_address >= end_address:
print('Invalid address range: start address should be less than end address.')
return
decompiler = DecompInterface()
decompiler.openProgram(current_program)
monitor = ConsoleTaskMonitor()
functions = list(getFunctions(start_address, end_address))
user_written_functions = list(filter(is_user_written_function,
functions))
decompiled_functions = {}
for function in user_written_functions:
decomp_result = decompiler.decompileFunction(function, 0,
monitor)
if decomp_result is not None:
decompiled_functions[function.getName()] = \
{'address': function.getEntryPoint(),
'code': decomp_result.getDecompiledFunction().getC()}
return decompiled_functions

View File

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

View File

@@ -0,0 +1,72 @@
# @category CodeCut
from ghidra.program.model.listing import Function
from ghidra.program.model.symbol import SourceType
def get_referenced_function_signatures(program, function_address,
monitor):
if function_address is None:
popup('No address entered')
return
function = \
program.getFunctionManager().getFunctionAt(function_address)
if function is None:
popup('No function found at the given address')
return
function_signatures = \
get_referenced_function_signatures_base(function, monitor)
sigs = '\n/* Refereneced Signatures for: ' + function.getName() \
+ ' */\n'
for signature in function_signatures:
sigs += signature
return sigs
def get_referenced_function_signatures_base(function, monitor):
if function is None:
raise ValueError('function is none')
funcRefs = getFunctionReferences(function, monitor)
signatures = []
for refFunc in funcRefs:
if isUserDefinedFunction(refFunc):
signatures.append(getFunctionSignature(refFunc) + ';\n')
return signatures
def getFunctionReferences(function, monitor):
refs = set()
instructions = \
function.getProgram().getListing().getInstructions(function.getBody(),
True)
for instr in instructions:
flowType = instr.getFlowType()
if flowType.isCall():
oprefs = instr.getOperandReferences(0)
if not oprefs: continue
target = oprefs[0].getToAddress()
func = function.getProgram().getFunctionManager().getFunctionAt(target)
if func is not None:
refs.add(func)
return refs
def getFunctionSignature(function):
sig = function.getPrototypeString(False, False)
return sig
def isUserDefinedFunction(function):
symbol = function.getSymbol()
namespace = symbol.getParentNamespace().getName()
standard_libraries = ['libc', 'libm', 'libpthread', 'libdl', 'std']
return not any(namespace.startswith(lib) for lib in
standard_libraries)

View File

@@ -0,0 +1,64 @@
from globalvars import get_global_variables
from funcsig import get_referenced_function_signatures
from decomprange import decompile_user_functions_in_range
import re
def fixCasting(code_str):
pattern = re.compile(r"\b([a-zA-Z0-9._]+)\._(\d{0,4})_(\d{0,4})_")
matches = pattern.finditer(code_str)
for match in matches:
name = match.group(1)
offset = match.group(2)
size = match.group(3)
if size == '4':
fixedref = '((int*)' + name + ')[' + offset + ']'
code_str = code_str.replace(match.group(), fixedref)
if size == '1':
fixedref = '*(uint8_t *)&' + name
code_str = code_str.replace(match.group(), fixedref)
return code_str
def generate_recompilable_c_code(
start_addr,
end_addr,
currentProgram,
monitor,
):
header_prefix = \
'''/* Ghidra type resolution */
#include "ghidra.h"
'''
referenced_funcs = ''
in_range_c_code = \
'''
/* Decompiled functions within address range: %s - %s */''' \
% (start_addr, end_addr)
global_vars = get_global_variables(currentProgram, start_addr, end_addr)
print('Global vars:')
print(global_vars)
decompiled_functions = \
decompile_user_functions_in_range(currentProgram, start_addr,
end_addr)
for (function_name, function_data) in decompiled_functions.items():
referenced_funcs += \
get_referenced_function_signatures(currentProgram,
function_data['address'], monitor)
in_range_c_code += function_data['code']
c_code = header_prefix + global_vars + referenced_funcs \
+ in_range_c_code
c_code = fixCasting(c_code)
return c_code

View File

@@ -0,0 +1,99 @@
from ghidra.program.model.symbol import SourceType
from ghidra.program.model.symbol import SymbolType
from ghidra.program.model.address import AddressSet
#from ghidra.program.flatapi.FlatProgramAPI import getFunctionAt, getDataAt
from ghidra.program.model.data import Array, FloatDataType, \
DoubleDataType
def get_global_variables(program, start_addr, end_addr):
global_vars = []
symbol_table = program.getSymbolTable()
start_address = \
program.getAddressFactory().getAddress(start_addr)
end_address = \
program.getAddressFactory().getAddress(end_addr)
addrset = AddressSet(start_address,end_address)
#set.addRange(start_addr, end_addr)
print(start_address, end_address)
print(addrset)
#for symbol in symbol_table.getAllSymbols(False):
for symbol in symbol_table.getSymbols(addrset,SymbolType.LABEL,True):
print(symbol)
if (symbol.getSymbolType() == SymbolType.LABEL):
if (symbol.isGlobal()):
if (not program.getListing().getFunctionAt(symbol.getAddress())):
if (program.getListing().getDataAt(symbol.getAddress())):
global_vars.append(symbol)
'''
def is_user_defined(var):
var_name = var.getName()
var_addr = var.getAddress()
if var_name.startswith('__') or var_name.startswith('_'):
return False
if var_name.startswith('imp_') or var_name.startswith('thunk_'):
return False
if var_name.startswith('fde_') or var_name.startswith('cie_'):
return False
if var_name.startswith('completed.0') \
or var_name.startswith('data_start'):
return False
if var_addr.toString().startswith('EXTERNAL:'):
return False
section_name = program.getMemory().getBlock(var_addr).getName()
#if section_name not in ['.data', '.bss']:
# return False
return True
'''
#global_vars = list(filter(is_user_defined, global_vars))
#global_vars = list(filter(is_global_var, global_vars))
print("G vars first pass:")
print(global_vars)
output = '/* Global Variables */\n'
for var in global_vars:
var_addr = var.getAddress()
var_name = var.getName()
data = program.getListing().getDataAt(var_addr)
if data is None:
continue
dt = data.getDataType()
dt_name = dt.getDisplayName()
value = data.getValue()
pointer_count = 0
while dt_name.endswith('*'):
pointer_count += 1
dt_name = dt_name[:-1].strip()
if isinstance(dt, Array):
value = '{' + ', '.join(str(value[i]) for i in
range(len(value))) + '}'
elif isinstance(dt, FloatDataType) or isinstance(dt,
DoubleDataType):
value = '{:.6f}'.format(value)
elif value is not None:
value = str(value)
else:
value = ''
output += '{}{} {}{}{};\n'.format(dt_name, (' '
if not dt_name.endswith('*') else ''), var_name, '*'
* pointer_count, (' = {}'.format(value) if value else ''
))
return output

View File

@@ -0,0 +1,351 @@
##############################################################################################
# Copyright 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# All rights reserved.
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
#
# 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
print(sys.executable)
import sys
import math
import nltk
import nltk.collocations
import re
#uncomment "print" to get debug prints
def debug_print(x):
#print(x)
return
### NLP Section ###
# This section of code attempts to name the modules based on common strings in the string references
# Not really based on any sound science or anything - your mileage may heavily vary. :-D
#string_range_tokenize(t):
#Take a long string and convert it into a list of tokens. If using a separator, this will appear in the token list
def string_range_tokenize(t):
#print "string_range_tokenize: raw text:"
#print t
#remove printf/sprintf format strings
#tc = re.sub("%[0-9A-Za-z]+"," ",t)
#convert dash to underscore
#tc = re.sub("-","_",tc)
#replace _ and / with space - may want to turn this off sometimes
#this will break up snake case and paths
#problem is that if you have a path that is used throughout the binary it will probably dominate results
#tc = re.sub("_"," ",tc)
#replace / and \\ with a space
#tc = re.sub("[/\\\\]"," ",tc)
#remove anything except alphanumeric, spaces, . (for .c, .cpp, etc) and _
#tc = re.sub("[^A-Za-z0-9_\.\s]"," ",tc)
#lowercase it - and store this as the original set of tokens to work with
tokens = [tk.lower() for tk in t.split()]
#remove English stop words
#this is the list from the MIT *bow project
eng_stopw = {"about","all","am","an","and","are","as","at","be","been","but","by","can","cannot","did","do","does","doing","done","for","from","had","has","have","having","if","in","is","it","its","of","on","that","the","these","they","this","those","to","too","want","wants","was","what","which","will","with","would"}
#remove "code" stop words
#e.g. common words in debugging strings
code_sw = {"error","err","errlog","log","return","returned","byte","bytes","status","len","length","size","ok","0x","warning","fail","failed","failure","invalid","illegal","param","parameter","done","complete","assert","assertion","cant","didnt","class","foundation","cdecl","stdcall","thiscall"}
#remove code stop words (from Joxean Koret's "IDAMagicStrings")
jk_sw = {"copyright", "char", "bool", "int", "unsigned", "long",
"double", "float", "signed", "license", "version", "cannot", "error",
"invalid", "null", "warning", "general", "argument", "written", "report",
"failed", "assert", "object", "integer", "unknown", "localhost", "native",
"memory", "system", "write", "read", "open", "close", "help", "exit", "test",
"return", "libs", "home", "ambiguous", "internal", "request", "inserting",
"deleting", "removing", "updating", "adding", "assertion", "flags",
"overflow", "enabled", "disabled", "enable", "disable", "virtual", "client",
"server", "switch", "while", "offset", "abort", "panic", "static", "updated",
"pointer", "reason", "month", "year", "week", "hour", "minute", "second",
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august',
'september', 'october', 'november', 'december', "arguments", "corrupt",
"corrupted", "default", "success", "expecting", "missing", "phrase",
"unrecognized", "undefined"}
stopw = eng_stopw.union(code_sw)
stopw = stopw.union(jk_sw)
c = 0
tokens_f = []
for t in tokens:
if t not in stopw:
tokens_f.append(t)
return tokens_f
#bracket_strings(t,b_brack,e_brack):
#Return the most common string in the text that begins with b_brack and ends with e_brack
# The count of how many times this string appeared is also returned
#I find somewhat often people format debug strings like "[MOD_NAME] Function X did Y!"
#This function is called by guess_module_names() - if you see this format with different brackets
#you can edit that call
def bracket_strings(t, b_brack,e_brack, sep):
#sep = "tzvlw"
#t = basicutils.CompileTextFromRange(start,end,sep)
tokens = [tk.lower() for tk in t.split(sep)]
#don't want to use tokenize here because it removes brackets
b=[]
for tk in tokens:
tk = tk.strip()
if tk.startswith(b_brack):
b_contents = tk[1:tk.find(e_brack)] if e_brack in tk else tk[1:]
#print("found bracket string, content: %s" % b_contents)
#Hack to get rid of [-],[+],[*] - could also try to remove non alpha
if (len(b_contents) > 3):
#Hack for debug prints that started with [0x%x]
if (b_contents != "0x%x"):
b.append(b_contents)
debug_print("bracket_strings tokens:")
debug_print(tokens)
debug_print(b)
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#is_source_file_str(f):
#return True if the file string ends with one of the source file extensions
#This uses structure borrowed from Joxean Koret's IDAMagicStrings
LANGS = {}
LANGS["C/C++"] = ["c", "cc", "cxx", "cpp", "h", "hpp"]
LANGS["C"] = ["c"]
LANGS["C++"] = ["cc", "cxx", "cpp", "hpp", "c++"]
LANGS["Obj-C"] = ["m"]
LANGS["Rust"] = ["rs"]
LANGS["Golang"] = ["go"]
LANGS["OCaml"] = ["ml"]
def is_source_file_str(f):
for key in LANGS:
for ext in LANGS[key]:
if f.endswith("." + ext):
return True
return False
#source_file_strings(start,end):
#Return the most common string that looks like a source file name in the given text string
# The count of how many times this string appeared is also returned
def source_file_strings(t, sep):
#sep = "tzvlw"
#t = basicutils.CompileTextFromRange(start,end,sep)
#normally would do lower here to normalize but we lose camel case that way
tokens = [tk for tk in t.split(sep)]
#for each string, remove quotes and commas, then tokenize based on spaces to generate the final list
tokens2=[]
for tk in tokens:
tk = tk.strip()
#strip punctuation, need to leave in _ for filenames and / and \ for paths
tk = re.sub("[\"\',]"," ",tk)
for tk2 in tk.split(" "):
tokens2.append(tk2)
debug_print("source_file_strings tokens2:")
debug_print(tokens2)
b=[]
for tk in tokens2:
tk = tk.strip()
if is_source_file_str(tk):
#If there's a dir path, only use the end filename
#This could be tweaked if the directory structure is part of the software architecture
#e.g. if there are multiple source directories with meaningful names
if tk.rfind("/") != -1:
ntk = tk[tk.rfind("/")+1:]
elif tk.rfind("\\") != -1:
ntk = tk[tk.rfind("\\")+1:]
else:
ntk = tk
b.append(ntk)
debug_print("source_file_strings tokens:")
debug_print(tokens)
debug_print(b)
#a better way to do this (if there are multiple)
#would be to sort, uniquify, and then make the name foo.c_and_bar.c
u_gram=""
u_gram_score=0
if (len(b) > 0):
f = nltk.FreqDist(b)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
return (u_gram,u_gram_score)
#common_strings(t, sep):
#Return a list of the common strings in the string "t" - lines separated by "sep"
#Uses NLTK to generate a list of unigrams, bigrams, and trigrams (1 word, 2 word phrase, 3 word phrase)
#If the trigram score > 1/2 * bigram score, the most common trigram is used
#If the bigram score > 1/2 * unigram score, the most common bigram is used
#Otherwise the most common unigram (single word is used)
def common_strings(t,sep):
CS_THRESHOLD = 6
tokens = string_range_tokenize(t)
#make a copy since we're going to edit it
u_tokens = tokens
c=0
while (c<len(u_tokens)):
if u_tokens[c] == sep:
del u_tokens[c]
else:
c+=1
debug_print("common_strings tokens:")
debug_print(tokens)
if len(u_tokens) < CS_THRESHOLD:
#print("less than threshold")
return ("",0)
f = nltk.FreqDist(u_tokens)
u_gram = f.most_common(1)[0][0]
u_gram_score = f.most_common(1)[0][1]
#print "Tokens:"
#print tokens
#print len(tokens)
bgs = list(nltk.bigrams(tokens))
c=0
while (c<len(bgs)):
if sep in bgs[c]:
del bgs[c]
else:
c+=1
debug_print("Bigrams:")
debug_print(bgs)
if (len(bgs) != 0):
fs = nltk.FreqDist(bgs)
b_gram = fs.most_common(1)[0][0]
#print "Most Common:"
#print b_gram
b_str = b_gram[0] + "_" + b_gram[1]
b_gram_score = fs.most_common(1)[0][1]
else:
b_str =""
b_gram_score = 0
tgs = list(nltk.trigrams(tokens))
c=0
while (c<len(tgs)):
if sep in tgs[c]:
del tgs[c]
else:
c+=1
debug_print("Trigrams:")
debug_print(tgs)
if (len(tgs) != 0):
ft = nltk.FreqDist(tgs)
t_gram = ft.most_common(1)[0][0]
t_str = t_gram[0] + "_" + t_gram[1] + "_" + t_gram[2]
t_gram_score = ft.most_common(1)[0][1]
else:
t_str = ""
t_gram_score = 0
debug_print("1: %s - %d 2: %s - %d 3: %s - %d\n" % (u_gram,u_gram_score,b_str,b_gram_score,t_str,t_gram_score))
if (b_gram_score > 1) and (b_gram_score * 2 >= u_gram_score):
if (t_gram_score > 1) and (t_gram_score * 2 >= b_gram_score):
ret = t_str
ret_s = t_gram_score
else:
ret = b_str
ret_s = b_gram_score
else:
ret = u_gram
ret_s = u_gram_score
return (ret,ret_s)
### End of NLP Section ###
#guess_module_names():
#Use the NLP section (above) to guess the names of modules and add them to the global module list
#Attempts to find common bracket strings (e.g. "[MOD_NAME] Debug print!")
#then source file names (most often left over from calls to assert())
#then common trigram/bigram/unigrams
#You can tweak the switchover thresholds below.
def guess_module_names(t,sep):
#idea - make score threshold based on the size of the module
# (e.g. smaller modules should have a smaller threshold
C_SCORE_THRESHOLD = 4 #we need to see at least <N> occurrences of a string set in order to pick that name
S_SCORE_THRESHOLD = 2 #if we see <N> occurrences of foo.c we'll pick "foo.c"
B_SCORE_THRESHOLD = 2 #if we see <N> occurrences of [foo] we'll pick "foo"
# first look for strings that start with [FOO], (bracket strings)
# then look for strings that contain source files (.c,.cpp,etc.)
# then try common strings
# above thresholds can be tweaked - they represent the number of strings that have to be repeated
# in order to use that string as the module name
(name,scr) = bracket_strings(t,"[","]",sep)
debug_print("bracket name: %s score: %d" %(name, scr))
#if (True):
if (scr < B_SCORE_THRESHOLD):
(name,scr) = source_file_strings(t,sep)
debug_print("source name: %s score: %d" % (name, scr))
#if (True):e
if (scr < S_SCORE_THRESHOLD):
(name,scr) = common_strings(t,sep)
debug_print("common name: %s score: %d" % (name, scr))
if (scr < C_SCORE_THRESHOLD):
#Couldn't come up with a name
name = "unknown"
return name
def main():
#t=""
sep = "tzvlw"
# java side handles adding sep between strings,
# read all in at once (no newlines between strings)
#t = sys.stdin.readline()
t = input()
#print ("text in: %s" % t)
name = guess_module_names(t,sep)
print(name)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,38 @@
#@category CodeCut
#@runtime PyGhidra
from generate_c import generate_recompilable_c_code
import os
from ghidra.util.task import TaskMonitor
def write_c_code_to_file(c_code, output_file_path):
with open(output_file_path, 'w') as f:
f.write(c_code)
if __name__ == '__main__':
args = getScriptArgs()
start_addr = args[0]
end_addr = args[1]
file_name = args[2]
output_dir = file_name.rsplit("/", 1)[0] + "/"
println("Recomp C Range Entry: %s - %s" % (start_addr, end_addr))
c_code = generate_recompilable_c_code(start_addr, end_addr,
currentProgram, monitor)
#file_name = currentProgram.getName()
#output_dir = askDirectory('Output Directory',
# 'Save C code output'
# ).getPath()
#output_file_path = os.path.join(output_dir, file_name)
write_c_code_to_file(c_code, file_name)
println('C code has been saved to %s' % file_name)

View File

@@ -0,0 +1,166 @@
from ghidra.app.decompiler import DecompileOptions
from ghidra.app.decompiler import DecompInterface
from ghidra.util.task import ConsoleTaskMonitor
from ghidra.program.model.symbol import RefType,SymbolType
from ghidra.program.model.address import Address, AddressRange
from ghidra.program.model.lang import LanguageCompilerSpecPair
from ghidra.program.model.listing import Program
from ghidra.util import Msg
from java.lang import IllegalArgumentException
import re
from __main__ import *
# Definitions for decompiler to function
program = getCurrentProgram()
ifc = DecompInterface()
ifc.setOptions(DecompileOptions())
ifc.openProgram(program)
# Standard label list
std = { "_init", "__cxa_finalize", "printf", "_start",
"deregister_tm_clones", "register_tm_clones", "__do_global_dtors_aux",
"frame_dummy", "_fini", "__libc_start_main", "_ITM_deregisterTMCloneTable",
"__gmon_start__", "_ITM_registerTMCloneTable", "__cxa_finalize",
"puts", "_exit", "_write", "_sbrk", "_read", "_lseek", "_kill", "_isatty", "_gettimeofday",
"_getpid", "_fstat", "_close", "__clzsi2", "__clzdi2", "__udivmoddi4", "__aeabi_uldivmod",
"__aeabi_d2iz", "__unorddf2", "__aeabi_dcmpgt", "__aeabi_dcmpge", "__aeabi_dcmple",
"__aeabi_dcmplt", "__aeabi_dcmpeq", "__aeabi_idivmod", ".divsi3_skip_div0_test",
"__divsi3", "__aeabi_uidivmod", "__aeabi_uidiv",
"_getpid_r", "_kill_r", "__sigtramp", "_init_signal", "signal", "raise", "__sigtramp_r",
"_raise_r", "_signal_r", "_init_signal_r", "abort", "__ascii_wctomb", "_wctomb_r",
"wcrtomb", "__aeabi_cdcmpeq", "__aeabi_cdrcmple", "__nedf2", "__ledf2", "__gedf2",
"__divdf3", "__muldf3", "__aeabi_idiv0", "_wcrtomb_r",
"__swbuf", "__swbuf_r", "strcmp", "_realloc_r", "_read_r", "memmove", "__ascii_mbtowc",
"_mbtowc_r", "_lseek_r", "setlocale", "__locale_mb_cur_max", "_setlocale_r", "_isatty_r",
"__sfvwrite_r", "_fstat_r", "fputwc", "_fputwc_r", "__fputwc", "fiprintf", "_fiprintf_r",
"fclose", "_fclose_r", "_fclose_r", "_close_r", "_calloc_r", "__assert", "__assert_func",
"_write_r", "__sbprintf", "vfiprintf", "_vfiprintf_r", "__sprint_r", "__sprint_r",
"strlen", "__sclose", "__sseek", "__swrite", "__seofread", "__sread", "_sbrk_r",
"_reclaim_reent", "cleanup_glue", "__any_on", "__copybits", "_mprec_log10", "__ratio", "__d2b",
"__b2d", "__ulp", "__mdiff", "__mcmp", "__lshift", "__pow5mult", "__multiply", "__i2b",
"__lo0bits", "__hi0bits", "__s2b", "__multadd", "_Bfree", "_Balloc", "__malloc_unlock",
"__malloc_lock", "memcpy", "memchr", "_malloc_r", "__swhatbuf_r", "__smakebuf_r",
"localeconv", "_localeconv_r", "__localeconv_l", "_gettimeofday_r", "_fwalk_reent",
"__sfp_lock_acquire", "__sinit", "_cleanup", "__sfp", "__sfmoreglue", "__sinit",
"__fp_unlock", "_cleanup_r", "__fp_lock", "fflush", "_fflush_r", "__sflush_r", "_dtoa_r",
"quorem", "__call_exitprocs", "__register_exitproc", "__swsetup_r", "vfprintf",
"_vfprintf_r", "time", "rand", "srand", "_printf_r", "memset", "__libc_init_array",
"__libc_fini_array", "exit", "atexit", "__aeabi_l2d", "__floatundidf", "__aeabi_f2d",
"__aeabi_i2d", "__floatunsidf", "__aeabi_dadd", "__subdf3", "__aeabi_drsub", "_fwalk",
"_free_r", "_malloc_trim_r", "__fp_unlock_all", "__fp_lock_all", "__sinit_lock_release",
"__sinit_lock_acquire", "__sfp_lock_release", "entry", "_stack_init", "register_fini",
"calloc", "realloc", "__stack_chk_fail", "err", "__printf_chk", "write"}
# Ghidra header file
# Needs to be replaced!! - Placeholder mostly
ghidra_h = """
#ifndef ghidra_h
#define ghidra_h
#include "stdint.h"
typedef uint8_t byte; // 8-bit unsigned entity.
typedef byte * pbyte; // Pointer to BYTE.
// int
typedef unsigned int uint;
typedef uint8_t undefined;
typedef uint16_t undefined2;
typedef uint32_t undefined4;
typedef uint64_t undefined8;
// long
typedef long unsigned int ulong;
typedef long long longlong;
// void
typedef void void4;
typedef void void8;
#endif
"""
# Fix ghidra casting
def fixCasting(filename):
file = open(filename,'r')
filebuf = file.read()
pattern = re.compile(r"\b([a-zA-Z0-9._]+)\._(\d{0,4})_(\d{0,4})_")
matches = pattern.finditer(filebuf)
file = open(filename,'w')
for match in matches:
name = match.group(1)
offset = match.group(2)
size = match.group(3)
if size == "4":
fixedref = "((int*)" + name + ")[" + offset + "]"
filebuf = filebuf.replace(match.group(), fixedref)
if size == "1":
fixedref = "*(uint8_t *)&" + name
filebuf = filebuf.replace(match.group(), fixedref)
file.write(filebuf)
# Write "ghidra.h" file
def writeHeader(path):
with open(path+'ghidra.h', 'w') as file:
file.write(ghidra_h)
# Wrapper function to get address of function offset
def getAddress(offset):
return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)
# Get each in range funciton entry point & Functions called by in range functions
# Get each in range funciton entry point & Functions called by in range functions
def getFunctionsInRange(start, end, externFunc, inRangeFunc):
fm = currentProgram.getFunctionManager()
programsymbols = fm.getFunctions(True)
for symbol in programsymbols:
item = int(symbol.getEntryPoint().toString(), 16)
if item in range(start, end):
funcName = fm.getFunctionAt(getAddress(item))
if funcName.getName() not in std:
print("Found function %s in range" % funcName.getName())
inRangeFunc.append(funcName.getEntryPoint().toString())
func = currentProgram.getFunctionManager().getFunctionAt(funcName.getEntryPoint())
func_list = funcName.getCalledFunctions(getMonitor())
print(func_list)
for item in func_list:
print(item)
#item = item.replace(",", "")
if item.getEntryPoint() not in inRangeFunc and item.getName() not in std:
externFunc.append(item.getName())
# Wrapper function to write to file
def writeToFile(filename, extern, label):
file = open(filename,'w')
# External functions
print >>file, """#include "ghidra.h"\n"""
for item in extern:
print("extern:",item)
functionList = getGlobalFunctions(item)
print(functionList)
if len(functionList) > 0:
function = functionList[0]
#if function is not None:
results = function.getSignature().getPrototypeString()
results = "extern " + results + ";"
print("Results:", results)
print >>file, results
# Decompiled functions
for item in label:
# function = getGlobalFunctions(item)[0]
function = currentProgram.getFunctionManager().getFunctionAt(getAddress(item))
results = ifc.decompileFunction(function, 0, ConsoleTaskMonitor())
filedata = results.getDecompiledFunction().getC()
file.write(filedata)
file.close()

View File

@@ -10,7 +10,7 @@
<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">
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY>

View File

@@ -0,0 +1,191 @@
/* ###
* © 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.
*/
package codecutguiv2;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.border.BevelBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import docking.DockingWindowManager;
import docking.widgets.EmptyBorderButton;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.filter.FilterOptions;
import docking.widgets.filter.FilterOptionsEditorDialog;
import docking.widgets.filter.TextFilterStrategy;
import docking.widgets.label.GLabel;
import ghidra.util.table.GhidraTable;
@SuppressWarnings("serial")
public class CCTableFilterPanel extends JPanel {
private List<TableRowSorter<TableModel>> sorters = new ArrayList<>();
JTextField textField;
private SymbolProvider symProvider;
private NamespacePanel nsPanel;
private FilterOptions filterOptions = new FilterOptions();
private EmptyBorderButton filterStateButton;
private static final boolean FILTER_NAME_ONLY_DEFAULT = true;
private boolean nameOnly = true;
public CCTableFilterPanel (List<GhidraTable> tables, SymbolProvider symProvider, NamespacePanel panel) {
this.symProvider = symProvider;
this.nsPanel = panel;
for (GhidraTable table: tables) {
TableRowSorter<TableModel> sort = new TableRowSorter<>(table.getModel());
sorters.add(sort);
table.setRowSorter(sort);
}
textField = new JTextField();
buildPanel();
}
public void buildPanel(){
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
this.add(Box.createHorizontalStrut(5));
this.add(new GLabel("Filter:"));
this.add(textField);
textField.getDocument().addDocumentListener(new DocumentListener()
{
@Override
public void insertUpdate(DocumentEvent e) {
String str = textField.getText();
if (str.trim().length() == 0) {
nsPanel.setTextFiltering(false);
for (TableRowSorter<TableModel> sort: sorters) {
sort.setRowFilter(null);
}
} else {
nsPanel.setTextFiltering(true);
String filterRegex = generateFilterRegex(filterOptions.getTextFilterStrategy(), filterOptions.isCaseSensitive(), str);
for (TableRowSorter<TableModel> sort: sorters) {
if (nameOnly) {
sort.setRowFilter(RowFilter.regexFilter(filterRegex, 0));
}
else {
sort.setRowFilter(RowFilter.regexFilter(filterRegex));
}
}
}
symProvider.updateTitle();
}
@Override
public void removeUpdate(DocumentEvent e) {
String str = textField.getText();
if (str.trim().length() == 0) {
nsPanel.setTextFiltering(false);
for (TableRowSorter<TableModel> sort: sorters) {
sort.setRowFilter(null);
}
} else {
nsPanel.setTextFiltering(true);
String filterRegex = generateFilterRegex(filterOptions.getTextFilterStrategy(), filterOptions.isCaseSensitive(), str);
for (TableRowSorter<TableModel> sort: sorters) {
if (nameOnly) {
sort.setRowFilter(RowFilter.regexFilter(filterRegex, 0));
}
else {
sort.setRowFilter(RowFilter.regexFilter(filterRegex));
}
}
}
symProvider.updateTitle();
}
@Override
public void changedUpdate(DocumentEvent e) {}
});
this.add(buildFilterStateButton());
final JCheckBox nameColumnOnlyCheckbox = new GCheckBox("Name Only");
nameColumnOnlyCheckbox.setName("NameOnly"); // used by JUnit
nameColumnOnlyCheckbox.setToolTipText(
"<html><b>Selected</b> causes filter to only consider the symbol's name.");
nameColumnOnlyCheckbox.setFocusable(false);
nameColumnOnlyCheckbox.setSelected(FILTER_NAME_ONLY_DEFAULT);
nameColumnOnlyCheckbox.addItemListener(e -> {
nameOnly = nameColumnOnlyCheckbox.isSelected();
});
this.add(nameColumnOnlyCheckbox);
}
private JComponent buildFilterStateButton() {
filterStateButton = new EmptyBorderButton(filterOptions.getFilterStateIcon());
filterStateButton.addActionListener(e -> {
FilterOptionsEditorDialog dialog = new FilterOptionsEditorDialog(filterOptions);
DockingWindowManager.showDialog(this, dialog);
FilterOptions resultFilterOptions = dialog.getResultFilterOptions();
if (resultFilterOptions != null) {
this.filterOptions = resultFilterOptions;
}
});
filterStateButton.setToolTipText("Filter Options");
updateFilterFactory();
return filterStateButton;
}
private void updateFilterFactory() {
filterStateButton.setIcon(filterOptions.getFilterStateIcon());
filterStateButton.setToolTipText(filterOptions.getFilterDescription());
}
private String generateFilterRegex(TextFilterStrategy type, Boolean isCaseSensitive, String input) {
String caseSensitivity = "";
if (!isCaseSensitive) {
caseSensitivity = "(?i)";
}
if (filterOptions.getTextFilterStrategy() == TextFilterStrategy.STARTS_WITH) {
return caseSensitivity + "^" + input;
}
else if (filterOptions.getTextFilterStrategy() == TextFilterStrategy.CONTAINS) {
return caseSensitivity + ".*" + input + ".*";
}
else if (filterOptions.getTextFilterStrategy() == TextFilterStrategy.MATCHES_EXACTLY) {
return "^" + input; // no case insensitivity
}
else {
return input;
}
}
}

View File

@@ -0,0 +1,215 @@
/* ###
* © 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.
*/
package codecutguiv2;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Set;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import docking.ActionContext;
import docking.WindowPosition;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.services.BlockModelService;
import ghidra.feature.vt.api.db.TableColumn;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.util.HelpLocation;
import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraTableCellRenderer;
import ghidra.util.table.GhidraThreadedTablePanel;
import graphcut.GraphCutProvider;
import resources.ResourceManager;
public class ChecklistProvider extends ComponentProviderAdapter implements ActionListener {
private static final ImageIcon ICON = ResourceManager.loadImage("images/textfield.png");
private static final String BUTTON_STRING = "Apply Changes";
private static final String RESET_STRING = "Reset Graph Filter";
private CodeCutGUIPlugin plugin;
private GraphCutProvider graphProvider;
GhidraTable table;
DefaultTableModel model;
private JPanel boxPanel;
ChecklistProvider(CodeCutGUIPlugin plugin){
super(plugin.getTool(), "Namespaces in Graph", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
this.graphProvider = plugin.getGraphProvider();
setIcon(ICON);
addToToolbar();
setHelpLocation(new HelpLocation(plugin.getName(), "CodeCut_Table"));
setWindowGroup("codecutTable");
setIntraGroupPosition(WindowPosition.BOTTOM);
boxPanel = new JPanel();
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
Object[] columnNames = {"Namespace", "Added to Graph"};
Object[][] data = {};
model = new DefaultTableModel(data, columnNames) {
@Override
public boolean isCellEditable(int row, int column) {
if(column == 1) {
return true;
}
return false;
}
};
table = new GhidraTable(model) {
@Override
public Class getColumnClass(int column) {
switch(column) {
case 0:
return Namespace.class;
case 1:
return Boolean.class;
default:
return String.class;
}
}
};
table.getTableHeader().setReorderingAllowed(false);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.setDefaultRenderer(Namespace.class, new DefaultTableCellRenderer() {
@Override
public void setValue(Object value) {
setText(((Namespace) value).getName());
}
});
JScrollPane scrollPane = new JScrollPane(table);
boxPanel.add(scrollPane);
boxPanel.setSize(boxPanel.getPreferredSize());
JPanel buttonPane = new JPanel();
JButton applyButton = new JButton(BUTTON_STRING);
applyButton.setVerticalTextPosition(AbstractButton.CENTER);
applyButton.setActionCommand(BUTTON_STRING);
applyButton.addActionListener(this);
JButton resetButton = new JButton(RESET_STRING);
resetButton.setVerticalTextPosition(AbstractButton.CENTER);
resetButton.setActionCommand(RESET_STRING);
resetButton.addActionListener(this);
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPane.add(Box.createHorizontalGlue());
buttonPane.add(applyButton);
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(resetButton);
boxPanel.add(buttonPane);
setIntraGroupPosition(WindowPosition.RIGHT);
buildTable();
}
void buildTable() {
model.setRowCount(0);
Set<Namespace>inGraph = graphProvider.getNamespacesInFilter();
for(Namespace ns: inGraph) {
model.addRow(new Object[]{ns, true});
}
}
void dispose() {
plugin = null;
}
@Override
public void actionPerformed(ActionEvent e) {
if(BUTTON_STRING.equals(e.getActionCommand())) {
Vector<Vector> data = model.getDataVector();
for(int i = 0; i < model.getRowCount(); i++) {
Namespace victim = (Namespace)data.elementAt(i).elementAt(0);
if(!(boolean)data.elementAt(i).elementAt(1)) {
graphProvider.removeFromWhitelist(victim);
}
}
}
else if(RESET_STRING.equals(e.getActionCommand())) {
graphProvider.resetWhitelist();
}
buildTable();
}
@Override
public JComponent getComponent() {
return boxPanel;
}
@Override
public ActionContext getActionContext(MouseEvent event) {
Program program = plugin.getProgram();
if(program == null) {
return null;
}
return new ProgramActionContext(this, program);
}
public void open() {
if (!isVisible()) {
setVisible(true);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -182,8 +186,11 @@ public class CodecutUtils {
SymbolType type = symbol.getSymbolType();
if (type == SymbolType.FUNCTION) {
Namespace ns = ((Function)symbol.getObject()).getParentNamespace();
if (!namespaceList.contains(ns)) {
namespaceList.add(ns);
//make sure it's a "real" namespace with a body - otherwise we can't work with it
if ((ns.getBody().getMinAddress() != null) && (ns.getBody().getMaxAddress() != null)) {
if (!namespaceList.contains(ns)) {
namespaceList.add(ns);
}
}
}
}
@@ -798,6 +805,7 @@ public class CodecutUtils {
Symbol currSym = s;
updatingNamespace = true;
Msg.info(new Object(),"Splitting namespace: old(" + a.toString() + "), new (" + s.getAddress().toString() + "," + a.getMaxAddress().toString() + ")");
int transactionID = p.startTransaction("nsSplit");
try {
do {

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -75,10 +79,12 @@ class CombineProvider extends ComponentProviderAdapter implements ActionListener
private Namespace firstNamespace;
private Namespace secondNamespace;
private Namespace combinedNamespace;
private SymbolProvider symProvider;
CombineProvider(CodeCutGUIPlugin plugin) {
super(plugin.getTool(), "Combine Namespaces", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
symProvider = plugin.getSymbolProvider();
setIcon(ICON);
addToToolbar();
@@ -124,7 +130,8 @@ class CombineProvider extends ComponentProviderAdapter implements ActionListener
Dimension dim = entryPanel.getPreferredSize();
boxPanel.add(entryPanel);
boxPanel.setSize(dim);
setIntraGroupPosition(WindowPosition.RIGHT);
}
public void actionPerformed(ActionEvent e) {
@@ -236,12 +243,12 @@ class CombineProvider extends ComponentProviderAdapter implements ActionListener
}
}
}
}
this.closeComponent();
symProvider.reload();
}

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -69,10 +73,13 @@ class CreateProvider extends ComponentProviderAdapter implements ActionListener
private Namespace namespace;
private Symbol symbol;
private SymbolProvider symProvider;
CreateProvider(CodeCutGUIPlugin plugin) {
super(plugin.getTool(), "Create Namespace", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
symProvider = plugin.getSymbolProvider();
setIcon(ICON);
addToToolbar();
@@ -100,6 +107,7 @@ class CreateProvider extends ComponentProviderAdapter implements ActionListener
Dimension dim = entryPanel.getPreferredSize();
boxPanel.add(entryPanel);
boxPanel.setSize(dim);
setIntraGroupPosition(WindowPosition.RIGHT);
}
@@ -136,9 +144,10 @@ class CreateProvider extends ComponentProviderAdapter implements ActionListener
Msg.info(this, "Exception when attempting to change namespace of symbol "
+ this.symbol.getName() + " to " + nS.getName());
}
this.closeComponent();
symProvider.reload();
}
}

View File

@@ -0,0 +1,174 @@
/* ###
* © 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.
*/
package codecutguiv2;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import javax.swing.AbstractButton;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import docking.ActionContext;
import docking.WindowPosition;
import ghidra.app.context.ProgramActionContext;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.layout.PairLayout;
import resources.ResourceManager;
class DecompileRangeProvider extends ComponentProviderAdapter implements ActionListener {
private static final ImageIcon ICON = ResourceManager.loadImage("images/textfield.png");
private CodeCutGUIPlugin plugin;
private JPanel boxPanel;
private JTextField firstTextField;
private JTextField secondTextField;
private JButton button;
private String startAddr;
private String endAddr;
private Function func;
DecompileRangeProvider(CodeCutGUIPlugin plugin) {
super(plugin.getTool(), "Decompile Range", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
setIcon(ICON);
addToToolbar();
setHelpLocation(new HelpLocation(plugin.getName(), "CodeCut_Table"));
setWindowGroup("codecutTable");
setIntraGroupPosition(WindowPosition.BOTTOM);
boxPanel = new JPanel();
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
JPanel entryPanel = new JPanel(new PairLayout(6,10));
JLabel firstLabel = new JLabel("Starting Address: ");
JLabel secondLabel = new JLabel("Ending Address: ");
firstTextField = new JTextField(30);
if (this.startAddr != null) {
firstTextField.setText(this.startAddr);
}
secondTextField = new JTextField(30);
if (this.endAddr != null) {
secondTextField.setText(this.endAddr);
}
button = new JButton("Decompile Range");
button.setVerticalTextPosition(AbstractButton.CENTER);
button.setHorizontalTextPosition(AbstractButton.CENTER);
button.setMnemonic(KeyEvent.VK_ENTER);
button.setActionCommand("submit");
button.addActionListener(this);
entryPanel.add(firstLabel);
entryPanel.add(firstTextField);
entryPanel.add(secondLabel);
entryPanel.add(secondTextField);
entryPanel.add(button);
entryPanel.setSize(entryPanel.getPreferredSize().width, firstTextField.getPreferredSize().height);
Dimension dim = entryPanel.getPreferredSize();
boxPanel.add(entryPanel);
boxPanel.setSize(dim);
}
public void actionPerformed(ActionEvent e) {
if (this.startAddr == null) {
this.startAddr = firstTextField.getText();
this.endAddr = secondTextField.getText();
//the right thing to do here would be to try to convert to Address
//and throw an error if that doesn't work
}
if (this.startAddr != null && this.endAddr != null) {
if ("submit".equals(e.getActionCommand())) {
Program program = plugin.getProgram();
plugin.exportC(startAddr, endAddr);
}
}
this.closeComponent();
}
void open() {
if (!isVisible()) {
setVisible(true);
}
}
void dispose() {
plugin = null;
}
public void setFunc(Address addr) {
this.func = plugin.getProgram().getFunctionManager().getFunctionAt(addr);
firstTextField.setText(func.getEntryPoint().toString());
secondTextField.setText(getFnEndAddr(func.getEntryPoint()).toString());
}
@Override
public ActionContext getActionContext(MouseEvent event) {
Program program = plugin.getProgram();
if (program == null) {
return null;
}
return new ProgramActionContext(this, program);
}
public void updateTitle() {
setSubTitle("Decompile Range");
}
protected Address getFnEndAddr(Address start) {
FunctionManager fm = plugin.getProgram().getFunctionManager();
Function fn = fm.getFunctionAt(start);
FlatProgramAPI fp = new FlatProgramAPI(plugin.getProgram());
return fp.getFunctionAfter(fn).getEntryPoint();
}
@Override
public JComponent getComponent() {
return boxPanel;
}
}

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -0,0 +1,278 @@
/* ###
* © 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.
*/
package codecutguiv2;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ghidra.app.script.GhidraScriptLoadException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.StringDataInstance;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.ReferenceManager;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.util.DefinedStringIterator;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.Swing;
import ghidra.util.datastruct.Accumulator;
import ghidra.util.datastruct.ListAccumulator;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskLauncher;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
public class ModNamingAnalyzer {
// Assumes these exist in your class, as in your original snippet:
private Map<Namespace, List<String>> stringMap = new HashMap<>();
private Map<Namespace, String> suggestedModuleNames = new HashMap<>();
Program currentProgram;
private static final String SEPARATOR = "tzvlw"; // separator used by modnaming.py
ModNamingAnalyzer(Program currentProgram) {
this.currentProgram = currentProgram;
getModuleStrings();
}
public void getModuleStrings() {
try {
SymbolTable symbolTable = currentProgram.getSymbolTable();
ReferenceManager refManager = currentProgram.getReferenceManager();
TaskMonitor monitor = new TaskMonitorAdapter();
monitor.setCancelEnabled(true);
Listing listing = currentProgram.getListing();
monitor.initialize(listing.getNumDefinedData());
Accumulator<ProgramLocation> accumulator = new ListAccumulator<>();
Swing.allowSwingToProcessEvents();
for (Data stringInstance : DefinedStringIterator.forProgram(currentProgram)) {
Address strAddr = stringInstance.getAddress();
ReferenceIterator refIterator = refManager.getReferencesTo(strAddr);
while (refIterator.hasNext()) {
Reference ref = refIterator.next();
Namespace refNamespace = symbolTable.getNamespace(ref.getFromAddress());
Namespace parentNs = refNamespace.getParentNamespace();
String str = StringDataInstance.getStringDataInstance(stringInstance).getStringValue();
// parent namespace is correct one to use BUT MAY BE NULL IF GLOBAL WAS ORIGINAL
Namespace module;
if (parentNs != null) {
module = parentNs;
}
else {
module = refNamespace;
}
List<String> list = stringMap.get(module);
if (list != null) {
list.add(str);
stringMap.put(module, list);
}
else {
List<String> newList = new ArrayList<String>();
newList.add(str);
stringMap.put(module, newList);
}
}
ProgramLocation pl = new ProgramLocation(currentProgram, stringInstance.getMinAddress(),
stringInstance.getComponentPath(), null, 0, 0, 0);
accumulator.add(pl);
//monitor.checkCanceled();
monitor.incrementProgress(1);
}
} catch (Exception e) {
Msg.error(this, "Error when getting strings for each module: " + e);
e.printStackTrace();
}
}
private String packStrings(List<String> strList) {
String allStrings = String.join(" " + SEPARATOR + " ", strList);
allStrings = allStrings.replaceAll("%[0-9A-Za-z]+"," ");
allStrings = allStrings.replaceAll("-","_");
allStrings = allStrings.replaceAll("_"," ");
allStrings = allStrings.replaceAll("[/\\\\]"," ");
allStrings = allStrings.replaceAll("[^A-Za-z0-9_.]"," ");
allStrings = allStrings.concat("\r\n\0");
return allStrings;
}
public void guessModuleNames() {
Task guessNamesTask = new Task("Guess Module Names", true, true, true) {
@Override
public void run(TaskMonitor monitor) {
monitor.setMessage("Gathering string information...");
long startCount = stringMap.size();
long numRemaining = stringMap.size();
monitor.initialize(startCount);
// Force the updating state so the CodeCut GUI does not attempt to refresh
// until after all updates are complete (makes things MUCH faster).
CodecutUtils.setUpdating(true);
try {
for (Map.Entry<Namespace, List<String>> entry : stringMap.entrySet()) {
if (!monitor.isCancelled()) {
Namespace ns = entry.getKey();
if (!ns.getName().equals("Global")) {
List<String> strList = entry.getValue();
monitor.setMessage("Guessing module name for " + ns.getName());
String allStrings = packStrings(strList);
AddressSetView set = ns.getBody();
if (set == null || set.isEmpty()) {
set = new AddressSet(currentProgram.getMinAddress(), currentProgram.getMaxAddress());
}
String suggestedName = ModNamingLauncher.execute(currentProgram, set, allStrings, monitor);
//if name is "unknown" (e.g. modnaming found no repeated strings) don't bother renaming
if (suggestedName.equals("unknown")) {
Msg.info(this, "No name guess found for module " + ns.getName() + ", leaving unchanged");
continue;
}
suggestedModuleNames.put(ns, suggestedName);
// Update namespace (module) to use new name
// suggestedModuleNames is created in case this is later
// extended to have a GUI window for the user to accept/modify
// names before updating, in which case this update should
// happen elsewhere.
monitor.setMessage("Updating module name of " + ns.getName() + "...");
String newName = suggestedName;
int num = 1;
while (!CodecutUtils.getMatchingNamespaces(newName, Arrays.asList(currentProgram.getGlobalNamespace()), currentProgram).isEmpty()) {
newName = suggestedName.concat(Integer.toString(num));
num++;
}
Namespace newNs = null;
int transactionId = currentProgram.startTransaction("CreateNamespace");
boolean success = false;
try {
newNs = currentProgram.getSymbolTable()
.createNameSpace(ns.getParentNamespace(), newName, SourceType.USER_DEFINED);
success = true;
} catch (DuplicateNameException ex) {
Msg.error(this, "Failed to create namespace for suggested name " + suggestedName, ex);
} finally {
currentProgram.endTransaction(transactionId, success);
}
try {
CodecutUtils.renameNamespace(currentProgram, ns, newNs);
Msg.info(this, "Namespace " + ns.getName() + " renamed to " + newNs.getName());
} catch (Exception ex) {
Msg.info(this, "Exception when renaming namespace " + ns.getName() + ": " + ex.getMessage());
}
}
numRemaining--;
monitor.setProgress(startCount - numRemaining);
}
else { // Task cancelled
suggestedModuleNames.clear();
suggestedModuleNames = null;
}
}
} catch (Exception e) {
Msg.error(this, "Module name guessing failed: " + e);
e.printStackTrace();
}
CodecutUtils.setUpdating(false);
}
};
new TaskLauncher(guessNamesTask, null, 250);
}
}
class ModNamingLauncher extends PyGhidraFileLauncher {
@Override protected String getScriptName() { return "ModNamingRun.py"; }
@Override protected String getInfilePrefix() { return "modnaming_in"; }
@Override protected String getOutfilePrefix() { return "modnaming_out"; }
@Override protected String getInfileSuffix() { return ".txt"; }
@Override protected String getOutfileSuffix() { return ".txt"; }
// No extra args needed
@Override protected String[] getExtraArgs(ghidra.framework.plugintool.PluginTool tool) { return new String[0]; }
// Convenience static method to preserve your old call-site signature
public static String execute(Program program,
AddressSetView set,
String inputPayload,
TaskMonitor monitor)
throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
return new ModNamingLauncher().runFileMode(program, set, inputPayload, monitor);
}
@Override protected String getLaunchFailDialogTitle() { return "Module Naming Failed to Launch"; }
@Override protected String getLaunchFailDialogBodyPrefix() {
return "Module Naming requires the PyGhidra extension.\n\nDetails: ";
}
}

View File

@@ -1,111 +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 codecutguiv2;
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 docking.widgets.dialogs.MultiLineMessageDialog;
import ghidra.framework.Application;
public class ModNamingPython {
public Runtime runtime;
public String pythonExec;
public Process process;
public OutputStream stdin;
public InputStream stdout;
public InputStream stderr;
public ModNamingPython(String pythonExec) {
this.pythonExec = pythonExec;
this.runtime = Runtime.getRuntime();
}
public int startProcess() throws IOException {
String pythonFile = Application.getModuleDataFile("modnaming.py").toString();
String[] exec = {pythonExec, pythonFile};
try {
process = runtime.exec(exec);
}
catch (IOException e) {
// show message about invalid python executable path
MultiLineMessageDialog.showMessageDialog(null, "Invalid Python Path",
"Python Error! Please check path under " +
"\n Edit -> Tool Options -> Python Executable.",
e.getMessage(), MultiLineMessageDialog.WARNING_MESSAGE);
return -1;
}
// Yes this is confusing. stdin is a Java OutputStream, stdin is an InputStream
stdin = process.getOutputStream();
stdout = process.getInputStream();
stderr = process.getErrorStream();
return 0;
}
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);
stdin.flush();
}
public String readProcessOutput() {
return readProcess(stdout);
}
public String readProcessError() {
return readProcess(stderr);
}
public String readProcess(InputStream stream) {
String result = "";
try {
if (stream != null && stream.available() > 0) {
result = new BufferedReader(new InputStreamReader(stream))
.lines().collect(Collectors.joining("\n"));
}
} catch (IOException e) {
return result;
}
return result;
}
}

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -40,14 +44,17 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import ghidra.app.services.GoToService;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.util.Msg;
import ghidra.util.layout.PairLayout;
import ghidra.util.table.GhidraTable;
@@ -60,6 +67,8 @@ class NamespacePanel extends JPanel {
private List<SymbolPanel> symPanels;
private JPanel boxPanel;
private JScrollPane listScroller;
private List<GhidraTable> tables;
private Boolean textFiltering = false;
NamespacePanel(Program program, PluginTool tool, SymbolProvider provider, SymbolRenderer renderer) {
BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS);
@@ -69,8 +78,10 @@ class NamespacePanel extends JPanel {
this.tool = tool;
this.symProvider = provider;
this.symPanels = new ArrayList<>();
this.tables = new ArrayList<>();
this.boxPanel = null;
this.listScroller = null;
this.renderer = renderer;
}
@@ -86,10 +97,10 @@ class NamespacePanel extends JPanel {
nsList.sort(new Comparator<Namespace>() {
@Override
public int compare(Namespace ns1, Namespace ns2) {
Address ns1MaxAddress = ns1.getBody().getMaxAddress();
Address ns2MaxAddress = ns2.getBody().getMaxAddress();
if (ns1MaxAddress != null && ns2MaxAddress != null) {
if (ns1MaxAddress.getAddressableWordOffset() < ns2MaxAddress.getAddressableWordOffset()) {
Address ns1MinAddress = ns1.getBody().getMinAddress();
Address ns2MinAddress = ns2.getBody().getMinAddress();
if (ns1MinAddress != null && ns2MinAddress != null) {
if (ns1MinAddress.getAddressableWordOffset() < ns2MinAddress.getAddressableWordOffset()) {
return -1;
}
}
@@ -109,7 +120,15 @@ class NamespacePanel extends JPanel {
JLabel longestLabel = new JLabel(longest);
int width = longestLabel.getPreferredSize().width;
while(it.hasNext()) {
Namespace ns = it.next();
AddressSetView ar = ns.getBody();
if ((ar.getMinAddress() != null) && (ar.getMaxAddress() != null)) {
Msg.info(this, "Add: " + ns.getName() + " " + ar.getMinAddress().toString() + " " + ar.getMaxAddress().toString());
}
else {
Msg.info(this, "Add: " + ns.getName() + " null min or max??");
}
SymbolIterator symIter = this.program.getSymbolTable().getSymbols(ns);
SymbolTableModel model = new SymbolTableModel(this.program, this.symProvider, this.tool, symIter, ns);
@@ -129,15 +148,17 @@ class NamespacePanel extends JPanel {
int totalWidth = panel.getPreferredSize().width;
panel.setPreferredSize(new Dimension(totalWidth, height));
symPanels.add(symPanel);
tables.add(symPanel.getTable());
symPanel.getTable().setNavigateOnSelectionEnabled(true);
boxPanel.add(panel);
}
listScroller = new JScrollPane(boxPanel);
listScroller.setPreferredSize(new Dimension(576, 400));
this.add(listScroller);
this.setPreferredSize(new Dimension(576, 400));
boxPanel.setAutoscrolls(true);
this.add(listScroller, BorderLayout.CENTER);
CCTableFilterPanel filterPanel = new CCTableFilterPanel(tables, symProvider, this);
this.add(filterPanel, BorderLayout.SOUTH);
this.setPreferredSize(new Dimension(576, 400));
revalidate();
}
@@ -210,7 +231,7 @@ class NamespacePanel extends JPanel {
Iterator<SymbolPanel> it = symPanels.iterator();
while (it.hasNext()) {
SymbolPanel panel = it.next();
count += panel.getActualSymbolCount();
count += panel.getModel().getRowCount();
}
return count;
}
@@ -257,4 +278,15 @@ class NamespacePanel extends JPanel {
return this.symPanels.iterator();
}
SymbolProvider getSymProvider() {
return this.symProvider;
}
public void setTextFiltering(boolean set) {
this.textFiltering = set;
}
public Boolean isTextFiltering() {
return this.textFiltering;
}
}

View File

@@ -1,27 +1,26 @@
/* ###
* © 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.
*/
* © 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)

View File

@@ -0,0 +1,200 @@
package codecutguiv2;
/*
* © 2025 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.
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.script.GhidraScript;
import ghidra.app.script.GhidraScriptLoadException;
import ghidra.app.script.GhidraScriptProvider;
import ghidra.app.script.GhidraScriptUtil;
import ghidra.app.script.GhidraState;
import ghidra.app.services.ConsoleService;
import ghidra.framework.model.Project;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Base class for launching PyGhidra scripts in "file mode":
* - writes input payload to a temp infile
* - runs a named script with args [infile, outfile, ...extraArgs]
* - reads output payload from the outfile
*
* Subclasses override:
* - script name
* - temp file prefixes/suffixes (optional)
* - extra args (optional)
* - UI strings for error dialogs (optional)
*/
public abstract class PyGhidraFileLauncher {
/** Provide the script file name that must be on the Ghidra script path. */
protected abstract String getScriptName();
/** Prefix for the temp input file (default: "in_"). */
protected String getInfilePrefix() { return "in_"; }
/** Suffix/extension for the temp input file (default: ".json"). */
protected String getInfileSuffix() { return ".json"; }
/** Prefix for the temp output file (default: "out_"). */
protected String getOutfilePrefix() { return "out_"; }
/** Suffix/extension for the temp output file (default: ".json"). */
protected String getOutfileSuffix() { return ".json"; }
/**
* Return any extra script args after [infile, outfile]. Default: none.
* If this is used, the subclass must be defined in its own .java file
* in order for Ghidra the correctly find the module data file
* (yes this is strange)
*/
protected String[] getExtraArgs(PluginTool tool) throws Exception { return new String[0]; }
/** Title and message for the “PyGhidra required” dialog. */
protected String getLaunchFailDialogTitle() { return "Script Failed to Launch"; }
protected String getLaunchFailDialogBodyPrefix() { return "This feature requires the PyGhidra extension.\n\nDetails: "; }
/**
* Run the script synchronously and return the outfile contents (trimmed), or null on cancel/error.
*/
public String runFileMode(Program program,
AddressSetView set,
String inputPayload,
TaskMonitor monitor)
throws IllegalAccessException, FileNotFoundException, GhidraScriptLoadException {
final String scriptName = getScriptName();
AutoAnalysisManager aam = AutoAnalysisManager.getAnalysisManager(program);
PluginTool tool = aam.getAnalysisTool();
Project project = tool != null ? tool.getProject() : null;
Msg.info(getClass(), "tool: " + tool.getName());
GhidraState state = new GhidraState(
tool,
project,
program,
new ProgramLocation(program, set.getMinAddress()),
new ProgramSelection(set),
null
);
PrintWriter out = getOut(tool);
PrintWriter err = getErr(tool);
Path inFile = null, outFile = null;
// 1) Locate script
ResourceFile sourceFile = GhidraScriptUtil.findScriptByName(scriptName);
if (sourceFile == null) {
throw new IllegalAccessException("Couldn't find script: " + scriptName);
}
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(sourceFile);
if (provider == null) {
throw new IllegalAccessException("Couldn't find script provider for: " + scriptName);
}
Msg.info(getClass(), "Chosen provider: " + provider.getClass().getName() +
" (runtime=" + provider.getRuntimeEnvironmentName() + ")");
GhidraScript script;
try {
script = provider.getScriptInstance(sourceFile, err);
} catch (GhidraScriptLoadException e) {
ghidra.util.Msg.showError(
null, null,
getLaunchFailDialogTitle(),
getLaunchFailDialogBodyPrefix() + e.getMessage()
);
throw e;
}
try {
// 2) Prep temp files
inFile = Files.createTempFile(getInfilePrefix(), getInfileSuffix());
outFile = Files.createTempFile(getOutfilePrefix(), getOutfileSuffix());
inFile.toFile().deleteOnExit();
outFile.toFile().deleteOnExit();
// write input payload
Files.writeString(inFile, (inputPayload == null ? "" : inputPayload) + "\n", StandardCharsets.UTF_8);
// 3) Assemble args: [infile, outfile, ...extra]
String[] extras = getExtraArgs(tool);
String[] args = new String[2 + extras.length];
args[0] = inFile.toString();
args[1] = outFile.toString();
System.arraycopy(extras, 0, args, 2, extras.length);
script.setScriptArgs(args);
// 4) Run blocking
script.execute(state, monitor, out);
// 5) Read result payload
return Files.readString(outFile, StandardCharsets.UTF_8).trim();
}
catch (CancelledException e) {
return null;
}
catch (Exception e) {
Msg.warn(getClass(), "Error running script " + scriptName + ": " + e.getMessage(), e);
return null;
}
finally {
try { if (inFile != null) Files.deleteIfExists(inFile); } catch (IOException ignored) {}
try { if (outFile != null) Files.deleteIfExists(outFile); } catch (IOException ignored) {}
}
}
// ----- console helpers -----
protected static PrintWriter getOut(PluginTool tool) {
if (tool != null) {
ConsoleService console = tool.getService(ConsoleService.class);
if (console != null) return console.getStdOut();
}
return new PrintWriter(System.out);
}
protected static PrintWriter getErr(PluginTool tool) {
if (tool != null) {
ConsoleService console = tool.getService(ConsoleService.class);
if (console != null) return console.getStdErr();
}
return new PrintWriter(System.err);
}
}

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -69,10 +73,12 @@ class RenameProvider extends ComponentProviderAdapter implements ActionListener
private JButton button;
private Namespace namespace;
private SymbolProvider symProvider;
RenameProvider(CodeCutGUIPlugin plugin) {
super(plugin.getTool(), "Rename Namespace", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
symProvider = plugin.getSymbolProvider();
setIcon(ICON);
addToToolbar();
@@ -100,8 +106,7 @@ class RenameProvider extends ComponentProviderAdapter implements ActionListener
Dimension dim = entryPanel.getPreferredSize();
boxPanel.add(entryPanel);
boxPanel.setSize(dim);
//addToTool();
setIntraGroupPosition(WindowPosition.RIGHT);
}
public void actionPerformed(ActionEvent e) {
@@ -169,6 +174,7 @@ class RenameProvider extends ComponentProviderAdapter implements ActionListener
this.closeComponent();
}
}
symProvider.reload();
}
}

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -59,7 +63,6 @@ class SymbolPanel extends JPanel {
private TableModelListener listener;
private FilterDialog filterDialog;
private GhidraThreadedTablePanel<Symbol> threadedTablePanel;
private GhidraTableFilterPanel<Symbol> tableFilterPanel;
private Namespace namespace;
private ListSelectionListener selectionListener;
@@ -108,44 +111,10 @@ class SymbolPanel extends JPanel {
}
add(threadedTablePanel, BorderLayout.CENTER);
createFilterFieldPanel();
filterDialog = symProvider.filterDialog;
}
private JPanel createFilterFieldPanel() {
tableFilterPanel = new GhidraTableFilterPanel<>(symTable, tableModel);
tableFilterPanel.setToolTipText("Filters the contents of the table on symbol " +
"names that start with the given pattern");
tableFilterPanel.add(Box.createHorizontalStrut(5));
final JCheckBox nameColumnOnlyCheckbox = new GCheckBox("Name Only");
nameColumnOnlyCheckbox.setName("NameOnly"); // used by JUnit
nameColumnOnlyCheckbox.setToolTipText(
"<html><b>Selected</b> causes filter to only consider the symbol's name.");
nameColumnOnlyCheckbox.setFocusable(false);
nameColumnOnlyCheckbox.setSelected(FILTER_NAME_ONLY_DEFAULT);
tableFilterPanel.setFilterRowTransformer(
updateRowDataTransformer(FILTER_NAME_ONLY_DEFAULT));
nameColumnOnlyCheckbox.addItemListener(e -> {
boolean nameOnly = nameColumnOnlyCheckbox.isSelected();
tableFilterPanel.setFilterRowTransformer(updateRowDataTransformer(nameOnly));
});
tableFilterPanel.add(nameColumnOnlyCheckbox);
return tableFilterPanel;
}
protected RowFilterTransformer<Symbol> updateRowDataTransformer(boolean nameOnly) {
if (nameOnly) {
return new NameOnlyRowTransformer();
}
return new DefaultRowFilterTransformer<>(tableModel, symTable.getColumnModel());
}
ProgramSelection getProgramSelection() {
return symTable.getProgramSelection();
}
@@ -154,7 +123,6 @@ class SymbolPanel extends JPanel {
symTable.getModel().removeTableModelListener(listener);
symTable.dispose();
threadedTablePanel.dispose();
tableFilterPanel.dispose();
symProvider = null;
filterDialog.close();
filterDialog = null;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;
@@ -32,21 +36,23 @@ import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JTable;
import docking.ActionContext;
import docking.DockingUtils;
import docking.action.KeyBindingData;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.context.ProgramSymbolActionContext;
import ghidra.app.services.GoToService;
import ghidra.app.util.SymbolInspector;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.table.GhidraTable;
import resources.ResourceManager;
@@ -59,10 +65,12 @@ class SymbolProvider extends ComponentProviderAdapter {
private SymbolTableModel symbolKeyModel;
private NamespacePanel namespacePanel;
public FilterDialog filterDialog;
private GoToService gotoService;
SymbolProvider(CodeCutGUIPlugin plugin) {
super(plugin.getTool(), "CodeCut Table", plugin.getName(), ProgramActionContext.class);
this.plugin = plugin;
gotoService = plugin.getGoToService();
setIcon(ICON);
addToToolbar();
@@ -92,6 +100,20 @@ class SymbolProvider extends ComponentProviderAdapter {
}
List<Symbol> symbols = namespacePanel.getSelectedSymbols();
Iterator<GhidraTable> tables = namespacePanel.getAllTables().iterator();
AddressFactory af = program.getAddressFactory();
// Hack to go to proper function when text filtering
while(tables.hasNext()) {
GhidraTable table = tables.next();
if (table.getSelectedRow() >= 0 && table.getSelectedRow() <= table.getRowCount()) {
Address addr = af.getAddress(table.getValueAt(table.getSelectedRow(), 1).toString());
if (addr != null && namespacePanel.isTextFiltering()) {
gotoService.goTo(addr);
}
return new ProgramSymbolActionContext(this, program, symbols, getTable());
}
}
return new ProgramSymbolActionContext(this, program, symbols, getTable());
}
@@ -193,11 +215,16 @@ class SymbolProvider extends ComponentProviderAdapter {
private String generateSubTitle() {
SymbolFilter filter = symbolKeyModel.getFilter();
int rowCount = symbolKeyModel.getRowCount();
int unfilteredCount = symbolKeyModel.getUnfilteredRowCount();
if (rowCount != unfilteredCount) {
int rowCount = 0;
int unfilteredCount = 0;
Iterator<GhidraTable> tables = getAllTables().iterator();
Iterator<SymbolPanel> panels = getSymPanels();
while(tables.hasNext() && panels.hasNext()) {
JTable table = tables.next();
rowCount += table.getRowCount();
unfilteredCount += panels.next().getModel().getUnfilteredRowCount();
}
if (namespacePanel.isTextFiltering()) {
return " (Text filter matched " + rowCount + " of " + unfilteredCount + " symbols)";
}
if (filter.acceptsAll()) {

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -1,26 +1,30 @@
/* ###
* © 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.
* © 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.
*/
package codecutguiv2;

View File

@@ -0,0 +1,88 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/EmptyFcgData.java
*/
package graphcut;
import ghidra.graph.viewer.GraphPerspectiveInfo;
import ghidra.program.model.symbol.Namespace;
/**
* empty data used to avoid null checks
*/
public class EmptyGraphCutData implements GraphCutData {
@Override
public Namespace getNamespace() {
throw new UnsupportedOperationException("Empty data has no namespace");
}
@Override
public boolean isNamespace(Namespace ns) {
return false;
}
@Override
public GraphCutGraph getGraph() {
throw new UnsupportedOperationException("Empty data has no graph");
}
@Override
public NamespaceEdgeCache getNamespaceEdgeCache() {
throw new UnsupportedOperationException("Empty data has no namespace edge cache");
}
@Override
public boolean hasResults() {
return false;
}
@Override
public void dispose() {
//nothing
}
@Override
public boolean isInitialized() {
return false;
}
@Override
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
throw new UnsupportedOperationException("Empty data does not need view information");
}
@Override
public void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
throw new UnsupportedOperationException("Empty data does not need view information");
}
}

View File

@@ -0,0 +1,126 @@
/* ###
* © 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.
*/
/*
* Heavily Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java
*/
package graphcut;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import functioncalls.graph.FcgEdge;
import functioncalls.graph.FcgVertex;
import generic.theme.GColor;
import ghidra.graph.viewer.GraphComponent;
import ghidra.graph.viewer.GraphViewer;
import ghidra.graph.viewer.SatelliteGraphViewer;
import ghidra.graph.viewer.VisualGraphViewUpdater;
import ghidra.graph.viewer.edge.VisualEdgeRenderer;
import ghidra.graph.viewer.layout.VisualGraphLayout;
import ghidra.graph.viewer.renderer.VisualVertexSatelliteRenderer;
import ghidra.graph.viewer.vertex.VisualVertexRenderer;
/**
* A graph component for GraphCut
*/
public class GraphCutComponent extends GraphComponent<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
private GraphCutGraph gcGraph;
private GraphCutVertexPaintTransformer vertexPaintTransformer =
new GraphCutVertexPaintTransformer(GraphCutVertex.DEFAULT_VERTEX_SHAPE_COLOR);
private GraphCutEdgePaintTransformer edgePaintTransformer =
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct"),
new GColor("color.bg.plugin.fcg.edge.primary.indirect"));
private GraphCutEdgePaintTransformer selectedEdgePaintTransformer =
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct.selected"),
new GColor("color.bg.plugin.fcg.edge.primary.indirect.selected"));
private GraphCutEdgePaintTransformer satelliteEdgePaintTransformer =
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.satellite.direct"),
new GColor("color.bg.plugin.fcg.edge.satellite.indirect"));
GraphCutComponent(GraphCutGraph g){
setGraph(g);
build();
}
@Override
protected GraphCutVertex getInitialVertex() {
return gcGraph.getSource();
}
@Override
protected void decoratePrimaryViewer(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
super.decoratePrimaryViewer(viewer, layout);
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
VisualVertexRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
(VisualVertexRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
edgeRenderer.setDrawColorTransformer(edgePaintTransformer);
edgeRenderer.setSelectedColorTransformer(selectedEdgePaintTransformer);
}
@Override
protected void decorateSatelliteViewer(SatelliteGraphViewer<GraphCutVertex, GraphCutEdge> viewer,
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
super.decorateSatelliteViewer(viewer, layout);
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
(VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
edgeRenderer.setDrawColorTransformer(satelliteEdgePaintTransformer);
}
@Override
public void dispose() {
gcGraph = null;
super.dispose();
}
@Override
public VisualGraphViewUpdater<GraphCutVertex, GraphCutEdge> getViewUpdater(){
return super.getViewUpdater();
}
}

View File

@@ -0,0 +1,97 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgData.java
*/
package graphcut;
import ghidra.graph.viewer.GraphPerspectiveInfo;
import ghidra.program.model.symbol.Namespace;
/**
* Allows us to retrieve and work on the graph. Makes caching data simple
*/
public interface GraphCutData {
/**
* The namespace of this data
* @return the namespace
*/
Namespace getNamespace();
/**
* The graph of this data
* @return the graph
*/
GraphCutGraph getGraph();
/**
* Returns the cache of edges. Not in the graph but used to track existing edges that are not yet in the graph.
* @return
*/
NamespaceEdgeCache getNamespaceEdgeCache();
/**
* True if this data has a valid namespace
* @return true if this data has a valid namespace
*/
boolean hasResults();
/**
* False if the graph in this data has not yet been loaded
*/
boolean isInitialized();
/**
* Dispose the contents of this data
*/
void dispose();
/**
* Returns the view's graph perspective. this is used by the view to restore itself.
* @return the view's graph perspective
*/
GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective();
/**
* Set the view information for this graph data
* @param info the perspective to set
*/
void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info);
/**
* Returns true if this data's namespace is equal to the given one
* @param ns the namespace to test
* @return true if this data's namespace is equal to the given one
*/
boolean isNamespace(Namespace ns);
}

View File

@@ -0,0 +1,79 @@
/* ###
* © 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.
*/
/*
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgDataFactory.java
*/
package graphcut;
import com.google.common.cache.*;
import ghidra.program.model.symbol.Namespace;
/**
* A factory that will create GraphCutGraph data objects for a given namespace
*/
public class GraphCutDataFactory {
private LoadingCache<Namespace, GraphCutData> cache;
GraphCutDataFactory(RemovalListener<Namespace, GraphCutData> listener){
cache = CacheBuilder
.newBuilder()
.maximumSize(5)
.removalListener(listener)
.build(new CacheLoader<Namespace, GraphCutData> () {
@Override
public GraphCutData load(Namespace ns) throws Exception {
return new ValidGraphCutData(ns, new GraphCutGraph());
}
});
}
GraphCutData create(Namespace ns) {
if (ns == null) {
return new EmptyGraphCutData();
}
GraphCutData data = cache.getUnchecked(ns);
return data;
}
void remove(Namespace ns) {
cache.invalidate(ns);
}
void dispose() {
cache.invalidateAll();
}
}

View File

@@ -0,0 +1,70 @@
/* ###
* © 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.
*/
package graphcut;
import ghidra.graph.viewer.edge.AbstractVisualEdge;
import graphcut.GraphCutVertex;
/**
* A GraphCut Edge
*/
public class GraphCutEdge extends AbstractVisualEdge<GraphCutVertex> {
public GraphCutEdge(GraphCutVertex start, GraphCutVertex end) {
super(start, end);
}
@SuppressWarnings("unchecked")
@Override
public GraphCutEdge cloneEdge(GraphCutVertex start, GraphCutVertex end) {
return new GraphCutEdge(start, end);
}
/**
* Returns true if an edge is direct from a lower level.
* @return true if this edge is a direct edge
*/
public boolean isDirectEdge() {
GraphCutLevel startLevel = getStart().getLevel();
GraphCutLevel endLevel = getEnd().getLevel();
if(startLevel.isSource() || endLevel.isSource()) {
return true;
}
GraphCutLevel parent = startLevel.parent();
if (parent.equals(endLevel)) {
return true;
}
GraphCutLevel child = startLevel.child();
return child.equals(endLevel);
}
}

View File

@@ -0,0 +1,76 @@
/* ###
* © 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.
*/
/*
* Heavily borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java
*/
package graphcut;
import com.google.common.base.Function;
import java.awt.Color;
import ghidra.util.ColorUtils;
public class GraphCutEdgePaintTransformer implements Function<GraphCutEdge, Color> {
private Color directColor;
private Color indirectColor;
private Color[] directColorWithAlpha = new Color[10];
public GraphCutEdgePaintTransformer(Color directColor, Color indirectColor) {
this.directColor = directColor;
this.indirectColor = indirectColor;
directColorWithAlpha = alphatize(directColor);
}
private Color[] alphatize(Color c) {
Color[] alphad = new Color[10];
alphad[0] = c;
for (int i = 1; i < 10; i++) {
double newAlpha = 255 - (i * 25.5);
alphad[i] = ColorUtils.withAlpha(c, (int) newAlpha);
}
return alphad;
}
@Override
public Color apply(GraphCutEdge e) {
if (e.isDirectEdge()) {
return getDirectEdgeColor(e);
}
return indirectColor;
}
private Color getDirectEdgeColor(GraphCutEdge e) {
return directColor;
}
}

View File

@@ -0,0 +1,67 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgEmphasizeEdgesJob.java
*/
package graphcut;
import java.util.Set;
import ghidra.graph.job.AbstractGraphVisibilityTransitionJob;
import ghidra.graph.viewer.GraphViewer;
public class GraphCutEmphasizeEdgesJob extends AbstractGraphVisibilityTransitionJob<GraphCutVertex, GraphCutEdge> {
private Set<GraphCutEdge> edges;
public GraphCutEmphasizeEdgesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer, Set<GraphCutEdge> edges) {
super(viewer, true);
this.edges = edges;
}
@Override
protected void updateOpacity(double percentComplete) {
double remaining = percentComplete;
if(percentComplete > 0.5){
remaining = 1 - percentComplete;
}
double modified = remaining * 10;
for (GraphCutEdge e : edges) {
e.setEmphasis(modified);
}
}
}

View File

@@ -0,0 +1,192 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgExpandingVertexCollection.java
*/
package graphcut;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import edu.uci.ics.jung.algorithms.layout.Layout;
import functioncalls.graph.FcgDirection;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.map.LazyMap;
import ghidra.graph.viewer.GraphViewer;
import util.CollectionUtils;
public class GraphCutExpandingVertexCollection {
private Comparator<GraphCutVertex> vertexComparator =
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
private Comparator<GraphCutVertex> sourceVertexComparator = this::compareVerticesByLayoutPosition;
private Map<GraphCutVertex, TreeSet<GraphCutVertex>> newVerticesBySource = LazyMap.lazyMap(
new TreeMap<>(sourceVertexComparator), () -> new TreeSet<>(vertexComparator));
private GraphViewer<GraphCutVertex, GraphCutEdge> viewer;
private GraphCutLevel parentLevel;
private GraphCutLevel expandingLevel;
private Set<GraphCutVertex> newVertices;
private Set<GraphCutEdge> newEdges;
private Set<GraphCutEdge> indirectEdges = Collections.emptySet();
private boolean isIncoming;
private Iterable<GraphCutVertex> sources;
public GraphCutExpandingVertexCollection(Iterable<GraphCutVertex> sources, GraphCutLevel parentLevel, GraphCutLevel expandingLevel,
Set<GraphCutVertex> newVertices, Set<GraphCutEdge> newEdges, Set<GraphCutEdge> allParentLevelEdges, boolean isIncoming,
GraphViewer<GraphCutVertex, GraphCutEdge> viewer) {
this.sources = sources;
this.parentLevel = parentLevel;
this.newVertices = newVertices;
this.newEdges = newEdges;
this.isIncoming = isIncoming;
this.viewer = viewer;
this.expandingLevel = expandingLevel;
for(GraphCutEdge e: allParentLevelEdges) {
GraphCutVertex start = e.getStart();
GraphCutVertex end = e.getEnd();
GraphCutLevel startLevel = start.getLevel();
GraphCutLevel endLevel = end.getLevel();
if (expandingLevel.equals(startLevel)) {
if(expandingLevel.equals(endLevel)) {
newVerticesBySource.get(start).add(end);
newVerticesBySource.get(end).add(start);
}
else {
newVerticesBySource.get(end).add(start);
}
}
else {
newVerticesBySource.get(start).add(end);
}
}
}
private int compareVerticesByLayoutPosition(GraphCutVertex v1, GraphCutVertex v2) {
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
GraphCutLevel l1 = v1.getLevel();
GraphCutLevel l2 = v2.getLevel();
int result = l1.compareTo(l2);
if (result != 0) {
if(l1.equals(parentLevel)) {
return -1;
}
if(l2.equals(parentLevel)) {
return 1;
}
return result;
}
Point2D p1 = layout.apply(v1);
Point2D p2 = layout.apply(v2);
return (int) (p1.getX() - p2.getX());
}
public List<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
List<GraphCutVertex> verticesAtLevel = existingVertices.stream().filter(v -> v.getLevel().equals(level)).collect(Collectors.toList());
return verticesAtLevel;
}
public List<GraphCutVertex> getAllVerticesAtNewLevel(){
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
LinkedHashSet<GraphCutVertex> sortedVertices = existingVertices
.stream()
.map(v -> newVerticesBySource.get(v))
.flatMap(set -> set.stream())
.filter(v -> v.getLevel().equals(expandingLevel))
.collect(Collectors.toCollection(LinkedHashSet::new));
return new ArrayList<>(sortedVertices);
}
public Set<GraphCutVertex> getNewVertices(){
return newVertices;
}
public Set<GraphCutEdge> getIndirectEdges() {
return indirectEdges;
}
public Iterable<GraphCutEdge> getNewEdges(){
return IterableUtils.chainedIterable(newEdges, indirectEdges);
}
public int getNewEdgeCount() {
return newEdges.size() + indirectEdges.size();
}
public void setIndirectEdges(Set<GraphCutEdge> indirectEdges) {
this.indirectEdges = CollectionUtils.asSet(indirectEdges);
}
public GraphCutLevel getExpandingLevel() {
return expandingLevel;
}
public FcgDirection getExpandingDirection() {
return expandingLevel.getDirection();
}
public Iterable<GraphCutVertex> getSources(){
return sources;
}
public boolean isIncoming() {
return isIncoming;
}
}

View File

@@ -0,0 +1,50 @@
/* ###
* © 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.
*/
package graphcut;
public interface GraphCutExpansionListener {
/**
* Show or hide those vertices that are on incoming edges to v
*
* @param v the vertex
*/
public void toggleIncomingVertices(GraphCutVertex v);
/**
* Show or hide those vertices that are on outgoing edges to v
*
* @param v the vertex
*/
public void toggleOutgoingVertices(GraphCutVertex v);
}

View File

@@ -0,0 +1,177 @@
/* ###
* © 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.
*/
/*
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FunctionCallGraph.java
*/
package graphcut;
import java.util.*;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.map.LazyMap;
import functioncalls.graph.FcgDirection;
import ghidra.graph.graphs.FilteringVisualGraph;
import ghidra.graph.viewer.layout.VisualGraphLayout;
import ghidra.program.model.symbol.Namespace;
/*
* A graph for the GraphCut Plugin
*/
public class GraphCutGraph extends FilteringVisualGraph<GraphCutVertex, GraphCutEdge> {
private VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout;
private GraphCutVertex source;
private Map<Namespace, GraphCutVertex> verticesByNamespace = new HashMap<>();
private Comparator<GraphCutVertex> vertexComparator =
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
private Map<GraphCutLevel, Set<GraphCutVertex>> verticesByLevel =
LazyMap.lazyMap(new HashMap<>(), () -> new TreeSet<>(vertexComparator));
/**
* Sets the source vertex from which the graph originates
* @param the source vertex
*/
public void setSource(GraphCutVertex source) {
if (this.source != null) {
throw new IllegalStateException("Cannot change graph source once it has been created");
}
this.source = source;
addVertex(source);
}
/**
* Returns the vertex from which the graph is created
* @return source vertex
*/
public GraphCutVertex getSource() {
return source;
}
/**
* returns whether there is a vertex for the given namespace
* @param ns Namespace
* @return True if graph contains a vertex for the namespace
*/
public boolean containsNamespace(Namespace ns) {
return verticesByNamespace.containsKey(ns);
}
/**
* Returns the vertex for the given namespace
* @param ns Namespace
* @return the vertex for the given namespace
*/
public GraphCutVertex getVertex(Namespace ns) {
return verticesByNamespace.get(ns);
}
/**
* Return all vertices in the given level
* @param level the level to retrieve
* @return all vertices in the given level
*/
public Iterable<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
return IterableUtils.unmodifiableIterable(verticesByLevel.get(level));
}
/**
* Returns the level furthest from the source node in the given direction
* @param direction the direction to search
* @return the furthest level
*/
public GraphCutLevel getLargestLevel(FcgDirection direction) {
GraphCutLevel greatest = new GraphCutLevel(1, direction);
Set<GraphCutLevel> keys = verticesByLevel.keySet();
for (GraphCutLevel level : keys) {
if (level.getDirection() != direction) {
continue;
}
if (level.getRow() > greatest.getRow()) {
greatest = level;
}
}
return greatest;
}
@Override
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(){
return layout;
}
@Override
public GraphCutGraph copy() {
GraphCutGraph newGraph = new GraphCutGraph();
for (GraphCutVertex v : vertices.keySet()) {
newGraph.addVertex(v);
}
for (GraphCutEdge e : edges.keySet()) {
newGraph.addEdge(e);
}
return newGraph;
}
public void setLayout(VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
this.layout = layout;
}
@Override
protected void verticesAdded(Collection<GraphCutVertex> added) {
for (GraphCutVertex v : added) {
Namespace ns = v.getNamespace();
verticesByNamespace.put(ns, v);
verticesByLevel.get(v.getLevel()).add(v);
}
super.verticesAdded(added);
}
@Override
protected void verticesRemoved(Collection<GraphCutVertex> removed) {
for (GraphCutVertex v : removed) {
Namespace ns = v.getNamespace();
verticesByNamespace.remove(ns);
verticesByLevel.get(v.getLevel()).remove(v);
}
}
}

View File

@@ -0,0 +1,136 @@
/* ###
* © 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.
*/
/*
* Borrows heavily from Ghidra File /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayout.java
*/
package graphcut;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import ghidra.graph.VisualGraph;
import ghidra.graph.viewer.layout.AbstractVisualGraphLayout;
import ghidra.graph.viewer.layout.Column;
import ghidra.graph.viewer.layout.GridLocationMap;
import ghidra.graph.viewer.layout.LayoutPositions;
import ghidra.graph.viewer.layout.Row;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class GraphCutLayout extends AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> {
protected GraphCutLayout(GraphCutGraph graph, String name){
super(graph, name);
}
public AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> createClonedLayout(VisualGraph<GraphCutVertex, GraphCutEdge> newGraph){
if (!(newGraph instanceof GraphCutGraph)) {
throw new IllegalArgumentException("Must pass a GraphCut Graph to clone");
}
GraphCutLayout newLayout = new GraphCutLayout((GraphCutGraph) newGraph, getLayoutName());
return newLayout;
}
protected Point2D getVertexLocation(GraphCutVertex v, Column col, Row<GraphCutVertex> row, Rectangle bounds) {
return getCenteredVertexLocation(v, col, row, bounds);
}
@Override
public boolean isCondensedLayout() {
return false;
}
@Override
public GraphCutGraph getVisualGraph() {
return (GraphCutGraph) getGraph();
}
@Override
protected GridLocationMap<GraphCutVertex, GraphCutEdge> performInitialGridLayout(VisualGraph<GraphCutVertex,GraphCutEdge> g) throws CancelledException {
if (!(g instanceof GraphCutGraph)) {
throw new IllegalArgumentException("This layout can only be used with the GraphCutGraph");
}
return layoutGraphCutGraph((GraphCutGraph)g);
}
@Override
public LayoutPositions<GraphCutVertex, GraphCutEdge> calculateLocations(VisualGraph<GraphCutVertex, GraphCutEdge> g, TaskMonitor taskMonitor){
LayoutPositions<GraphCutVertex, GraphCutEdge> locs = super.calculateLocations(g, taskMonitor);
return locs;
}
private GridLocationMap<GraphCutVertex, GraphCutEdge> layoutGraphCutGraph(GraphCutGraph g){
GridLocationMap<GraphCutVertex, GraphCutEdge> grid = new GridLocationMap<>();
GraphCutVertex source = Objects.requireNonNull(g.getSource());
// Incoming nodes on top
// Sorted by id
List<GraphCutEdge> inEdges = new ArrayList<>(g.getInEdges(source));
List<GraphCutVertex> inVertices = inEdges.stream().map(e -> e.getStart()).collect(Collectors.toList());
inVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
//first row -> incoming nodes
int row = 0;
for(int col = 0; col < inVertices.size(); col++) {
GraphCutVertex v = inVertices.get(col);
grid.set(v, row, col);
}
//middle row -> source
row = 1;
grid.set(source, row, 0);
//bottom row -> outgoing nodes
List<GraphCutEdge> outEdges = new ArrayList<>(g.getOutEdges(source));
List<GraphCutVertex> outVertices = outEdges.stream().map(e -> e.getEnd()).collect(Collectors.toList());
outVertices.removeAll(inVertices); //prevent cycles
outVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
row = 2;
for (int col = 0; col < outVertices.size(); col++) {
GraphCutVertex v = outVertices.get(col);
grid.set(v, row, col);
}
grid.centerRows();
return grid;
}
}

View File

@@ -0,0 +1,393 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/BowTieExpandVerticesJob.java
*/
package graphcut;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.base.Function;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.visualization.RenderContext;
import ghidra.graph.job.AbstractGraphTransitionJob;
import ghidra.graph.viewer.GraphViewer;
import ghidra.graph.viewer.GraphViewerUtils;
import ghidra.util.Msg;
// bowTieExpandVerticesJob
public class GraphCutLayoutExpandVerticesJob extends AbstractGraphTransitionJob<GraphCutVertex, GraphCutEdge> {
private boolean incoming;
private GraphCutLevel expandingLevel;
private GraphCutExpandingVertexCollection newVertexCollection;
public GraphCutLayoutExpandVerticesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
GraphCutExpandingVertexCollection newVertexCollection, boolean useAnimation) {
super(viewer, useAnimation);
this.newVertexCollection = newVertexCollection;
this.incoming = newVertexCollection.isIncoming();
this.expandingLevel = newVertexCollection.getExpandingLevel();
if(!(graphLayout instanceof GraphCutLayout)) {
throw new IllegalArgumentException("The current graph layout must be the GraphCut Layout to use this job");
}
Msg.trace(this, "\n Layout Expand Job - new vertices: " + newVertexCollection.getNewVertices());
}
@Override
protected boolean isTooBigToAnimate() {
return graph.getVertexCount() > 1000;
}
@Override
protected void updateOpacity(double percentComplete) {
double x = percentComplete;
double x2 = x*x;
double remaining = 1-percentComplete;
double y = x2 - remaining;
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
double vertexAlpha = x;
double edgeAlpha = Math.max(y, 0);
for(GraphCutVertex v : newVertices) {
v.setAlpha(vertexAlpha);
}
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
for(GraphCutEdge e : newEdges) {
e.setAlpha(edgeAlpha);
}
}
@Override
public boolean canShortcut() {
return true;
}
@Override
public void shortcut() {
isShortcut = true;
if(vertexLocations.isEmpty()) {
initializeVertexLocations();
}
stop();
}
@Override
protected void initializeVertexLocations() {
Map<GraphCutVertex, TransitionPoints> destinationLocations = createDestinationLocation();
vertexLocations.putAll(destinationLocations);
}
private Map<GraphCutVertex, TransitionPoints> createDestinationLocation(){
Map<GraphCutVertex, Point2D> finalDestinations = arrangeNewVertices();
Map<GraphCutVertex, TransitionPoints> transitions = new HashMap<>();
GraphCutLevel parentLevel = expandingLevel.parent();
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
for(GraphCutEdge e : newEdges) {
GraphCutVertex newVertex = incoming ? e.getStart() : e.getEnd();
if(!finalDestinations.containsKey(newVertex)) {
continue;
}
if(!newVertices.contains(newVertex)) {
continue;
}
GraphCutVertex existingVertex = incoming ? e.getEnd() : e.getStart();
GraphCutLevel existingLevel = existingVertex.getLevel();
if (!existingLevel.equals(parentLevel)) {
continue;
}
Point2D start = (Point2D) toLocation(existingVertex).clone();
Point2D end = finalDestinations.get(newVertex);
TransitionPoints trans = new TransitionPoints(start, end);
transitions.put(newVertex, trans);
}
return transitions;
}
private Map<GraphCutVertex, Point2D> arrangeNewVertices(){
GraphCutLayout bowTie = (GraphCutLayout) graphLayout;
boolean isCondensed = bowTie.isCondensedLayout();
int widthPadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING_CONDENSED :
GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING;
widthPadding *= expandingLevel.getDistance();
int heightPadding = calculateHeightPadding(isCondensed);
GraphCutLevel parentLevel = expandingLevel.parent();
List<GraphCutVertex> parentLevelVertices = newVertexCollection.getVerticesByLevel(parentLevel);
if(parentLevelVertices.isEmpty()) {
return Collections.emptyMap();
}
Rectangle existingRowBounds = getBounds(parentLevelVertices);
Msg.trace(this, "existing row bounds " + existingRowBounds);
double existingY = existingRowBounds.y;
double existingCenterX = existingRowBounds.x + (existingRowBounds.width/2);
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
double newRowWidth = getWidth(allLevelVertices, widthPadding);
double newRowHeight = getHeight(allLevelVertices);
double newRowX = existingCenterX - (newRowWidth/2);
double newRowY = 0;
if(newVertexCollection.isIncoming()) {
newRowY = existingY - newRowHeight - heightPadding;
}
else {
newRowY = existingY +existingRowBounds.height + heightPadding;
}
Msg.trace(this, "new row bounds " + new Rectangle2D.Double(newRowX, newRowY, newRowWidth, newRowHeight));
Map<GraphCutVertex, Point2D> locations = getExistingLocations(allLevelVertices);
if(!locations.isEmpty()) {
return locations;
}
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
double x = newRowX;
double y = newRowY;
int n = allLevelVertices.size();
//Dynamic Layout
Set<GraphCutVertex> placed = new HashSet<>();
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
//Make shallow copy
List<GraphCutVertex> allLevelVerticesOrig = new ArrayList<>();
for(GraphCutVertex v : allLevelVertices) {
allLevelVerticesOrig.add(v);
}
// 1. Place visible vertices
for(GraphCutVertex v: allLevelVerticesOrig) {
if(v.visible) {
GraphCutVertex tmpVertex = allLevelVertices.get(v.layoutIndex);
int tmpIndex = allLevelVertices.indexOf(v);
allLevelVertices.set(v.layoutIndex, v);
allLevelVertices.set(tmpIndex, tmpVertex);
placed.add(v);
}
}
// 2. Place newVertices
for(GraphCutVertex v: newVertices) {
if(placed.contains(v)) {
continue;
}
placed.add(v);
int index = findEmptyLayoutIndex(allLevelVertices);
v.layoutIndex = index;
v.visible = true;
GraphCutVertex tmpVertex = allLevelVertices.get(index);
int tmpIndex = allLevelVertices.indexOf(v);
allLevelVertices.set(tmpIndex, tmpVertex);
allLevelVertices.set(v.layoutIndex, v);
}
// 3. Place all invisible vertices randomly
int curr = 0;
for(GraphCutVertex v: allLevelVerticesOrig) {
if(placed.contains(v)) {
continue;
}
//find empty spot
while(allLevelVertices.get(curr).visible) {
curr++;
}
allLevelVertices.set(curr, v);
}
for(int i = 0; i < n; i++) {
GraphCutVertex v = allLevelVertices.get(i);
Rectangle myBounds = shaper.apply(v).getBounds();
double myHalf = myBounds.width / 2;
double nextHalf = 0;
boolean isLast = i == n-1;
if(!isLast) {
GraphCutVertex nextV = allLevelVertices.get(i+1);
Rectangle nextBounds = shaper.apply(nextV).getBounds();
nextHalf = nextBounds.width/2;
}
Point2D p = new Point2D.Double(x,y);
locations.put(v, p);
double vWidth = myHalf + widthPadding + nextHalf;
Msg.trace(this, v + " at x,width: "+x+","+vWidth);
x+=vWidth;
}
return locations;
}
private int findEmptyLayoutIndex(List<GraphCutVertex> vertices) {
//Check middle
int mid = vertices.size()/2;
if(!vertices.get(mid).visible) {
return mid;
}
// start checking both sides
int left = mid-1;
int right = mid+1;
while(left >= 0 || right <=vertices.size()-1) {
if(left>=0 && !vertices.get(left).visible) {
return left;
}
left--;
if(right <= vertices.size()-1 && !vertices.get(right).visible) {
return right;
}
right++;
}
return -1;
}
private int calculateHeightPadding(boolean isCondensed) {
int basePadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING_CONDENSED
: GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING;
double separationFactor = expandingLevel.getDistance();
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
int count = allLevelVertices.size();
double to = 1.25;
double power = Math.pow(separationFactor, to);
int maxPadding = (int) (basePadding * power);
int delta = maxPadding - basePadding;
double percent = Math.min(count / 20f, 1);
int padding = basePadding + (int) (delta * percent);
return padding;
}
private Map<GraphCutVertex, Point2D> getExistingLocations(List<GraphCutVertex> vertices){
Map<GraphCutVertex, Point2D> locations = new HashMap<>();
for(GraphCutVertex v: vertices) {
Point2D p = toLocation(v);
if (p.getX() == 0 && p.getY() == 0) {
return new HashMap<>();
}
locations.put(v, (Point2D) p.clone());
}
return locations;
}
private Rectangle getBounds(List<GraphCutVertex> vertices) {
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
Rectangle area = null;
for (GraphCutVertex v : vertices) {
Rectangle bounds = shaper.apply(v).getBounds();
Point2D loc = layout.apply(v);
int x = (int) loc.getX();
int y = (int) loc.getY();
bounds.setLocation(x,y);
if(area == null) {
area = bounds;
}
area.add(bounds);
}
return area;
}
private int getWidth(List<GraphCutVertex> vertices, int widthPadding) {
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
int width = 0;
for (GraphCutVertex v : vertices) {
width += shaper.apply(v).getBounds().width + widthPadding;
}
return width;
}
private int getHeight(List<GraphCutVertex> vertices) {
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
int height = 0;
for (GraphCutVertex v: vertices) {
height = Math.max(height, shaper.apply(v).getBounds().height);
}
return height;
}
}

View File

@@ -0,0 +1,68 @@
/* ###
* © 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.
*/
/*
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java
*/
package graphcut;
import javax.swing.Icon;
import generic.theme.GIcon;
import ghidra.graph.viewer.layout.AbstractLayoutProvider;
import ghidra.graph.viewer.layout.VisualGraphLayout;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* A layout provider for GraphCut
*/
public class GraphCutLayoutProvider extends AbstractLayoutProvider<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
public static final String NAME = "GraphCut Layout";
private static final Icon DEFAULT_ICON = new GIcon("icon.plugin.fcg.layout.bow.tie");
@Override
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(GraphCutGraph graph, TaskMonitor taskMonitor) throws CancelledException{
GraphCutLayout layout = new GraphCutLayout(graph, NAME);
initVertexLocations(graph, layout);
return layout;
}
@Override
public String getLayoutName() {
return NAME;
}
@Override
public Icon getActionIcon() {
return DEFAULT_ICON;
}
}

View File

@@ -0,0 +1,193 @@
/* ###
* © 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.
*/
/*
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgEdge.java
*/
package graphcut;
import static functioncalls.graph.FcgDirection.*;
import functioncalls.graph.FcgDirection;
// A container class that represents a GraphCut row.
public class GraphCutLevel implements Comparable<GraphCutLevel> {
private int row;
private FcgDirection direction;
public static GraphCutLevel sourceLevel() {
return new GraphCutLevel(0, IN_AND_OUT);
}
public GraphCutLevel(int distance, FcgDirection direction) {
this.row = toRow(distance);
this.direction = direction;
if (row == 0) {
throw new IllegalArgumentException("Graph Cut uses a 1-based row system");
}
if (row == 1 && direction != IN_AND_OUT) {
throw new IllegalArgumentException("Row 1 must be FcgDirection.IN_AND_OUT");
}
}
private int toRow(int distance) {
int oneBased = distance + 1;
return (direction == OUT) ? -oneBased : oneBased;
}
public int getRow() {
return row;
}
public int getDistance() {
return Math.abs(row) - 1;
}
public FcgDirection getDirection() {
return direction;
}
/**
* Returns true if this level is level 1
* @return true if this level represents the source level
*/
public boolean isSource() {
return direction.isSource();
}
public GraphCutLevel parent() {
if (direction == IN_AND_OUT) {
// undefined--we are the parent of all
throw new IllegalArgumentException(
"To get the parent of the source level you must use the constructor directly");
}
int newDistance = getDistance() - 1;
FcgDirection newDirection = direction;
if (newDistance == 0) {
newDirection = IN_AND_OUT;
}
return new GraphCutLevel(newDistance, newDirection);
}
public GraphCutLevel child() {
if (direction == IN_AND_OUT) {
// undefined--this node goes in both directions
throw new IllegalArgumentException(
"To get the child of the source level you " + "must use the constructor directly");
}
return child(direction);
}
public boolean isParentOf(GraphCutLevel other) {
if (isSource()) {
return other.getDistance() == 1;
}
if (direction != other.direction) {
return false;
}
// e.g., row 2 - row 1 = 1
return other.getDistance() - getDistance() == 1;
}
public boolean isChildOf(GraphCutLevel other) {
return other.isParentOf(this);
}
public GraphCutLevel child(FcgDirection newDirection) {
if (newDirection == IN_AND_OUT) {
// undefined--IN_AND_OUT goes in both directions
throw new IllegalArgumentException("Direction cannot be IN_AND_OUT");
}
int newDistance = getDistance() + 1;
return new GraphCutLevel(newDistance, newDirection);
}
@Override
public String toString() {
return direction + " - row " + Integer.toString(getRelativeRow());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((direction == null) ? 0 : direction.hashCode());
result = prime * result + row;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
GraphCutLevel other = (GraphCutLevel) obj;
if (direction != other.direction) {
return false;
}
if (row != other.row) {
return false;
}
return true;
}
private int getRelativeRow() {
return direction == OUT ? -row : row;
}
@Override
public int compareTo(GraphCutLevel l2) {
int result = getDirection().compareTo(l2.getDirection());
if (result != 0) {
return result;
}
return -(getRelativeRow() - l2.getRelativeRow());
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
/* ###
* © 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.
*/
/*
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgTooltipProvider.java
*/
package graphcut;
import java.awt.Component;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.*;
import ghidra.graph.viewer.event.mouse.VertexTooltipProvider;
public class GraphCutTooltipProvider implements VertexTooltipProvider<GraphCutVertex, GraphCutEdge> {
@Override
public JComponent getTooltip(GraphCutVertex v) {
JToolTip tip = new JToolTip();
tip.setTipText(v.getName());
return tip;
}
@Override
public JComponent getTooltip(GraphCutVertex v, GraphCutEdge e) {
return null;
}
@Override
public String getTooltipText(GraphCutVertex v, MouseEvent e) {
Component child = e.getComponent();
if(child instanceof JButton) {
return ((JButton) child).getToolTipText();
}
return v.getName();
}
}

View File

@@ -0,0 +1,664 @@
/* ###
* © 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.
*/
/*
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java
*/
package graphcut;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import java.awt.image.BufferedImage;
import java.util.Objects;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import ghidra.program.model.symbol.Namespace;
import docking.widgets.EmptyBorderButton;
import docking.widgets.label.GDLabel;
import functioncalls.graph.FcgDirection;
import functioncalls.graph.FcgVertex;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.Gui;
import ghidra.graph.viewer.vertex.AbstractVisualVertex;
import ghidra.graph.viewer.vertex.VertexShapeProvider;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.util.StringUtilities;
import resources.Icons;
import resources.ResourceManager;
// A GraphCutVertex
public class GraphCutVertex extends AbstractVisualVertex implements VertexShapeProvider {
public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.default");
private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.toobig");
//@formatter:on
public static final Icon NOT_ALLOWED_ICON = Icons.ERROR_ICON;
private static final Icon EXPAND_ICON =
ResourceManager.getScaledIcon(Icons.EXPAND_ALL_ICON, 10, 10);
private static final Icon COLLAPSE_ICON =
ResourceManager.getScaledIcon(Icons.COLLAPSE_ALL_ICON, 10, 10);
// higher numbered layers go on top
private static final Integer VERTEX_SHAPE_LAYER = 100;
private static final Integer TOGGLE_BUTTON_LAYER = 200;
private static final Integer LABEL_LAYER = 300;
private static final int GAP = 2;
private static final int VERTEX_SHAPE_SIZE = 50;
private static final int MAX_NAME_LENGTH = 30;
private Namespace namespace;
private JLayeredPane layeredPane;
private JButton toggleInsButton = new EmptyBorderButton(EXPAND_ICON);
private JButton toggleOutsButton = new EmptyBorderButton(EXPAND_ICON);
private JLabel nameLabel = new GDLabel();
private JLabel vertexImageLabel = new GDLabel();
private Double vertexShape;
private Double compactShape;
private Shape fullShape;
// these values are set after construction from external sources
private boolean hasIncomingReferences;
private boolean hasOutgoingReferences;
private boolean tooManyIncomingReferences;
private boolean tooManyOutgoingReferences;
private boolean incomingExpanded;
private boolean outgoingExpanded;
// set this to true to see borders around the components of this vertex
private boolean useDebugBorders = false;
private Paint inPaint;
private Paint outPaint;
private GraphCutLevel level;
// Dynamic Layout Variables
public int layoutIndex;
public boolean visible;
/**
* Constructor
* @param namespace Namespace represented by this vertex
* @param level The level of this vertex
* @param expansionListener listener for expanding connections to this vertex
*/
public GraphCutVertex(Namespace namespace, GraphCutLevel level, GraphCutExpansionListener expansionListener) {
this.namespace = namespace;
this.level = level;
Objects.requireNonNull(expansionListener);
toggleInsButton.addActionListener(e -> {
if (tooManyIncomingReferences) {
return;
}
expansionListener.toggleIncomingVertices(GraphCutVertex.this);
});
toggleOutsButton.addActionListener(e -> {
if (tooManyOutgoingReferences) {
return;
}
expansionListener.toggleOutgoingVertices(GraphCutVertex.this);
});
buildUi();
setTogglesVisible(false);
}
private void createPaints() {
Color vertexShapeColor = getVertexShapeColor();
Color lightColor = vertexShapeColor;
Color darkColor = Gui.darker(vertexShapeColor);
Color darkestColor = Gui.darker(darkColor);
int offset = 5 * level.getDistance();
int half = VERTEX_SHAPE_SIZE / 2;
int start = 0;
int end = half + offset;
// paint top-down: dark to light for incoming; light to dark for outgoing
inPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
new float[] { .0f, .2f, 1f }, new Color[] { darkestColor, darkColor, lightColor });
start = half - offset; // (offset + 10);
end = VERTEX_SHAPE_SIZE;
outPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
new float[] { .0f, .8f, 1f }, new Color[] { lightColor, darkColor, darkestColor });
}
private void buildUi() {
createPaints();
String truncated = StringUtilities.trimMiddle(getName(), MAX_NAME_LENGTH);
nameLabel.setText(truncated);
buildVertexShape();
// calculate the needed size
layeredPane = new JLayeredPane();
Border border = createDebugBorder(new LineBorder(Palette.GOLD, 1));
layeredPane.setBorder(border);
updateLayeredPaneSize();
// layout the components
addVertexShape();
addToggleButtons();
addNameLabel();
buildFullShape();
}
private Border createDebugBorder(Border border) {
if (useDebugBorders) {
return border;
}
return BorderFactory.createEmptyBorder();
}
private void buildFullShape() {
// Note: this method assumes all bounds have been set
Area parent = new Area();
Area v = new Area(vertexShape);
Area name = new Area(nameLabel.getBounds());
parent.add(v);
parent.add(name);
// for now, the buttons only appear on hover, but if we want to avoid clipping when
// painting, we need to account for them in the shape's overall bounds
Area in = new Area(toggleInsButton.getBounds());
Area out = new Area(toggleOutsButton.getBounds());
parent.add(in);
parent.add(out);
fullShape = parent;
}
private void updateLayeredPaneSize() {
//
// The overall component size is the total width and height of all components, with any
// spacing between them.
//
Dimension shapeSize = vertexImageLabel.getPreferredSize();
Dimension nameLabelSize = nameLabel.getPreferredSize();
int height = shapeSize.height + GAP + nameLabelSize.height;
Dimension insSize = toggleInsButton.getPreferredSize();
Dimension outsSize = toggleOutsButton.getPreferredSize();
int buttonWidth = Math.max(insSize.width, outsSize.width);
int offset = buttonWidth / 3; // overlap the vertex shape
int width = offset + shapeSize.width;
width = Math.max(width, nameLabelSize.width);
layeredPane.setPreferredSize(new Dimension(width, height));
}
private void buildVertexShape() {
int w = VERTEX_SHAPE_SIZE;
int h = VERTEX_SHAPE_SIZE;
Double circle = new Ellipse2D.Double(0, 0, w, h);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FcgDirection direction = level.getDirection();
if (direction.isSource()) {
g2.setColor(getVertexShapeColor());
}
else if (direction.isIn()) {
g2.setPaint(inPaint);
}
else {
g2.setPaint(outPaint);
}
g2.fill(circle);
g2.dispose();
vertexShape = circle;
compactShape = (Double) vertexShape.clone();
vertexImageLabel.setIcon(new ImageIcon(image));
Border border = createDebugBorder(new LineBorder(Palette.PINK, 1));
vertexImageLabel.setBorder(border);
}
private Color getVertexShapeColor() {
if (isInDirection() && tooManyIncomingReferences) {
return TOO_BIG_VERTEX_SHAPE_COLOR;
}
if (isOutDirection() && tooManyOutgoingReferences) {
return TOO_BIG_VERTEX_SHAPE_COLOR;
}
return DEFAULT_VERTEX_SHAPE_COLOR;
}
private boolean isInDirection() {
FcgDirection direction = level.getDirection();
boolean isIn = direction.isIn() || direction.isSource();
return isIn;
}
private boolean isOutDirection() {
FcgDirection direction = level.getDirection();
boolean isOut = direction.isOut() || direction.isSource();
return isOut;
}
private void addVertexShape() {
Dimension parentSize = layeredPane.getPreferredSize();
Dimension size = vertexImageLabel.getPreferredSize();
// centered
int x = (parentSize.width / 2) - (size.width / 2);
int y = 0;
vertexImageLabel.setBounds(x, y, size.width, size.height);
Dimension shapeSize = vertexShape.getBounds().getSize();
// setFrame() will make sure the shape's x,y values are where they need to be
// for the later 'full shape' creation
vertexShape.setFrame(x, y, shapeSize.width, shapeSize.height);
layeredPane.add(vertexImageLabel, VERTEX_SHAPE_LAYER);
}
private void addNameLabel() {
Border border = createDebugBorder(new LineBorder(Palette.GREEN, 1));
nameLabel.setBorder(border);
Rectangle parentBounds = vertexImageLabel.getBounds();
Dimension size = nameLabel.getPreferredSize();
int x = (parentBounds.x + (parentBounds.width / 2)) - (size.width / 2);
int y = parentBounds.y + parentBounds.height + GAP;
nameLabel.setBounds(x, y, size.width, size.height);
layeredPane.add(nameLabel, LABEL_LAYER);
}
private void addToggleButtons() {
// hide the button background
toggleInsButton.setBackground(Palette.NO_COLOR);
toggleOutsButton.setBackground(Palette.NO_COLOR);
// This is needed for Flat Dark theme to work correctly, due to the fact that it wants to
// paint its parent background when the button is opaque. The parent background will get
// painted over any items that lie between the button and the parent.
toggleInsButton.setOpaque(false);
toggleOutsButton.setOpaque(false);
Rectangle parentBounds = vertexImageLabel.getBounds();
Dimension size = toggleInsButton.getPreferredSize();
// upper toggle; upper-left
int x = parentBounds.x - (size.width / 3);
int y = 0;
toggleInsButton.setBounds(x, y, size.width, size.height);
layeredPane.add(toggleInsButton, TOGGLE_BUTTON_LAYER);
// lower toggle; lower-left, lined-up with the vertex shape
size = toggleOutsButton.getPreferredSize();
Dimension vertexSize = parentBounds.getSize();
y = vertexSize.height - size.height;
toggleOutsButton.setBounds(x, y, size.width, size.height);
layeredPane.add(toggleOutsButton, TOGGLE_BUTTON_LAYER);
}
public String getName() {
return namespace.getName();
}
public Namespace getNamespace() {
return namespace;
}
public GraphCutLevel getLevel() {
return level;
}
public int getDegree() {
return level.getRow();
}
public FcgDirection getDirection() {
return level.getDirection();
}
public JButton getIncomingToggleButton() {
return toggleInsButton;
}
public JButton getOutgoingToggleButton() {
return toggleOutsButton;
}
public void setIncomingExpanded(boolean setExpanded) {
validateIncomingExpandedState(setExpanded);
this.incomingExpanded = setExpanded;
toggleInsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
String hideShow = setExpanded ? "hide" : "show";
toggleInsButton.setToolTipText("Click to " + hideShow + " incoming edges");
}
private void validateOutgoingExpandedState(boolean isExpanding) {
if (isExpanding) {
if (!canExpandOutgoingReferences()) {
throw new IllegalStateException("Vertex cannot be expanded: " + this);
}
return;
}
// collapsing
if (!isOutgoingExpanded()) {
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
}
}
private void validateIncomingExpandedState(boolean expanding) {
if (expanding) {
if (!canExpandIncomingReferences()) {
throw new IllegalStateException("Vertex cannot be expanded: " + this);
}
return;
}
// collapsing
if (!isIncomingExpanded()) {
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
}
}
/**
* Returns true if this vertex is showing all edges in the incoming direction
*
* @return true if this vertex is showing all edges in the incoming direction
*/
public boolean isIncomingExpanded() {
return incomingExpanded;
}
/**
* Sets to true if this vertex is showing all edges in the outgoing direction
*
* @param setExpanded true if this vertex is showing all edges in the outgoing direction
*/
public void setOutgoingExpanded(boolean setExpanded) {
validateOutgoingExpandedState(setExpanded);
this.outgoingExpanded = setExpanded;
toggleOutsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
String hideShow = setExpanded ? "hide" : "show";
toggleInsButton.setToolTipText("Click to " + hideShow + " outgoing edges");
}
/**
* Returns true if this vertex is showing all edges in the outgoing direction
*
* @return true if this vertex is showing all edges in the outgoing direction
*/
public boolean isOutgoingExpanded() {
return outgoingExpanded;
}
/**
* Returns whether this vertex is fully expanded in its current direction
*
* @return whether this vertex is fully expanded in its current direction
*/
public boolean isExpanded() {
FcgDirection direction = level.getDirection();
if (direction.isSource()) {
return isIncomingExpanded() && isOutgoingExpanded();
}
if (direction.isIn()) {
return isIncomingExpanded();
}
return isOutgoingExpanded();
}
/**
* Sets whether this vertex has too many incoming references, where too many is subjectively
* defined by this class. Too many nodes in the display would ruin rendering and general
* usability.
*
* @param tooMany if there are too many references
*/
public void setTooManyIncomingReferences(boolean tooMany) {
this.tooManyIncomingReferences = tooMany;
toggleInsButton.setIcon(NOT_ALLOWED_ICON);
toggleInsButton.setToolTipText("Too many incoming references to show");
buildUi();
}
/**
* Sets whether this vertex has too many outgoing references, where too many is subjectively
* defined by this class. Too many nodes in the display would ruin rendering and general
* usability.
*
* @param tooMany if there are too many references
*/
public void setTooManyOutgoingReferences(boolean tooMany) {
this.tooManyOutgoingReferences = tooMany;
toggleOutsButton.setIcon(NOT_ALLOWED_ICON);
toggleOutsButton.setToolTipText("Too many outgoing references to show");
buildUi();
}
/**
* Returns whether this vertex has too many incoming references, where too many is subjectively
* defined by this class. Too many nodes in the display would ruin rendering and general
* usability.
*
* @return true if there are too many references
*/
public boolean hasTooManyIncomingReferences() {
return tooManyIncomingReferences;
}
/**
* Returns whether this vertex has too many outgoing references, where too many is subjectively
* defined by this class. Too many nodes in the display would ruin rendering and general
* usability.
*
* @return true if there are too many references
*/
public boolean hasTooManyOutgoingReferences() {
return tooManyOutgoingReferences;
}
/**
* Returns true if this vertex can expand itself in its current direction, or in either
* direction if this is a source vertex
*
* @return true if this vertex can be expanded
*/
public boolean canExpand() {
FcgDirection direction = level.getDirection();
if (direction.isSource()) {
return canExpandIncomingReferences() || canExpandOutgoingReferences();
}
if (direction.isIn()) {
return canExpandIncomingReferences();
}
return canExpandOutgoingReferences();
}
public boolean canExpandIncomingReferences() {
return hasIncomingReferences && !tooManyIncomingReferences && !incomingExpanded;
}
public boolean canExpandOutgoingReferences() {
return hasOutgoingReferences && !tooManyOutgoingReferences && !outgoingExpanded;
}
/**
* Sets whether this vertex has any incoming references
*
* @param hasIncoming true if this vertex has any incoming references
*/
public void setHasIncomingReferences(boolean hasIncoming) {
this.hasIncomingReferences = hasIncoming;
}
/**
* Sets whether this vertex has any outgoing references
*
* @param hasOutgoing true if this vertex has any outgoing references
*/
public void setHasOutgoingReferences(boolean hasOutgoing) {
this.hasOutgoingReferences = hasOutgoing;
}
@Override
public void setHovered(boolean hovered) {
super.setHovered(hovered);
setTogglesVisible(hovered);
}
private void setTogglesVisible(boolean visible) {
boolean isIn = isInDirection();
boolean turnOn = isIn && hasIncomingReferences && visible;
toggleInsButton.setVisible(turnOn);
boolean isOut = isOutDirection();
turnOn = isOut && hasOutgoingReferences && visible;
toggleOutsButton.setVisible(turnOn);
}
@Override
public JComponent getComponent() {
return layeredPane;
}
@Override
public Shape getCompactShape() {
return compactShape;
}
@Override
public Shape getFullShape() {
return fullShape;
}
@Override
public String toString() {
return getName();// + " @ " + level; // + " (" + System.identityHashCode(this) + ')';
}
@Override
public int hashCode() {
return Objects.hash(namespace);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if(getClass() != obj.getClass()) {
return false;
}
GraphCutVertex other = (GraphCutVertex) obj;
return Objects.equals(namespace, other.namespace);
}
@Override
public void dispose() {
// nothing to do
}
public long getID() {
return getNamespace().getID();
}
}

View File

@@ -0,0 +1,56 @@
/* ###
* © 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.
*/
/*
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgVertexPaintTransformer.java
*/
package graphcut;
import com.google.common.base.Function;
import java.awt.Color;
import java.awt.Paint;
import ghidra.util.ColorUtils;
/**
* A class that takes a GraphCutVertex and determines which color to paint it with
*/
public class GraphCutVertexPaintTransformer implements Function<GraphCutVertex, Paint> {
private Color color;
public GraphCutVertexPaintTransformer(Color color) {
this.color = color;
}
@Override
public Paint apply(GraphCutVertex v) {
return color;
}
}

View File

@@ -0,0 +1,63 @@
/* ###
* © 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.
*/
/*
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgView.java
*/
package graphcut;
import ghidra.graph.viewer.VisualGraphView;
import ghidra.graph.viewer.options.VisualGraphOptions;
public class GraphCutView extends VisualGraphView<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
private VisualGraphOptions options;
public GraphCutView(VisualGraphOptions options) {
this.options = options;
}
@Override
protected void installGraphViewer() {
GraphCutComponent component = createGraphComponent();
component.setGraphOptions(options);
setGraphComponent(component);
}
private GraphCutComponent createGraphComponent() {
GraphCutComponent component = new GraphCutComponent(getVisualGraph());
return component;
}
@Override
public GraphCutComponent getGraphComponent() {
return (GraphCutComponent) super.getGraphComponent();
}
}

View File

@@ -0,0 +1,92 @@
/* ###
* © 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.
*/
package graphcut;
import java.util.Objects;
import ghidra.program.model.symbol.Namespace;
public class NamespaceEdge {
private Namespace start;
private Namespace end;
NamespaceEdge(Namespace start, Namespace end){
this.start = start;
this.end = end;
}
Namespace getStart() {
return start;
}
Namespace getEnd() {
return end;
}
@Override
public String toString() {
return "[" + start + ", " + end + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime*result + ((end == null) ? 0 : end.hashCode());
result = prime * result + ((start == null) ? 0 : start.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
NamespaceEdge other = (NamespaceEdge) obj;
if(!Objects.equals(end, other.end)) {
return false;
}
if(!Objects.equals(start, other.start)) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,65 @@
/* ###
* © 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.
*/
package graphcut;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.map.LazyMap;
import ghidra.program.model.symbol.Namespace;
/**
* A class to cache known namespace edges
*/
public class NamespaceEdgeCache {
//contains all known edges, even those not shown in the graph
private Map<Namespace, Set<NamespaceEdge>> allEdgesByNamespace =
LazyMap.lazyMap(new HashMap<>(), () -> new HashSet<>());
// track processed namespaces
private Set<Namespace> tracked = new HashSet<>();
public Set<NamespaceEdge> get(Namespace ns){
return allEdgesByNamespace.get(ns);
}
public boolean isTracked(Namespace ns) {
return tracked.contains(ns);
}
public void setTracked(Namespace ns) {
tracked.add(ns);
}
}

View File

@@ -0,0 +1,101 @@
/* ###
* © 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.
*/
/*
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/ValidFcgData.java
*/
package graphcut;
import java.util.Objects;
import ghidra.graph.viewer.GraphPerspectiveInfo;
import ghidra.program.model.symbol.Namespace;
public class ValidGraphCutData implements GraphCutData {
private Namespace namespace;
private GraphCutGraph graph;
private GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> perspectiveInfo;
private NamespaceEdgeCache allEdgesByNamespace = new NamespaceEdgeCache();
ValidGraphCutData(Namespace namespace, GraphCutGraph graph){
this.namespace = Objects.requireNonNull(namespace);
this.graph = Objects.requireNonNull(graph);
}
@Override
public Namespace getNamespace() {
return namespace;
}
@Override
public boolean isNamespace(Namespace ns) {
return namespace.equals(ns);
}
@Override
public GraphCutGraph getGraph() {
return graph;
}
@Override
public NamespaceEdgeCache getNamespaceEdgeCache() {
return allEdgesByNamespace;
}
@Override
public boolean hasResults() {
return true;
}
@Override
public boolean isInitialized() {
return !graph.isEmpty();
}
@Override
public void dispose() {
graph.dispose();
}
@Override
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
return perspectiveInfo;
}
@Override
public void setGraphPerspective( GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
this.perspectiveInfo = info;
}
}

View File

@@ -30,39 +30,18 @@ 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.
### Native Python 3
The Deepcut graph based machine learning model needs Python 3 to
execute (outside of Ghidra). The analyzer calls an 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:
#### ### PyGhidra and Dependencies
DeepCut requires the PyGhidra extension, and is not compatible with Jython. It uses [PyTorch Geometric](https://pytorch-geometric.readthedocs.io/) to perform machine learning on the function call graph. It has the following Python 3 dependencies:
- torch
- torch-geometric
- networkx
- scipy
DeepCut attempts to automatically install the dependencies when the tool is launched, but they can also be installed using the Python associated with PyGhidra by running:
```bash
pip install torch==1.7.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
pip install -r requirements-torch_geometric.txt
pip install torch torch-geometric networkx scipy
```
The torch-cluster dependency can take a significant amount of time to
build and install.
The torch-geometric 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
@@ -76,8 +55,4 @@ If there are any errors please make sure you are using the proper path
to Python 3 and the requirement dependencies installed.
## Troubleshooting
You can verify that dependencies are correct by navigating to:
`~/.ghidra/.ghidra_${VERSION}/Extensions/deepcut-ghidra/data`
and running `./python3 deepcut.py`. Python will throw errors if it
can't find dependencies. If the process runs and sits there waiting
for input, then the dependencies should be correct.
The main analysis is performed by the script `deepcut.py` in the directory `~/.ghidra/.ghidra_${VERSION}/Extensions/deepcut-ghidra/ghidra_scripts/`, which can be run outside the context of Ghidra. Python will throw errors if it can't find dependencies. If the process runs and sits there waiting for input, then the dependencies should be correct.

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

Binary file not shown.

View File

@@ -0,0 +1,74 @@
# @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
from dependency_bootstrap import DependencyManager
# list the packages you need
# dictionary of "import name" : "pip name"
# for when they differ, e.g. "sklearn": "scikit-learn"
deps = DependencyManager(
{"networkx": "networkx",
"scipy": "scipy",
"torch": "torch",
"torch_geometric": "torch-geometric"})
# make sure they're installed
if not deps.ensure_or_prompt():
println("[DeepCut] Required Python packages not available, exiting.")
exit(1)
from deepcut import Deepcut
# Pass Ghidra context + args into your package entry point
# run(currentProgram, state, monitor, *args)
def main():
args = list(getScriptArgs())
with open(args[0], "r") as f:
fcg = json.load(f)
model_path = args[2]
d = Deepcut(fcg, model_path)
with open(args[1], "w") as f:
json.dump(d.module_list(), f)
print("Successfully exported module boundaries")
if __name__ == "__main__":
main()

View File

@@ -1,4 +1,4 @@
# © 2021 The Johns Hopkins University Applied Physics Laboratory LLC
# (C) 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (JHU/APL). All Rights Reserved.
#
# This material may be only be used, modified, or reproduced by or for
@@ -7,7 +7,7 @@
# permission, please contact the Office of Technology Transfer at
# JHU/APL.
#
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED AS IS. JHU/APL
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED "AS IS." JHU/APL
# MAKES NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF
# THE MATERIALS, INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL
# VIABILITY, AND DISCLAIMS ALL WARRANTIES IN THE MATERIAL, WHETHER
@@ -54,13 +54,13 @@ class Net(torch.nn.Module):
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.gin1 = nn.GINEConv(mlp1, train_eps=True)
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.gin2 = nn.GINEConv(mlp2, train_eps=True)
self.bn2 = nn.PairNorm() # nn.LayerNorm(dim) #torch.nn.BatchNorm1d(dim)
self.e_mlp2 = Sequential(Linear(3*dim, dim),
ReLU(),
@@ -74,7 +74,7 @@ class Net(torch.nn.Module):
Linear(dim, dim),
ReLU(),
Linear(dim, dim))
self.gin3 = nn.GINEConv(mlp3, train_eps=True).jittable()
self.gin3 = nn.GINEConv(mlp3, train_eps=True)
self.bn3 = nn.PairNorm() # nn.LayerNorm(dim)
self.e_mlp3 = Sequential(Linear(3*dim, dim),
ReLU(),
@@ -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):
@@ -142,7 +130,8 @@ def load_gnn(model_file):
)
loaded_weights = torch.load(model_file,
map_location=torch.device('cpu'))
map_location=torch.device('cpu'),
weights_only=True)
model.load_state_dict(loaded_weights)
return model

View File

@@ -1,6 +1,4 @@
#!/usr/bin/env python
#
# © 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (C) 2022 The Johns Hopkins University Applied Physics Laboratory LLC
# (JHU/APL). All Rights Reserved.
#
# This material may be only be used, modified, or reproduced by or for
@@ -9,7 +7,7 @@
# permission, please contact the Office of Technology Transfer at
# JHU/APL.
#
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED AS IS. JHU/APL
# NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED "AS IS." JHU/APL
# MAKES NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF
# THE MATERIALS, INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL
# VIABILITY, AND DISCLAIMS ALL WARRANTIES IN THE MATERIAL, WHETHER
@@ -29,7 +27,6 @@
# Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
# under Contract Number N66001-20-C-4024.
import json
import sys
import numpy as np
@@ -39,6 +36,7 @@ import torch
from math import log2, copysign
from networkx import DiGraph
from scipy.linalg import toeplitz
from scipy.sparse import coo_matrix, diags, csr_matrix
import GNN_Net
@@ -109,38 +107,44 @@ class Deepcut:
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):
# Build sparse adjacency from predicted edge scores
rows = []
cols = []
vals = []
for (e, v) in zip(self.graph_connectivity, self.predicted_labels.flatten()):
e0, e1 = e
A[e0, e1] = v
rows.append(e0)
cols.append(e1)
vals.append(float(v))
A += A.T
A *= 0.5
A = coo_matrix((vals, (rows, cols)), shape=(num_funcs, num_funcs))
"""
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)
# Symmetrize and average: (A + A^T)/2
A = (A + A.T).multiply(0.5).tocsr()
return A
# Add small off-diagonal connection (equivalent to toeplitz([0, 0.05, 0, ...]))
off = diags([0.05 * np.ones(num_funcs - 1), 0.05 * np.ones(num_funcs - 1)],
offsets=[-1, 1], shape=(num_funcs, num_funcs), format='csr')
A = (A + off).tocsr()
return A # CSR sparse matrix
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
A = self._adjacency_matrix() # sparse CSR
# node degrees (as dense 1D array for lightweight vector ops)
k = np.array(A.sum(axis=0)).ravel()
two_m = 2.0 * k.sum() # denominator used in modularity B term
def compute_partial_modularity(start, stop):
return np.sum(Q[start:stop, start:stop])
# Sum of A over the block [start:stop, start:stop]
A_block_sum = A[start:stop, start:stop].sum()
# Sum of degrees in the block
k_block_sum = k[start:stop].sum()
# Sum of B over the block: (sum_k_block)^2 / (2m)
B_block_sum = (k_block_sum * k_block_sum) / two_m if two_m > 0 else 0.0
# Return sum(Q_block) = sum(A_block) - sum(B_block)
return float(A_block_sum) - float(B_block_sum)
scores = [0.0]
scores = np.array(scores)
@@ -151,15 +155,15 @@ class Deepcut:
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)]
range(max(0, index - max_cluster_size), index)]
if index > max_cluster_size:
update = [0]*(index-max_cluster_size) + update
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)
i = np.argmax(updated_scores[index - max_cluster_size:]) + (index - max_cluster_size)
s = updated_scores[i]
c = cuts[i] + [index]
@@ -188,7 +192,7 @@ def main():
if len(sys.argv) == 2:
model_file = sys.argv[1]
else:
model_file = "model_weights_1.p"
model_file = "model_weights.p"
d = Deepcut(fcg, model_file)

View File

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

Some files were not shown because too many files have changed in this diff Show More