SuperAPI AI Directory

re-ghidra

Security & auditing

View repository

Updated 10-15 21:34

About this skill

Ghidra Reverse Engineering Workflow

When to Use / When Not to Use

  • Use: when decompilation and deep static analysis are needed; headless batch processing; scripted auto-annotation/decryption loops; full PE/ELF/Mach-O support
  • Don't use: memory <4GB (lags immediately on startup, switch to [[re-radare2]]); when only a quick initial survey is needed (go to [[re-triage]])
  • Don't use: when an IDA workflow already exists and the target is clear (choose by RE_DECOMPILER session variable)

Tool Preparation

Refer to [[re-analyze/platform-tips]]—Ghidra is the mainstay for static analysis (sandbox-free); in low-memory environments switch to [[re-radare2]] per platform experience; headless batch processing suits remote environments.

Ghidra (official installation, Java 21 required)

  • Download: GitHub NationalSecurityAgency/ghidra releases, extract and use (no installation needed)
  • JDK 21 (required by Ghidra 11.3+):
    • Linux: apt install openjdk-21-jdk / dnf install java-21-openjdk / pacman -S jdk21-openjdk
    • macOS: brew install openjdk@21 or brew install --cask temurin
    • Windows: choco install temurin21(or Oracle JDK 21)
  • Launch: ./ghidraRun(GUI)/ ./support/analyzeHeadless(headless)
  • Verify: java -version(must be 21+);./support/analyzeHeadless -help outputs normally
  • Version: 12.x is the current mainline (verified baseline 12.1.4); at install time, defer to the Latest on the official Releases; running the official release only requires JDK 21, while building Ghidra itself from source requires JDK 25 + Gradle 9.1+; 11.x → 12.x has breaking script API changes, so check the target version's javadoc before writing scripts, see [[gotchas]] for details

ghidra-bridge (Python remote control)

  • All platforms: pip install ghidra-bridge
  • Prerequisite: In the Ghidra GUI, run the Script Manager ghidra_bridge_server.py
  • Verify: python3 -c "import ghidra_bridge; print(ghidra_bridge.__version__)"

Procedure

  1. analyzeHeadless headless import + analysis:

    $GHIDRA/support/analyzeHeadless /tmp/proj sample_proj \
      -import ./sample.bin -deleteProject -log /tmp/ghidra.log
    

    Add when only creating a project without interaction -overwrite; for batch processing multiple samples, invoke in a loop. Check the log at -log, analysis completion indicator: no exceptions and the project can be re-imported.

    • -process mode (rerun scripts/analysis on files already imported into the project, choose one of two with -import ):
      $GHIDRA/support/analyzeHeadless /tmp/proj sample_proj \
        -process -postScript MyScript.java -scriptPath /tmp/scripts
      
    • Add when only doing symbols/strings/single-function decompilation -noanalysis(skips auto-analysis, completes in seconds); add for read-only review -readOnly; for the full parameter family see [[commands]]
  2. GUI: navigation/cross-references/decompilation:

    • File > Import File → select sample → Analyze(wait for the progress in the lower-left corner to complete)
    • Jump: Go To(G) enter address; the entry point is already marked in Program Trees entry
    • Cross-references: with the cursor on a function/variable press R(References window), or right-click > References > Show References To
    • Decompile: in the Listing press Ctrl+E(Decompiler window, the default shortcut may differ by version/keymap, defer to Help > Key Bindings) or right-click > Decompile Function, the decompiled view can be copied
    • Function graph: on a function press F(Function Graph) to see branch/loop structure, with synchronized navigation with the Decompiler
    • Underlined address difference: the Listing shows VA (including ImageBase), in scripts often use getAddressFactory().getDefaultAddressSpace().getAddress("0x401000")
  3. Rename + type propagation annotation:

    • Function rename: in the Listing L; variable rename: in the Decompiler L
    • Set type: right-click variable > Set Data Type (y), e.g. char *、DWORD、int (*)(int)
    • Define a struct: Data Type Manager > create a new Structure; after it is referenced in the Decompiler, type propagation automatically improves decompilation quality
    • Mark known library functions: right-click > Set Data Type + f(Function signature), improving parameter semantics at subsequent call sites
  4. Python scripts (automatic annotation, decryption loop emulation):

    # @category Analysis  — 放 GhidraScripts 目录,Script Manager 中 Run
    from ghidra.program.model.listing import CodeUnit
    fm = currentProgram.getFunctionManager()
    for f in fm.getFunctions(True):
        body = f.getBody()
        if body.getNumAddresses() > 10000:
            print("large:", f.getName(), hex(body.getMaxAddress().getOffset()))
    

    Decryption loop: after locating the XOR loop, either patch by script or compute directly:

    from ghidra.program.model.mem import *
    fm = currentProgram.getFunctionManager()
    f = fm.getFunctionAt(currentAddress)
    # 示例: 从 0x403000 起 0x100 字节异或 0x55
    addr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress("0x403000")
    for i in range(0x100):
        b = getByte(addr.add(i)) ^ 0x55
        setByte(addr.add(i), b)
    
    • Make a copy before changing bytes:setByte writes directly to the current Program (saving modifies the original file) — when analyzing malicious samples you must first copy the Program (File > Save As save a copy as) or operate on a temporary copy; never patch the original sample directly, otherwise you destroy the chain of evidence Headless batch: analyzeHeadless ... -postScript MyScript.java -scriptPath <dir>
  5. Export decompiled C:

    • File > Export Program → choose format C/C++, exporting the entire decompilation tree
    • or in the Decompiler window, per function Copy to notes
    • What is exported is the decompilation result, not recovered original source code: variable names/type inference may be wrong (they improve only after renaming), and do not represent the original implementation — use it only as a reading aid; key logic must be verified against the disassembly/Listing
    • After export, verify: unsigned function names in the C retain comments (function addresses); compare against the original Listing

Function analysis context checklist

Before analyzing each function, first collect (see the context checklist in [[re-analyze/analysis-contract]]): xrefs (who references it/who it references), strings referenced by the target function, caller/callee signatures, the named symbol table, and recovered structs. Provide everything at once before analyzing to avoid repeatedly digging through xrefs; proactively request additional evidence with no more than 8 tool calls per function.

Single-function deep analysis order

Proceed through the five steps of the “Single-function deep analysis order” in [[re-analyze/analysis-contract]] (types → constants → vtables → identity → decompilation; do not skip steps, and do not decompile first and work backward). Corresponding operations in Ghidra: for types use Type Manager / Apply Function Signature, for vtables use vtable analysis, and for symbol/constant evidence you can use readelf / strings / objdump exports as aids.

Cross-domain combination

  • [[re-address-space]]: converting between Ghidra base addresses and runtime addresses (load bias)

  • [[re-binary-core]]: the default decompiler for step 5 of the workflow

  • [[re-malware]]: deep analysis of malicious samples (obfuscated script annotation)

  • [[re-ctf]]: the main tool for reverse engineering challenges

  • [[re-firmware]]: decompiling firmware ELF components

  • [[re-mobile]]: analysis of App .so libraries

  • Works with [[re-format-pe]] / [[re-format-elf]] / [[re-format-macho]] to read structures; in low-memory environments use [[re-radare2]]

Common pitfalls and traps

  • Automatic analysis misses obfuscated code: junk instructions/misordered code sections may not be disassembled — manually select the section and press C(code) to force marking, and if necessary fix function boundaries (right-click > Create Function)

  • Startup fails due to Java version mismatch: if it reports UnsupportedClassVersionError → confirm java -version is 21+, andJAVA_HOME points to the correct JDK

  • Lag when memory is <4GB: analyzing a large binary exhausts memory → switch to [[re-radare2]] or reduce the analysis scope (-analysisTimeoutPerFile)

  • Headless default analysis options differ from the GUI (some optional items are missing) → use -postScript to explicitly execute the analysis script and ensure consistency

  • Automatic analysis of large files hangs: Symptom — after importing a large binary, automatic analysis does not finish for a long time / the interface hangs; Cause — the triggers for large-file hangs = indirect call explosion / large C++ RTTI / obfuscated control flow / large data segments; Countermeasure — first reduce the scope of automatic analysis (limit/turn off indirect call and RTTI analysis options), prioritize locating entry points/strings/cross-references, and then gradually expand, see [[re-analyze/platform-tips]] static-first principle

  • Abnormal function boundaries → check for decompilation illusions: Symptom — in the decompiled view, functions are incorrectly split/merged, fake parameters or stack variables are disordered, the function body looks like junk data, and analyzing accordingly yields absurd logic; Cause — handwritten assembly, obfuscated code, tail calls (tail call causes adjacent functions to be incorrectly merged), and no frame pointer (not using rbp/ebp distorts frame inference) cause the decompiler's boundary and frame inference to err; Countermeasure — first check the Listing assembly against the real bytes, and follow C/Create Function to manually correct boundaries; for functions with tail calls and no frame pointer, take the assembly semantics as authoritative and do not fully trust the decompiler output (see [[re-binary-core]] analysis methodology R4)

  • The built-in script interpreter is Jython 2.7, not Python 3: Symptom — the script reports SyntaxErroras soon as it runs (f-string/walrus operator) or ImportError(cannot find third-party libraries installed by pip); Cause — Ghidra's built-in Jython 2.7 uses Python 2 syntax and standard library, does not support Python 3 syntax, and cannot import packages installed by pip; Countermeasure — write scripts with Python 2 compatible syntax (do not use f-strings; use xrange), and when modern Python capabilities (numpy, etc.) are needed, switch to ghidra-bridge to let an external Python 3 interpreter drive the analysis (see tool preparation)

  • Improper script/extension selection → runaway automation maintenance costs: Symptom — one-off batch processing logic becomes more and more complex, manual triggering each time is annoying, or persistent automation is needed but the script is repeatedly clicked manually; Cause — the boundary between Script (script: lightweight single file, manual trigger, suitable for one-off/simple repetitive tasks) and Extension (extension: can register menus/panels/event listeners, automatically execute when the project loads, ZIP packaged for team distribution) is not clearly distinguished; Countermeasure — use scripts for simple repetitive tasks, ready to use and discard after use; only build an extension when UI integration, external service access, automatic execution on load, or standardized team distribution is needed

  • Script API is incompatible across versions: Symptom — headless script compilation fails (skipping and reporting that getPermissions()/getExecute() class methods do not exist); Cause — APIs such as MemoryBlock change between Ghidra versions (12.x is isExecute(), and method names differ across versions); Countermeasure — before writing a script, first check the current version's javadoc (with a small verification script); when compilation fails, suspect API differences first rather than business logic

  • If full analysis is too slow, use -noanalysis: when only doing symbol table/strings/single-function decompilation,analyzeHeadless -noanalysis after import the script can be used directly — symbol (including JNI exports) and string scanning do not depend on auto-analysis and complete in seconds

  • For a command quick reference (headless parameter family / GUI shortcut family / script API family), see [[commands]]; for more pitfalls with version differences, headless batch processing, and script APIs, see [[gotchas]]