Every obfuscator works fine on console apps and class libraries. WPF is where they break - and the reason is always the same: BAML.
In WPF, your UI is not compiled into normal IL. It's compiled into BAML (Binary Application Markup Language) and embedded inside your assembly's .g.resources section. BAML is not just markup - it's a binary encoding of every symbol your UI references:
{Binding MyProperty} path stored as a literal stringWhen a classical obfuscator renames CustomerViewModel to ?_0 in your IL, it must also find every reference to CustomerViewModel inside the BAML and rewrite them to ?_0. This is called BAML rewriting - and it is extraordinarily difficult to implement correctly because BAML references symbols in at least eight different ways, many of them context-dependent and runtime-resolved.
When an obfuscator's BAML rewriting fails, you see some combination of these at runtime:
InitializeComponent fails silently. The window opens but renders nothing - no layout, no controls.
Bindings connect to a renamed property that no longer exists. Controls display empty or default values with no error.
IValueConverter types were renamed in IL but not in BAML. The converter reference resolves to nothing.
XamlParseException or TypeInitializationException thrown inside InitializeComponent before any UI appears.
Event handler names in BAML no longer match their renamed IL counterparts. Clicks, loads, and custom events are silently dropped.
Style triggers reference dependency property names. After renaming, trigger conditions never match and styles are ignored.
Opaquer does not rename BAML symbols. It doesn't need to. Instead, it cryptographically encrypts the entire BAML resource - making the rename-and-rewrite problem disappear entirely.
.g.resources BAML section
Open an Opaquer-protected WPF assembly in ILSpy and navigate to yourapp.g.resources. This is what you see:
At application startup, Opaquer's runtime component decrypts the BAML resource in memory, on demand, when each WPF view is first loaded. The decrypted content is handed directly to WPF's XAML loader and is never written to disk. There is no persistent plaintext file an attacker could extract from the filesystem.
WPF-specific protection varies enormously across tools. This table focuses exclusively on WPF-relevant capabilities.
| WPF Protection Feature | Opaquer | ConfuserEx | Dotfuscator CE | Obfuscar | SmartAssembly |
|---|---|---|---|---|---|
| BAML / XAML handling | |||||
| BAML cryptographic encryption | ✔ Full | ✘ | ✘ | ✘ | ✘ |
| Reliable BAML symbol rewriting | ✔ Not needed | ✘ Unreliable | △ Partial | ✘ Breaks | △ Partial |
| Binding path safety (reflection strings) | ✔ Preserved | ✘ Breaks | △ Limited | ✘ Breaks | △ Limited |
| Dependency property preservation | ✔ Automatic | ✘ Manual exclusion | △ Manual exclusion | ✘ Manual exclusion | △ Auto-detect |
| Attached property preservation | ✔ Automatic | ✘ Breaks | △ Partial | ✘ Breaks | △ Partial |
| Routed event name safety | ✔ Preserved | ✘ May break | △ Partial | ✘ May break | △ Partial |
| Converter resolution after obfuscation | ✔ Works | ✘ Breaks | △ Requires exclusion | ✘ Breaks | △ Requires exclusion |
| Resource key safety | ✔ Encrypted | △ Exposed | △ Exposed | △ Exposed | △ Exposed |
| UI structure hidden from ILSpy | ✔ NotSupportedException | ✘ Readable | ✘ Readable | ✘ Readable | ✘ Readable |
| General obfuscation | |||||
| Name obfuscation (Non-Displayable) | ✔ | ✔ | △ Basic | ✔ | ✔ |
| String encryption | ✔ | ✔ | ✘ | ✘ | ✔ |
| Control flow obfuscation | ✔ | ✔ | ✘ | ✘ | ✔ |
| Actively maintained (.NET 10) | ✔ | ✘ Abandoned | △ Paid only | △ Community | ✔ Paid |
| Free tier | ✔ Full algorithms | ✔ Unmaintained | △ Very limited | ✔ OSS | ✘ Paid only |
△ = partial support, requires manual exclusion lists, or unreliable in practice. Table reflects publicly documented capabilities and community-reported behavior as of 2026.
The most common questions from WPF developers evaluating Opaquer.
.g.resources section of the compiled binary, rather than attempting to rename BAML symbols and rewrite BAML content. This eliminates the root cause of every WPF obfuscation failure: the mismatch between renamed IL symbols and unrewritten BAML references. Bindings, converters, dependency properties, routed events, and resource keys all work exactly as before. Download the free Basic edition and test it on your WPF project..g.resources section of your assembly. BAML contains type names, property names, converter names, attached property identifiers, routed event names, resource keys, and binding path strings. When a classical obfuscator renames classes and properties in the IL, it must also locate and update every reference to those names inside the BAML - a process called BAML rewriting. This is extremely difficult to implement correctly. Most tools miss binding paths stored as runtime strings, fail to preserve dependency property registrations, and leave converter references dangling. The result is blank UI, silent binding failures, startup crashes, and events that never fire..g.resources binary section - the section containing all compiled XAML. The original symbols are never renamed inside BAML, so there is nothing to rewrite and no risk of any binding, converter, or event reference breaking. At runtime, Opaquer's embedded component decrypts the BAML resource in memory on demand, passes it directly to WPF's XAML loader, and never writes the decrypted content to disk.yourapp.g.resources in ILSpy and attempt to decompile the BAML, ILSpy throws: System.NotSupportedException: Specified method is not supported. This is intentional - ILSpy's BAML reader cannot parse a cryptographically encrypted binary stream. Your WPF form structure, control hierarchies, layout definitions, binding configurations, and style trees are completely hidden. This is the strongest proof that the protection is working.RelativeSource bindings, ElementName bindings, attached property bindings, and reflection-based property paths like {Binding Path=MyNestedObject.Property}. The underlying C# properties that bindings reference are protected independently in the IL layer through name obfuscation and string encryption.Download the free Basic edition. Load your WPF assembly. Check the result in ILSpy. Your BAML will be completely unreadable - and your application will run exactly as before.