Let’s be honest, releasing a library, desktop app, or mobile app can be a bit scary. Once your software is freely available to the world, you lose a certain degree of control over how it will be used. In particular, developers are often concerned with the threat of reverse engineering.
On many platforms and languages, code obfuscation tools are a familiar way to guard against reverse engineering. For instance, if you’re an Android developer, you may have already used ProGuard to shrink and obfuscate Java code.
Now, Xamarin developers have access to that same kind of protection across all major mobile device families, from Android and iOS to Universal Windows (UWP). The tool for the job is Dotfuscator, the Community Edition of which is available in Visual Studio.
Today I’ll explain how obfuscation can protect a Xamarin.Android app from reverse engineering, and how you can apply that same protection to your own Xamarin apps with a few simple steps.
How Obfuscation Protects Apps
Obfuscation is a process where an app’s compiled code is transformed into code that is functionally-identical but harder to reverse engineer. Typically, this is done by an automated obfuscation tool, or obfuscator. Below is a simple example to demonstrate how obfuscation guards apps against reverse engineering.
Consider the following C# method in the source code for a Xamarin.Android game:
When the developers of this game are ready to deploy it to a device, or upload it to an app store, they compile the source code into libraries and then package those libraries into an app bundle. In this example, the developers package the libraries into an APK file for distribution on Android devices.
However, once the app is released to an app store, a bad actor can easily obtain and reverse engineer the APK, producing decompiled code that is nearly identical to the original source code:
Note that the type, method, and member identifiers are the same here as they were in the source code, even if those code elements aren’t normally accessible from outside the project (i.e. they were marked
internal). Also note that the general control flow of the method, such as the ordering of
if statements, is plainly visible.
If, before distributing the APK, the developers also ran the libraries through the Dotfuscator Community Edition, the results of reverse engineering would be different:
The code has been protected with renaming obfuscation, a basic form of code obfuscation. Properties with straightforward names, such as
ArrowsOnHand, have been replaced by method calls with unintuitive names, such as
g. Other code elements have similarly been renamed. This makes reading and reasoning about the decompiled code much harder, as important contextual clues provided by the names are no longer available.
Renaming obfuscation is the main focus of this blog post, but we’ll discuss more advanced forms of obfuscation, and how to apply them, later.
How to Obfuscate Your App
Now, let’s go over how to integrate Dotfuscator Community Edition’s renaming obfuscation into your Xamarin build pipeline. As an example, I’ll be using the Xamarin.Android app mentioned in the previous section. You can follow along with your own Xamarin app, including those for iOS and UWP.
We’ll be using PreEmptive Protection – Dotfuscator, a .NET obfuscator and protection tool that now also supports Xamarin.
Note: These steps assume you are developing your app with Visual Studio 2017 for Windows.
Install and Set Up Dotfuscator
First, you need to install Dotfuscator on your development machine. Since we’ll be using Dotfuscator’s command line interface, you also need to register your copy and record the path to the interface.
To install and set up Dotfuscator:
- Visit the Dotfuscator Downloads page on the PreEmptive Solutions website.
- Download the latest update of Dotfuscator Community Edition (CE) for Visual Studio 2017.
- While Dotfuscator is included with Visual Studio, PreEmptive Solutions occasionally releases important updates to Dotfuscator between releases of Visual Studio. Installing Dotfuscator this way ensures you have the latest updates.
- Run the VSIX file you downloaded and follow the instructions.
- Open Visual Studio 2017 and select Tools -> PreEmptive Protection – Dotfuscator to launch the Dotfuscator Community Edition user interface.
- You’ll need to register your copy of Dotfuscator before you can use the command line interface. Dotfuscator will ask you to register when you run it for the first time; follow these instructions.
- To register later or check your registration status, look for the Registration status text in the upper-right corner of the Dotfuscator Community Edition start page.
- Browse to the install directory for your installation of Visual Studio 2017. For instance, the default install directory for Visual Studio 2017 Professional is
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional.
- Within this directory, locate the Dotfuscator Community Edition extension files in
dotfuscatorCLI.exeexecutable is the Dotfuscator Community Edition command line interface. Record the absolute path to the executable for use later.
Download the Build Integration File
To simplify the integration process, the Dotfuscator team has created an MSBuild targets file, which your Xamarin projects can reference. You can download it here.
PreEmptive.Dotfuscator.Xamarin.targets file to your solution’s directory, under source control.
Modify the Project to Use the Build Integration
Next, you’ll need to modify the project file for the Visual Studio project you want to obfuscate. To modify your project file:
- Note what project build configurations you want to protect. Typically these are everything except Debug configurations. For more guidance, see the Select What to Protect section of the full documentation.
- Open the project file in a text editor. An example project file for C# would be `YourProjectName.csproj`.
- Note the relative path from this file to the build integration file you downloaded.
- Import the build integration file by adding the following line to the file, immediately before the
<Import Project="..\..\PreEmptive.Dotfuscator.Xamarin.targets" />, substituting the relative path noted in step 3.
- Under the
<PropertyGroup>tag with no
Conditionattribute, add the following tags:
<DotfuscatorXamarinCliPath>C:\pathto\dotfuscatorCLI.exe</DotfuscatorXamarinCliPath>, substituting the absolute path to the Dotfuscator Community Edition command line interface you recorded earlier.
- For each build configuration noted in step 1, locate the corresponding
<PropertyGroup>and add the following tag:
- After the last
<ItemGroup>tag, add the following:
<ItemGroup><None Include="DotfuscatorConfig.xml" /></ItemGroup>
- Save and close the file.
Build the App
Now you can build the app with Dotfuscator’s obfuscation protection. To do so:
- Open or reload your project in Visual Studio.
- Select a solution build configuration that exercises a project build configuration you decided to protect.
- Build the project.
- After this first build, note the build output contains the following lines regarding Dotfuscator:
- Note the addition of a
DotfuscatorConfig.xmlfile in your project. This is the Dotfuscator config file, which tells Dotfuscator how to obfuscate your code. It is recommended to check it into source control.
- On the filesystem, notice the new
DotfuscatorReportsdirectory in your project’s directory. This directory contains information about how the project was obfuscated, including how to reverse the renaming process. You should treat this directory like a build output, and have source control ignore it.
- Test your app. If you see errors, you may need to configure Dotfuscator further to maintain correct behavior; see the next section for reference.
- Continue developing your app, building as you would normally. When Dotfuscator is used during a build, the build output will contain the following lines:
For more information on continuing development with obfuscation in place, please see the Continuing Development section in the Dotfuscator User Guide.
There may be some cases where an app assumes that the name of a code element at compile time will be the same at runtime. This is especially true for Xamarin apps, which rely on XAML and reflection. Renaming obfuscation can break this assumption, causing the obfuscated app to behave differently.
While newer versions of Dotfuscator are better able to handle these scenarios automatically, some cases may need to be manually configured. For instructions and an example, see the Identify Renaming Exclusions page of the Dotfuscator User Guide.
Instead of the free Dotfuscator Community Edition, you can also obfuscate your Xamarin apps with Dotfuscator Professional Edition. Professional Edition is licensed for use on commercial products, and free trials are available upon request.
To see the difference between Community and Professional editions, consider the game example from earlier. If the developers ran their libraries through Dotfuscator’s Professional Edition, instead of Community Edition, the results of reverse engineering would look like this:
In addition to renaming obfuscation, this code is now also protected by control flow obfuscation. The original code’s statements are scattered among obtuse `switch` blocks, in a seemingly random order, making it very difficult to follow. This and other advanced forms of obfuscation are exclusive to Dotfuscator Professional Edition.
In this blog post, we’ve seen how Dotfuscator can be used to protect Xamarin libraries and apps from reverse engineering. While I used an Android app as an example, these same steps can also be applied to iOS and UWP projects, so you can protect your app no matter what platforms it runs on.
For more details on how to protect Xamarin projects with Dotfuscator, see the Xamarin page of the Dotfuscator User Guide. There you’ll also find a git repository demonstrating how to integrate Dotfuscator into a Xamarin app for all three platforms.