Obfuscationadvanced
Control-Flow Flattening
Replacing a function's natural branching with a single dispatcher loop driven by a state variable, destroying the original control-flow graph that decompilers rely on.
Control-flow flattening rewrites a function into a while (state) switch (state)
dispatcher. Every original basic block becomes a case that computes the next
state value, so the decompiler sees one giant loop instead of the real CFG.
Shape
int state = 0x1A2B;
while (state != DONE) {
switch (state) {
case 0x1A2B: /* block A */ state = cond ? 0x77F0 : 0x0C31; break;
case 0x77F0: /* block B */ state = 0x4ED2; break;
/* ... */
}
}Recovering the original flow
- Symbolic execution of the dispatcher recovers the state-transition graph (e.g. D-810, HexRaysDeob, or custom miasm/Triton scripts).
- Identify the state variable feeding the
switch, enumerate reachable case values, then stitch blocks back into a real CFG. - Frequently paired with opaque predicates to make the transitions harder to constant-fold.
Votes