#!/bin/bash # MCGhidra Docker Entrypoint # Starts Ghidra in headless mode with HTTP API server set -e MCGHIDRA_MODE=${MCGHIDRA_MODE:-headless} MCGHIDRA_PORT=${MCGHIDRA_PORT:-8192} MCGHIDRA_MAXMEM=${MCGHIDRA_MAXMEM:-2G} GHIDRA_HOME=${GHIDRA_HOME:-/opt/ghidra} # User scripts directory - Python scripts don't need OSGi bundle registration SCRIPT_DIR=${SCRIPT_DIR:-/home/ghidra/ghidra_scripts} # Project settings PROJECT_DIR=${PROJECT_DIR:-/projects} PROJECT_NAME=${PROJECT_NAME:-MCGhidra} echo "==============================================" echo " MCGhidra Docker Container" echo "==============================================" echo " Mode: ${MCGHIDRA_MODE}" echo " Port: ${MCGHIDRA_PORT}" echo " Memory: ${MCGHIDRA_MAXMEM}" echo " Project: ${PROJECT_DIR}/${PROJECT_NAME}" echo "==============================================" # Ensure directories exist mkdir -p "${PROJECT_DIR}" # Handle different modes case "${MCGHIDRA_MODE}" in headless) # Headless mode: Import a binary and start HTTP server if [ $# -eq 0 ]; then echo "" echo "Usage: docker run mcghidra:latest [binary_path] [options]" echo "" echo "Examples:" echo " # Analyze a binary mounted at /binaries/sample.exe" echo " docker run -p 8192:8192 -v ./samples:/binaries mcghidra /binaries/sample.exe" echo "" echo " # With custom project name" echo " docker run -p 8192:8192 -v ./samples:/binaries -e PROJECT_NAME=malware mcghidra /binaries/sample.exe" echo "" echo "Environment variables:" echo " MCGHIDRA_PORT - HTTP API port (default: 8192)" echo " MCGHIDRA_MAXMEM - Max JVM heap (default: 2G)" echo " PROJECT_NAME - Ghidra project name (default: MCGhidra)" echo " PROJECT_DIR - Project directory (default: /projects)" echo " GHIDRA_LANGUAGE - Processor language ID (e.g., ARM:LE:32:v4t)" echo " GHIDRA_BASE_ADDRESS - Base address for raw binaries (e.g., 0x00000000)" echo " GHIDRA_LOADER - Loader type (e.g., BinaryLoader for raw firmware)" echo "" echo "Starting in wait mode..." echo "Container will stay running for debugging or manual operation." echo "You can exec into this container to run analyzeHeadless manually." echo "" # Keep container alive for debugging/manual operation tail -f /dev/null else BINARY_PATH="$1" shift if [ ! -f "${BINARY_PATH}" ]; then echo "ERROR: Binary not found: ${BINARY_PATH}" echo "Make sure to mount the binary directory with -v /host/path:/binaries" exit 1 fi BINARY_NAME=$(basename "${BINARY_PATH}") echo "Importing and analyzing: ${BINARY_NAME}" echo "" # Build the analyzeHeadless command ANALYZE_CMD="${GHIDRA_HOME}/support/analyzeHeadless" ANALYZE_ARGS=( "${PROJECT_DIR}" "${PROJECT_NAME}" -import "${BINARY_PATH}" -max-cpu 2 -scriptPath "${SCRIPT_DIR}" -postScript "MCGhidraServer.py" "${MCGHIDRA_PORT}" ) # Optional: processor/language for raw binaries if [ -n "${GHIDRA_LANGUAGE}" ]; then if ! echo "${GHIDRA_LANGUAGE}" | grep -qE '^[A-Za-z0-9_]+:[A-Z]{2}:[0-9]+:[A-Za-z0-9._-]+$'; then echo "ERROR: Invalid GHIDRA_LANGUAGE format: ${GHIDRA_LANGUAGE}" echo "Expected: ARCH:ENDIAN:SIZE:VARIANT (e.g., ARM:LE:32:v4t)" exit 1 fi ANALYZE_ARGS+=(-processor "${GHIDRA_LANGUAGE}") fi # Optional: base address if [ -n "${GHIDRA_BASE_ADDRESS}" ]; then if ! echo "${GHIDRA_BASE_ADDRESS}" | grep -qE '^(0x)?[0-9a-fA-F]+$'; then echo "ERROR: Invalid GHIDRA_BASE_ADDRESS format: ${GHIDRA_BASE_ADDRESS}" echo "Expected hex: 0x00000000 or 00000000" exit 1 fi ANALYZE_ARGS+=(-loader-baseAddr "${GHIDRA_BASE_ADDRESS}") fi # Optional: explicit loader (e.g., BinaryLoader for raw firmware) if [ -n "${GHIDRA_LOADER}" ]; then if ! echo "${GHIDRA_LOADER}" | grep -qE '^[A-Za-z0-9_]+$'; then echo "ERROR: Invalid GHIDRA_LOADER format: ${GHIDRA_LOADER}" echo "Expected alphanumeric name (e.g., BinaryLoader)" exit 1 fi ANALYZE_ARGS+=(-loader "${GHIDRA_LOADER}") fi # Add any extra arguments passed ANALYZE_ARGS+=("$@") echo "Running: ${ANALYZE_CMD} ${ANALYZE_ARGS[*]}" echo "" exec "${ANALYZE_CMD}" "${ANALYZE_ARGS[@]}" fi ;; server) # Server mode: Open existing project with HTTP server echo "Starting MCGhidra server on existing project..." if [ $# -eq 0 ]; then echo "Usage: docker run -e MCGHIDRA_MODE=server mcghidra [program_name]" echo "" echo " program_name: Name of program in the project to open" exit 1 fi PROGRAM_NAME="$1" shift exec "${GHIDRA_HOME}/support/analyzeHeadless" \ "${PROJECT_DIR}" "${PROJECT_NAME}" \ -process "${PROGRAM_NAME}" \ -noanalysis \ -scriptPath "${SCRIPT_DIR}" \ -postScript "MCGhidraServer.py" "${MCGHIDRA_PORT}" \ "$@" ;; analyze) # Analyze mode: Import and analyze, then exit (no HTTP server) if [ $# -eq 0 ]; then echo "Usage: docker run -e MCGHIDRA_MODE=analyze mcghidra [binary_path]" exit 1 fi BINARY_PATH="$1" shift echo "Analyzing binary: ${BINARY_PATH}" exec "${GHIDRA_HOME}/support/analyzeHeadless" \ "${PROJECT_DIR}" "${PROJECT_NAME}" \ -import "${BINARY_PATH}" \ -max-cpu 2 \ "$@" ;; shell) # Interactive shell exec /bin/bash ;; *) echo "Unknown mode: ${MCGHIDRA_MODE}" echo "Valid modes: headless, server, analyze, shell" exit 1 ;; esac