Skip to Content
New release 12 available 🎉
ObfuscatorSymbols RenamingCross Assembly Renaming

Cross Assembly Renaming

During the obfuscation process, Babel Obfuscator renames all the symbols that are not externally visible to the assembly, which includes private and internal symbols. This means that Babel will change the names of fields, methods, classes, and other code elements that are not meant to be accessed outside of the assembly.

Babel will not rename symbols externally visible to the assembly, such as public symbols. This is because public symbols are meant to be accessed by other assemblies, and renaming them would break the application’s functionality. Therefore, Babel only renames the symbols not meant to be accessed by other assemblies, ensuring that the application still works as intended.

However, Babel provides the ability to obfuscate both public and internal members across multiple assemblies. This is accomplished by fixing the names of the obfuscated symbols referenced in each assembly using XML map files.

This is because when an assembly is obfuscated, the names of its symbols are changed. Thus, any reference to these symbols made by another assembly must be updated to reflect the new names. By specifying these input and output XML map files, Babel Obfuscator can use them to fix cross-name references between all participating assemblies. This ensures that the obfuscated code works correctly and does not break due to incorrect symbol names.

It is important to keep map files private and not deploy them with the obfuscated application under any circumstances, as they can be used to reverse engineer the obfuscation and compromise the security of the application.

Setup Cross Assembly Renaming

To setup cross assembly renaming we have to consider all the assemblies that partecipate to renaming process. Consider the main assembly application MainAssembly.dll which consumes the public interface of two external components: Library1.dll and Library2.dll. Where Library1.dll also need to access Library2.dll public interface according to the following scheme:

  • MainAssembly.dll
    1. Library1.dll
    2. Library2.dll
  • Library1.dll
    1. Library2.dll

This configuration highlights the relationships between the assemblies involved in the obfuscation process. The first step is to configure Babel to obfuscate the public symbols in Library1.dll and Library2.dll. You can achieve this by adding the following assembly-level custom attribute to the source code of both libraries:

[assembly: System.Reflection.ObfuscateAssembly(true)]

This attribute instructs Babel to obfuscate the public symbols of the specified assembly without the need for external XML rule files. Setting the Boolean parameter to true ensures that the assembly’s public interface is treated as private, allowing public member names to be safely obfuscated.

Alternatively, you can configure Babel to rename the public interface of an assembly using an XML rules file. This method provides greater flexibility and control, allowing you to selectively obfuscate parts of the public interface. Below is an example of an XML rule file named public.xml that forces the obfuscation of all public member names:

<Rules> <Rule name="obfuscate public" exclude="false"> <Access>Public</Access> <Pattern isRegEx="false">*</Pattern> <Description>Obfuscate all public symbols.</Description> </Rule> </Rules>

Compared to the ObfuscateAssembly attribute, the XML rule approach offers more granular control over which public symbols to obfuscate. Using the Pattern expression, you can specify which parts of the public interface should be obfuscated, allowing for tailored obfuscation strategies.

At this point, we have Library1.dll and Library2.dll configured to use either the ObfuscateAssembly attribute or the XML rule file (in this case, public.xml)

  • MainAssembly.dll
  • Library1.dll (configured with public.xml)
  • Library2.dll (configured with public.xml)

For each assembly that has been configured to rename its public interface, we need to enable the generation of an XML map file.

This file contains the mapping between the original symbol names and their obfuscated counterparts. The XML map file will be utilized by all assemblies participating in the obfuscation process that reference at least one assembly with a renamed public interface. This ensures proper name resolution across the obfuscated assemblies.

To obfuscate Library1.dll and Library2.dll, we use the following CLI syntax:

babel Library2.dll --rules public.xml --mapout

This first command obfuscates Library2.dll and generates an XML map file named Library2.map.xml, which contains the mapping between original symbol names and the obfuscated names.

Since Library1.dll references Library2.dll and consumes its public interface, when obfuscating Library1.dll, we must provide the Library2.map.xml file as input to ensure proper mapping of Library2.dll’s obfuscated symbols. Additionally, as we want to obfuscate the public interface of Library1.dll, we configure Babel to load the public.xml rule file and generate a corresponding XML map file for Library1.dll.

The CLI command for this step is as follows:

babel Library1.dll --rules public.xml --mapout --mapin Library2.map.xml

This ensures that Library1.dll correctly references the obfuscated symbols from Library2.dll, while also generating its own map file for subsequent use in the obfuscation process.

Finally, to obfuscate MainAssembly.dll, we need to configure Babel to load the XML map files for both Library1.dll and Library2.dll, as these assemblies are referenced by MainAssembly. This ensures that MainAssembly can correctly resolve the obfuscated symbols from its dependent libraries during the obfuscation process.

The CLI command for this step is:

babel MainAssembly.dll --mapin Library1.map.xml --mapin Library2.map.xml

This command takes in the previously generated map files (Library1.map.xml and Library2.map.xml) to ensure that the references to the obfuscated symbols in these libraries are properly handled in MainAssembly.

It’s crucial to follow the correct order when obfuscating assemblies. Libraries referenced by other assemblies, such as Library2.dll and Library1.dll, must be obfuscated first to generate the necessary map files. Then, dependent assemblies like Library1.dll and MainAssembly.dll can be obfuscated using the map files.

Setup From MSBuild Task

To configure cross-assembly renaming with MSBuild, it is necessary to specify the input and output XML map files for each assembly involved in the obfuscation project including the XML rule file. Each obfuscated assembly must generate an XML map file, which will then be provided as input to all other obfuscated assemblies that reference this target assembly.

Here’s an example of how to configure cross-assembly renaming between one main assembly and two referenced assemblies arranged according to the following scheme.

  • MainAssembly.dll
    1. Library1.dll
    2. Library2.dll
  • Library1.dll
    1. Library2.dll

We begin with the Library2 project, which has no dependencies. Since it doesn’t rely on any other assemblies, it can be obfuscated independently without requiring any input XML map files.

Library2 Assembly Project

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <GenerateMapOutFile>true</GenerateMapOutFile> </PropertyGroup> <Target Name="Obfuscate" AfterTargets="CoreCompile"> <ItemGroup> <RulesFile Include="path\to\referenced\public.xml" /> </ItemGroup> <Babel Input="$(TargetPath)" RulesFiles="@(RulesFile)" GenerateMapOutFile="$(GenerateMapOutFile)" /> </Target> </Project>

It is worth noticing that as Library1 references Library2, the obfuscation project, besides generating the XML map file with GenerateMapOutFile=true, must also reference the mapping file generated for Library2.

Library1 Assembly Project

<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <Reference Include="path\to\referenced\Library2.dll" /> </ItemGroup> <PropertyGroup> <GenerateMapOutFile>true</GenerateMapOutFile> </PropertyGroup> <Target Name="Obfuscate" AfterTargets="CoreCompile"> <ItemGroup> <MapInFile Include="path\to\referenced\Library2.dll.map.xml" /> </ItemGroup> <ItemGroup> <RulesFile Include="path\to\referenced\public.xml" /> </ItemGroup> <Babel Input="$(TargetPath)" MapInFiles="@(MapInFile)" RulesFiles="@(RulesFile)" GenerateMapOutFile="$(GenerateMapOutFile)" /> </Target> </Project>

As the MainAssembly project references the two libraries, Library1 and Library2, which have been obfuscated in their public interface, the Babel task needs to be configured to load the two XML mapping files generated for each library.

Main Assembly Project

<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <Reference Include="path\to\referenced\Library1.dll" /> <Reference Include="path\to\referenced\Library2.dll" /> </ItemGroup> <Target Name="Obfuscate" AfterTargets="CoreCompile"> <ItemGroup> <MapInFile Include="path\to\referenced\Library1.dll.map.xml" /> <MapInFile Include="path\to\referenced\Library2.dll.map.xml" /> </ItemGroup> <Babel Input="$(TargetPath)" MapInFiles="@(MapInFile)" /> </Target> </Project>

This ensures that any cross-referencing between Library1 and Library2 is handled correctly during the obfuscation process. Without referencing the XML map file generated for Library2, the obfuscation process for Library1 may not correctly handle cross-referencing between the two libraries, leading to potential issues at runtime. Therefore, it is essential to ensure that all necessary XML map files are generated and referenced correctly when configuring cross-assembly renaming.

Setup From Babel Desktop

A Babel Desktop project can hold all the assemblies involved. On the project canvas, connect each library to the assembly that uses it and choose Pass the map file: the library then writes its map file, the consumer reads it, and the library is obfuscated first. In the example above, connect Library2 to Library1 and to MainAssembly, and Library1 to MainAssembly. A connection with Execution order only sets the order but passes no map file.

You still add the public renaming rules to each library, with XML rules or RulesFiles. The Map files group of the target properties shows the maps each target writes and reads, and lets you add map files from earlier builds. See Execution Order and Map Files.

Last updated on