Performance & Tuning
Control flow obfuscation trades a little runtime for protection. The lightweight algorithms are essentially free; the flattening algorithms add a dispatcher that runs on every call and therefore cost more. This page compares the algorithms, explains the iterations setting, and shows how to keep hot methods fast.
Comparing the Algorithms
| Algorithm | Family | Relative runtime cost | Verifiable IL | Edition |
|---|---|---|---|---|
if | Lightweight | Negligible | Yes | All |
goto | Lightweight | Negligible | Yes | All |
switch | Flattening | High | Yes | All |
case | Flattening (with switch) | High | Yes | All |
call | Flattening (with switch) | High | Yes | All |
value | Flattening (with switch) | High | Yes | All |
chain (Chained State) | Flattening | High (≈ switch) | Yes | Ultimate |
token | — | Low | No | All |
underflow | — | Low | No | All |
Reading the table.
ifandgotoadd branches and conditions but no dispatcher, so their runtime cost is negligible — you can apply them broadly.- The flattening family (
switch,case,call,value) andchainrebuild a method around a dispatcher. On a small method called in a tight loop tens of millions of times, a single flattening pass adds roughly an order of magnitude to that method’s per-call time. Chained State stays within a few percent ofswitchdespite being much harder to deobfuscate — the extra protection is essentially free relative to flattening itself. tokenandunderfloware cheap at runtime but produce non-verifiable IL, so Babel disables them on .NET and .NET Core.
These are worst-case figures from a micro-benchmark that does nothing but call one tiny flattened method in a loop. Most methods are not invoked in such hot loops, so the real-world impact of flattening is usually small — but it is still worth reserving flattening for the methods that matter and keeping it off hot paths.
Control Flow Iterations
The obfuscation impact of any control flow algorithm is primarily governed by the number of iterations applied to a method: the higher the count, the more complex the result — and, for the flattening algorithms, the higher the runtime cost, because each pass adds another layer of dispatch.
Babel lets you set the iteration count with --iterations <n> (or ILIterations from MSBuild). Setting it to 0 disables control flow obfuscation. There is an upper limit beyond which a given method’s flow can no longer be altered — it depends on the method’s structure — so increasing the count does not always add more instructions.
Limiting Control Flow Obfuscation
Because flattening adds branches to every method it touches, applying it indiscriminately can slow down performance-critical code. Use XML rules to limit control flow obfuscation to the methods that need it and exclude the rest — for example, compiler-generated methods, which rarely contain intellectual property worth protecting:
<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 with exclude="true", and applyToMembers="true" extends it to all members of the matching classes. The <Target> element selects the kind of element (here, Classes), <Pattern> matches their names (* = all), and <HasAttribute> restricts the match to classes carrying CompilerGeneratedAttribute.
The same approach lets you exclude any method you know to be performance-critical, so you can balance protection against speed: flatten the sensitive code, and leave the hot paths untouched.