Created
December 28, 2020 15:12
-
-
Save JaciBrunning/53c62ffd1aecd525915532f9892f9273 to your computer and use it in GitHub Desktop.
Ghidra Pathfinder - Find execution paths between two functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from ghidra.program.model.symbol import RefType | |
import itertools | |
def memoize(func): | |
cache = dict() | |
def memoized_func(*args): | |
if args in cache: | |
return cache[args] | |
result = func(*args) | |
cache[args] = result | |
return result | |
return memoized_func | |
def group(iterator, n): | |
while True: | |
chunk = tuple(itertools.islice(iterator, n)) | |
if not chunk: | |
return | |
yield chunk | |
@memoize | |
def who_calls(func): | |
valid_types = [RefType.UNCONDITIONAL_CALL, RefType.COMPUTED_CALL, RefType.CONDITIONAL_CALL, RefType.CONDITIONAL_COMPUTED_CALL] | |
refs = filter(lambda x: x.getReferenceType() in valid_types, func.getReferences()) | |
return [listing.getFunctionContaining(x.getFromAddress()).getSymbol() for x in refs] | |
listing = currentProgram.getListing() | |
symbols = currentProgram.getSymbolTable() | |
def ask_symbol(title, message): | |
sym = None | |
while sym is None: | |
sym = symbols.getSymbol(askString(title, message)) | |
return sym | |
src_func = ask_symbol("Source Function", "Source function name?") | |
dst_func = ask_symbol("Destination Function", "Destination function name?") | |
def find_bfs(start_func, stop_func): | |
visited = [ start_func ] | |
queue = [ [ start_func ] ] | |
while queue: | |
path = queue.pop(0) | |
func = path[-1] | |
if func == stop_func: | |
yield path | |
for caller in who_calls(func): | |
# Change path to visited to prevent loops globally, not just in the current path. | |
# Can be useful when you only want the shortest path for each tree. | |
if caller not in path: | |
visited.append(caller) | |
new_path = list(path) | |
new_path.append(caller) | |
queue.append(new_path) | |
for path in find_bfs(dst_func, src_func): | |
print("Path({}):".format(len(path))) | |
first = True | |
for el in group(reversed(path), 20): | |
s = " -> ".join([str(x) for x in el]) | |
print("\t{}{}".format("-> " if not first else "", s)) | |
first = False |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment