I recently heard about the "control-flow flattening" obfuscation which seems to be is used to break the structure of the CFG of the binary program (see Diablo obfuscation module and Symbolic Execution and CFG Flattening).

Can somebody make an explanation of what is its basic principle and, also, how to produce such obfuscation (tools, programming technique, ...) ? And, it would be nice to know if there are ways to extract the real shape of the control-flow of the program.


2 Answers 2


For a good example of this obfuscation, check Apple's FairPlay code, e.g. iTunes or iOS libs. Here's a typical graph of a function which had this obfuscation applied:

enter image description here

As you can see, all edges between basic blocks - both conditional and unconditional - has been redirected to a dispatcher node which uses a new artificial variable to decide which block should be jumped to next. This variable is updated at the end of each separated basic block.

Here's the dispatcher node:

LDR    R3, =0xF26A85D2
ADD    R3, R2, R3
CMP    R3, #0x40 ; switch 65 cases
ADDLS  PC, PC, R3,LSL#2 ; switch jump

It uses R2 as the control value.

And here's one of the basic blocks:

LDR  R2, =0x853FD863 ; jumptable 00532EFC case 33
LDR  R1, [SP,#0x130+var_108]
STR  R2, [SP,#0x130+var_134]
LDR  R2, =0xD957A31
STR  R1, [SP,#0x130+var_44]
B    loc_532ED0

It updates R2 with the value which will be used to jump to the next block.

Recovering it shouldn't be too difficult in most cases - just track the control variable updates and replace jumps to the dispatcher node with jumps to the next block corresponding to the new control variable value.

  • How do you edit the assembly without changing the actual binary? Jun 10, 2013 at 20:00
  • 2
    @heinrich5991 In IDA we have the ability to make changes to the assembly representation of the binary we analysing, without changing the actual binary, then within IDA we can save this representation for later use.
    – nomilk
    Jun 10, 2013 at 20:08

From this paper by Timea Laszlo and Akos Kiss :

The basic method for flattening a function is the following.

First, we break up the body of the function to basic blocks, and then we put all these blocks, which were originally at different nesting levels, next to each other.

The now equal-leveled basic blocks are encapsulated in a selective structure (a switch statement in the C++ language) with each block in a separate case, and the selection is encapsulated in turn in a loop.

Finally, the correct flow of control is ensured by a control variable representing the state of the program, which is set at the end of each basic block and is used in the predicates of the enclosing loop and selection.

Image showing how control-flow flattening obfuscation alters code that contains loop structures.
enter image description here

A simple example:

int original()
    print "Do"
    print "you"
    print "like"
    print "milk?"

int obfuscated()
    int ctrFlowVar = 1;

    while(ctrFlowVar != 0)
            case 1:
                print "do"
                ctrFlowVar = 2;
            case 2:
                print "you"
                ctrFlowVar = 3;
            case 3:
                print "like"
                ctrFlowVar = 4;
            case 4:
                print "milk?"
                ctrFlowVar = 0;

If you are familiar with how switch statements are written in assembly (i know 2 ways, the if-style and the jumptable one) then the above example is easy to de-obfuscate.The break; instruction is a jmp.You could make it jump to the block thats supposed to be next.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.