Ryan Malloy 112c1969c8
Some checks failed
Build Ghidra Plugin / build (push) Has been cancelled
Fix port allocation to skip ports used by external Docker containers
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.
2026-02-11 05:37:40 -07:00
..

MCGhidra Docker Setup

This directory contains Docker configuration for running MCGhidra in headless mode.

Quick Start

# Build the image
docker build -t mcghidra:latest -f docker/Dockerfile .

# Analyze a binary
docker run -p 8192:8192 -v /path/to/binaries:/binaries mcghidra /binaries/sample.exe

# Check API health
curl http://localhost:8192/

Architecture

The Docker container includes:

  1. Ghidra 11.4.2 - Full headless installation
  2. MCGhidra Extension - The Java plugin (installed in Extensions/)
  3. MCGhidraServer.py - Headless HTTP server (Jython, full API parity)

Why Two HTTP Servers?

The MCGhidra plugin (MCGhidraPlugin.java) is a full Ghidra GUI plugin that requires:

  • Ghidra's PluginTool framework
  • ProgramManager service for program access
  • GUI event handling

These GUI services don't exist in headless mode. Instead, the container uses MCGhidraServer.py, a Jython script that:

  • Runs via analyzeHeadless -postScript
  • Has direct access to currentProgram from the script context
  • Provides full API parity with the GUI plugin (45 routes)
  • Supports all read and write operations

Available Endpoints (Headless Mode)

The headless server implements the complete MCGhidra HTTP API:

Category Endpoints Description
Info GET /, /info, /program API info, program metadata
Functions GET /functions, /functions/{addr}, /functions/by-name/{name} List and detail
Decompile GET /functions/{addr}/decompile, /functions/by-name/{name}/decompile C pseudocode
Disassembly GET /functions/{addr}/disassembly, /functions/by-name/{name}/disassembly Assembly listing
Data GET /data, /strings Defined data and strings
Memory GET /memory, /memory/blocks Read bytes, list segments
Xrefs GET /xrefs Cross-references (to/from)
Structs GET /structs Data type structures
Symbols GET /symbols, /imports, /exports Symbol tables
Analysis GET /analysis/callgraph, /analysis/dataflow Static analysis
Write Ops PATCH /functions/*, POST /data, POST /structs/* Rename, annotate, create

See GHIDRA_HTTP_API.md for the complete API specification.

Container Modes

Headless Mode (Default)

Imports a binary, analyzes it, and starts the HTTP API server:

docker run -p 8192:8192 \
  -v ./samples:/binaries \
  mcghidra /binaries/sample.exe

Server Mode

Opens an existing project and program:

docker run -p 8192:8192 \
  -e MCGHIDRA_MODE=server \
  -v ./projects:/projects \
  mcghidra program_name

Analyze Mode

Imports and analyzes without starting HTTP server:

docker run \
  -e MCGHIDRA_MODE=analyze \
  -v ./samples:/binaries \
  -v ./projects:/projects \
  mcghidra /binaries/sample.exe

Shell Mode

Interactive debugging:

docker run -it \
  -e MCGHIDRA_MODE=shell \
  mcghidra

Environment Variables

Variable Default Description
MCGHIDRA_MODE headless Container mode (headless, server, analyze, shell)
MCGHIDRA_PORT 8192 HTTP API port
MCGHIDRA_MAXMEM 2G JVM heap memory
PROJECT_DIR /projects Ghidra project directory
PROJECT_NAME MCGhidra Ghidra project name

Docker Compose

Use docker-compose for easier management:

# Development mode (hot-reload scripts)
docker compose --profile dev up mcghidra-dev

# Production mode
docker compose --profile prod up mcghidra

# Interactive shell
docker compose --profile debug run --rm mcghidra-shell

MCP Integration

The MCGhidra Python server includes Docker management tools:

# Check Docker status
await docker_status()

# Start container for a binary
await docker_start(binary_path="/path/to/binary.exe", port=8192)

# Wait for container to be ready
await docker_wait(port=8192, timeout=300)

# Automatic mode - starts container if no Ghidra available
await docker_auto_start(binary_path="/path/to/binary.exe")

# Get container logs
await docker_logs("mcghidra-server")

# Stop container
await docker_stop("mcghidra-server")

Building

# Using Make
make build

# Using Docker directly
docker build -t mcghidra:latest -f docker/Dockerfile .

# Build with specific Ghidra version
docker build -t mcghidra:latest \
  --build-arg GHIDRA_VERSION=11.4.2 \
  --build-arg GHIDRA_DATE=20250826 \
  -f docker/Dockerfile .

Troubleshooting

Container starts but API doesn't respond

Analysis takes time. Monitor progress with:

docker logs -f mcghidra-server

Port already in use

Stop existing containers:

docker stop $(docker ps -q --filter "name=mcghidra")

Memory issues with large binaries

Increase JVM heap:

docker run -e MCGHIDRA_MAXMEM=4G -p 8192:8192 mcghidra /binaries/large.exe

Permission denied on volumes

The container runs as user ghidra (UID 1001). Ensure volume permissions:

sudo chown -R 1001:1001 /path/to/binaries