XAML Renaming
Windows Presentation Foundation (WPF) and, more recently, MAUI applications use XAML declarative markup language and BAML (compiled XAML) to directly enable visual designers to create user interface elements.
Babel Obfuscator can analyse XAML and BAML resources and rename all the members referenced within them, which increases the percentage of obfuscated symbols and makes the XAML code more difficult to read. Additionally, Babel can merge multiple assembly files containing XAML or BAML resources into a single assembly file, improving the organization and simplifying the deployment of the application.
The XAML and BAML symbols renaming is enabled by entering the --xaml flag at the command line. This switch has additional optional parameters, which can be used to enhance the XAML (BAML) obfuscation.
Command Line
babel.exe myapp.exe --xamlMSBuild Babel Task
<PropertyGroup>
<ObfuscateXaml>true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Babel Obfuscator allows some advanced XAML settings for additional configuration of the XAML obfuscation process by using key-value pairs passed after the --xaml switch.
Available key-value pairs include:
keys
In XAML, a static resource is a resource that is defined at design-time and can be referenced from other parts of the application, such as controls or styles. The resource is identified by a key name used to reference it from the XAML code.
When enabled, Babel Obfuscator will rename the key names of static resources in the XAML/BAML code. This can help increase the level of obfuscation of the code and make it more difficult for attackers to understand the original purpose of a resource.
res
When enabled, allows Babel to obfuscate the XAML/BAML resource names. This means that the names of any resources used in the XAML/BAML code, such as images or strings, will be renamed to obscure their original purpose. This can make it more difficult for attackers to understand the structure and function of the XAML/BAML code, which can improve the overall security of your application.
strip
This option is used to remove line information and white spaces from the obfuscated XAML/BAML code. This can make it more difficult for attackers to reverse engineer the original code, as it removes debug information that could potentially help an attacker reconstruct the original source code. Removing line information and white spaces can also help to reduce the size of the obfuscated XAML/BAML file, making it more efficient and faster to load.
manual
By default, Babel Obfuscator automatically obfuscates all public members referenced within the XAML or BAML code. However, in cases where a more fine-tuned approach is necessary, the manual option can be enabled. This allows the user to manually specify which public members should be obfuscated, using either quick rule or XML rule files. This gives greater control over the obfuscation process but requires more configuration by the user.
babel.exe myapp.exe --xaml keys=on --xaml res=on --xaml strip=on<PropertyGroup>
<ObfuscateXaml>keys=true;strip=true;manual=false;res=true;true</ObfuscateXaml>
</PropertyGroup>
<Babel ObfuscateXaml="$(ObfuscateXaml)" />Aligning string literals with renamed XAML-bound members
When a WPF assembly is built, the compiler typically embeds each XAML page as BAML — the binary form of XAML — into the assembly’s resources. During the read phase, Babel inspects this BAML and, for every x:Name declaration, attempts to bind the name to the corresponding code-behind backing field on the root element type. A field that the binding succeeds for is treated as XAML-bound for the rest of the obfuscation run.
When such a XAML-bound member is renamed, Babel performs an additional alignment step on the declaring type. It walks every method body in the type and rewrites every string literal whose value equals the member’s original name, replacing it with the member’s new name. The match is plain string equality on the literal text, and the rewrite is applied to all such literals in the type regardless of how they are subsequently used. The only literals exempt from this rewrite are those passed to System.Resources.ResourceManager and call sites explicitly excluded by user-supplied renaming rules.
The intent is to keep WPF name-based runtime lookups in code-behind working after renaming. Patterns like this.FindName("tabPreise"), custom helpers such as GetControlByName<T>(string name), or any other code that resolves a member or named element by its source-time string name continue to function because the literals have been kept in sync with the renamed field. Because the matcher is structural rather than attribute-based, this alignment picks up user-defined helpers automatically without requiring an opt-in attribute on the helper.
For example, given the following code-behind:
private TabItem tabPreise { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("tabPreise");
// ...
}After Babel obfuscates the assembly, the field is renamed and the literal that names it is aligned to the new name:
private TabItem cm { get; set; }
void Wire()
{
var tab = GetControlByName<TabItem>("cm");
// ...
}The alignment fires only when the BAML binding described above succeeds. If the BAML element type cannot be resolved — typically because the assembly that defines it is not on Babel’s search path and the resolver emits warning W00013 for that assembly — the binding silently fails, and the member is not flagged as XAML-bound. Field renaming itself does not depend on the XAML flag, so the field still receives its new name; the literals naming the original field, however, are left untouched, and the obfuscated assembly will contain inconsistent IL. Any name-based runtime lookup that relied on those literals will fail at runtime.
Two mitigations apply, in order:
-
Treat W00013 as build-blocking for projects that contain embedded BAML. Add the directories containing every referenced assembly that defines XAML element types to Babel’s search path with the
--addsearchoption, so that the BAML resolver can bind every element type. With every element type resolved, the alignment step runs as designed. -
Where keeping the original name is the desired outcome — for example when standalone
.xamlfiles are shipped alongside the assembly and reference the field by its original name — exclude the field from renaming with a locked XML rule:
<Rule name="keep-xname-tabPreise"
feature="renaming" exclude="true" locked="true">
<Target>Fields,Properties,Methods</Target>
<Pattern>MyNamespace.MyForm::tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::get_tabPreise</Pattern>
<Pattern>MyNamespace.MyForm::set_tabPreise</Pattern>
</Rule>With the field name unchanged, the alignment step has nothing to rewrite, and the assembly remains consistent with both BAML and any loose XAML files that reference tabPreise.
For the broader picture of when W00013 is informational versus when it correlates with a real change in the obfuscated output, see W00013 in the BAML-binding path in the command-line reference.