Reference docs: {baseDir}/references/android-re.md · {baseDir}/references/linux-re.md · {baseDir}/references/macos-re.md · {baseDir}/references/windows-re.md · {baseDir}/references/anti-re-bypass.md · {baseDir}/references/automation-scripts.md
Scripts: {baseDir}/scripts/triage.sh · {baseDir}/scripts/decompile.py · {baseDir}/scripts/strings-extract.py
Hypothesis-Driven Analysis Loop
ALL analysis follows this cycle. NEVER skip it:
FACTS → HYPOTHESIS → EXPERIMENT → RESULTS → (new FACTS)
- FACTS: Observed data from tool output, hex dumps, strings, imports.
- HYPOTHESIS: Specific, falsifiable claim (e.g., "binary uses UPX packing").
- EXPERIMENT: Run targeted tool/command to test hypothesis.
- RESULTS: Compare output against hypothesis. If confirmed → new FACTS. If refuted → new HYPOTHESIS.
- Circuit breaker: After 3 consecutive identical-result failures, STOP and escalate to human.
- Human-in-the-loop gates: ALWAYS ask before: patching binaries, writing to filesystem, executing untrusted code, modifying system state.
Phase 0: Platform Detection (AUTO-RUN FIRST)
INPUT: binary file path
│
├─ Read first 4 bytes (magic)
│ ├─ 7F 45 4C 46 → ELF → Phase 0A (Linux)
│ ├─ 4D 5A → PE → Phase 0C (Windows)
│ ├─ CE FA ED FE → Mach-O (little-endian) → Phase 0B (macOS)
│ ├─ FE ED FA CE → Mach-O (big-endian) → Phase 0B (macOS)
│ ├─ CA FE BA BE → Universal/FAT Mach-O → Phase 0B (macOS)
│ ├─ 64 65 78 0A → DEX → Phase 0D (Android DEX)
│ ├─ 50 4B 03 04 → ZIP → check for APK (AndroidManifest.xml) → Phase 0D
│ ├─ 00 61 73 6D → WASM → Phase 0E (WebAssembly)
│ ├─ 50 4B 03 04 → also check for IPA (Payload/) → Phase 0F
│ └─ unknown → entropy analysis → packed? → try identifyPacker
│
├─ Architecture detection:
│ ELF: readelf -h <bin> | grep Machine
│ PE: objdump -f <bin> | grep "machine"
│ Mach-O: otool -h <bin> | grep cputype
│ DEX: strings <bin> | grep -E "arm|x86|mips"
│
└─ Bitness: 32-bit vs 64-bit from header (ELF: EI_CLASS, PE: Machine, Mach-O: CPU_SUBTYPE)
Quick detect: file "$TARGET" && xxd -l 16 "$TARGET" | head -1
Phase 1: Triage
1A: Universal Triage (ALL platforms)
# File identification
file "$TARGET"
# Entropy (high = likely packed/encrypted)
python3 -c "
import math,sys
d=open(sys.argv[1],'rb').read(); s=len(d)
e=-sum((d.count(b)/s)*math.log2(d.count(b)/s) for b in set(d)) if s else 0
print(f'Entropy: {e:.4f}/8.0000 ({\"PACKED\" if e>7.0 else \"normal\"})')
" "$TARGET"
# String extraction
strings -a -n 4 "$TARGET" | head -500
# Size and hash
ls -la "$TARGET" && md5sum "$TARGET" && sha256sum "$TARGET"
1B: Platform-Specific Triage
| Platform | Command | Purpose |
|---|---|---|
| Linux | checksec --file="$TARGET" |
NX/PIE/RELRO/Canary/Fortify |
| Linux | readelf -h "$TARGET" |
ELF header |
| Linux | readelf -S "$TARGET" |
Section headers |
| Linux | readelf -l "$TARGET" |
Program headers |
| Linux | readelf -r "$TARGET" |
Relocations |
| Linux | readelf --dyn-syms "$TARGET" |
Dynamic symbols |
| Windows | python3 -c "import pefile;pe=pefile.PE('$TARGET');print(pe.dump_info())" |
PE analysis |
| Windows | python3 -c "import pefile;pe=pefile.PE('$TARGET');pe.dump_sections()" |
Sections |
| macOS | otool -h "$TARGET" |
Mach-O header |
| macOS | otool -l "$TARGET" |
Load commands |
| macOS | otool -L "$TARGET" |
Linked libraries |
| macOS | codesign -dv "$TARGET" 2>&1 |
Code signing |
| Android | aapt dump badging "$TARGET" |
APK info |
| Android | apktool d "$TARGET" -o apk_out |
Decode APK |
| Android | jadx "$TARGET" -d jadx_out |
Decompile |
1C: What to Look For
- High entropy (>7.0): Packed/encrypted section → Phase 4 (Anti-RE bypass)
- Missing sections: Stripped binary → use symbol recovery
- Unusual section names:
.vmp,.themida,.upx→ identify packer - Many imports: Rich functionality surface → map attack surface
- Few imports + high entropy: Packed → unpack first
- Crypto constants:
0x67452301(MD5),0x6A09E667(SHA-256),0x9E3779B9(TEA/XTEA)
Phase 2: Static Analysis
Decision Tree
Is binary native or managed?
├─ .NET CLR header? → ILSpy/dnSpy
├─ Java/DEX? → JADX → if obfuscated → de4dot (if .NET) / ProGuard deobfuscation
├─ Obj-C metadata? → class-dump + Ghidra
├─ Swift? → Ghidra (Swift support) + swift-demangle
├─ Native (ELF/PE/Mach-O)?
│ ├─ Large binary (>5MB)? → Ghidra headless (better memory handling)
│ ├─ Need scripting? → radare2/rizin (r2pipe)
│ ├─ Need emulation? → Unicorn/QEMU
│ └─ Default → Ghidra headless → radare2 for targeted analysis
└─ WASM? → wasm2wat + wasm-decompile
2A: Ghidra Headless (ALL native platforms)
$GHIDRA_HOME/support/analyzeHeadless /tmp/ghidra_proj "$(basename $TARGET)" \
-import "$TARGET" \
-postScript /dev/stdin <<'PY'
from ghidra.program.model.symbol import SymbolType
fm = currentProgram.getFunctionManager()
listing = currentProgram.getListing()
# List all functions
for func in fm.getFunctions(True):
print(f"FUNC: {func.getName()} @ {func.getEntryPoint()}")
# List imports
st = currentProgram.getSymbolTable()
for sym in st.getExternalEntryPointIterator():
print(f"IMPORT: {sym}")
# List strings
dt = currentProgram.getDataTypeManager()
for data in listing.getDefinedData(True):
if data.hasStringValue():
print(f"STRING: {data.getValue()} @ {data.getAddress()}")
PY
2B: radare2 Quick Analysis
r2 -q -c "aaa; afl; ii; iz; iS; iSS" "$TARGET"
2C: JADX (Android)
jadx "$TARGET" -d output_dir --show-bad-code
2D: ILSpy (.NET)
ilspycmd "$TARGET" > decompiled.cs
Failure Modes
| Problem | Fix |
|---|---|
| Ghidra OOM | Increase -Xmx in ghidraRun.bat/launch.properties |
| JADX fails on DEX | Try --show-bad-code or fallback to dex2jar + JD-GUI |
| radare2 misidentifies arch | Set manually: e asm.arch=arm; e asm.bits=64 |
| Stripped binary | Use function signature matching (FLIRT/FindCrypt) |
Phase 3: Dynamic Analysis
Decision Tree
Platform?
├─ Linux → GDB (+ pwndbg/GEF/PEDA)
├─ macOS → LLDB (+ Frida)
├─ Windows → x64dbg (+ ScyllaHide)
├─ Android → Frida (+ adb)
│ ├─ Rooted device? → Frida direct
│ └─ Non-rooted? → Patch APK with Frida-gadget
└─ Need cross-platform? → Frida (works on ALL)
3A: GDB (Linux)
gdb -q "$TARGET"
# With pwndbg: auto-loads context
# Key commands:
break main
run
info functions
info registers
x/20i $pc # disassemble at PC
vmmap # memory map (pwndbg)
checksec # mitigations (pwndbg)
3B: LLDB (macOS)
lldb "$TARGET"
# Key commands:
breakpoint set -n main
run
image list # loaded images
frame variable # local vars
dis -p # disassemble at PC
3C: x64dbg (Windows)
# Launch → F9 to run
# Set breakpoint: bp <address>
# Step over: F8, Step into: F7
# Command: ScyllaHide to patch anti-debug
3D: Frida (Universal)
# List processes
frida-ps -U # USB (Android)
frida-ps # Local
# Attach
frida -U -n "com.example.app" -l hook.js
# Spawn
frida -U -f com.example.app -l hook.js --no-pause
Universal Frida hook template:
// Auto-hook all methods of a class
Java.perform(function() {
var cls = Java.use("com.target.ClassName");
cls.methodName.implementation = function(arg1) {
console.log("[HOOK] methodName called with: " + arg1);
var ret = this.methodName(arg1);
console.log("[HOOK] returnValue: " + ret);
return ret;
};
});
// Native function hook (all platforms)
Interceptor.attach(Module.findExportByName(null, "open"), {
onEnter: function(args) { console.log("open(" + args[0].readUtf8String() + ")"); },
onLeave: function(retval) { console.log(" => " + retval); }
});
Phase 4: Anti-RE Bypass
Full reference: {baseDir}/references/anti-re-bypass.md
Quick Bypass Matrix
| Technique | Detection | Bypass | Tool |
|---|---|---|---|
IsDebuggerPresent |
Windows API | Patch return to 0 | x64dbg/ScyllaHide |
ptrace(PTRACE_TRACEME) |
Linux syscall | Patch syscall / LD_PRELOAD | GDB script |
sysctl PFLAG |
macOS | Patch return | LLDB/Frida |
TracerPid != 0 |
/proc/self/status |
Patch status file / Frida | Frida |
| Timing checks | rdtsc/clock() |
Patch comparison | x64dbg/LLDB |
| VM detection | CPUID/registry | Spoof responses | ScyllaHide |
| Frida detection | Port 27042/memory scan | frida-server -l 0.0.0.0:1234 |
Frida |
| Root detection | su/Superuser.apk |
Magisk Hide / Frida | Magisk |
| Code integrity | Hash checks | Patch hash verification | Hex editor |
| Packing | High entropy | Identify + unpack | See Phase 5 |
GDB Anti-Debug Bypass (Linux)
# Bypass ptrace-based anti-debug
gdb -q "$TARGET" -ex 'catch syscall ptrace' -ex 'commands 1' -ex 'set ($rax)=0' -ex 'continue' -ex 'end'
# Patch /proc/self/status TracerPid
# Use: set hook for open() + rewrite TracerPid line
Frida Anti-Debug Bypass (Universal)
// Bypass ptrace anti-debug
Interceptor.attach(Module.findExportByName(null, "ptrace"), {
onEnter: function(args) { if(args[0].toInt32() === 0) this.patch = true; },
onLeave: function(retval) { if(this.patch) retval.replace(0); }
});
// Bypass IsDebuggerPresent
Interceptor.attach(Module.findExportByName("kernel32.dll","IsDebuggerPresent"), {
onLeave: function(retval) { retval.replace(0); }
});
Phase 5: Deobfuscation
Decision Tree
Obfuscation type?
├─ Packer (UPX/ASPack/PECompact)
│ └─ Try: upx -d, or manual unpacking in debugger
├─ Control Flow Flattening
│ └─ D-810 Ghidra plugin, GOOMBA, or manual CFF reconstruction
├─ MBA Obfuscation (Mixed Boolean-Arithmetic)
│ └─ Z3 solver: simplify expressions
├─ String Encryption
│ └─ Identify decrypt function → Frida hook at decryption → dump plaintext
├─ Virtualization (VMProtect/Themida)
│ └─ VM handler identification + trace-based devirtualization
├─ Opaque Predicates
│ └─ Angr symbolic execution to prove always-true/false
└─ .NET Obfuscation
└─ de4dot (supports 30+ obfuscators)
Z3 MBA Simplification
from z3 import *
x, y = BitVecs('x y', 32)
# Example: (x | y) - (x & y) = x ^ y
expr = (x | y) - (x & y)
simplified = simplify(expr)
print(simplified) # Output: x ^ y
String Decryption via Frida
// Hook the decryption function and dump results
var decrypt = Module.findExportByName(null, "decrypt_string");
Interceptor.attach(decrypt, {
onLeave: function(retval) {
console.log("[DECRYPT] " + retval.readUtf8String());
}
});
Phase 6: Vulnerability Assessment
6A: Binary Hardening Check
# Linux
checksec --file="$TARGET"
# macOS
python3 -c "import macholibre; macholibre.check('$TARGET')" 2>/dev/null || otool -I "$TARGET"
# Windows (manual)
python3 -c "
import pefile
pe=pefile.PE('$TARGET')
flags=pe.OPTIONAL_HEADER.DllCharacteristics
print(f'NX/DEP: {bool(flags & 0x100)}')
print(f'ASLR: {bool(flags & 0x40)}')
print(f'CFG: {bool(flags & 0x4000)}')
"
6B: Symbolic Execution (angr)
import angr, claripy
proj = angr.Project("/path/to/binary", auto_load_libs=False)
# Find path to target address
state = proj.factory.entry_state()
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=0x400800, avoid=0x400900)
if simgr.found:
found = simgr.found[0]
print("Reached target! Input:", found.posix.dumps(0))
6C: Fuzzing Quick-Start
# AFL++ (Linux)
afl-cc -o target_fuzz target.c -lz
afl-fuzz -i seeds/ -o findings/ -- ./target_fuzz @@
# libFuzzer (LLVM-based)
clang -fsanitize=fuzzer -o target_fuzz target.c
./target_fuzz seeds/
Phase 7: Report Generation
Output Template
# Reverse Engineering Report: [BINARY_NAME]
## Executive Summary
- Platform: [Linux/Windows/macOS/Android]
- Architecture: [x86_64/ARM64/...]
- Binary Type: [Native/Managed/Hybrid]
- Threat Level: [Low/Medium/High/Critical]
## File Metadata
| Field | Value |
|-------|-------|
| SHA-256 | [hash] |
| Size | [bytes] |
| Format | [ELF/PE/Mach-O/DEX] |
| Compiler | [identified compiler] |
| Packed | [Yes/No - packer name] |
## Analysis Findings
### Anti-RE Techniques Detected
- [list with offsets and bypass status]
### Interesting Strings
- [URLs, IPs, paths, crypto indicators]
### Import/Export Analysis
- [suspicious APIs, network calls, file I/O]
### Vulnerability Indicators
- [buffer overflow patterns, format strings, hardcoded creds]
## IOCs
| Type | Value | Context |
|------|-------|---------|
| [IP/URL/Hash/Domain] | [value] | [where found] |
## Recommendations
1. [actionable items]
## Appendix
- [tool output, scripts used, full string list]
Quick-Reference: Phase → Tool Mapping
| Phase | Linux | Windows | macOS | Android |
|---|---|---|---|---|
| Triage | file/checksec/readelf | pefile/Die | otool/codesign | aapt/apktool |
| Static | Ghidra/r2/angr | Ghidra/IDA/ILSpy | Ghidra/class-dump | JADX/JEB |
| Dynamic | GDB/pwndbg | x64dbg/IDA | LLDB/Frida | Frida/adb |
| Anti-RE | LD_PRELOAD/patch | ScyllaHide/patch | Frida/LLDB | Magisk/Frida |
| Deobfus | D-810/angr/Z3 | de4dot/Scylla | D-810/Frida | de4dot/Frida |
| Vuln | checksec/angr/AFL | pefile/AFL | otool/angr | MobSF/drozer |
| Report | Template above | Template above | Template above | Template above |
ALWAYS consult {baseDir}/references/ for detailed commands, scripts, and edge cases.