Skip to content

Instantly share code, notes, and snippets.

@axlan
Created February 14, 2026 17:34
Show Gist options
  • Select an option

  • Save axlan/c38f7b01e54ab9f7cdefea51cd1dc9ed to your computer and use it in GitHub Desktop.

Select an option

Save axlan/c38f7b01e54ab9f7cdefea51cd1dc9ed to your computer and use it in GitHub Desktop.
Ghidra script to dump functions that match a certain name pattern.
# Export decompiled code for all functions matching a name regex
# @category Export
# @author Claude
#
# Usage:
# - Run from Ghidra Script Manager (GUI mode)
# - Or headless: analyzeHeadless ... -postScript export_decompiled.py "my_regex" "/tmp/out"
#
# Script arguments (optional):
# ARG 0: regex pattern (default: ".*" — matches everything)
# ARG 1: num params to filter for (default: -1 - don't filter)
# ARG 2: output path (default: <project_dir>/decompiled_export.c)
import re
import os
from ghidra.app.decompiler import DecompInterface, DecompileOptions
from ghidra.util.task import ConsoleTaskMonitor
# ── Configuration ─────────────────────────────────────────────────────────────
def get_args():
"""
Pull arguments from script args (headless) or fall back to sensible defaults.
In GUI mode you can also hard-code values here.
"""
args = getScriptArgs()
pattern = args[0] if len(args) > 0 else ".*"
num_params = int(args[1]) if len(args) > 1 else -1
default_out = os.path.join(
str(currentProgram.getDomainFile().getParent().getPathname()).lstrip("/"),
"decompiled_export.c"
)
out_path = args[2] if len(args) > 2 else default_out
return pattern, num_params, out_path
# ── Decompiler setup ──────────────────────────────────────────────────────────
def setup_decompiler(program):
iface = DecompInterface()
opts = DecompileOptions()
iface.setOptions(opts)
iface.openProgram(program)
return iface
# ── Main ──────────────────────────────────────────────────────────────────────
def main():
pattern, num_params, out_path = get_args()
try:
regex = re.compile(pattern)
except re.error as e:
print("[!] Invalid regex '{}': {}".format(pattern, e))
return
print("[*] Pattern : {}".format(pattern))
print("[*] Output : {}".format(out_path))
fm = currentProgram.getFunctionManager()
monitor = ConsoleTaskMonitor()
decomp = setup_decompiler(currentProgram)
timeout_secs = 30 # per-function decompile timeout
matched = 0
failed = 0
results = []
all_functions = list(fm.getFunctions(True)) # True = forward iteration
total = len(all_functions)
print("[*] Scanning {} functions…".format(total))
for i, func in enumerate(all_functions):
name = func.getName()
if not regex.search(name):
continue
if num_params >= 0 and num_params != func.getParameterCount(): # change to whatever you need
continue
matched += 1
addr = func.getEntryPoint()
print(" [{}/{}] Decompiling: {} @{}".format(i + 1, total, name, addr))
result = decomp.decompileFunction(func, timeout_secs, monitor)
if result and result.decompileCompleted():
code = result.getDecompiledFunction().getC()
results.append(
"/* ===== {} @ {} ===== */\n{}\n".format(name, addr, code)
)
else:
msg = result.getErrorMessage() if result else "unknown error"
print(" [!] Failed: {}".format(msg))
results.append(
"/* ===== {} @ {} — DECOMPILE FAILED: {} ===== */\n\n".format(
name, addr, msg
)
)
failed += 1
decomp.dispose()
# ── Write output ──────────────────────────────────────────────────────────
if not results:
print("[!] No functions matched pattern '{}'".format(pattern))
return
# Ensure output directory exists
out_dir = os.path.dirname(out_path)
if out_dir and not os.path.exists(out_dir):
os.makedirs(out_dir)
header = (
"/*\n"
" * Decompiled export\n"
" * Program : {}\n"
" * Pattern : {}\n"
" * Matched : {}\n"
" * Failed : {}\n"
" */\n\n"
).format(currentProgram.getName(), pattern, matched, failed)
with open(out_path, "w") as f:
f.write(header)
f.write("\n".join(results))
print("\n[+] Done. {} matched, {} failed.".format(matched, failed))
print("[+] Written to: {}".format(out_path))
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment