<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
---
name: reverse-engineering-with-ghidra
description: >-
  Reverse engineer malware using Ghidra for disassembly, decompilation, function
  identification, control flow analysis, and automated scripting via Ghidra's API.
domain: cybersecurity
subdomain: malware-analysis
tags:
  - ghidra
  - reverse-engineering
  - disassembly
  - decompilation
  - static-analysis
  - binary-analysis
version: "1.0"
author: defconxt
license: AGPL-3.0
metadata:
  mitre-attack: ["T1587.001"]
---

# Reverse Engineering with Ghidra

## Overview

Ghidra is an open-source software reverse engineering framework developed by the NSA. It provides disassembly, decompilation, scripting, and graphing capabilities for analyzing malware binaries across architectures (x86, x64, ARM, MIPS). Ghidra's headless analyzer enables automated batch analysis, and its Java/Python scripting API allows custom analysis plugins. This skill covers using Ghidra for malware reverse engineering including function identification, string decryption, control flow analysis, and C2 protocol reconstruction.

## Prerequisites

| Requirement | Details |
|---|---|
| Ghidra 11.0+ (Java 17+ required) | Required |
| Python 3.10+ with `ghidra-bridge` or Ghidra's built-in Jython | Required |
| Familiarity with x86/x64 assembly and calling conventions | Required |
| Understanding of PE/ELF binary formats | Required |
| Isolated analysis VM (FlareVM or REMnux) | Required |

## Key Concepts

### Ghidra Project Structure

Ghidra organizes analysis in projects containing programs (binaries). Each program stores disassembly, decompilation, annotations, bookmarks, and cross-references. The headless analyzer (`analyzeHeadless`) enables batch processing without the GUI.

### Decompiler Output

Ghidra's decompiler converts assembly to C pseudocode, recovering variable types, control flow structures, and function signatures. The output is approximate — analysts must validate decompiler assumptions, especially around struct layouts, calling conventions, and optimized code.

### P-Code and Intermediate Representation

Ghidra translates architecture-specific instructions to P-Code, an intermediate representation enabling cross-architecture analysis. Custom P-Code injection allows modeling of unknown instructions or obfuscated operations.

## Workflow

### Step 1: Headless Analysis

```bash
# Create project and import binary
analyzeHeadless /tmp/ghidra_projects MalwareProject \
  -import sample.exe \
  -postScript AnalyzeStrings.java \
  -postScript ResolveImports.java \
  -scriptPath /opt/ghidra_scripts

# Batch analyze multiple samples
for f in samples/*.exe; do
  analyzeHeadless /tmp/ghidra_projects BatchProject \
    -import "$f" \
    -postScript ExportFunctions.py \
    -deleteProject
done

# Export decompiled C code
analyzeHeadless /tmp/ghidra_projects MalwareProject \
  -process sample.exe \
  -postScript DecompileAll.py \
  -noanalysis
```

### Step 2: Ghidra Script — Function Analysis

```python
# Ghidra Python script: identify_suspicious_functions.py
# Run inside Ghidra's Script Manager or via headless analyzer

from ghidra.program.model.symbol import SourceType
from ghidra.app.decompiler import DecompileInterface

SUSPICIOUS_APIS = [
    "VirtualAlloc", "VirtualAllocEx", "VirtualProtect",
    "CreateRemoteThread", "NtCreateThreadEx",
    "WriteProcessMemory", "NtWriteVirtualMemory",
    "WinExec", "ShellExecuteA", "ShellExecuteW",
    "CreateProcessA", "CreateProcessW",
    "URLDownloadToFileA", "InternetOpenA",
    "CryptEncrypt", "CryptDecrypt",
    "RegSetValueExA", "RegSetValueExW",
]

def find_suspicious_calls():
    """Find functions calling suspicious APIs."""
    fm = currentProgram.getFunctionManager()
    ref_mgr = currentProgram.getReferenceManager()
    results = []

    for func in fm.getFunctions(True):
        body = func.getBody()
        refs = ref_mgr.getReferencesFrom(body.getMinAddress(), body.getMaxAddress())

        called_apis = []
        iter = body.getAddresses(True)
        while iter.hasNext():
            addr = iter.next()
            for ref in ref_mgr.getReferencesFrom(addr):
                target_func = fm.getFunctionAt(ref.getToAddress())
                if target_func and target_func.getName() in SUSPICIOUS_APIS:
                    called_apis.append(target_func.getName())

        if called_apis:
            results.append({
                "function": func.getName(),
                "address": str(func.getEntryPoint()),
                "suspicious_calls": list(set(called_apis)),
            })
            println(f"[!] {func.getName()} @ {func.getEntryPoint()} calls: {', '.join(set(called_apis))}")

    return results

find_suspicious_calls()
```

### Step 3: Decompile and Analyze Key Functions

```python
# Ghidra script: decompile_function.py
from ghidra.app.decompiler import DecompileInterface, DecompileOptions

def decompile_at(address_str):
    """Decompile function at given address."""
    decomp = DecompileInterface()
    decomp.openProgram(currentProgram)

    addr = currentProgram.getAddressFactory().getAddress(address_str)
    func = currentProgram.getFunctionManager().getFunctionContaining(addr)
    if not func:
        println(f"No function at {address_str}")
        return

    result = decomp.decompileFunction(func, 60, monitor)
    if result.decompileCompleted():
        println(f"=== {func.getName()} @ {func.getEntryPoint()} ===")
        println(result.getDecompiledFunction().getC())
    else:
        println(f"Decompilation failed: {result.getErrorMessage()}")

    decomp.dispose()
```

### Step 4: String Decryption Script

```python
# Ghidra script: decrypt_xor_strings.py
from ghidra.program.model.mem import MemoryAccessException

def find_xor_encrypted_strings(xor_key):
    """Find and decrypt XOR-encoded strings in the binary."""
    memory = currentProgram.getMemory()
    listing = currentProgram.getListing()
    results = []

    # Search data sections for encrypted strings
    for block in memory.getBlocks():
        if not block.isInitialized():
            continue
        if block.getName() in [".text", ".plt"]:
            continue

        start = block.getStart()
        end = block.getEnd()
        size = end.subtract(start) + 1

        if size > 0x100000:  # Skip sections > 1MB
            continue

        data = bytearray(size)
        try:
            memory.getBytes(start, data)
        except MemoryAccessException:
            continue

        # XOR decrypt and look for printable strings
        decrypted = bytes([b ^ xor_key for b in data])
        i = 0
        while i < len(decrypted):
            # Find runs of printable ASCII
            j = i
            while j < len(decrypted) and 0x20 <= decrypted[j] <= 0x7e:
                j += 1
            if j - i >= 6:  # Minimum string length
                s = decrypted[i:j].decode("ascii")
                addr = start.add(i)
                results.append((str(addr), s))
                println(f"[+] {addr}: {s}")
                # Add comment in Ghidra
                listing.setComment(addr, 0, f"Decrypted (XOR 0x{xor_key:02x}): {s}")
            i = j + 1

    return results

# Try common XOR keys
for key in [0x55, 0xAA, 0xFF, 0x37, 0x42]:
    println(f"\n--- Trying XOR key 0x{key:02x} ---")
    results = find_xor_encrypted_strings(key)
    if results:
        println(f"Found {len(results)} strings with key 0x{key:02x}")
```

### Step 5: Control Flow Graph Export

```python
# Ghidra script: export_cfg.py
from ghidra.program.model.block import BasicBlockModel

def export_function_cfg(func_name):
    """Export function control flow graph as DOT format."""
    fm = currentProgram.getFunctionManager()
    func = None
    for f in fm.getFunctions(True):
        if f.getName() == func_name:
            func = f
            break

    if not func:
        println(f"Function {func_name} not found")
        return

    bbm = BasicBlockModel(currentProgram)
    blocks = bbm.getCodeBlocksContaining(func.getBody(), monitor)

    println(f"digraph {func_name} {{")
    println("  node [shape=box];")
    block = blocks.next() if blocks.hasNext() else None
    while block:
        addr = str(block.getMinAddress())
        println(f'  "{addr}" [label="{addr}"];')
        dests = block.getDestinations(monitor)
        dest = dests.next() if dests.hasNext() else None
        while dest:
            target = str(dest.getDestinationAddress())
            println(f'  "{addr}" -> "{target}";')
            dest = dests.next() if dests.hasNext() else None
        block = blocks.next() if blocks.hasNext() else None
    println("}")
```

## Detection

```yaml
title: Reverse Engineering With Ghidra Detection
id: c5a10a09-5cc1-405e-9306-baff73669798
status: experimental
description: Detects suspicious activity related to reverse engineering with ghidra techniques in malware analysis context
logsource:
  category: process_creation
  product: windows
detection:
  selection:
    CommandLine: "*reverse*engineering*"
  condition: selection
level: high
tags:
  - attack.t1587.001
  - attack.execution
falsepositives:
  - Sandbox detonation environments analyzing submitted samples
```


**Detection Opportunities**

| Indicator | Source | Detection Logic |
|---|---|---|
| Reverse Engineering With Ghidra Detection | windows/process_creation | Sigma rule (high) |
| ATT&CK Coverage | MITRE ATT&CK | T1587.001 |

## Verification

- [ ] Binary imported and auto-analysis completed
- [ ] Suspicious API calls identified and mapped to functions
- [ ] Key functions decompiled and annotated
- [ ] Encrypted strings decrypted and documented
- [ ] Control flow of critical functions understood
- [ ] C2 protocol or payload logic reconstructed
- [ ] MITRE ATT&CK TTPs mapped from observed capabilities

## References

- [Ghidra Official Documentation](https://ghidra-sre.org/)
- [Ghidra Scripting API (Java/Python)](https://ghidra.re/ghidra_docs/api/)
- [MITRE ATT&CK Software Analysis](https://attack.mitre.org/techniques/T1588/)
- [Ghidra Headless Analyzer Guide](https://ghidra.re/ghidra_docs/analyzeHeadlessREADME.html)
- [Ghidra Ninja - Reverse Engineering Tutorials](https://www.youtube.com/@ghidraninja)
