Initial public release: dockerized reverse-engineering workbench
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
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# -*- 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")
|
||||
Reference in New Issue
Block a user