Some checks are pending
Build Ghidra Plugin / build (push) Waiting to run
Separate Maven dependency resolution from compilation: - COPY pom.xml first, run dependency:resolve (cached layer) - COPY src second (only this invalidates on code changes) - Build step reuses cached dependencies Result: Code changes rebuild in ~30s instead of 3-5 min (Ghidra download and Maven deps stay cached)
149 lines
6.2 KiB
Docker
149 lines
6.2 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 first and download dependencies (cached until pom.xml changes)
|
|
COPY pom.xml .
|
|
RUN mvn dependency:resolve -P plugin-only -q \
|
|
-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 \
|
|
|| true
|
|
|
|
# Now copy source - only this layer rebuilds on code changes
|
|
COPY src ./src
|
|
|
|
# Build the plugin (skip git-commit-id plugin since .git isn't in Docker context)
|
|
RUN mvn 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 and binaries
|
|
RUN mkdir -p /projects /binaries /home/ghidra/.ghidra \
|
|
&& chown -R ghidra:ghidra /projects /binaries /home/ghidra
|
|
|
|
# Copy GhydraMCP scripts to the BSim module's scripts directory
|
|
# BSim is a working feature module with proper OSGi bundle configuration for scripts
|
|
COPY docker/GhydraMCPServer.java /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/
|
|
COPY docker/ImportRawARM.java /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/
|
|
COPY docker/TestScript.java /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/
|
|
|
|
# Set proper ownership, permissions, and timestamp to match Ghidra installation
|
|
# Ghidra appears to validate scripts by timestamp - newer files may be rejected
|
|
RUN chown ghidra:ghidra /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/GhydraMCPServer.java \
|
|
/opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/ImportRawARM.java \
|
|
/opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/TestScript.java \
|
|
&& touch -t 202508261420 /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/GhydraMCPServer.java \
|
|
&& touch -t 202508261420 /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/ImportRawARM.java \
|
|
&& touch -t 202508261420 /opt/ghidra/Ghidra/Features/BSim/ghidra_scripts/TestScript.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"]
|