Publish .NET App

This example demonstrates how to use the Babel task to configure cross-assembly renaming during the build process of a .NET application. Specifically, the public interface of the MathNet.Numerics package will be obfuscated to showcase how to publish an obfuscated application that consumes an obfuscated assembly. It is worth noting that the Babel.Obfuscator NuGet package is required to follow this example, and an Ultimate or Server license edition is necessary to use it. The example will showcase how to configure cross-assembly renaming to enhance the obfuscation yield of the application, making it more challenging for reverse engineering.

The complete source code example is available on GitHub and can be downloaded with the following command:

git clone https://github.com/babelfornet/cross-assembly-reference-example.git

The example code is a simple .NET console application that performs some basic statistical operations using MathNet.Numerics library.

To start configuring cross-assembly renaming, we need first to reference the Babel Obfuscator NuGet package using the Visual Studio NuGet package manager or by adding the following MSBuild instruction to the project file:

<PackageReference Include="Babel.Obfuscator" Version="10.0.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

This will make to obfuscate the target assembly Math.dll without cross-assembly renaming enabled.

Once the package is added, we can use the Babel task to configure cross-assembly renaming during the build process by renaming the public interface of the referenced NuGet package library MathNet.Numerics.

<!-- Obfuscate the public interface of MathNet.Numerics reference -->
<Target Name="BeforeObfuscate">
  <PropertyGroup>
    <MathNetNumerics Condition="'%(filename)' == 'MathNet.Numerics'">@(ReferencePathWithRefAssemblies->'%(fullpath)')</MathNetNumerics>
    <MathNetRules>
      <Rules>
        <Rule name="rename public" feature="renaming" exclude="false">
          <Access>Public</Access>
          <Pattern>*</Pattern>
      </Rule>
    </Rules>
  </MathNetRules>
</PropertyGroup>
<Message Text="MathNet.Numerics: $(MathNetNumerics)" Importance="high" />
  <Babel InputFile="$(MathNetNumerics)" OutputFile="$(TargetDir)MathNet.Numerics.dll" 
         FlattenNamespaces="true" XmlRules="$(MathNetRules)" 
         GenerateMapOutFile="true" />
</Target>

Specifically, we need to get the full path of the referenced components from the list of references used to build the application.

<MathNetNumerics Condition="'%(filename)' == 'MathNet.Numerics'">@(ReferencePathWithRefAssemblies->'%(fullpath)')</MathNetNumerics>

This will be the input of the Babel task with the XML rule that will configure babel to rename the public interface of the component. We also need to generate the mapping file that will be used when obfuscating the target assembly by setting the property GenerateMapOutFile="true".

Note that we set the target name to BeforeObfuscate which is an entry point defined by the Babel Obfuscator NuGet package that allows performing some additional tasks before the target assembly is obfuscated.

To enable cross-assembly renaming for the target assembly Math.dll, we need to add the XML mapping file generated for the referenced library MathNet.Numerics.dll to the obfuscation task for the target assembly. This can be done using the properties defined for the Babel Obfuscator NuGet package, which are described in the NuGet Package Reference.

<!-- Target assembly obfuscation settings -->
<ItemGroup>
  <MapInFile Include="$(TargetDir)MathNet.Numerics.dll.map.xml" />
</ItemGroup>
<PropertyGroup>
  <StringEncryption>true</StringEncryption>
  <ValueEncryption>array=true;true;</ValueEncryption>
  <ControlFlowObfuscation>goto=on;if=on;switch=on;case=on;call=on</ControlFlowObfuscation>
  <CopyOutputSymbolsToPublishDirectory>false</CopyOutputSymbolsToPublishDirectory>
</PropertyGroup>

In order to prevent attackers from extracting additional information that can be used to analyze the obfuscated code, the publishing of PDB files has been disabled by setting:

CopyOutputSymbolsToPublishDirectory=false.

PDB files contain debugging information, such as source code file names and line numbers, that can make it easier for attackers to understand the obfuscated code.

Upon building the project, the cross-assembly obfuscated application will be generated in the target directory. In order to create the deployable package, it is necessary to substitute the file reference to the MathNet.Numerics.dll from the NuGet package with the file path to the obfuscated version. This step is essential to ensure that Visual Studio packages the correct obfuscated assemblies.

<!-- Replace the deployed MathNet.Numerics.dll assembly reference with the obfuscated one -->
<Target Name="UpdateFilesToPublish" AfterTargets="ComputeFilesToPublish">
  <ItemGroup>
    <ResolvedFileToPublish Remove="$(MathNetNumerics)" />
    <ResolvedFileToPublish Include="$(TargetDir)MathNet.Numerics.dll">
      <RelativePath>MathNet.Numerics.dll</RelativePath>
    </ResolvedFileToPublish>
  </ItemGroup>
</Target>

The MSBuild XML fragment shown is a target named UpdateFilesToPublish that is executed after the target ComputeFilesToPublish. This target is used to replace the original MathNet.Numerics.dll assembly reference from the NuGet package with the obfuscated one in the deployment package.

The target first defines an item group that removes the original reference to the MathNet.Numerics.dll file by using the "Remove" attribute and referencing the property that contains the original file path.

Then, the target adds the obfuscated version of the MathNet.Numerics.dll file to the item group by using the "Include" attribute and referencing the obfuscated file path in the target directory. The "RelativePath" element is used to specify the relative path to the file from the root of the deployment directory.

When the target is executed, it will remove the original file reference and add the obfuscated file reference to the deployment package, ensuring that the obfuscated assembly is deployed instead of the original one.

To publish the completely obfuscated application, navigate to the project folder and execute the following command:

dotnet publish

Overall, the example serves as a starting point for developers who want to integrate Babel obfuscation into their .NET build pipeline and protect their code using cross-assembly obfuscation. In addition, we have provided some supplementary advice on how to modify the deployment package in order to incorporate the obfuscated assemblies.

Last updated