Static Analysis for Reverse Engineering
How to analyze binaries without running them - tools, techniques, and a methodology for CTF RE challenges.
Static Analysis for Reverse Engineering
Static analysis means examining a binary without executing it. It's always the first step — it's safe, doesn't require the right OS/architecture, and often reveals enough to solve the challenge outright. A surprising number of CTF challenges have the flag hardcoded in the binary, visible with just strings.
Why Static Analysis First?
- Safe: no risk of running malicious code
- Architecture-independent: analyze ARM on x86
- Often sufficient: flags hardcoded, XOR encoded with visible key, comparison visible in disassembly
- Informs dynamic analysis: know what to breakpoint before running
Run strings | grep -i flag before anything else. A surprising number of CTF challenges have the answer right there in the binary.
Systematic Static Analysis Approach
Basic Recon: Identify the Binary
file ./challenge
# Examples:
# ELF 64-bit LSB executable, x86-64, dynamically linked, not stripped
# PE32 executable (console) Intel 80386, for MS Windows
# data ← unrecognized, possibly encrypted or packed
strings ./challenge | grep -iE "(flag|ctf|key|pass|secret|correct|wrong)"
strings -e l ./challenge # UTF-16 (Windows)
xxd ./challenge | head -20 # raw hexELF Inspection (Linux Binaries)
readelf -S ./challenge # list sections
readelf -s ./challenge # list symbols
nm ./challenge # symbol table
ldd ./challenge # dynamic dependencies
objdump -d -M intel ./challenge | grep -A 80 "<main>:"Check Protections
checksec --file=./challenge| Flag | Meaning | Bypass Approach |
|---|---|---|
No canary | No stack cookie | Direct overflow to return addr |
NX enabled | Stack/heap not executable | Use ROP/ret2libc |
No PIE | Fixed binary addresses | No leak needed |
Stripped | No symbol names | Functions named sub_XXXXXXXX |
Ghidra Deep Dive
Ghidra transforms machine code into readable C-like pseudocode.
- Launch Ghidra → New Project → Import the binary
- Auto-analyze: accept all defaults → click Analyze
- Wait for analysis (progress bar at bottom right)
- Open CodeBrowser → Window → Defined Strings → search for flag/correct/wrong
- Double-click a string → right-click → References → find where it's used
- Navigate to the function → read the decompiled logic
Unpack if Packed
file ./challenge | grep -i upx
upx -d ./challenge -o ./challenge_unpackedGhidra vs Radare2 vs IDA
Best for: General CTF work, scripting, unfamiliar architectures
- Free and open source
- Excellent decompiler — competes with IDA Pro
- Handles x86, ARM, MIPS, PPC, SPARC, and more
- Python + Java scripting API
Workflow: Import → Auto-analyze → Symbol Tree → Defined Strings → DecompileRecognizing Common Patterns
Ghidra Navigation Shortcuts
| Key | Action |
|---|---|
G | Go to address or function name |
L | Rename label/variable |
Ctrl+L | Retype variable |
X | Show cross-references |
; | Add comment |
Ctrl+D | Bookmark current address |
| Window → Defined Strings | All strings in the binary |
| Window → Decompile | C pseudocode of current function |
Checklist
-
file ./binary→ architecture, stripped?, linked? -
checksec --file=./binary→ what protections exist? -
strings | grep -i flag→ quick win: hardcoded flag? -
readelf -s/nm→ are symbols present? find interesting functions - Ghidra: import → analyze → browse Symbol Tree → Defined Strings
- Rename variables in Ghidra until code makes sense
- Look for: strcmp, memcmp, XOR loops, encoding/decoding functions
- Extract arrays/constants → decode in Python
- Packed? →
upx -dfirst, then re-analyze
Last updated on