Anti-Debug Enterprise
Anti-debug makes it harder to attach a debugger to your application. Detection checks are scattered across method entry points so that removing one check doesn't disable all detection. When a debugger is detected, the process terminates immediately.
Usage
| CLI | MSBuild | Default |
|---|---|---|
| (enabled by default at Enterprise) | (enabled by default at Enterprise) | On |
--no-anti-debug | <ObfuscateNoAntiDebug>true</ObfuscateNoAntiDebug> | Disable |
Detection Layers
Two independent detection mechanisms provide defense in depth:
Layer 1: Managed Detection (All Platforms)
System.Diagnostics.Debugger.IsAttached detects managed debuggers (Visual Studio, JetBrains Rider, dnSpy). This works on Windows, Linux, and macOS, and is fully NativeAOT-compatible.
Layer 2: Native Detection (Windows)
kernel32!IsDebuggerPresent via P/Invoke detects native debuggers (WinDbg, x64dbg, OllyDbg) that operate below the managed runtime. This call is guarded by OperatingSystem.IsWindows() at runtime, so it only executes on Windows. The NativeAOT compiler statically links the P/Invoke.
How Checks Are Distributed
Rather than placing a single check in the module initializer (which an attacker could NOP out), Demeanor scatters detection calls across approximately 20% of method entry points. The selection is deterministic (based on a hash of the method index and a license-derived seed), ensuring reproducible builds.
Each check is a single call instruction at the start of the method body, calling a static method on an injected infrastructure type. That type gets renamed, its constants encrypted, and its control flow obfuscated — making it indistinguishable from application code.
Response
Environment.FailFast(null) terminates the process immediately. Unlike Environment.Exit or throwing an exception, FailFast cannot be caught, filtered, or suppressed by any exception handler. The process is gone.
NativeAOT Compatibility
All injected code uses NativeAOT-safe APIs. Debugger.IsAttached is a static property (no reflection). IsDebuggerPresent is a P/Invoke that the AOT compiler statically links. OperatingSystem.IsWindows() allows the linker to trim the native call on non-Windows platforms.
When to Disable
- Debugging obfuscated builds: If you need to attach a debugger to a Release build for production diagnostics, disable anti-debug for that build.
- Automated testing under debugger: Some test runners attach a debugger. Anti-debug will terminate the process. Use
--no-anti-debugfor test configurations.
Ready to protect your .NET code?