Control Flow Flattening

Control Flow Flattening aims to obfuscate the program flow by flattening it. To achieve this the transformation splits all the source code basic blocks such as function body, loops, and conditional branches, and puts them all inside a single infinite loop with a switch statement that controls the program flow. This makes the program flow significantly harder to follow because natural conditional constructs that made the code easier to read are now gone.

The following diagram is an abstract representation of what happens to control flow and is a simplification of what a Control Flow Graph (CFG) would look like before (on the left) and after (on the right) flattening the program flow to a Static Code Analysis Tool.

Original vs Flattened Code

The CFG on the left is unflattened, and because of that it is easy to pinpoint conditional statements like the red node that creates a forked path (also known as branches) to the green and orange nodes. After flattening the control flow, the CFG nodes are all in the same nesting level, switching and looping back to the black node to choose the next node to go to.

Control Flow Flattening offers parameterization, allowing it to increase the level of confusion when trying to reverse engineer it, and resilience against static code analysis.

Clones

Clones are semantically equivalent copies of basic blocks that can be executed interchangeably with their original basic blocks.

Clones

By adding these semantically equivalent clones and making the program choose randomly between them the code becomes more confusing and the program flow becomes harder to understand.

Dead Clones

Dead Clones are dummy copies of basic blocks that are never executed, but mimic and can be confused with the code that will be executed, adding up to the confusion factor.

Dead Clones

Depending on the size and complexity of the source code, Jscrambler may choose not to add dead clones if it determines whether they are needed or not, resulting in smaller code.

Opaque Steps

Opaque Steps obfuscates the switching variable, making it harder to understand what is the next switch case that will be executed.

Opaque Steps

This improves the resilience against static code analysis, as opaque steps make it harder for static code analysis to determine the next step without actually executing the code and therefore harder to reverse such a transformation back into its unflattened equivalent.

Protecting an application with Jscrambler’s Control Flow Flattening makes it really troublesome to follow the program flow making it almost impossible to understand and reverse-engineer. It allows the addition of conditional opaqueness, flattening of the control flow, and adds confusion with irrelevant code clones. Combining it with other Jscrambler protection transformations is safe and works out of the box, and will result in a even more potent and resilient protection.

Remember to test this and other transformations at https://app.jscrambler.com/ and contact us if you have any questions.