mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-11 14:27:58 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5207d70934 | ||
|
|
d9bfeff6b7 | ||
|
|
04181bce35 | ||
|
|
8fbf5c8cf7 | ||
|
|
20c9025d24 | ||
|
|
8d26ba6e0b | ||
|
|
bbc19924e3 | ||
|
|
b657cf2782 | ||
|
|
2a77c349b8 | ||
|
|
22c0a93da4 | ||
|
|
3953e9d357 | ||
|
|
046f4706d2 | ||
|
|
f2901905ea | ||
|
|
bec42aa376 | ||
|
|
9400cc6c69 | ||
|
|
44dbcdce55 | ||
|
|
b1a348bc48 | ||
|
|
cab7f1774c | ||
|
|
a7dd1a2916 | ||
|
|
1b169e834f | ||
|
|
4829f1c12b | ||
|
|
b56b6e583c |
@@ -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()
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ""
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
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
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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__()
|
||||
@@ -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
|
||||
77
README.md
77
README.md
@@ -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
|
||||

|
||||
|
||||
Configure the native Python path for CodeCut by choosing **Edit -> Tool Options** and selecting "Python Executable."
|
||||
|
||||
### Configuring DeepCut Python Path
|
||||

|
||||
|
||||
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
|
||||

|
||||
|
||||
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
|
||||

|
||||
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
74
codecut-gui/ghidra_scripts/ModNamingRun.py
Normal file
74
codecut-gui/ghidra_scripts/ModNamingRun.py
Normal 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()
|
||||
1358
codecut-gui/ghidra_scripts/OutputObjFile.py
Executable file
1358
codecut-gui/ghidra_scripts/OutputObjFile.py
Executable file
File diff suppressed because it is too large
Load Diff
63
codecut-gui/ghidra_scripts/decomprange.py
Normal file
63
codecut-gui/ghidra_scripts/decomprange.py
Normal 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
|
||||
|
||||
100
codecut-gui/ghidra_scripts/dependency_bootstrap.py
Normal file
100
codecut-gui/ghidra_scripts/dependency_bootstrap.py
Normal 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 pip’s version check and ensure no interactive prompts
|
||||
env = dict(os.environ)
|
||||
env.setdefault("PIP_DISABLE_PIP_VERSION_CHECK", "1")
|
||||
env.setdefault("PYTHONWARNINGS", "ignore") # optional: quiet noisy warnings
|
||||
|
||||
|
||||
# pip 20+: use cli.main
|
||||
from pip._internal.cli.main import main as pip_main # type: ignore
|
||||
|
||||
try:
|
||||
code = pip_main(args)
|
||||
except SystemExit as e: # pip may call sys.exit()
|
||||
code = int(e.code) if e.code is not None else 0
|
||||
|
||||
if int(code) == 0:
|
||||
return True
|
||||
print(f"[deps] pip (in-process) failed with code {code}")
|
||||
|
||||
|
||||
def _reload_paths(self) -> None:
|
||||
importlib.invalidate_caches()
|
||||
try:
|
||||
import site
|
||||
importlib.reload(site) # process site-packages & .pth files
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
import pkg_resources # type: ignore
|
||||
pkg_resources.working_set.__init__() # rebuild dist cache
|
||||
except Exception:
|
||||
pass
|
||||
72
codecut-gui/ghidra_scripts/funcsig.py
Normal file
72
codecut-gui/ghidra_scripts/funcsig.py
Normal 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)
|
||||
|
||||
64
codecut-gui/ghidra_scripts/generate_c.py
Normal file
64
codecut-gui/ghidra_scripts/generate_c.py
Normal 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
|
||||
|
||||
99
codecut-gui/ghidra_scripts/globalvars.py
Normal file
99
codecut-gui/ghidra_scripts/globalvars.py
Normal 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
|
||||
|
||||
351
codecut-gui/ghidra_scripts/modnaming.py
Normal file
351
codecut-gui/ghidra_scripts/modnaming.py
Normal 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()
|
||||
38
codecut-gui/ghidra_scripts/range.py
Normal file
38
codecut-gui/ghidra_scripts/range.py
Normal 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)
|
||||
|
||||
166
codecut-gui/ghidra_scripts/std.py
Normal file
166
codecut-gui/ghidra_scripts/std.py
Normal 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()
|
||||
@@ -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>
|
||||
191
codecut-gui/src/main/java/codecutguiv2/CCTableFilterPanel.java
Normal file
191
codecut-gui/src/main/java/codecutguiv2/CCTableFilterPanel.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal file
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal 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
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
278
codecut-gui/src/main/java/codecutguiv2/ModNamingAnalyzer.java
Normal file
278
codecut-gui/src/main/java/codecutguiv2/ModNamingAnalyzer.java
Normal 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: ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
200
codecut-gui/src/main/java/codecutguiv2/PyGhidraFileLauncher.java
Normal file
200
codecut-gui/src/main/java/codecutguiv2/PyGhidraFileLauncher.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal file
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal 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");
|
||||
}
|
||||
}
|
||||
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal file
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal file
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal 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);
|
||||
}
|
||||
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal file
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal file
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal file
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
136
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal file
136
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal file
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal 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());
|
||||
}
|
||||
}
|
||||
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal file
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal file
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal 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();
|
||||
}
|
||||
}
|
||||
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal file
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal file
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal 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);
|
||||
}
|
||||
}
|
||||
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal file
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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
BIN
deepcut-ghidra/ghidra_scripts/.DS_Store
vendored
Normal file
Binary file not shown.
74
deepcut-ghidra/ghidra_scripts/DeepCutRun.py
Normal file
74
deepcut-ghidra/ghidra_scripts/DeepCutRun.py
Normal 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()
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
100
deepcut-ghidra/ghidra_scripts/dependency_bootstrap.py
Normal file
100
deepcut-ghidra/ghidra_scripts/dependency_bootstrap.py
Normal 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 pip’s version check and ensure no interactive prompts
|
||||
env = dict(os.environ)
|
||||
env.setdefault("PIP_DISABLE_PIP_VERSION_CHECK", "1")
|
||||
env.setdefault("PYTHONWARNINGS", "ignore") # optional: quiet noisy warnings
|
||||
|
||||
|
||||
# pip 20+: use cli.main
|
||||
from pip._internal.cli.main import main as pip_main # type: ignore
|
||||
|
||||
try:
|
||||
code = pip_main(args)
|
||||
except SystemExit as e: # pip may call sys.exit()
|
||||
code = int(e.code) if e.code is not None else 0
|
||||
|
||||
if int(code) == 0:
|
||||
return True
|
||||
print(f"[deps] pip (in-process) failed with code {code}")
|
||||
|
||||
|
||||
def _reload_paths(self) -> None:
|
||||
importlib.invalidate_caches()
|
||||
try:
|
||||
import site
|
||||
importlib.reload(site) # process site-packages & .pth files
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
import pkg_resources # type: ignore
|
||||
pkg_resources.working_set.__init__() # rebuild dist cache
|
||||
except Exception:
|
||||
pass
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user