Dotfuscator provides .NET obfuscation and application protection across a variety of platforms - including Xamarin! An important aspect of obfuscation is ensuring that it is integrated into your build, so it is consistently and automatically applied. This article focuses on build integration; for general obfuscation advice, please see the relevant user guide (Professional, Community Edition).

There are many different methods you could use to obfuscate a Xamarin project with Dotfuscator. The process outlined here is essentially:

  1. Configure the Xamarin build to run Dotfuscator as an AfterBuild target
    1. Configure a Copy task to copy the obfuscated binaries back to their original locations
  2. Configure Dotfuscator
    1. Specify the inputs
    2. Exclude things from renaming (as usual / as needed)
    3. Only use Mono-compatible transforms (Pro-only)
  3. Build, verify obfuscation, and test

Sample Project

The examples below use a sample application from Xamarin, BugSweeper, and focus on the Android platform. These instructions can be applied to other projects and platforms (e.g. iOS); you'll need to adapt the filenames and paths accordingly. (If you are building a UWP or Windows Phone project, we recommend building the store-ready package (APPX or XAP) first and then running it through Dotfuscator as usual.)

It's always a useful exercise to first see what the unobfuscated application looks like in a decompiler. Try building the BugSweeper.Android project in the Release configuration and opening the two managed DLLs with a .NET decompiler like ILSpy. They are located in the project's bin\Release directory (BugSweeper.dll and BugSweeper.Android.dll). In ILSpy, you will see something like this, which looks a lot like the original source code:

Decompiled source, before obfuscation 

Dotfuscator Editions

These instructions cover both the Community Edition and the Professional Edition of Dotfuscator. Where needed, the differences will be called out.

To use the Professional Edition, simply ensure it is installed and runs without issue.

To use the Community Edition, you'll need a version with command line build support (first released in Visual Studio 2015 Update 3) and you'll need to register it. You can find the command line interface here:

<Program Files>\Microsoft Visual Studio <version>\PreEmptive Solutions\Dotfuscator and Analytics Community Edition\dotfuscatorCLI.exe

Future versions of Visual Studio may install to different locations; you will need to update the path accordingly.

Integrate Dotfuscator into the Xamarin build pipeline

The most consistent and secure method of obfuscating your Xamarin apps is to integrate Dotfuscator into the MSBuild pipeline. This allows you to obfuscate your project using standard build tools, and lets you test your obfuscation using Xamarin's built-in debugger workflow.

We do this by updating each .csproj file with a new AfterBuild target, in which we will:

  1. Run Dotfuscator
  2. Pass properties to Dotfuscator to tell it where to find inputs and where to put outputs
  3. Copy Dotfuscator's outputs back to their original input locations, so the remainder of the Xamarin build can operate on them

For the Professional Edition, we'll add a reference to Dotfuscator's custom MSBuild task (Dotfuscate):

<UsingTask TaskName="PreEmptive.Tasks.Dotfuscate" AssemblyFile="$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4\PreEmptive.Dotfuscator.Tasks.dll" />

...and then use that task in the new target:

  <Target Name="AfterBuild">
    <Dotfuscate ConfigPath="Obfuscate.Android.xml" Properties="$(DotfuscatorProperties)"/>
    <!--MORE TO COME, BELOW-->

For the Community Edition, the MSBuild task isn't available, so we'll call the Dotfuscator executable directly:

  <Target Name="AfterBuild">
    <Exec Command="&quot;C:\Program Files (x86)\Microsoft Visual Studio 14.0\PreEmptive Solutions\Dotfuscator and Analytics Community Edition\DotfuscatorCLI.exe&quot; -p=OutDir=$(OutDir) $(ProjectDir)\Obfuscate.Android.xml" />
    <!--MORE TO COME, BELOW-->

In both Editions, we finish the target with:

      <ObfuscatedFiles Include="$(ProjectDir)\Dotfuscated\*.dll" />
    <Copy SourceFiles="@(ObfuscatedFiles)" DestinationFolder="$(OutDir)" />
    <Copy SourceFiles="$(ProjectDir)\Dotfuscated\BugSweeper.dll" DestinationFolder="$(ProjectDir)\..\BugSweeper\$(OutputPath)" />

Please review the following aspects of the XML above:

  • OutDir represents the output path of the Xamarin build. From Dotfuscator's point of view, it is really an input directory.
  • Obfuscate.Android.xml is a Dotfuscator config file that we will create in the next step.
  • BugSweeper.dll will need to change to match your particular project.
  • There are two copy tasks: one that copies the assemblies back to their original locations, and another that copies a PCL (Portable Class Library) assembly back to its project-specific location. That second copy task is required to make the Xamarin Android build succeed.

Configure Dotfuscator

The overall process for configuring Dotfuscator is the same between Community Edition and Professional Edition, but the UI is different, and the Professional Edition has more options and settings to configure. We'll start with a high-level overview, then show exactly what to do in each product.

1: Run the GUI

Professional Edition will typically be found in the Start Menu. Community Edition will typically be found in the Tools menu of Visual Studio. (If it is missing, you may need to re-run the Visual Studio installer and add the component.)

2: Change settings to enable Xamarin compatability

Dotfuscator Professional supports control-flow obfuscation in addition to the renaming transforms supported by Community Edition. Some of the control-flow transforms are not Mono-compatible, so they have to be disabled in Professional Edition. To do so, go to Settings -> Global Options and change "Use only Mono-compatible transforms" to "Yes".

No changes are required for Community Edition.

3: Configure project properties

The MSBuild Target that we created above uses OutDir to pass the location of the input files to Dotfuscator. Dotfuscator has to be told to "see" these properties, or it will ignore them.

On the Project Properties (Pro) or Properties (CE) page, add a new property named OutDir and set its initial value to the full path of the build output (typically ending in "Release"). It will be overridden at build time by the path that's passed in from MSBuild.

4: Add Inputs

Our sample Android application has two assemblies: the portable code is in BugSweeper.dll, and the Android specific code is in BugSweeper.Android.dll. Add these two assemblies to Dotfuscator on the Inputs page. Instead of browsing for them on the filesystem, type them in so they reference the "OutDir" property:

  • ${OutDir}\BugSweeper.dll
  • ${OutDir}\BugSweeper.Android.dll

5: Manually exclude symbols from renaming, as appropriate

We recommended keeping Library Mode enabled which excludes renaming public classes, fields, and methods. Disabling Library Mode is not well supported in Xamarin mainly due to heavy use of XAML data bindings. Improvements are in development which will help with this issue.

Some names in BugSweeper.dll need to be excluded from renaming, because they are referenced from the application's XAML in ways that will break if they are renamed. In Dotfuscator, you can exclude specific symbols from renaming from the Renaming -> Exclusions page. Exclude these symbols:

Renaming exclusions 

6: Save

Save the Dotfuscator project to the BugSweeper.Android project's directory. Name the file Obfuscate.Android.xml.

Build, Verify, and Test

Now you should be able to see Dotfuscator's build output during your builds in either Visual Studio or Xamarin Studio:

Dotfuscator's output 

You may need to set Visual Studio's "MSBuild project build output verbosity" option to "Detailed" if you want to see Dotfuscator's output in the VS Output Window during the build. You can find this setting in Visual Studio's Options dialog as shown:

Set te he MSBuild output level to 'Detailed' 

To see how the renaming worked, open the output assemblies in a decompiler as before. Here is a view of the same decompiled code as shown above, after being built with Dotfuscator Community Edition:

Decompiled source, after obfuscation 

The renaming created a layer of obfuscation that hides much of the code's intent and makes it more difficult to follow.

Dotfuscator Professional Edition includes additional transforms, such as control flow obfuscation and string encryption, that provide even more protection by making the decompiler output incorrect code, or no code at all:

Decompiled source, after Dotfuscator Professional 

Community Edition users might want to try a Dotfuscator Professional Edition evaluation!