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,144 @@
|
||||
# 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 <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 `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.
|
||||
Reference in New Issue
Block a user