Skip to content

Instantly share code, notes, and snippets.

@JaciBrunning
Created December 28, 2020 15:12
Show Gist options
  • Save JaciBrunning/53c62ffd1aecd525915532f9892f9273 to your computer and use it in GitHub Desktop.
Save JaciBrunning/53c62ffd1aecd525915532f9892f9273 to your computer and use it in GitHub Desktop.
Ghidra Pathfinder - Find execution paths between two functions
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