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
167 lines
7.4 KiB
Docker
167 lines
7.4 KiB
Docker
# syntax=docker/dockerfile:1
|
|
#
|
|
# ChipBench — self-contained reverse-engineering environment for 8-bit
|
|
# (and small embedded) chip dumps. Bundles: Ghidra 11.3.2 + GhidraMCP 1.4,
|
|
# radare2, binwalk v3, binutils for several targets, sdcc, gputils,
|
|
# capstone/unicorn/keystone, plus a firmware-hacker toolset (flashrom,
|
|
# avrdude, openocd, srecord, simavr, unpacking tools, serial consoles).
|
|
# Optional VNC/noVNC desktop so the Ghidra GUI also runs headlessly.
|
|
#
|
|
# Nothing runs as root; runtime user is mapped to host uid/gid so
|
|
# bind-mounted artifacts keep their owner.
|
|
#
|
|
# This project is AGPLv3 (see LICENSE). It builds tooling from public
|
|
# sources; no binaries are hosted by the project.
|
|
|
|
# ---- Stage 1: build binwalk v3 (Rust) in an isolated builder ----------------
|
|
FROM rust:1-slim-bookworm AS binwalk-builder
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
pkg-config libfontconfig1-dev ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
RUN cargo install --root /out --version 3.1.0 binwalk
|
|
|
|
# ---- Stage 2: main image ----------------------------------------------------
|
|
ARG BUILD_UID=1001
|
|
ARG BUILD_GID=1001
|
|
|
|
FROM ubuntu:24.04
|
|
|
|
# ARGs above do not cross FROM boundaries; re-declare for this stage
|
|
# (overridable at build time: --build-arg BUILD_UID=$(id -u) etc.)
|
|
ARG BUILD_UID
|
|
ARG BUILD_GID
|
|
|
|
ENV DEBIAN_FRONTEND=noninteractive \
|
|
TZ=UTC \
|
|
LANG=C.UTF-8 \
|
|
LC_ALL=C.UTF-8 \
|
|
DISPLAY=:0 \
|
|
JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 \
|
|
GHIDRA_HOME=/opt/ghidra \
|
|
GHIDRAMCP_HOME=/opt/ghidramcp \
|
|
VENV_HOME=/opt/venv \
|
|
GHIDRA_SCRIPTS=/opt/ghidra-scripts \
|
|
PATH="${JAVA_HOME}/bin:/opt/ghidra:/opt/ghidra/support:/opt/venv/bin:/usr/local/bin:${PATH}"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 1. System packages
|
|
# - GUI/VNC stack (optional desktop for the Ghidra GUI)
|
|
# - core RE CLI: radare2, binutils-multiarch, binutils-avr, sdcc, gputils
|
|
# - chip-programming & debug: flashrom, avrdude, openocd, stlink-tools
|
|
# - EPROM/SREC/HEX wrangling: srecord
|
|
# - simulators: simavr (AVR), gpsim (PIC)
|
|
# - firmware-unpacking: binwalk deps (7z, cabextract, lzma, cpio, squashfs,
|
|
# unar), u-boot-tools (mkimage), device-tree-compiler (dtc)
|
|
# - serial: tio, picocom
|
|
# - misc: esptool, z80dasm, vbindiff
|
|
# NOTE: openjdk-21-jdk is UNPINNED — in-process javac for Ghidra .java
|
|
# user scripts has broken before on point-release drift. The supported
|
|
# script path here is Jython (.py); the .java helper scripts are not shipped.
|
|
# -----------------------------------------------------------------------------
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
ca-certificates wget git unzip xz-utils \
|
|
openjdk-21-jdk \
|
|
xvfb x11vnc fluxbox supervisor \
|
|
novnc websockify \
|
|
xterm dbus-x11 \
|
|
libfontconfig1 fonts-dejavu-core \
|
|
python3 python3-venv python3-pip \
|
|
file xxd hexyl binutils \
|
|
binutils-avr \
|
|
binutils-multiarch \
|
|
gputils \
|
|
sdcc \
|
|
radare2 \
|
|
net-tools iproute2 procps less vim-tiny \
|
|
flashrom avrdude openocd stlink-tools \
|
|
srecord \
|
|
simavr gpsim \
|
|
z80dasm \
|
|
squashfs-tools p7zip-full cabextract lzma cpio unar \
|
|
u-boot-tools device-tree-compiler \
|
|
tio picocom \
|
|
esptool \
|
|
vbindiff \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# binwalk v3 binary (Rust) from the builder stage.
|
|
COPY --from=binwalk-builder /out/bin/binwalk /usr/local/bin/binwalk
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 2. Ghidra 11.3.2 (pinned: latest version the GhidraMCP plugin supports)
|
|
# -----------------------------------------------------------------------------
|
|
ARG GHIDRA_VERSION=11.3.2
|
|
ARG GHIDRA_ZIP=ghidra_11.3.2_PUBLIC_20250415.zip
|
|
ARG GHIDRA_URL=https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.3.2_build/${GHIDRA_ZIP}
|
|
ARG GHIDRA_SHA256=99d45035bdcc3d6627e7b1232b7b379905a9fad76c772c920602e2b5d8b2dac2
|
|
|
|
RUN cd /tmp \
|
|
&& wget -q -O ghidra.zip "${GHIDRA_URL}" \
|
|
&& echo "${GHIDRA_SHA256} ghidra.zip" | sha256sum -c - \
|
|
&& unzip -q ghidra.zip -d /opt \
|
|
&& rm -f ghidra.zip \
|
|
&& mv /opt/ghidra_* "${GHIDRA_HOME}"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 3. GhidraMCP 1.4 plugin (optional REST server inside the Ghidra GUI).
|
|
# The GitHub release ships a NESTED zip; unpack both layers.
|
|
# (Harmless "Module manifest file error" warnings at headless startup are
|
|
# known noise from this plugin's manifest formatting.)
|
|
# -----------------------------------------------------------------------------
|
|
ARG GHIDRAMCP_VERSION=1.4
|
|
ARG GHIDRAMCP_ZIP=GhidraMCP-release-1-4.zip
|
|
ARG GHIDRAMCP_URL=https://github.com/LaurieWired/GhidraMCP/releases/download/${GHIDRAMCP_VERSION}/${GHIDRAMCP_ZIP}
|
|
ARG GHIDRAMCP_SHA256=b81ca5240fdde57ea4e899170dcd9fdee6ed29246280c74263a509bfcfc7e734
|
|
|
|
RUN cd /tmp \
|
|
&& wget -q -O mcp-outer.zip "${GHIDRAMCP_URL}" \
|
|
&& echo "${GHIDRAMCP_SHA256} mcp-outer.zip" | sha256sum -c - \
|
|
&& mkdir -p outer && unzip -q mcp-outer.zip -d outer \
|
|
&& inner_zip="$(find outer -name 'GhidraMCP-*.zip' | head -n1)" \
|
|
&& test -n "$inner_zip" \
|
|
&& mkdir -p inner && unzip -q "$inner_zip" -d inner \
|
|
&& extdir="$(dirname "$(find inner -name extension.properties | head -n1)")" \
|
|
&& test -n "$extdir" \
|
|
&& mkdir -p "${GHIDRA_HOME}/Ghidra/Extensions" \
|
|
&& cp -r "$extdir" "${GHIDRA_HOME}/Ghidra/Extensions/GhidraMCP" \
|
|
&& rm -rf /tmp/*
|
|
|
|
ARG BRIDGE_URL=https://raw.githubusercontent.com/LaurieWired/GhidraMCP/1.4/bridge_mcp_ghidra.py
|
|
# Non-fatal: the MCP bridge is optional (GUI-only convenience). GitHub raw
|
|
# occasionally rate-limits (429); retries + a warning keep builds reproducible.
|
|
RUN mkdir -p "${GHIDRAMCP_HOME}" \
|
|
&& ( wget -q --tries=3 --timeout=30 -O "${GHIDRAMCP_HOME}/bridge_mcp_ghidra.py" "${BRIDGE_URL}" \
|
|
|| echo "[warn] GhidraMCP bridge download failed; GUI MCP bridge disabled (headless workflow unaffected)" )
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 4. Python tooling (isolated venv; respects PEP 668)
|
|
# -----------------------------------------------------------------------------
|
|
RUN python3 -m venv "${VENV_HOME}" \
|
|
&& "${VENV_HOME}/bin/pip" install --no-cache-dir --upgrade pip \
|
|
&& "${VENV_HOME}/bin/pip" install --no-cache-dir \
|
|
"mcp==1.5.0" "requests==2.32.3" "pyserial>=3.5" \
|
|
capstone unicorn \
|
|
&& ( "${VENV_HOME}/bin/pip" install --no-cache-dir keystone-engine \
|
|
|| echo "[warn] keystone-engine unavailable on this platform; skipping (non-fatal)" )
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# 5. Runtime user matching host uid/gid (no root needed at runtime)
|
|
# -----------------------------------------------------------------------------
|
|
RUN groupadd -g "${BUILD_GID}" chip \
|
|
&& useradd -m -u "${BUILD_UID}" -g "${BUILD_GID}" -s /bin/bash chip
|
|
|
|
COPY scripts/ghidra-scripts/ "${GHIDRA_SCRIPTS}/"
|
|
COPY conf/supervisord.conf /opt/conf/supervisord.conf
|
|
COPY conf/profile.d/chipbench.sh /etc/profile.d/chipbench.sh
|
|
COPY scripts/entrypoint.sh /opt/entrypoint.sh
|
|
RUN chmod +x /opt/entrypoint.sh \
|
|
&& chown -R chip:chip "${GHIDRA_SCRIPTS}" /opt/entrypoint.sh /opt/conf
|
|
|
|
USER chip:chip
|
|
WORKDIR /data
|
|
|
|
EXPOSE 5900 6080 8081
|
|
|
|
ENTRYPOINT ["/opt/entrypoint.sh"]
|
|
CMD ["supervisor"]
|