Know what breaks before you obfuscate.
Run demeanor audit against a compiled assembly. Demeanor tells you in plain language what’s safe, what breaks, and what to change — before a single byte is rewritten.

Obfuscation tuned to your app — not a generic pass.
Most .NET obfuscators run a transformation pass, write a new DLL, and hand it back. If it crashes at runtime, that becomes a debugging problem you own — for days. Demeanor works the other way around: it reads your assemblies first, tells you which constructs in your code would break, which Demeanor already handles, and what to change for tighter protection. You start the obfuscation run knowing what’s going to happen.
- Run a fixed transformation pass on your assembly.
- Treat every codebase the same — no awareness of your reflection, serialization, or framework patterns.
- Ship the output. Good luck.
- If it breaks at runtime, the debugging is on you — often through obfuscated stack traces.
- Every edge case means trial-and-error exclusions, another build, another crash.
- Analyzes your app first.
demeanor auditscans every assembly and surfaces the constructs that are problematic for obfuscation. - Tells you what’s safe, what isn’t, and why. Classifies each finding as auto-handled, needs an exclusion, or needs a code change — with the exact file and line.
- Recommends fixes. Shows the specific
[Obfuscation]attribute, CLI flag, or code alternative that would make the construct obfuscation-compatible. - You approve the work upfront. No surprise crashes after the fact.
- Then obfuscates — correctly, the first time.
What the decompiler sees.
Your code in, three outputs back — the original, Community-tier renaming, and Enterprise-tier full protection. Each panel is real ILSpy output.
public class PricingEngine
{
private readonly decimal _baseDiscount;
private decimal _lastTotal;
public decimal DiscountRate => _baseDiscount;
public string EngineName => "Standard";
public event EventHandler<decimal>? PriceChanged;
public decimal CalculateTotal(int quantity, decimal unitPrice)
{
var subtotal = ComputeSubtotal(quantity, unitPrice);
var discount = ApplyDiscount(subtotal);
var total = subtotal - discount;
_lastTotal = total;
NotifyPriceChanged(total);
return total;
}
public decimal GetLastTotal() => _lastTotal;
private decimal ComputeSubtotal(int quantity, decimal unitPrice)
=> quantity * unitPrice;
private decimal ApplyDiscount(decimal subtotal)
=> subtotal * _baseDiscount;
private void NotifyPriceChanged(decimal total)
=> PriceChanged?.Invoke(this, total);
public override string ToString()
=> $"PricingEngine(discount={_baseDiscount})";
public override bool Equals(object? obj)
=> obj is PricingEngine p && _baseDiscount == p._baseDiscount;
public override int GetHashCode() => _baseDiscount.GetHashCode();
}public class PricingEngine
{
private readonly decimal m_a;
private decimal b;
private EventHandler<decimal>? c;
public decimal DiscountRate => m_a;
public string EngineName => "Standard";
public event EventHandler<decimal>? PriceChanged;
decimal a(int a, decimal a) => (decimal)a * a;
decimal a(decimal a) => a * m_a;
void a(decimal a) => c?.Invoke(this, a);
public decimal CalculateTotal(int quantity, decimal unitPrice)
{
decimal num = a(quantity, unitPrice);
decimal num2 = a(num);
decimal num3 = (b = num - num2);
a(num3);
return num3;
}
public decimal GetLastTotal() => b;
public override string ToString()
=> $"PricingEngine(discount={m_a})";
public override bool Equals(object? obj)
=> obj is PricingEngine p && m_a == p.m_a;
public override int GetHashCode() => m_a.GetHashCode();
}Public API preserved for compatibility. Internal helpers all collapse to a — three methods, three parameters per method, all named the same. Real ILSpy output.
public class a
{
private decimal m_a;
private decimal m_b;
private EventHandler<decimal> m_c;
decimal () => this.m_a;
string () => b.a("\u0003\r\u00cd\u00c60\u001c\u00c2\u00c8");
decimal (int a, decimal a)
{
decimal num = (a, a);
decimal num2 = (num);
decimal result = (this.m_b = num - num2);
(result);
return result;
}
decimal () => this.m_b;
decimal (int a, decimal a) => (decimal)a * a;
decimal (decimal a) { d.a(); return a * this.m_a; }
void (decimal a) => this.m_c?.Invoke(this, a);
public virtual string a() { /* control-flow obfuscated */
return b.a("\u00df\u0094\u001f\u00df..."); }
public virtual bool b(object a) { d.a(); /* control-flow obfuscated */ }
public virtual int c() { d.a(); return this.m_a.GetHashCode(); }
}Type renamed. Method names use Unicode glyphs the C# parser cannot read. Strings encrypted. Anti-tamper and anti-debug active. Control flow obfuscated. Real ILSpy output.
Build succeeded.
0 errors.CS0100: The parameter name 'a' is a duplicate
CS0111: Type 'PricingEngine' already defines a member called 'a'
Build FAILED. 2 errors.CS1001: Identifier expected
CS1525: Invalid expression term 'decimal'
CS1003: Syntax error, ',' expected
CS1002: ; expected
CS0106: The modifier 'public' is not valid for this item
Build FAILED. 47 errors.