mcghidra/docker/Dockerfile
Ryan Malloy ac06111288 fix: Add Gson dependency for headless script support
GhydraMCPServer.java imports Gson but headless scripts run in a
separate OSGi classloader that can't access extension lib JARs.

Fix: Download gson-2.13.1.jar to Framework/Generic/lib/ where it's
available to all scripts regardless of execution mode.

Closes issue documented in BUG_REPORT_HEADLESS_GSON.md
2026-01-26 03:28:33 -07:00

132 lines
5.0 KiB
Docker

# GhydraMCP Docker Image
# Ghidra + GhydraMCP Plugin pre-installed for headless binary analysis
#
# Build: docker build -t ghydramcp:latest -f docker/Dockerfile .
# Run: docker run -p 8192:8192 -v /path/to/binaries:/binaries ghydramcp:latest
ARG GHIDRA_VERSION=11.4.2
ARG GHIDRA_DATE=20250826
# =============================================================================
# Stage 1: Build the GhydraMCP plugin
# =============================================================================
FROM eclipse-temurin:21-jdk-jammy AS builder
ARG GHIDRA_VERSION
ARG GHIDRA_DATE
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
maven \
git \
&& rm -rf /var/lib/apt/lists/*
# Download and extract Ghidra
WORKDIR /opt
RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
-o ghidra.zip \
&& unzip -q ghidra.zip \
&& rm ghidra.zip \
&& mv ghidra_${GHIDRA_VERSION}_PUBLIC ghidra
ENV GHIDRA_HOME=/opt/ghidra
# Copy GhydraMCP source and build
WORKDIR /build
COPY pom.xml .
COPY src ./src
# Build the plugin (skip git-commit-id plugin since .git isn't in Docker context)
RUN mvn clean package -P plugin-only -DskipTests \
-Dmaven.gitcommitid.skip=true \
-Dghidra.generic.jar=${GHIDRA_HOME}/Ghidra/Framework/Generic/lib/Generic.jar \
-Dghidra.softwaremodeling.jar=${GHIDRA_HOME}/Ghidra/Framework/SoftwareModeling/lib/SoftwareModeling.jar \
-Dghidra.project.jar=${GHIDRA_HOME}/Ghidra/Framework/Project/lib/Project.jar \
-Dghidra.docking.jar=${GHIDRA_HOME}/Ghidra/Framework/Docking/lib/Docking.jar \
-Dghidra.decompiler.jar=${GHIDRA_HOME}/Ghidra/Features/Decompiler/lib/Decompiler.jar \
-Dghidra.utility.jar=${GHIDRA_HOME}/Ghidra/Framework/Utility/lib/Utility.jar \
-Dghidra.base.jar=${GHIDRA_HOME}/Ghidra/Features/Base/lib/Base.jar
# =============================================================================
# Stage 2: Runtime image with Ghidra + GhydraMCP
# =============================================================================
# NOTE: Ghidra requires JDK (not JRE) - it checks for javac in LaunchSupport
FROM eclipse-temurin:21-jdk-jammy AS runtime
ARG GHIDRA_VERSION
ARG GHIDRA_DATE
LABEL org.opencontainers.image.title="ghydramcp" \
org.opencontainers.image.description="Ghidra + GhydraMCP Plugin for AI-assisted reverse engineering" \
org.opencontainers.image.source="https://github.com/starsong-consulting/GhydraMCP" \
org.opencontainers.image.licenses="Apache-2.0"
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
fontconfig \
libfreetype6 \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -g 1001 ghidra && useradd -u 1001 -g ghidra -m -s /bin/bash ghidra
# Download and extract Ghidra (in runtime stage for cleaner image)
WORKDIR /opt
RUN curl -fsSL "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
-o ghidra.zip \
&& unzip -q ghidra.zip \
&& rm ghidra.zip \
&& mv ghidra_${GHIDRA_VERSION}_PUBLIC ghidra \
&& chown -R ghidra:ghidra /opt/ghidra
ENV GHIDRA_HOME=/opt/ghidra
ENV PATH="${GHIDRA_HOME}:${PATH}"
# Install the GhydraMCP plugin
COPY --from=builder /build/target/GhydraMCP-*.zip /tmp/
RUN mkdir -p /opt/ghidra/Ghidra/Extensions \
&& unzip -q /tmp/GhydraMCP-*.zip -d /opt/ghidra/Ghidra/Extensions/ \
&& rm /tmp/GhydraMCP-*.zip \
&& chown -R ghidra:ghidra /opt/ghidra/Ghidra/Extensions/
# Create directories for projects, binaries, and scripts
RUN mkdir -p /projects /binaries /home/ghidra/.ghidra /opt/ghidra/scripts \
&& chown -R ghidra:ghidra /projects /binaries /home/ghidra /opt/ghidra/scripts
# Download Gson JAR for headless script support
# (GhydraMCPServer.java requires Gson but headless scripts can't access extension libs)
RUN curl -fsSL "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar" \
-o /opt/ghidra/Ghidra/Framework/Generic/lib/gson-2.13.1.jar \
&& chown ghidra:ghidra /opt/ghidra/Ghidra/Framework/Generic/lib/gson-2.13.1.jar
# Copy the GhydraMCP scripts
COPY docker/GhydraMCPServer.java /opt/ghidra/scripts/
COPY docker/ImportRawARM.java /opt/ghidra/scripts/
RUN chown -R ghidra:ghidra /opt/ghidra/scripts/ && chmod 644 /opt/ghidra/scripts/*.java
# Copy entrypoint script (755 so ghidra user can read and execute)
COPY docker/entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
# Switch to non-root user
USER ghidra
WORKDIR /home/ghidra
# Expose the GhydraMCP HTTP API port (and additional ports for multiple instances)
EXPOSE 8192 8193 8194 8195
# Default environment
ENV GHYDRA_MODE=headless
ENV GHYDRA_PORT=8192
ENV GHYDRA_MAXMEM=2G
# Healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:${GHYDRA_PORT}/ || exit 1
ENTRYPOINT ["/entrypoint.sh"]