Control Flow Obfuscation Enterprise
Decompilers reconstruct if/else, for, while, and switch statements by recognizing branch patterns in IL. Demeanor breaks these patterns by flattening method bodies into a state machine driven by a switch dispatch loop, inserting opaque predicates that always evaluate the same way but cannot be determined statically.
Usage
| CLI | MSBuild | Default |
|---|---|---|
--cfg Flatten | <ObfuscateControlFlow>Flatten</ObfuscateControlFlow> | Maximum (default) |
--cfg Predicates | <ObfuscateControlFlow>Predicates</ObfuscateControlFlow> | Medium |
--cfg Reorder | <ObfuscateControlFlow>Reorder</ObfuscateControlFlow> | Light |
--no-cfg | <ObfuscateControlFlow>None</ObfuscateControlFlow> | Disable |
Before & After
YOUR CODE
public void ApplyDiscount(DiscountType type, decimal amount)
{
_discount = type switch
{
DiscountType.Percentage => _basePrice * amount / 100,
DiscountType.FixedAmount => amount,
DiscountType.BuyOneGetOne => _basePrice / 2,
_ => 0
};
}AFTER OBFUSCATION (Flatten)
void a(g a, decimal a)
{
if (1 == 0) { }
decimal num;
switch (a)
{
case (g)3:
num = this.m_a / 2m;
goto IL_0054;
case (g)1:
num = this.m_a * a /
new decimal(0x5A2E3FCA ^ 0x5A2E3FAE);
goto IL_0054;
default:
if ((0x321AE74B & -840623948) == 0)
{
num = 0m;
goto IL_0054;
}
_ = 1 + 1;
throw null;
}
IL_0054:
if (1 == 0) { }
c = num;
}Real ILSpy output. The clean switch expression is restructured with goto labels, opaque predicates (if (1 == 0), if ((0x321AE74B & ...) == 0)), and a dead throw null branch. Combined with constants encryption, the 100 divisor becomes 0x5A2E3FCA ^ 0x5A2E3FAE.
Obfuscation Levels
- Reorder — shuffles basic block order. Cheapest, smallest IL size increase.
- Predicates — adds opaque predicates (always-true/always-false conditions) plus reordering.
- Flatten — converts the method to a state machine with switch dispatch. Maximum protection, larger IL bodies. Methods that cannot be safely flattened automatically fall back to Predicates.
When to Disable
- Performance-critical inner loops — flatten adds a switch dispatch per iteration. The JIT mitigates this, but for microsecond-sensitive code consider excluding specific methods.
- Debugging — CFG-obfuscated methods are very hard to step through. Use
--no-cfgfor Debug builds.
Ready to protect your .NET code?