EpochZero Learn
EpochZero LearnMulti-Domain Tech Learning Hub
Courses
LeaderboardAbout
Dashboard
EpochZero
EpochZero Learn
Multi-Domain Tech Learning Hub

Structured learning for Reverse Engineering, Cloud Security, Cryptography, and Web Development. Articles, videos, tests, and peer discussion.

Learn

  • Learning Path
  • All Articles
  • Video Lessons
  • Podcast
  • eBooks & PDFs
  • Question Banks
  • Cheatsheets
  • MCQ Banks

Tests & Forum

  • All Tests
  • REMA Tests
  • Cloud Tests
  • Forum
  • REMA Forum
  • Cloud Forum
  • Crypto Forum
  • Web Dev Forum

Campus

  • REMA Club
  • Full Stack Dev Club
  • Extension Activity
  • Events
  • CTF Competitions
  • Workshops
  • Industrial Visits

Platform

  • Dashboard
  • Leaderboard
  • About
  • Verify Certificate

© 2026 EpochZero Learn. Educational content for learning purposes.

Course Instructor: Ashish Revar

All articles
Educationassemblycfgloops

Assembly Logic Structures in the Disassembler

How if/else, for, while, and switch statements compile to x86 — recognising these patterns in IDA Pro and Ghidra to reconstruct program logic from raw disassembly.

Ashish Revar12 May 202616 min read2 views

Sign in to mark this article as read and track your progress.

Related to this topic

Continue learning

Listen

The Malicious Process Lifecycle: From Execution to Evasion

How malware executes, establishes persistence, injects into legitimate processes, and evades detection inside modern operating systems.

Reference material

eBook
REMA eBook 2026
v1.0
Open resource
Cheatsheet
REMA Cheatsheet 2026
v1.0
Open resource
MCQ Bank
REMA MCQ Bank 2026
v1.0
Open resource
Question Bank
REMA Question Bank 2026
v1.0
Open resource

External references

Compiler Explorer — See Control Flow Structures Live

Write a C function with if/else, for loop, and switch. Watch the compiler generate exactly the patterns described in this topic.

tool
IDA Pro Graph View — CFG Navigation

Press Spacebar in IDA to switch to graph view. Back-edges (upward arrows) identify loops immediately. Essential for structured analysis.

tool
REMA eBook 2026 — Chapter 3, Section 3.1

Read the full CFG diagrams for if/else, loop, and switch patterns in the REMA eBook.

ebook
More articlesTest your knowledge

Overview

High-level constructs like if/else, for, while, and switch do not exist in machine code. The compiler translates them into sequences of comparison instructions, conditional jumps, and unconditional jumps. A reverse engineer must recognise these patterns in disassembly to reconstruct the original program logic.

If / Else

An if/else block compiles into a comparison followed by a conditional jump that skips the true body and enters the false body.

/* C source */
if (eax == 0) {
    // true body
} else {
    // false body
}
; x86 assembly
    cmp  eax, 0
    jnz  else_block       ; jump when NOT equal (opposite condition)
    ; --- true body ---
    jmp  end_if
else_block:
    ; --- false body ---
end_if:

Key insight: The compiler generates a jump for the opposite condition so the true body falls through naturally. jnz (jump if not zero) is used even though the C condition is == 0.

In the CFG (Control Flow Graph)

  • True path (ZF=1, equal): falls through to the true body
  • False path (ZF=0, not equal): jumps to else_block
  • Both paths converge at end_if

Refer to REMA eBook 2026, Figure 3.1 for the CFG diagram of an if/else block.

For and While Loops

Both for and while loops compile to the same pattern: a comparison at the top and a conditional jump back to the beginning.

/* C source */
for (int i = 0; i < 10; i++) {
    buffer[i] ^= key;
}
    xor  ecx, ecx         ; i = 0
loop_start:
    cmp  ecx, 0Ah         ; i < 10?
    jge  loop_end         ; exit if i >= 10
    xor  [esi+ecx], bl    ; buffer[i] ^= key
    inc  ecx              ; i++
    jmp  loop_start
loop_end:

The back-edge — the unconditional jmp from the end of the loop body back to loop_start — is the defining feature of any loop in a CFG. In IDA Pro graph view, a back-edge points upward. Spotting upward arrows immediately identifies loops.

Pattern: XOR decryption loop

When you see a tight loop containing XOR operating byte-by-byte over a buffer (ECX as counter, ESI or EDI as buffer pointer), you are almost certainly looking at a decryption routine. Extract the key byte and buffer address to decrypt the payload statically without executing the malware.

Switch / Case

A switch statement with a small number of cases compiles into a chain of CMP/JE pairs. When the number of cases is large and values are contiguous, the compiler generates a jump table.

Jump table

    cmp  eax, 4             ; value > max case?
    ja   default_case       ; if above max, go to default
    jmp  [jump_table+eax*4] ; index into table

jump_table:
    dd   case_0
    dd   case_1
    dd   case_2
    dd   case_3
    dd   case_4

The jump table is an array of code addresses indexed by the switch variable. In IDA Pro, it appears as a block of dd offset entries in .rdata. Ghidra renders it as a switch statement in the decompiler output automatically.

Malware relevance: Malware that dispatches C2 commands frequently uses a switch on the command byte. The jump table is a direct map of the malware's command vocabulary — each entry is a handler for a specific command.

Recognising Patterns in Practice

PatternAssembly SignatureWhat It Means
If/elseCMP + Jcc + body + JMP + else bodyConditional logic
LoopCMP + Jcc (exit) + body + JMP (back)Iteration
XOR decrypt loopLoop with XOR [ESI+ECX], BLDecryption routine
Jump tableCMP + JA default + JMP [table+reg*4]Command dispatcher
Back-edge (upward arrow in CFG)Unconditional JMP to lower addressLoop of any type

CFG Obfuscation Techniques

Malware authors attempt to break the CFG using:

TechniqueEffect on Disassembler
Opaque predicatesCreates false edges to unreachable garbage code
Overlapping instructionsMisaligns subsequent disassembly
Indirect jumps (JMP EAX)Destination unknown without execution
Exception-based flowCFG misses exception-driven paths

Opaque predicate example:

    xor  eax, eax
    cmp  eax, eax       ; always equal
    jnz  garbage_code   ; NEVER taken — but disassembler does not know
    ; real code here
garbage_code:
    db   0xFF, 0xFF     ; intentionally invalid bytes

Bypass: confirm with dynamic analysis. The CPU always takes the correct path — let the debugger show you the real flow, then patch the garbage jump to a NOP in the disassembler.