How Demeanor Works

Demeanor operates on compiled .NET assemblies (DLLs and EXEs), not source code. It reads each assembly, applies layered protections, and writes a new assembly that executes identically but resists decompilation. No source-code access is required — Demeanor runs after compilation, either via MSBuild or as a standalone CLI tool.

What You Get

Every obfuscated assembly Demeanor produces has, at the Enterprise tier:

1

Unreadable identifiers

Type, method, field, property, event, and parameter names are replaced with short meaningless identifiers. Names that frameworks resolve at runtime — serialization contracts, EF Core entities, ASP.NET Core routes, data-bound properties — are detected and preserved automatically.

2

Strings that aren’t in the binary

Connection strings, API keys, error messages, and other literal text are no longer visible to a hex editor or a decompiler. The application sees the original strings only when it uses them.

3

Constants that don’t look like constants

Magic numbers, buffer sizes, protocol values, and algorithm parameters are replaced with equivalent expressions that compute the same result. The numeric value never appears in the decompiled output.

4

Encrypted embedded resources

Images, config files, and data files embedded in the assembly are compressed and encrypted; the application loads them transparently. A resource viewer sees opaque blobs.

5

Control flow a decompiler can’t reconstruct

The order and shape of operations inside each method is restructured so the original if/else, for, while, and switch patterns cannot be recovered. The decompiled output is not recompilable C#.

6

Hidden call targets

Static call-graph analysis cannot determine which methods call which. The reverser loses the ability to follow program flow without running the application.

7

Tamper detection

If the obfuscated assembly is modified after the build, the application terminates immediately. Detection is keyed to your license, so even an attacker who understands the technique cannot patch a clean copy.

8

Debugger-aware termination

Both managed and native debuggers are detected at runtime; the process exits when one attaches. Detection is layered so removing a single check does not disable the protection.

9

Disassembler refusal

The .NET SDK’s ildasm refuses to open the obfuscated assembly. Other tools see metadata that makes their analysis less reliable.

What Stays the Same

Obfuscation preserves execution semantics. The obfuscated assembly:

  • Passes the CLR verifier (peverify / ILVerify)
  • Loads in the same runtime contexts as the original
  • Has the same public API surface (unless --include-publics is used)
  • Produces the same outputs given the same inputs
  • Works with NativeAOT, ReadyToRun, and single-file publish

Features Demeanor Deliberately Omits

Some obfuscation techniques sound impressive in a feature checklist but provide little protection in practice. Demeanor focuses on transformations that permanently alter the binary and survive execution, rather than runtime tricks an attacker can bypass by running the application. The sections below explain why four commonly-advertised features are absent by design. See the FAQ for quick answers on common concerns.

Dead code injection

Dead code injection adds fake methods and branches that never execute, hoping to confuse reverse engineers. It provides no meaningful protection:

  • Automated removal. Static analysis tools like de4dot and ILSpy strip unreachable code automatically. An attacker runs one command and the injected code is gone.
  • Targeted attacks ignore it. Real attackers use cross-references to find the specific method they care about — they don’t read the entire assembly. Fake methods with no callers are invisible to that workflow.
  • NativeAOT eliminates it. With ahead-of-time compilation, the linker removes all unreferenced methods, so injected dead code never makes it into the deployed binary.
  • Binary size cost. Injecting realistic fake methods can double assembly size — a visible cost to customers with zero security return.

Demeanor’s control-flow protection achieves a stronger result by reshaping the real method bodies, so unreachable regions cannot be separated from live code by call-graph analysis.

Method body encryption

Method body encryption replaces IL with encrypted stubs and decrypts at runtime before JIT compilation. It sounds strong — a decompiler sees only stubs. The fundamental weakness is structural:

  • “Run it once and dump.” The decrypted IL must exist in memory for the JIT to compile it. An attacker hooks the JIT entry point (compileMethod), runs the application, and captures every method body as it’s decrypted. Tools that automate this have existed for over a decade.
  • Single point of failure. The decryptor is itself a method in the assembly. Find it, extract the key, and decrypt every method offline without ever running the application.
  • Incompatible with NativeAOT. The ahead-of-time compiler reads IL at build time. If the IL is encrypted stubs, it compiles the stubs — producing a broken binary.
  • Runtime cost. Per-method decryption adds latency to cold paths. Decrypt-all-at-once adds a fixed startup penalty. Either way, customers notice.

Demeanor’s existing protections — tamper detection, string encryption, constants encryption, and control-flow obfuscation — are all permanent transformations that persist in the deployed binary and cannot be reversed by running the application. Demeanor invests in protections that survive execution, not ones that are defeated by it.

Anti-dump protection

Anti-dump erases IL from memory after JIT compilation to defeat memory-dumping tools like MegaDumper and ExtremeDumper. Demeanor deliberately omits it:

  • Requires method body encryption first. Without encrypted IL bodies, the IL is on disk in the assembly file. There’s nothing to “dump” that the attacker doesn’t already have. Anti-dump only matters as a companion to method body encryption — which Demeanor also deliberately omits (see above).
  • Windows-only. Erasing loaded PE pages requires VirtualProtect — a Windows kernel API that doesn’t exist on Linux or macOS. Demeanor runs cross-platform.
  • Fragile on modern .NET. .NET 5+ changed how assemblies are mapped into memory. Older anti-dump techniques that worked on .NET Framework are unreliable on modern runtimes.
  • Meaningless for NativeAOT. AOT binaries contain no IL. There is nothing to dump and nothing to erase.
  • Arms race. Dumper authors counter each anti-dump technique within weeks. The reverser community treats anti-dump as a solved problem: attach before the eraser runs, or hook the JIT to capture methods before erasure.

Code virtualization

Code virtualization converts .NET IL into custom virtual machine bytecode that runs on an embedded interpreter. It is the strongest protection against both static and dynamic analysis — and the most complex. A few competitors offer it (Eazfuscator.NET, .NET Reactor, Babel, ArmDot). Demeanor does not currently offer code virtualization. Here’s why:

  • Incompatible with NativeAOT. The ahead-of-time compiler cannot compile custom VM bytecode to native code. Virtualized methods must be interpreted at runtime, negating the performance benefits of AOT.
  • Significant runtime overhead. Interpreted bytecode runs 10–100x slower than JIT-compiled IL. Vendors recommend virtualizing only “hot” methods (license checks, key algorithms), but selective application limits the protection surface.
  • Debugging and compatibility challenges. Stack traces become meaningless. Profilers can’t instrument virtualized methods. Exception handling behaves differently inside the VM.

Customer demand for virtualization is on the roadmap radar. If your threat model requires this level of protection, consider pairing Demeanor’s obfuscation with NativeAOT compilation — AOT eliminates IL from the deployed binary entirely, achieving a similar “no readable IL” outcome without the runtime cost of an embedded interpreter.