Some checks failed
Build Ghidra Plugin / build (push) Has been cancelled
When port 8192 was already in use by a non-MCGhidra container (e.g., LTspice), docker_start would fail instead of trying the next port. Now loops through the pool, checking each candidate against Docker's published ports before using it. Also includes Docker build retry improvements from earlier session.
153 lines
6.0 KiB
Docker
153 lines
6.0 KiB
Docker
# MCGhidra Docker Image
|
|
# Ghidra + MCGhidra Plugin pre-installed for headless binary analysis
|
|
#
|
|
# Build: docker build -t mcghidra:latest -f docker/Dockerfile .
|
|
# Run: docker run -p 8192:8192 -v /path/to/binaries:/binaries mcghidra:latest
|
|
|
|
ARG GHIDRA_VERSION=11.4.2
|
|
ARG GHIDRA_DATE=20250826
|
|
|
|
# =============================================================================
|
|
# Stage 1: Build the MCGhidra 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
|
|
# Download with retries and resume support for unreliable connections
|
|
RUN for i in 1 2 3 4 5; do \
|
|
curl -fSL --http1.1 -C - \
|
|
"https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
|
-o ghidra.zip && break || sleep 30; \
|
|
done \
|
|
&& unzip -q ghidra.zip \
|
|
&& rm ghidra.zip \
|
|
&& mv ghidra_${GHIDRA_VERSION}_PUBLIC ghidra
|
|
|
|
ENV GHIDRA_HOME=/opt/ghidra
|
|
|
|
# Copy MCGhidra 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 + MCGhidra
|
|
# =============================================================================
|
|
# 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="mcghidra" \
|
|
org.opencontainers.image.description="Ghidra + MCGhidra Plugin for AI-assisted reverse engineering" \
|
|
org.opencontainers.image.source="https://github.com/starsong-consulting/MCGhidra" \
|
|
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
|
|
# Download with retries and resume support for unreliable connections
|
|
RUN for i in 1 2 3 4 5; do \
|
|
curl -fSL --http1.1 -C - \
|
|
"https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_${GHIDRA_VERSION}_build/ghidra_${GHIDRA_VERSION}_PUBLIC_${GHIDRA_DATE}.zip" \
|
|
-o ghidra.zip && break || sleep 30; \
|
|
done \
|
|
&& 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 MCGhidra plugin
|
|
COPY --from=builder /build/target/MCGhidra-*.zip /tmp/
|
|
RUN mkdir -p /opt/ghidra/Ghidra/Extensions \
|
|
&& unzip -q /tmp/MCGhidra-*.zip -d /opt/ghidra/Ghidra/Extensions/ \
|
|
&& rm /tmp/MCGhidra-*.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 MCGhidra Python scripts to user scripts directory
|
|
# Python/Jython scripts don't require OSGi bundle registration - they work without issue
|
|
RUN mkdir -p /home/ghidra/ghidra_scripts
|
|
COPY docker/MCGhidraServer.py /home/ghidra/ghidra_scripts/
|
|
COPY docker/ImportRawARM.java /home/ghidra/ghidra_scripts/
|
|
|
|
# Set proper ownership and permissions
|
|
RUN chown -R ghidra:ghidra /home/ghidra/ghidra_scripts \
|
|
&& chmod 755 /home/ghidra/ghidra_scripts/*.py 2>/dev/null || true \
|
|
&& chmod 755 /home/ghidra/ghidra_scripts/*.java 2>/dev/null || true
|
|
|
|
# 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 MCGhidra HTTP API port (and additional ports for multiple instances)
|
|
EXPOSE 8192 8193 8194 8195
|
|
|
|
# Default environment
|
|
ENV MCGHIDRA_MODE=headless
|
|
ENV MCGHIDRA_PORT=8192
|
|
ENV MCGHIDRA_MAXMEM=2G
|
|
|
|
# Healthcheck
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
|
CMD curl -f http://localhost:${MCGHIDRA_PORT}/ || exit 1
|
|
|
|
ENTRYPOINT ["/entrypoint.sh"]
|