# 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) ```bash ./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 [args...] ``` `` 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` | ` [limit]` | functions whose name contains query | | `func` | `` | one function's metadata (signature, body, size) | | `decompile` | `` | decompiled C of a function | | `disasm` | `` | disassembly of the function at/containing addr | | `xrefs-to` | ` [limit]` | references TO an address (callers etc.) | | `xrefs-from` | ` [limit]` | references FROM an address | | `func-xrefs` | ` [limit]` | references to a function by name | | `strings` | `[filter] [limit]` | defined strings with addresses | | `data` | `[offset] [limit]` | defined data items | | `mem` | ` ` | raw hex+ASCII dump of `` 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 ``` 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 `javac` for Ghidra `.java` user 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](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.