LAB-07Medium
Decompiler Output
Match decompiler pseudocode to the underlying assembly and verify the logic.
15 min5 prerequisites5 tools
Disassembly
00: mov eax, 5
01: add eax, 3
02: sub eax, 1
03: imul eax, eax, 4
04: cmp eax, 28
05: jne fail
06: mov ebx, 1
07: ret
08: mov ebx, 0
09: ret Hints
Hint 1
((5 + 3) - 1) * 4 = ?
Hint 2
JNE jumps when ZF = 0, i.e. when the comparison is NOT equal.
Hint 3
Trace: 5 + 3 = 8, 8 - 1 = 7, 7 * 4 = 28.
Submit Findings
Solution
Decompiler Output — Solution
The assembly computes ((5 + 3) - 1) * 4 = 28:
- EAX after
imul= 28. cmp eax, 28→ equal → ZF=1 →jne failis not taken, so execution falls through tomov ebx, 1— the success branch.- The decompiler would render this as
if (eax == 28) { result = 1; } else { result = 0; }.
Key lesson: the decompiler recovered the branch correctly, but the meaning (why 28?) still requires you to read the constants and reason about intent. Pseudocode orients you; the assembly confirms.
Prerequisites
- sa5-decompilation
- a2-arithmetic-logic
- a3-control-flow
- Ghidra decompiler basics
- C syntax reading
Methodology
Investigation Methodology
1. Read Assembly Line by Line
Trace register values:
mov eax, 5→ EAX = 5add eax, 3→ EAX = 8sub eax, 1→ EAX = 7imul eax, eax, 4→ EAX = 7 * 4 = 28cmp eax, 28→ 28 - 28 = 0 → ZF = 1jne fail→ ZF=1 → NOT taken- Fall through:
mov ebx, 1→ EBX = 1 ret→ return 1 (success)
2. Map to High-Level Logic
The decompiler shows:
int check() {
int x = ((5 + 3) - 1) * 4;
if (x == 28) return 1;
return 0;
}
3. Verify Decompiler Accuracy
- Check: Does decompiler match assembly control flow?
- Check: Are constants correct? (28 = literal)
- Check: Are variable names meaningful? (x, result)
- Check: Is branch direction correct? (jne = jump if NOT equal)
4. Common Decompiler Artifacts
- Goto statements: Irreducible control flow
- Stack variables:
local_8,local_10→ rename based on use - Type inference: May guess wrong (int vs pointer, signed vs unsigned)
- Inlined functions: May appear as straight-line code
- Optimized patterns:
leafor multiply,xorfor zero, etc.
5. Cross-Reference Assembly ↔ Pseudocode
- Click variable in decompiler → highlights in assembly
- Click instruction in assembly → highlights in decompiler
- Use this bidirectional navigation to verify
Common Pitfalls
- Trusting decompiler output blindly — always verify critical logic in assembly
- Missing that `jne` jumps when NOT equal (ZF=0), not when equal
- Misreading `imul eax, eax, 4` as `eax *= 4` vs `eax = eax * 4` (same here, but 3-operand form allows different destination)
- Overlooking that decompiler may simplify constants (e.g., show `28` directly)
- Confusing signed vs unsigned comparisons (`jl` vs `jb`, `jg` vs `ja`)
Tools
- Ghidra Decompiler (F5)
- Binary Ninja Decompiler (IL/MLIL/HLIL)
- IDA Pro Hex-Rays Decompiler
- retdec (open-source)
- snowman (open-source)
References
- Lesson SA5: Decompilation
- Lesson A2: Arithmetic & Logic
- Lesson A3: Control Flow
- Ghidra Decompiler User Guide
- Hex-Rays Decompiler Documentation
Extensions & Challenges
- Decompile a real function from a malware sample, trace one variable through
- Find a case where Ghidra decompiler is wrong (type, control flow, variable merge)
- Write a Ghidra script to auto-rename variables based on API arguments
- Compare decompiler output across Ghidra, Binary Ninja, IDA for same function