Binary Reverse Engineering with Ghidra: Disassembly, Decompilation, and Patching
A beginner-friendly guide to analyzing compiled executables, understanding assembly instructions, and finding hidden logic.
1. The Decompilation Pipeline
When developers write C, C++, or Rust code, the compiler optimizes and transforms human-readable text into raw CPU opcodes.
Disassemblers convert machine opcodes back into human-readable assembly instructions. Ghidra goes a major step further: its decompiler analyzes control flow graphs and variable lifetimes to reconstruct legible C pseudo-code.
2. Essential x86-64 Assembly Fundamentals
`MOV RAX, RBX`: Copies the 64-bit value from RBX into RAX.
`CMP RAX, 0`: Compares the value in RAX with 0 and sets CPU status flags (Zero Flag, Sign Flag).
`JE / JZ (Jump if Equal / Zero)`: Jumps to target memory address if the Zero Flag is set.
`CALL` and `RET`: Manages subroutine execution and stack frame allocation.
3. Triage in the Ghidra GUI
1. Import the target binary (`File -> Import File`) and select automatic analysis.
2. Navigate to `Window -> Defined Strings`. Search for keywords like 'password', 'key', 'error', or 'success'. Double-clicking a string transports you to its reference in the Program Listing.
3. Inspect the Decompiler window: Ghidra displays real-time C pseudo-code synchronized with your assembly cursor.
// Ghidra Decompiled Pseudo-Code Example
undefined8 validate_license(char *input_key) {
int result;
result = strcmp(input_key, "CYBERLIUM-SECRET-KEY-2026");
if (result == 0) {
puts("Access Granted!");
return 1;
}
puts("Access Denied!");
return 0;
}4. Binary Patching Practice
In reverse engineering challenges, analysts patch conditional jump instructions (`JZ` to `JNZ` or replacing instructions with `NOP` opcodes: `0x90`) to bypass authentication checks without knowing the password.