| name | reverse-engineering |
| description | Reverse engineer and debug binaries using Ghidra (static analysis, decompilation) and GDB (live debugging of running processes). Use when the user wants to analyze binaries, decompile functions, debug running processes, set breakpoints, or inspect memory. |
Reverse Engineering & Debugging Skill
Use Ghidra for static analysis/decompilation and GDB for live debugging of running processes.
All commands use nix shell to get the tools without installing them globally.
Ghidra Headless Analysis
Use ghidra-analyzeHeadless for static analysis without the GUI.
Import and analyze a binary
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects MyProject \
-import /path/to/binary -overwrite
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects MyProject \
-import /path/to/binary -processor x86:LE:64:default -overwrite
Run analysis scripts
Ghidra ships with many built-in scripts. Use -postScript to run them after analysis.
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects MyProject \
-process binary_name -postScript DecompileAllFunctions.java \
-noanalysis -readOnly -scriptlog /dev/stdout 2>/dev/null
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects MyProject \
-process binary_name -postScript ListFunctions.java \
-noanalysis -readOnly -scriptlog /dev/stdout 2>/dev/null
Custom Ghidra scripts (Java)
Write a custom script to extract specific information. Save as .java and pass with -postScript:
import ghidra.app.script.GhidraScript;
import ghidra.app.decompiler.*;
import ghidra.program.model.listing.*;
public class DecompileFunction extends GhidraScript {
@Override
public void run() throws Exception {
String targetName = getScriptArgs()[0];
DecompInterface decomp = new DecompInterface();
decomp.openProgram(currentProgram);
FunctionManager fm = currentProgram.getFunctionManager();
for (Function f : fm.getFunctions(true)) {
if (f.getName().contains(targetName)) {
DecompileResults res = decomp.decompileFunction(f, 30, monitor);
if (res.decompileCompleted()) {
println("=== " + f.getName() + " at " + f.getEntryPoint() + " ===");
println(res.getDecompiledFunction().getC());
}
}
}
decomp.dispose();
}
}
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects MyProject \
-process binary_name \
-postScript /tmp/ghidra_scripts/DecompileFunction.java "main" \
-scriptPath /tmp/ghidra_scripts -noanalysis -readOnly \
-scriptlog /dev/stdout 2>/dev/null
Workflow: Analyze an unknown binary
- Import:
nix shell nixpkgs#ghidra -c ghidra-analyzeHeadless /tmp/ghidra_projects Proj -import /path/to/binary -overwrite
- List functions to find interesting targets
- Decompile specific functions of interest
- Look for strings, cross-references, and data structures
GDB Live Debugging
Use GDB to attach to running processes, set breakpoints, and inspect state.
Attach to a running process
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "bt"
nix shell nixpkgs#gdb -c gdb -batch -p $(pidof process_name) -ex "bt"
Non-interactive GDB commands
Use -batch and -ex for scripted debugging:
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "thread apply all bt"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "print some_global_var"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "x/100x 0x7fff12345678"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "info threads"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "info sharedlibrary"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "info registers"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> \
-ex "break function_name" \
-ex "continue" \
-ex "bt" \
-ex "info locals"
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> \
-ex "info threads" \
-ex "thread apply all bt" \
-ex "info registers"
GDB with binary (not attached)
nix shell nixpkgs#gdb -c gdb -batch -ex "run" -ex "bt" --args ./binary arg1 arg2
nix shell nixpkgs#gdb -c gdb -batch -ex "run" -ex "bt full" -ex "info registers" --args ./binary
nix shell nixpkgs#gdb -c gdb -batch \
-ex "break main" \
-ex "run" \
-ex "step 10" \
-ex "info locals" \
-ex "bt" \
--args ./binary
GDB Python scripting
For complex analysis, use GDB's Python API:
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "python
import gdb
for thread in gdb.inferiors()[0].threads():
thread.switch()
frame = gdb.newest_frame()
print(f'Thread {thread.num}: {frame.name()} at {frame.pc():#x}')
"
Workflow: Debug a running process
- Find the process:
ps aux | grep process_name or pidof process_name
- Get overview:
sudo nix shell nixpkgs#gdb -c gdb -batch -p <PID> -ex "info threads" -ex "thread apply all bt"
- Check specific state: inspect variables, registers, memory
- Set breakpoints if needed for dynamic analysis
- Combine with Ghidra: decompile the binary to understand what functions do, then use GDB to observe runtime behavior
Combining Ghidra + GDB
- Find the binary path:
readlink -f /proc/<PID>/exe
- Import into Ghidra for static analysis: understand the code structure
- Use GDB to observe runtime behavior: set breakpoints at interesting functions found in Ghidra
- Cross-reference: Ghidra gives you function names and decompiled code, GDB shows you actual runtime values
Tips
- Ghidra headless output goes to scriptlog; use
-scriptlog /dev/stdout to capture it
- Use
-noanalysis -readOnly when running scripts on already-analyzed projects
- GDB
-batch mode is essential for non-interactive use — it runs commands and exits
sudo is typically needed for GDB to attach to processes you don't own
- Check
/proc/sys/kernel/yama/ptrace_scope if attach fails (set to 0 for debugging)