ChipBench packages Ghidra, radare2, binwalk, chip-programming tools,
simulators, and firmware-unpacking utilities into one reproducible container
for analyzing raw chip dumps entirely from the command line or an AI CLI.
Headless Jython scripts drive import, forced-disassembly sweeps, live
queries, and bulk decompilation exports without any GUI.
Derived from a private engagement environment, generalized for public
release under AGPLv3. No engagement-specific artifacts are included.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
66 lines
2.4 KiB
Python
66 lines
2.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Part of ChipBench (AGPLv3). SPDX-FileCopyrightText: 2026 Starting Line Productions LLC
|
|
# ExportAll.py -- Jython bulk export (no javac needed).
|
|
# Produces <prog>.functions.txt, .strings.txt, .segments.txt, .decompiled.c
|
|
import os
|
|
from ghidra.app.decompiler import DecompInterface
|
|
from ghidra.app.decompiler import DecompileOptions
|
|
|
|
outdir = os.environ.get("DECOMPILE_OUT", "/data/output")
|
|
prog = currentProgram
|
|
name = prog.getName()
|
|
fm = prog.getFunctionManager()
|
|
rm = prog.getReferenceManager()
|
|
|
|
print("ExportAll.py -> %s" % outdir)
|
|
|
|
# functions
|
|
with open(os.path.join(outdir, name + ".functions.txt"), "w") as fh:
|
|
for f in fm.getFunctions(True):
|
|
fh.write("%s @ %s\n" % (f.getName(), f.getEntryPoint()))
|
|
print("functions: %d" % fm.getFunctionCount())
|
|
|
|
# segments
|
|
with open(os.path.join(outdir, name + ".segments.txt"), "w") as fh:
|
|
for b in prog.getMemory().getBlocks():
|
|
fh.write("%s %s-%s %d %s%s\n" % (b.getName(), b.getStart(), b.getEnd(),
|
|
b.getSize(), "R" if b.isRead() else "-", "W" if b.isWrite() else "-"))
|
|
# strings (defined string data)
|
|
with open(os.path.join(outdir, name + ".strings.txt"), "w") as fh:
|
|
di = prog.getDataTypeManager()
|
|
listing = prog.getListing()
|
|
it = listing.getDefinedData(True)
|
|
n = 0
|
|
while it.hasNext():
|
|
d = it.next()
|
|
dt = d.getDataType()
|
|
if dt is not None and ("string" in dt.getName().lower() or "char" in dt.getName().lower()):
|
|
try:
|
|
v = d.getValue()
|
|
except:
|
|
v = None
|
|
if v is not None and len(str(v)) >= 3:
|
|
fh.write("%s: %r\n" % (d.getAddress(), str(v)))
|
|
n += 1
|
|
print("strings: %d" % n)
|
|
|
|
# decompile everything
|
|
ifc = DecompInterface()
|
|
ifc.setOptions(DecompileOptions())
|
|
ifc.openProgram(prog)
|
|
nf = 0
|
|
with open(os.path.join(outdir, name + ".decompiled.c"), "w") as fh:
|
|
fh.write("// Decompiled by ExportAll.py (Ghidra %s)\n" % "11.3.2")
|
|
for f in fm.getFunctions(True):
|
|
res = ifc.decompileFunction(f, 90, monitor)
|
|
if res.decompileCompleted():
|
|
fh.write("\n/* ==== %s @ %s ==== */\n" % (f.getName(), f.getEntryPoint()))
|
|
fh.write(res.getDecompiledFunction().getC())
|
|
nf += 1
|
|
else:
|
|
fh.write("\n/* ==== %s @ %s : DECOMPILE FAILED ==== */\n" % (f.getName(), f.getEntryPoint()))
|
|
ifc.dispose()
|
|
print("decompiled: %d" % nf)
|
|
print("ExportAll.py done")
|