Automating Patch Diffing with Headless Ghidra Scripts

Manual patch diffing is one of the most effective ways to discover high-value security vulnerabilities, but doing it interactively through a graphical user interface quickly becomes a bottleneck during large update cycles. When a software update modifies dozens of system binaries, loading each file pair into a GUI disassembler, waiting for auto-analysis, and manually correlating changed functions takes hours.
To streamline this process, you can build an automated patch-diffing pipeline using Ghidra’s headless analyzer combined with a Python script. This approach extracts decompiled functions and assembly differentials in batch mode, outputting actionable diff summaries straight to your terminal.
Headless Execution Strategy
Ghidra includes a powerful batch processing tool called analyzeHeadless. Instead of launching the heavy Java Swing interface, analyzeHeadless creates temporary projects, imports targeted binaries, runs specified auto-analysis passes, and executes custom scripts against the program database.
To compare an unpatched binary with its patched counterpart, the pipeline operates in three distinct phases:
- Import and analyze the pre-patch binary in a temporary headless project.
- Import and analyze the post-patch binary in the same project context.
- Run a post-analysis Python script that maps functions between both binaries, compares their instruction sequences or ASTs (Abstract Syntax Trees), and flags functions with altered control flow or modified conditional checks.
Using headless mode reduces analysis time from tens of minutes per binary down to seconds, as rendering overhead is eliminated entirely.
Building the Ghidra Diff Script
Ghidra’s Python scripting engine exposes the flat Java API. To perform differential analysis scriptably, we can compare calculated function hashes or evaluate structural instruction changes.
Here is a simplified example of a Ghidra Python script (diff_functions.py) designed to run within the headless analyzer environment:
# Headless script to dump basic function information
from ghidra.program.model.symbol import SymbolType
def get_function_bytes(func):
addr_set = func.getBody()
code_units = currentProgram.getListing().getCodeUnits(addr_set, True)
byte_list = []
for unit in code_units:
byte_list.append(str(unit))
return "".join(byte_list)
fm = currentProgram.getFunctionManager()
functions = fm.getFunctions(True)
print("[+] Function disassembly hash dump for: " + currentProgram.getName())
for func in functions:
if func.isThunk() or func.isExternal():
continue
disasm_str = get_function_bytes(func)
print("FUNC:{} | HASH:{}".format(func.getName(), hash(disasm_str)))
By invoking analyzeHeadless on both binaries and piping the output into a local Python orchestrator, you can quickly cross-reference function hashes. Any function name that exists in both versions but yields non-matching disassembly hashes is immediately marked for deeper inspection.
Automating the Batch Execution
To execute this analysis seamlessly from your terminal, wrap the headless analyzer calls inside a shell script or custom Python controller. The terminal invocation follows this structural pattern:
$GHIDRA_HOME/support/analyzeHeadless \
/tmp/ghidra_projects TempDiffProj \
-import /path/to/vulnerable_sample.dll \
-postScript diff_functions.py > unpatched_results.txt
$GHIDRA_HOME/support/analyzeHeadless \
/tmp/ghidra_projects TempDiffProj \
-import /path/to/patched_sample.dll \
-postScript diff_functions.py > patched_results.txt
A secondary Python parser then reads unpatched_results.txt and patched_results.txt, diffing the generated function signatures. Functions with mismatched hashes indicate modified code blocks—often revealing newly added bounds checks, altered integer validations, or patched pointer dereferences.
Speeding Up Root Cause Analysis
Once the automation flags modified functions, you can focus your interactive reverse engineering solely on the pinpointed offsets. Instead of auditing thousands of lines of decompiled code, you go straight to the specific logic modification that fixes the vulnerability.
Automating headless analysis transforms monthly patch cycles from an exhausting chore into a fast, predictable threat intelligence capability.
Photo by Conny Schneider on Unsplash.