PreEmptive logo

Xamarin Applications and Dotfuscator

Project properties

Note: this document is deprecated. Please see Obfuscating Xamarin Applications with Dotfuscator for up to date instructions on obfuscating Xamarin applications.

We are often asked if Dotfuscator supports protecting Xamarin applications. The answer is yes, given that Xamarin applications are based on Mono, a .NET compatible runtime! However, applying obfuscation transformations to Mono assemblies is only one half of an effective obfuscation solution; the other half is making sure that the configuration and automation of the obfuscation process itself is straightforward and stable. We’ve been working hard to make Dotfuscator more Mono-friendly lately, specifically with an eye towards improving Xamarin compatibility. 

You could use many different methods to get your Xamarin assemblies processed by Dotfuscator and then packaged for deployment to devices. The steps outlined below should be the easiest to implement while giving you a reasonable expectation of protection. Note that the instructions below are specifically for Android and iOS projects. We recommend building the store-ready XAP first and then running it through Dotfuscator as usual for Windows Phone projects.

Obfuscating Xamarin Applications

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. For the obfuscated outputs to be appropriately processed by Xamarin, Dotfuscator’s “Mono Compatible” global setting should be set to “Yes,” and a project property of “controlflow.disabled_manglers” with a value of “ILSpyBreaker” should be added.

Xamarin’s platform-specific utilities heavily use reflection, so as a starting point, it is recommended to simply exclude the input assemblies from renaming (while still allowing control-flow obfuscation). Once that is working, you can then enable renaming if desired, and take the time to determine the minimum number of exclusions needed for your application.

In each Android or iOS csproj file, you should then add a reference to the Dotfuscate task and a target for AfterBuild, like so:

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

////SNIP////

<Target Name="AfterBuild">
    <PropertyGroup>
        <DotfuscatorProperties>
            <OutDir>$(OutDir)</OutDir>
            <OutputPath>$(OutputPath)</OutputPath>
        </DotfuscatorProperties>
    </PropertyGroup>
    <Dotfuscate ConfigPath="Obfuscate.Android.xml" Properties="$(DotfuscatorProperties)"/>
  </Target>

Notice that we are passing in specific properties from the build process to the Dotfuscator process. Specifically, OutDir and OutPath. By using project properties with default values, we can specify paths in the Dotfuscator project file, allowing us to configure the project using the stand-alone Dotfuscator UI while having the build process handle where they actually are at build time.

Project Properties

For the Xamarin platform-specific build process to properly find the obfuscated assemblies, they must be copied back into the original assembly locations after obfuscation. Android has an additional restriction in that the original obfuscated PCL must also be copied back to its project-specific location. The easiest way to accomplish this is to have a post-build event in the Dotfuscator project to do the copying:

Post-build events

Adding an “ObRelease” and/or “ObDebug” configuration can be helpful to for obfuscating only when explicitly needed and wanted. This can be accomplished by adding a Condition property to the Dotfuscate element in the csproj (for instance: Condition=" '$(Configuration)' == 'ObRelease' "). Note that when adding a new “Release” config for Android, one needs to disable “Use Shared Runtime” and “Enable developer instrumentation” in the Android Options under the Packaging tab.

Once these steps are complete, you should be able to see Dotfuscator’s build output during your builds in either Visual Studio or Xamarin Studio:

code output
target afterbuild

This will produce output packages containing obfuscated assemblies that are ready for deployment and testing!

Example Dotfuscator File

This is a fully configured Dotfuscator file for an Android project, as described in this post. Note the use of properties and the post-build event.


<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE dotfuscator SYSTEM "https://www.preemptive.com/dotfuscator/dtd/dotfuscator_v2.3.dtd">
<dotfuscator version="2.3">
  <propertylist>
    <property name="controlflow.disabled_manglers" value="ILSpyBreaker" />
    <property name="OutDir" value="C:UsersObfuscationUserDocumentsVisual Studio 2015ProjectsObXFormsPObXFormsPObXFormsP.DroidbinRelease" />
    <property name="OutputPath" value="binRelease" />
  </propertylist>
  <global>
    <option>monocompat</option>
    <option>verbose</option>
  </global>
  <input>
    <loadpaths />
    <asmlist>
      <inputassembly refid="52f75f71-2d9e-4e8a-911b-a24e252f60c6">
        <option>honoroas</option>
        <option>stripoa</option>
        <option>transformxaml</option>
        <file dir="${OutDir}" name="ObXFormsP.dll" />
      </inputassembly>
      <inputassembly refid="840c659d-7536-4ad6-9040-2f9c520a8968">
        <option>honoroas</option>
        <option>stripoa</option>
        <option>transformxaml</option>
        <file dir="${OutDir}" name="ObXFormsP.Droid.dll" />
      </inputassembly>
    </asmlist>
  </input>
  <output>
    <file dir="${configdir}Dotfuscated" />
  </output>
  <renaming>
    <option>xmlserialization</option>
    <excludelist>
      <assembly>
        <file dir="${OutDir}" name="ObXFormsP.Droid.dll" />
      </assembly>
      <type name="ObXFormsP.App" />
    </excludelist>
    <mapping>
      <mapoutput overwrite="false">
        <file dir="${configdir}Dotfuscated" name="Map.xml" />
      </mapoutput>
    </mapping>
    <referencerulelist>
      <referencerule rulekey="{6655B10A-FD58-462d-8D4F-5B1316DFF0FF}" />
      <referencerule rulekey="{7D9C8B02-2383-420f-8740-A9760394C2C1}" />
      <referencerule rulekey="{229FD6F8-5BCC-427b-8F72-A7A413ECDF1A}" />
      <referencerule rulekey="{2B7E7C8C-A39A-4db8-9DFC-6AFD38509061}" />
      <referencerule rulekey="{494EA3BA-B947-44B5-BEE8-A11CC85AAF9B}" />
      <referencerule rulekey="{89769974-93E9-4e71-8D92-BE70E855ACFC}" />
      <referencerule rulekey="{4D81E604-A545-4631-8B6D-C3735F793F80}" />
    </referencerulelist>
  </renaming>
  <controlflow level="high" />
  <eventlist>
    <event type="postbuild">
      <option>buildsuccessful</option>
      <program>
        <file dir="c:windowssystem32" name="cmd.exe" />
        <environment commandline="/c copy /y &quot;${configdir}Dotfuscated*.dll&quot; &quot;${OutDir}&quot; &amp; copy /y &quot;${configdir}DotfuscatedObxFormsP.dll&quot; &quot;${configdir}..ObXFormsP${OutputPath}&quot;" workingdir="" />
      </program>
    </event>
  </eventlist>
  <sos mergeruntime="true">
    <option>version:v4</option>
    <option>dontsendtamper</option>
  </sos>
  <smartobfuscation>
    <smartobfuscationreport verbosity="all" overwrite="false" />
  </smartobfuscation>
</dotfuscator>

In This Article:

Start a Free Trial of PreEmptive Today