Last updated on: October 24th, 2019
Last time, on Jscrambler 101 — Self Defending, we covered using Self Defending and its anti-tampering and anti-debugging capabilities.
This time, we’re going to talk about Control Flow Flattening.
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's 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 the 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. It depicts 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 with a Static Code Analysis Tool.
The CFG on the left is unflattened and, because of that, it’s easy to pinpoint conditional statements like the red node that creates a forked path (also known as branches) to the green and orange nodes. We can see that, after flattening the control flow, the CFG nodes are all on 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 are semantically equivalent copies of basic blocks that can be executed interchangeably with their original basic blocks.
By adding these semantically equivalent clones and making the program choose randomly between them, we are adding up to the confusion and making the program flow harder to understand.
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.
Depending on the size and complexity of the source code, Jscrambler may choose not to add dead clones if it determines that they aren’t needed. This will result in smaller code.
Opaque Steps obfuscates the switching variable, making it harder to understand what's the next
switch case that’ll be executed.
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. Therefore, reversing such a transformation into its unflattened equivalent becomes much harder.
Summing up, protecting your 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.
This allows you to add conditional opaqueness, flattening the control flow, and adding confusion with irrelevant code clones. Combining it with other Jscrambler protection transformations is safe and works out of the box, and will result in an even more potent and resilient protection.
Also, remember to test it out on the Jscrambler Web App.
Feel free to proceed to one of our other 101 Tutorials:
- Jscrambler 101 — First Use
- Jscrambler 101 — Code Annotations (Code Performance)
- Jscrambler 101 — Self Defending
- Jscrambler 101 — Code Locks
- Jscrambler 101 — How to use the CLI
- Jscrambler 101 — Source Maps
- Jscrambler 101 — Countermeasures
- Jscrambler 101 — Self-Healing
- Jscrambler 101 — Profiling (Code Performance)
- Jscrambler 101 — App Classification
- Jscrambler 101 — Memory Protection
- Jscrambler 101 — SIEM Integration
Enjoy your testing and start protecting your Applications ASAP! If you have any additional questions, feel free to contact us.