Demeanor for .NET Documentation
CLI reference, MSBuild properties, licensing, exclusions, and CI/CD integration.
Installation
CLI tool (one-time, per machine)
dotnet tool install -g Demeanor.NET Installs the demeanor command on your PATH. Includes native binaries for Windows, Linux, and Mac. To update later: dotnet tool update -g Demeanor.NET
Build integration (once per project)
dotnet add package Demeanor.NET.Build Adds MSBuild targets that automatically obfuscate your assembly on Release builds. Acquired via dotnet restore on any machine — CI agents and teammates get it automatically.
Quick Start
Install the CLI
dotnet tool install -g Demeanor.NET One-time setup. This puts the demeanor command on your PATH across Windows, Linux, and Mac.
Add Demeanor to your project
dotnet add package Demeanor.NET.Build Run once per project. This adds the MSBuild targets that obfuscate your assembly on Release builds.
Build
dotnet build -c Release Your Release output is now obfuscated. Every subsequent Release build is too.
Inspect the result
demeanor inspect bin/Release/net10.0/MyProject.dll Shows exactly what was renamed, encrypted, and obfuscated. Compare against your original source to see the transformation.
Licensing
Per-company licensing. No seat counting, no machine locking, no activation server. License keys are self-validating — they work completely offline.
| Feature | Community (Free) | Professional ($799) | Enterprise ($1,499/yr) |
|---|---|---|---|
| Symbol renaming | ✓ | ✓ | ✓ |
| Alpha naming mode | ✓ | ✓ | ✓ |
| Unicode naming mode | ✓ | ✓ | |
--include-publics | ✓ | ✓ | |
| String encryption | ✓ | ✓ | |
| Constants encryption | ✓ | ✓ | |
| Resource encryption | ✓ | ✓ | |
| Control flow obfuscation | ✓ | ✓ | |
| Reference proxy | ✓ | ✓ | |
--cc (CompilerControlled) | ✓ | ✓ | |
| SuppressIldasm | ✓ | ✓ | |
| HinderReflection | ✓ | ✓ | |
--include-deps (multi-assembly) | ✓ | ||
| Incremental obfuscation | ✓ | ||
| Satellite assemblies | ✓ | ||
| JSON report generation | ✓ |
Professional is a perpetual per-company license ($799 one-time) with 1 year of package updates. After that year, your license continues working with package versions released during your entitlement window. Renew for $299/yr for access to newer releases.
Enterprise is a per-company subscription ($1,499/yr) with all features and all updates. When the subscription expires, the license degrades to Community tier.
Community is free — no license key required. Symbol renaming only, alpha naming mode, single assembly.
Applying Your License Key
Project file:
<DemeanorLicense>YOUR_LICENSE_KEY</DemeanorLicense> Environment variable (recommended for CI/CD):
DEMEANOR_LICENSE=YOUR_LICENSE_KEY CLI flag:
demeanor --license YOUR_LICENSE_KEY MyApp.dll Expiry Behavior
- Professional (update entitlement expired): Upgrading to a package version released after your entitlement date fails the build with an error. Install an earlier package version or renew.
- Enterprise (subscription expired): Degrades to Community tier (renaming only). The build succeeds but without encryption, CFG, or other Professional+ features.
- Invalid or missing key: Community tier. Build succeeds with renaming only.
Verifying Your License
demeanor license YOUR_LICENSE_KEY Command-Line Interface
The Demeanor CLI is a self-contained native binary — no .NET runtime required.
demeanor [options] <assembly>
demeanor <command> [options] | Command | Description |
|---|---|
| (default) | Obfuscate an assembly |
inspect | Inspect assembly metadata, IL, and dependencies |
license | Decode and display license key information |
CLI Reference — Obfuscate
Input / Output
| Option | Description | Default |
|---|---|---|
<assembly> | Path to the .NET assembly to obfuscate | (required) |
--out <dir> | Output directory | ./Demeanor/ |
Scope
| Option | Description | Default | Tier |
|---|---|---|---|
--include-publics | Also obfuscate public/protected symbols. Use for executables not referenced by other assemblies. | off | Professional |
--include-deps | Also obfuscate co-located private dependency assemblies. | off | Enterprise |
Naming
| Option | Description | Default | Tier |
|---|---|---|---|
--names <mode> | Alpha (a, b, c) or Unicode | Alpha | Unicode: Professional |
--prefix <ns> | Namespace prefix for obfuscated type names | (none) | Community |
--cc | CompilerControlled accessibility for maximum overloading | off | Professional |
Protection Features
All protection features are enabled by default at Professional tier and above. At Community tier, only renaming is active.
| Option | Description | Default |
|---|---|---|
--no-strings | Disable string encryption | (enabled) |
--no-constants | Disable integer constant encryption | (enabled) |
--no-resource-encryption | Disable resource encryption | (enabled) |
--no-reference-proxy | Disable reference proxy (call hiding) | (enabled) |
--proxy-threshold <N> | Minimum IL body size for proxying | 16 |
--cfg <level> | Reorder, Predicates, or Flatten | Flatten |
--no-cfg | Disable control flow obfuscation | (enabled) |
--suppress-ildasm | Inject [SuppressIldasm] | true |
--hinder-reflection | Hinder reflection-based analysis | true |
Exclusions
| Option | Description |
|---|---|
--exclude <name> | Exclude a type or member by fully-qualified name. Repeatable. |
--xr <pattern> | Exclude by regex pattern. Repeatable. |
--xa <assembly> | Exclude an assembly (with --include-deps). Repeatable. |
--add-assembly <name> | Include a dynamically referenced assembly. Repeatable. |
Category Exclusions
| Option | Description |
|---|---|
--no-types | Disable type renaming |
--no-methods | Disable method renaming |
--no-fields | Disable field renaming |
--no-properties | Disable property renaming |
--no-events | Disable event renaming |
--no-parameters | Disable parameter renaming |
--no-enumerations | Disable enumeration renaming |
--no-resources | Disable resource name renaming |
--no-serializable | Exclude serializable types and their fields |
Reporting & Incremental (Enterprise)
| Option | Description |
|---|---|
--report | Generate JSON report mapping original to obfuscated names |
--report-file <path> | Path for the report file |
--prior-report <path> | Prior report for incremental obfuscation |
--satellite-assemblies | Update resource names in satellite assemblies |
--sa-cultures <culture> | Restrict satellite processing to specific cultures |
Strong Name Re-signing
| Option | Description |
|---|---|
--keyfile <path> | Strong name key file (.snk) |
--keycontainer <name> | Strong name key container |
Output Control
| Option | Description | Default |
|---|---|---|
--license <key> | License key (also reads DEMEANOR_LICENSE env var) | |
--verbose | Verbose obfuscation statistics | off |
--quiet | Suppress all non-error output | off |
--debug | Preserve debug data (PDB) | off |
--no-logo | Suppress the startup banner | off |
CLI Reference — inspect
Inspect assembly metadata, IL, and dependencies without obfuscating. When no flags are specified, enters an interactive REPL mode.
demeanor inspect <assembly> [options] | Option | Description |
|---|---|
--summary | High-level summary |
--metadata | Display metadata tables |
--il | Display IL for all methods |
--dependencies | Assembly and type dependencies |
--json | Structured JSON output |
--filter <name> | Filter types or members by name |
--public-only | Restrict to public symbols |
CLI Reference — license
Decode and display license key information.
demeanor license YOUR_LICENSE_KEY Also reads from the DEMEANOR_LICENSE environment variable if no argument is provided.
MSBuild Property Reference
All properties are optional. Set them in a <PropertyGroup> in your .csproj.
| Property | CLI Equivalent | Default |
|---|---|---|
<Obfuscate> | — | false |
<DemeanorLicense> | --license | env var |
<ObfuscateIncludePublics> | --include-publics | false |
<ObfuscateIncludeDeps> | --include-deps | false |
<ObfuscateNamingMode> | --names | Alpha |
<ObfuscateNamespacePrefix> | --prefix | (none) |
<ObfuscateCompilerControlled> | --cc | false |
<ObfuscateNoStrings> | --no-strings | false |
<ObfuscateEncryptConstants> | (inverse of --no-constants) | true |
<ObfuscateNoReferenceProxy> | --no-reference-proxy | false |
<ObfuscateProxyThreshold> | --proxy-threshold | 16 |
<ObfuscateControlFlow> | --cfg | Flatten |
<ObfuscateSuppressIldasm> | --suppress-ildasm | true |
<ObfuscateHinderReflection> | --hinder-reflection | true |
<ObfuscateReport> | --report | false |
<ObfuscateReportFile> | --report-file | (auto) |
<ObfuscatePriorReport> | --prior-report | (none) |
<ObfuscateVerbose> | --verbose | false |
<ObfuscateKeyFile> | --keyfile | (none) |
<ObfuscateExclude> | --exclude | (none) |
<ObfuscateExcludeRegex> | --xr | (none) |
<ObfuscateNoTypes> | --no-types | false |
<ObfuscateNoMethods> | --no-methods | false |
<ObfuscateNoFields> | --no-fields | false |
<ObfuscateNoProperties> | --no-properties | false |
<ObfuscateNoEvents> | --no-events | false |
<ObfuscateNoParameters> | --no-parameters | false |
<ObfuscateNoEnumerations> | --no-enumerations | false |
Release-Only Obfuscation
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Obfuscate>true</Obfuscate>
</PropertyGroup> Exclusions Guide
Some symbols must keep their original names. Demeanor provides multiple exclusion mechanisms.
Automatic Exclusions
Demeanor automatically preserves entry points, runtime-critical methods, and public/protected symbols in library DLLs (unless --include-publics is used).
[Obfuscation] Attribute
[Obfuscation(Exclude = true)]
public class MyApiResponse { ... }
[Obfuscation(Exclude = true, ApplyToMembers = true)]
public class MyDataContract { ... } Name Exclusions
demeanor --exclude "MyApp.Models.ApiResponse" MyApp.dll In MSBuild (semicolon-separated):
<ObfuscateExclude>MyApp.Models.ApiResponse;MyApp.Services.PaymentService</ObfuscateExclude> Regex Exclusions
demeanor --xr ".*ViewModel$" --xr ".*Controller$" MyApp.dll Common Patterns
- WinForms: Exclude form types —
--xr ".*Form$" --xr ".*UserControl$" - Serialization: Use
[Obfuscation(Exclude = true, ApplyToMembers = true)]on serialized types - Reflection: Exclude types accessed by
Type.GetMethod("Name")or similar - Plugin systems: Exclude types loaded by name from configuration or DI containers
CI/CD Integration
Store your license key as a secret and set the DEMEANOR_LICENSE environment variable.
GitHub Actions
- name: Build and obfuscate
env:
DEMEANOR_LICENSE: ${{ secrets.DEMEANOR_LICENSE }}
run: dotnet build -c Release Azure Pipelines
- task: DotNetCoreCLI@2
inputs:
command: build
arguments: '-c Release'
env:
DEMEANOR_LICENSE: $(DemeanorLicense) Add DemeanorLicense as a secret variable in your pipeline settings.
Troubleshooting
"Assembly has already been obfuscated by Demeanor"
Your build pipeline is running obfuscation twice. Ensure <Obfuscate> is only set for the final build step.
Reflection breaks at runtime
Code that accesses types or members by name (Type.GetType("MyClass")) needs those names excluded. Use [Obfuscation(Exclude = true)] or --exclude.
Serialization/deserialization fails
Types serialized to JSON, XML, or binary depend on property names. Exclude with [Obfuscation(Exclude = true, ApplyToMembers = true)].
WinForms designer or data binding breaks
WinForms uses reflection extensively. Exclude form types: --xr ".*Form$".
Build fails with update entitlement error
Your license's update entitlement has expired and you've upgraded to a newer package. Either renew or pin to an earlier package version.
Output assembly crashes at runtime
Contact [email protected] with the error details.
Supported Platforms
Target assemblies (what you can obfuscate)
- .NET 10, 9, 8, 7, 6
- .NET Framework 4.x
- C++/CLI mixed-mode assemblies
Host platforms (where Demeanor runs)
- Windows x64
- Linux x64
- macOS x64 (Intel)
- macOS ARM64 (Apple Silicon)