Analysis Workflows
These workflows assume you have MCGhidra installed and configured as described in the Installation guide.
Triage a Binary
Section titled “Triage a Binary”The fastest way to get oriented in an unknown binary. Start a container, wait for Ghidra to finish analysis, then survey the surface area.
1. Start analysis
Section titled “1. Start analysis”docker_auto_start(binary_path="/path/to/target.exe")This returns immediately with a port number. It does not block while Ghidra runs.
2. Wait for analysis to complete
Section titled “2. Wait for analysis to complete”Poll until the HTTP API responds:
docker_health(port=8195)For a small binary (under 1 MB), expect about 20 seconds. Larger binaries can take several minutes. Check docker_logs(port=8195) while waiting to see Ghidra’s progress.
3. Set the instance as current
Section titled “3. Set the instance as current”instances_use(port=8195)After this, every tool call defaults to this instance. No need to pass port again.
4. Get the program overview
Section titled “4. Get the program overview”program_info()functions_list(page_size=100)data_list_strings(page_size=100)program_info returns architecture, compiler, and image base address. The function and string listings give a first sense of scale and naming conventions.
5. Search for interesting patterns
Section titled “5. Search for interesting patterns”Use server-side grep to find functions and strings related to security-sensitive behavior:
functions_list(grep="password|key|auth|crypt|login|verify", page_size=100)data_list_strings(grep="password|secret|key|token|credential", page_size=100)From here, decompile anything that looks relevant and follow cross-references to understand the surrounding logic.
Rename and Annotate Loop
Section titled “Rename and Annotate Loop”Ghidra auto-analysis produces generic names like FUN_00401234. As you reverse engineer, renaming functions and adding comments makes the decompiled output progressively easier to read.
1. Decompile a function
Section titled “1. Decompile a function”functions_decompile(address="00401234")2. Identify what it does
Section titled “2. Identify what it does”Read the pseudocode. Look at string references, called functions, and parameter usage to determine the function’s purpose.
3. Rename it
Section titled “3. Rename it”functions_rename(address="00401234", new_name="validate_user_credentials")4. Set the signature
Section titled “4. Set the signature”If you can determine the parameter types and return type:
functions_set_signature( address="00401234", signature="int validate_user_credentials(char *username, char *password)")5. Add a comment
Section titled “5. Add a comment”functions_set_comment( address="00401234", comment="Checks username/password against the SQLite user table. Returns 1 on success.")6. Re-decompile
Section titled “6. Re-decompile”functions_decompile(address="00401234")The decompiled output now uses your names, types, and annotations. Functions called from validate_user_credentials also reflect the updated name wherever they reference it. Repeat this loop for each function you investigate.
Firmware Reverse Engineering
Section titled “Firmware Reverse Engineering”Raw firmware (bootloaders, embedded system images, bare-metal code) requires extra setup because there is no ELF/PE header for Ghidra to parse.
1. Start with the right loader
Section titled “1. Start with the right loader”Specify the processor language and base address:
docker_auto_start( binary_path="/path/to/firmware.bin", language="ARM:LE:32:v4t", base_address="0x00000000")When language is set, MCGhidra uses BinaryLoader to map the raw bytes at the given address. See the Installation guide for a table of common language IDs.
2. Find the entry point
Section titled “2. Find the entry point”ARM firmware typically starts with an exception vector table at address 0x00000000. The first entry is the initial stack pointer, and the second is the reset vector (entry point):
memory_read(address="0x00000000", length=32, format="hex")functions_decompile(address="0x00000004")3. Identify peripherals
Section titled “3. Identify peripherals”Embedded firmware talks to hardware through memory-mapped I/O. Look for reads and writes to addresses outside the firmware’s code and data regions:
data_list_strings(grep="UART|SPI|I2C|GPIO")functions_list(grep="init_periph|hw_init|bsp_")Constants like 0x40000000, 0x48000000, or 0xE000E000 (ARM Cortex-M NVIC) are strong indicators of peripheral access.
4. Trace interrupt handlers
Section titled “4. Trace interrupt handlers”Interrupt vector tables are typically at fixed offsets. For Cortex-M, the vector table starts at the base address. Each 4-byte entry points to a handler:
memory_read(address="0x00000000", length=256, format="hex")Create functions at each non-null vector address:
functions_create(address="0x00000040")functions_decompile(address="0x00000040")5. Map protocol implementations
Section titled “5. Map protocol implementations”Firmware that communicates over a bus (UART, SPI, USB, CAN) will have recognizable patterns: ring buffers, state machines with packet parsing, and checksum calculations. Use call graph analysis to trace from peripheral init functions to protocol handlers:
analysis_get_callgraph(name="uart_init", max_depth=4)Using Analysis Prompts
Section titled “Using Analysis Prompts”MCGhidra includes 13 built-in prompts that guide Claude through structured analysis workflows. Each prompt defines a series of steps, tool calls, and checks for a specific reverse engineering task.
Running a prompt
Section titled “Running a prompt”In Claude Code or Claude Desktop, use the /prompt command:
/prompt malware_triageClaude will then execute a multi-step analysis: listing functions, scanning strings, checking imports, and producing a structured report. Prompts that involve scanning (like malware_triage or identify_crypto) report progress as they work through each step.
Available prompts
Section titled “Available prompts”| Prompt | What it does |
|---|---|
malware_triage | Quick capability assessment across 21 scanning steps: checks for network activity, file manipulation, process injection, anti-analysis tricks, and persistence mechanisms |
identify_crypto | Scans for known crypto constants (AES S-boxes, SHA magic numbers), function names matching crypto libraries, and common key schedule patterns |
find_authentication | Searches for password checks, credential storage, license validation, certificate handling, and authentication bypass patterns |
analyze_protocol | Framework for reversing network or file format protocols: identifies packet structures, state machines, serialization routines |
trace_data_flow | Follows data forward or backward through a program to map how input reaches sensitive operations |
find_main_logic | Navigates past CRT startup, compiler-generated wrappers, and initialization to find the actual application entry point |
analyze_imports | Categorizes imported functions by capability (file I/O, networking, crypto, process management) and flags suspicious combinations |
analyze_strings | Groups strings by category (URLs, file paths, error messages, format strings) and cross-references them to find their usage |
analyze_switch_table | Identifies jump tables and command dispatchers, maps case values to handler functions |
find_config_parsing | Locates configuration file readers, command-line parsers, registry access, and environment variable lookups |
compare_functions | Side-by-side comparison of two functions to identify patches, variants, or shared library code |
document_struct | Traces struct usage across the binary to document field types, offsets, sizes, and purpose |
find_error_handlers | Maps error handling paths, cleanup routines, exception handlers, and exit patterns |
Prompt examples
Section titled “Prompt examples”Triage an unknown binary for malicious capabilities:
/prompt malware_triageFind all cryptographic implementations:
/prompt identify_cryptoTrace how user input flows to a specific sink:
/prompt trace_data_flowWhat happens during a prompt
Section titled “What happens during a prompt”Each prompt orchestrates a series of MCP tool calls. For example, malware_triage will:
- Call
program_info()to determine the architecture and format - Call
functions_list(grep=...)repeatedly with patterns for each capability category (networking, file ops, process injection, etc.) - Call
data_list_strings(grep=...)to find suspicious string patterns - Call
symbols_imports(grep=...)to categorize imported APIs - Produce a summary with findings organized by risk category
Prompts that scan many patterns report numeric progress (e.g., “Step 12/21: Checking for anti-debug techniques”) so you can see where they are in the analysis.