ChipBench — Dockerized reverse-engineering workbench for chip dumps
A fully self-contained firmware reverse-engineering environment that
installs nothing on your host (Docker only). Drop a flash/EEPROM/ROM
dump into artifacts/ and analyze it entirely from your terminal or from
an AI CLI — no GUI required. Headless Ghidra scripts (Jython) plus
radare2, binwalk, capstone/unicorn, chip-programmer tools, simulators, and
firmware-unpacking utilities.
Built and battle-tested on real engagements (8-bit embedded controllers with no symbols, no map files, and no mercy).
Quick start (headless, no GUI)
./re-build # one-time image build
# put your dump in artifacts/dump.bin, then:
./re-analyze dump.bin -processor "8051:BE:16:default"
./re-q dump.bin info # query it (commands below)
./re-export dump.bin # bulk-export everything to output/
./re-analyze, ./re-q, ./re-export use one-shot containers (tools
service) — no desktop stack needs to be running. Build once with
./re-build; you never need ./re-up unless you want the GUI.
Headless query interface — re-q
./re-q <program> <command> [args...]
<program> is the domain-file name in the project (usually the artifact's
basename, e.g. dump.bin). Commands:
| Command | Args | What it returns |
|---|---|---|
info |
— | name, language, image base, size, function count, segments |
segments |
— | memory segments (name, range, perms) |
funcs |
[offset] [limit] [filter] |
function list: name @ entry |
search |
<query> [limit] |
functions whose name contains query |
func |
<addr> |
one function's metadata (signature, body, size) |
decompile |
<name|addr> |
decompiled C of a function |
disasm |
<addr> |
disassembly of the function at/containing addr |
xrefs-to |
<addr> [limit] |
references TO an address (callers etc.) |
xrefs-from |
<addr> [limit] |
references FROM an address |
func-xrefs |
<name> [limit] |
references to a function by name |
strings |
[filter] [limit] |
defined strings with addresses |
data |
[offset] [limit] |
defined data items |
mem |
<addr> <len> |
raw hex+ASCII dump of <len> bytes |
exports / imports |
[limit] |
external entry points / symbols |
Addresses accept Ghidra's form (00102030) or 0x-prefixed. Each query
spins up a short-lived Ghidra JVM (~10 s) reading the already-analyzed
program (read-only).
Bulk export — re-export
./re-export <program>
One Ghidra run writes, to output/: *.info.txt, *.functions.txt,
*.strings.txt, *.segments.txt, *.data.txt, *.decompiled.c.
Read/grep these instantly for most questions; use re-q for targeted
live queries.
Architecture forcing
Let Ghidra auto-detect, or force with -processor (see re-analyze -h
comment header). Raw 8051 dumps get automatic vector+sweep disassembly via
Analyze8051.py (override with RE_NO_SWEEP=1).
What's inside
| Category | Tools |
|---|---|
| Decompiler / RE workbench | Ghidra 11.3.2 + GhidraMCP 1.4 plugin |
| Headless scripts (Jython) | Query.py, ExportAll.py, Analyze8051.py, MakeFuncs.py, AutoFuncs.py |
| CLI disassemblers | radare2 (r2/rabin2), binutils-multiarch, binutils-avr, gputils (gpdasm), sdcc, z80dasm |
| Firmware scanning / unpacking | binwalk v3, 7-zip, cabextract, lzma, cpio, squashfs-tools, unar, u-boot-tools (mkimage), device-tree-compiler |
| Chip programming / debug | flashrom, avrdude, openocd, stlink-tools, esptool |
| Simulators | simavr (AVR), gpsim (PIC) |
| EPROM/SREC/HEX wrangling | srecord (srec_cat & co.) |
| Serial consoles | tio, picocom (pyserial in the venv) |
| Python RE libs | capstone, unicorn, keystone (in /opt/venv) |
| Desktop (optional) | Xvfb + fluxbox + x11vnc + noVNC |
Optional extras not packaged (build from source if needed): minipro
(TL866 programmers), stm8flash.
GUI + MCP bridge (optional)
./re-up boots a headless desktop with Ghidra:
| URL / port | What |
|---|---|
| http://localhost:6080/vnc.html | Ghidra GUI in a browser (VNC pw chipbench) |
| localhost:5900 | raw VNC |
| http://localhost:8081/sse | GhidraMCP bridge (MCP over SSE) |
The MCP bridge only serves data once a program is opened in the CodeBrowser
tool AND the GhidraMCP plugin is enabled there (one-time manual GUI step).
The headless re-q/re-export interface covers the same ground without
any GUI interaction.
Known issues
- Use the Jython (.py) scripts. In-process
javacfor Ghidra.javauser scripts has broken across JDK point releases in Ubuntu images ("class could not be found" at script load). The .py scripts are immune. - GhidraMCP's Module.manifest emits harmless warnings at headless startup.
- Ghidra 11.3.2 is pinned (latest GhidraMCP 1.4 supports).
Layout
ChipBench/
├── docker/
│ ├── Dockerfile # two-stage build (binwalk builder + main)
│ ├── conf/ # supervisord, profile.d, entrypoint
│ └── scripts/ghidra-scripts/ # Jython headless scripts (host-mounted)
├── docker-compose.yml # ghidra (GUI) + tools (CLI) services
├── re-build # build the image
├── re-analyze re-q re-export # headless chat-driven workflow
├── re-identify re-binwalk re-shell # triage / shell
└── re-up re-down re-mcp-test # optional GUI/MCP
Directories artifacts/ (read-only mount), work/, output/ are created
on first use.
License
AGPLv3 — see LICENSE. The Dockerfile pulls third-party tools at build time under their own licenses (Ghidra: Apache-2.0; GhidraMCP and binwalk: MIT; radare2: LGPL-3.0; etc.). No binaries are hosted here.
Contributing
Issues and PRs welcome — especially additional headless Jython recipes
(per-architecture sweep scripts, NVM/checksum scanners) and tested tool
additions. Keep the image reasonably lean; heavy/specialized tools belong
in documented pip/apt side-notes rather than the base image.