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

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 = 5
  • add eax, 3 → EAX = 8
  • sub eax, 1 → EAX = 7
  • imul eax, eax, 4 → EAX = 7 * 4 = 28
  • cmp eax, 28 → 28 - 28 = 0 → ZF = 1
  • jne 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: lea for multiply, xor for 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