Control Flow Obfuscation

Control flow obfuscation is a technique that aims to make it harder to understand the flow of the code by altering the structure of the program while preserving its functionality. Babel, a code obfuscation tool, achieves control flow obfuscation by modifying the if statements and loops in the code. This can involve adding extra branches or making the if statements more complex by inserting extra conditions. Babel can also insert switch instructions that are not related to the original program flow to add more confusion. The idea is to make it challenging for attackers to comprehend the logic of the code, thus making it more difficult to reverse engineer or tamper with the software.

Control Flow Algorithms

Babel Obfuscator provides several different algorithms for control flow obfuscation:

  • goto

  • if

  • switch

  • case

  • call

  • value

  • token

  • underflow

The goto algorithm inserts irrelevant branches, making the control flow more complex. The if algorithm makes if statements more complex to read by introducing additional conditions. The switch algorithm adds switch statements to the code, making the control flow less predictable. The switch statements can be made more difficult to decode when case, call and value algorithms are enabled. In fact, the case algorithm makes switch case constants less readable while the call algorithm adds variables to determine the next jump in the switch body, which are modified by calls to external methods. The value algorithm further obfuscates switch cases using the Value Encryption obfuscation feature.

The token algorithm inserts invalid metadata tokens into the control flow, while the underflow algorithm adds points to the method body where the managed stack can underflow. However, these last two algorithms make the IL not verifiable and are not recommended if the assembly should run in a fully trusted environment.

The token and underflow control flow algorithms are not compatible with the verifiable nature of .NET and .NET Core assemblies and can cause runtime errors if used. Therefore, Babel Obfuscator automatically disables these algorithms when targeting .NET or .NET Core assemblies.

Control Flow Iterations

The impact on code obfuscation of any control flow algorithm is primarily governed by the number of iterations of the algorithm applied to a method. The higher the number of iterations, the more complex and obfuscated the control flow becomes.

Babel Obfuscator provides the option to configure the number of iterations that any control flow algorithm should apply when obfuscating a method. This configuration allows for more fine-grained control over the impact of control flow obfuscation on the code.

Increasing the value may result in a greater obfuscation impact, thus making it more difficult to analyze the code. However, the number of control flow instructions that can be added to a certain method has an upper limit beyond which the control flow cannot be altered by the algorithm. This limit depends on the method's control flow structure and can vary according to the method considered. Therefore, increasing the value does not always lead to an increased number of control flow instructions added.

Invalid Opcodes Option

The "Emit Invalid Opcodes" option, available in Babel Obfuscator when running control flow obfuscation, adds additional invalid MSIL instructions code along with the instructions added for each algorithm which could make it more difficult for decompilers to reconstruct the original code. Enabling this option makes the assembly not IL verifiable and forces the CLR to run the application as a 32-bit process.

It is important to note that enabling this option is not recommended if the application needs to run in a 64-bit process or if the application is targeting .NET Core or .NET Framework, where the assembly needs to be IL verifiable to be executed. In such cases, it is best to avoid using this option.

Configuring Control Flow Obfuscation

Control Flow Obfuscation can be configured using one of three methods: Command Line, MSBuild Babel task, or Babel UI.

In addition to these configuration methods, Babel Obfuscator also allows developers to use XML rules to fine-tune the obfuscation algorithms for specific sets of methods. These rules can be used to customize the number of iterations for each algorithm, disable specific algorithms for certain methods, or enable certain algorithms only for specific methods.

This level of flexibility allows developers to create custom obfuscation configurations tailored to their specific needs and requirements.

Command Line

babel myapp.exe --controlflow goto=on --controlflow if=on --controlflow switch=on --controlflow call=on --iterations 3

The --controlflow option can be used to enable the specified algorithms, in this case, goto, if, switch and call. While the option --iterations sets the number of iterations to apply to each algorithm.

MSBuild Babel Task

<PropertyGroup>
  <ControlFlowObfuscation>goto=true;if=true;switch=true;case=false;call=true;
     value=false;token=false;underflow=false;true</ControlFlowObfuscation>
  <ILIterations>5</ILIterations>
</PropertyGroup>

<Babel ControlFlowObfuscation="$(ControlFlowObfuscation)" 
       ILIterations="$(ILIterations)" />

The ILIterations property group sets the number of iterations for control flow obfuscation algorithms.

Babel UI

To enable control flow obfuscation from the Babel UI, you need to follow these steps:

  1. Open the Babel Obfuscator UI.

  2. Load the .NET assembly that you want to obfuscate in the input grid.

  3. Navigate to "Settings" from the left-hand side panel.

  4. Under the "Control Flow" section, you can check the Obfuscate Control Flow and select the algorithms you want to use for control flow obfuscation. The available algorithms are Goto, If, Switch, Case, Call, Value, Token, and Underflow.

  5. You can also specify the number of iterations each algorithm should perform on each method under the "Iterations" section. Additionally, you can enable the insertion of invalid opcodes.

  6. Click on the "Obfuscate" button to start the obfuscation process.

Once the obfuscation is completed, you can examine the Control Flow Obfuscation statistics by opening the "Statistics" view in the Babel UI. This view provides detailed information on the obfuscation process, including the methods obfuscated, the number of control flow instructions added, and the number of iterations performed by each control flow algorithm.

The information in the Statistics view can help you fine-tune your control flow obfuscation configuration for optimal performance and security.

Limit Control Flow Obfuscation

Control flow obfuscation, eventually, could add many branch instructions, which can potentially lead to performance degradation in the obfuscated assembly. To mitigate this, Babel Obfuscator provides the ability to use XML rules to limit the application of control flow obfuscation to specific methods, reducing its impact on the overall performance of the obfuscated assembly.

For instance, one can create a rule that targets compiler-generated methods, which often do not contain any sensitive intellectual property to protect. This way, control flow obfuscation can be limited to only those methods that require it, while other methods can be excluded to minimize performance impact.

<Rules>  
  <Rule name="rule" feature="control flow" exclude="true" applyToMembers="true">
    <Target>Classes</Target>
    <Pattern>*</Pattern>
    <HasAttribute onEnclosingType="false">System.Runtime.CompilerServices.CompilerGeneratedAttribute</HasAttribute>
  </Rule>
</Rules>

This rule targets the control flow feature, exclude is set to true to exclude the matching elements from obfuscation, and applyToMembers is set to true to apply the rule to all members of the matching elements.

The <Target> element specifies the type of element to which the rule should apply (in this case, Classes). The <Pattern> element specifies a wildcard pattern to match against the names of the classes to which the rule should apply (in this case, * matches all classes). The <HasAttribute> element is used to match elements that have a specific attribute. In this case, it matches classes that have the System.Runtime.CompilerServices.CompilerGeneratedAttribute attribute, which is commonly applied to compiler-generated methods.

Overall, this rule is used to exclude control flow obfuscation on compiler-generated methods, which typically do not have any intellectual property to protect and may cause performance degradation if obfuscated. By selectively applying control flow obfuscation to specific methods or classes, the performance degradation can be minimized while still achieving the desired level of obfuscation for the sensitive code.

For example, a developer could write a rule that excludes certain methods from control flow obfuscation, such as methods that are known to be performance-critical or methods that don't contain any sensitive intellectual property. By using this kind of targeted approach, the developer can balance the tradeoff between obfuscation and performance, ensuring that their application remains fast and responsive while still protecting the most sensitive parts of their code.

Last updated