UWP Applications and Dotfuscator

NOTE: These instructions are deprecated; There are new instructions for Dotfuscator Community and for Dotfuscator Professional v4.37 and above.

As of its 4.20 release, Dotfuscator Professional supports protecting Universal Windows Platform (UWP) applications.

There are two recommended ways to incorporate Dotfuscator into your UWP application build process: (1) integrate Dotfuscator into the MSBuild pipeline or (2) use Dotfuscator directly on your appx packages. These methods differ in their ease-of-use and in the level of protection they provide.

Note There is an issue with Method 1 when working with solutions that include a library project. We recommend using Method 2 for all projects. Please contact support if you have issues or questions.

Table of Contents

UWP Release-for-Store Process

In order to assess which approach is right for you, we need to think about the build process for UWP applications. The following diagram illustrates the process of generating artifacts when choosing Store > Create App Packages… in Visual Studio.

All of the diagrams and instructions in this article assume that the following are true:

  1. After choosing Store > Create App Packages…, you answered Yes to the question: Do you want to build packages to upload to the Windows Store? Among other things, this guarantees that your build will be running under the Release configurations.
  2. You have chosen Generate app bundle: Always.
  3. You have not unchecked Compile with .NET Native tool chain in your Release configurations.

When building a UWP application to deploy to the Windows Store in this manner, two application builds are performed.

The first is the Store Build. The assemblies are compiled to IL, packaged in appx files, and archived together in an appbundle. The appbundle, along with other ancillary files, is packaged in an appxupload archive. This archive file is what you upload to the Windows Store. After upload, the Windows Store itself compiles the assemblies to native code suitable for the relevant target platforms.

The second is the Test Build. The assemblies are compiled to IL and then to native code with the .NET Native compiler. They are packaged in appx files and archived together in an appbundle. The appbundle along with other ancillary files are put into a directory whose name will be something like MyApplication_1.3.2.0_Test. Inside of this directory will be a powershell script that will help you sideload the native-code application. Because these assemblies are compiled to native code, testing this application will be most like testing what your customers will obtain from the Windows Store.

uwp build flow method 0

Method 1 Overview: Integrate Dotfuscator into the MSBuild pipeline

uwp build flow method 1

We recommend integrating Dotfuscator into the MSBuild pipeline, because it is the easiest to setup and the easiest to use. It further allows you to easily test natively-compiled obfuscated code, just like your users will get from the store.

However, this approach currently offers somewhat less protection than running Dotfuscator directly on the appx packages post-build. In particular, the XAML (BAML) resources will not be processed for renaming. The next version of Dotfuscator will address this issue so that you will not have to turn off XAML transformation on your input assemblies when using the convenient MSBuild integration. At that time, this approach will be the clear choice over using Dotfuscator manually on the appx packages. UPDATE Version 4.21 of Dotfuscator supports XAML resources as part of the MSBuild pipeline, this is the preferred method going forward.

Find detailed instructions for integrating Dotfuscator into the MSBuild pipeline below.

Method 2 Overview: Use Dotfuscator on the appx packages

This method is most often used in organizations where one team is responsible for developing the application while another team is responsible for adding protection to the application after it has already been built but before it has been deployed to the Windows Store or distributed internally as an LOB application. In other words, you don’t need to have access to the source code or build environment in order to protect your UWP application with Dotfuscator.

uwp build flow method 2

Notice that the Test Build will not be obfuscated, because Dotfuscator cannot process native code assemblies.

Find detailed instructions for using Dotfuscator directly on the appx packages below.

Method 1 Detailed Instructions: Integrate Dotfuscator into the MSBuild pipeline

When incorporating your UWP application into the MSBuild process, you should turn off Renaming and Removal until you have verified that Dotfuscator is, in fact, executing in the build process and that the resulting application is working correctly. Once you’ve verified this, you can turn Renaming and Removal back on and configure any exclusions that may be necessary.

Turn off XAML Transformation

Until there is a Dotfuscator release that processes your XAML (BAML) resources during the MSBuild process, you should uncheck Transform XAML on your UWP assemblies. This can be done on the Input tab of the stand-alone Dotfuscator UI:

uwp turn off transform

Add Dotfuscator to the UWP project files

In each of your UWP csproj files, add a UsingTask reference to the Dotfuscator task:

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

Note that we referenced version 4 of the PreEmptive.Dotfuscator.Tasks.dll. Make sure that you are using the most up-to-date version of Dotfuscator you have (in case you have side-by-side installations of Dotfuscator).

Next, in these same csproj files, configure this Dotfuscator task to be executed during the AfterGenerateAppxManifest build target:

  <Target Name="AfterGenerateAppxManifest">
    <PropertyGroup>
      <DotfuscatorProperties>
        <OutDir>$(OutDir)</OutDir>
        <OutputPath>$(OutputPath)</OutputPath>
      </DotfuscatorProperties>
    </PropertyGroup>
    <Dotfuscate ConfigPath="Dotfuscator.xml" Properties="$(DotfuscatorProperties)" />
  </Target>

The AfterGenerateAppxManifest target will run before any native code compilation and before the packaging step in the Visual Studio deployment.

Notice that we are passing in the OutDir and OutPath properties from the build process to the Dotfuscator process. We can then specify paths in the Dotfuscator project to allow us to configure the project using the stand-alone Dotfuscator UI, while having the build process handle where they actually are at build time.

UPDATE As of Dotfuscator 4.21, you will want to include the $(OutDir) directory as the input. Dotfuscator will recognize the directory as an exploded Appx package, allowing it to properly update markup files.

Configure an assembly-copying Post-Build Event

In order for the UWP-specific build process to find the obfuscated assemblies, they have to be copied back into the original assembly locations after obfuscation. The easiest way to accomplish this is to configure a post-build event in the Dotfuscator project to do this copying for you:

uwp assembly copying post build event

UPDATE As of Dotfuscator 4.21, you will want to include the $(OutDir) directory as the input. Dotfuscator will recognize the directory as an exploded Appx package, allowing it to properly update markup files.

/c xcopy /e /y "${configdir}Dotfuscated" "${OutDir}"

Verify Dotfuscator is executing

Once these steps are complete, you should be able to see Dotfuscator build output during your builds in Visual Studio or when running MSBuild from the command line.

Set MSBuild project build output verbosity to at least Normal in order to see Dotfuscator-related output. (The following image is from using Detailed verbosity.) In Visual Studio 2015, you can set this verbosity level under Tools > Options > Projects and Solution ‒ Build and Run.

uwp vs output

Configure further protection

You can now judiciously turn on Removal and Renaming. Minimally, exclusions will be required for classes and methods referenced in XAML and in the appxmanifest.

Method 2 Detailed Instructions: Use Dotfuscator on the appx packages

For simplicity, these instructions assume that the person building the application is the same as who is processing the application with Dotfuscator. If these people or teams are different, it’s only a matter of creating agreement on how the application will be built in order for it to be processed by Dotfuscator.

When you choose Store > Create App Packages… in Visual Studio, you will be asked Do you want to build packages to upload to the Windows Store?. The following instructions assume that you have answered Yes. This will cause the build process to generate both an appxupload archive suitable for upload to the Windows Store and a Test folder containing a version of the application suitable for sideloading. If you answered No, note that the build process will only generate the Test application for you.

Obtain the appx files

The appxupload file is the file that is ultimately destined for the Windows Store. It contains an appx package file for every platform that your application targets. These appx package files contain managed IL assemblies.

  1. Extract the contents of the appxupload archive file to a directory that we’ll call appxupload-dir. Appxupload files are simply ZIP archives so you can use standard archiving tools (we use 7-Zip) for this step.
  2. Move the appxbundle from that directory to a different working directory. Later, you will move your new appxbundle containing obfuscated assemblies to appxupload-dir and recreate the appxupload from its contents.
  3. Open the Developer Command Prompt for VS2015.
  4. Run the following command to extract the appx package files from the appxbundle archive file (using the name of your appxbundle):
    makeappx unbundle /p MyApplication_1.0.0.0_x86_x64_arm.appxbundle /d unbundled 

In directory unbundled, you should now have an appx package file for each target platform as well as some other files.

Configure and Run Dotfuscator

The following instructions should be followed for each (platform-specific) appx file that will be protected by Dotfuscator.

Redirect the Renaming report

By default, Dotfuscator puts a Map.xml file in the output directory along with your obfuscated packages. For convenience in later steps, have Dotfuscator put this report somewhere other than the output directory.

  1. Open the Dotfuscator stand-alone UI.
  2. On the Settings tab, select Settings > Reports > Renaming.
  3. By default, the “Renaming Report File” will be placed in ${configdir}DotfuscatedMap.xml. Change this to ${configdir}Map.xml or anywhere else other than in the Dotfuscated output directory.

Add Appx as Input

First, open the Dotfuscator stand-alone UI. On the Input tab, add the appx package as the input for Dotfuscator.

Configure Appx Signing

If your appx is signed as part of the MSBuild process, you will need to configure Dotfuscator to re-sign it.

  1. On the Input tab, click on the appx package to highlight it.
  2. Click on the “Modify properties of selected input” button.
  3. Provide the path to the Certificate File, and fill in the rest of the fields as appropriate. The name of your certificate file will be something like MyApplication_StoreKey.pfx; it should have been generated automatically for you by Visual Studio when you generated the appxupload file in the first place.
uwp dotf input properties

Configure Obfuscation and Protection

You can now configure the various Dotfuscator features (Renaming, Removal, String Encryption, etc.) as desired. Remember, though, it is best to get started with all of these features turned off to make sure that your general set-up is working properly. Then begin to turn on features one at a time so that you can comfortably adjust the settings for each feature (e.g. specifying exclusions in Renaming). If you are new to Dotfuscator in general, visit the Dotfuscator Quick Start Guide located on the Dotfuscator Support page to learn the basics.

Automation advice

Managing a separate Dotfuscator configuration file for each platform-specific appx package can get a bit onerous. Consider creating a configuration file that has a Project Property for the name of the input appx package file. You could then run Dotfuscator over each of the appx packages with the same Dotfuscator configuration file, supplying the value of the property on the commandline. Contact Dotfuscator Support if you need any further information on this strategy.

Package the obfuscated application

Rebuild the appxbundle

After running Dotfuscator on all of the extracted appx packages, you should have an appx file for each platform in the Dotfuscator output directory (${configdir}Dotfuscated by default).

Run the following command in the Developer Command Prompt for VS2015 (replacing ..Dotfuscated with the actual path to your Dotfuscator output directory and using the actual name of your appxbundle):

makeappx bundle /o /d "..Dotfuscated" /p MyApplication_1.0.0.0_x86_x64_arm.appxbundle

Sign the appxbundle

With the proper path to your pfx file and the proper name of your appxbundle, run the following command in the Developer Command Prompt for VS2015:

signtool sign /fd sha256 /f "....MyApplication_StoreKey.pfx" MyApplication_1.0.0.0_x86_x64_arm.appxbundle

Rebuild the appxupload

  1. Find the appxupload-dir directory where you extracted the contents of the appxupload file in this earlier step.
  2. Replace the appxbundle in that directory with the one you just packaged.
  3. Using your ZIP archiving tool of choice, rezip the contents of that directory.
  4. Give the archive the same name as the original appxupload file. It will be something appropriately similar to MyApplication_1.0.0.0_x86_x64_arm_bundle.appxupload.

You now have an appxupload that contains assemblies processed by Dotfuscator. It is ready to be uploaded to the Windows Store!

Testing the application

To get a Test application that is obfuscated, build the application with the Debug configuration. Open the assemblies’ project properties windows in Visual Studio. In the Build ‒ General section, ensure that Compile with .NET Native tool chain is unchecked for all platforms under the Debug configuration (it should be by default).

Choose Store > Create App Packages… in Visual Studio. This time, answer No to Do you want to build packages to upload to the Windows Store?. Also, choose the Debug configurations for all platforms.

This action will generate a directory having a name that is something like MyApplication_1.3.2.0_Debug_Test. Inside of this directory you will find an appxbundle. Extract the appx packages and run Dotfuscator on them just like you did in the early steps for the appx packages in the Store build. Repackage the appx packages, and sign the resulting appxbundle. Place the new appxbundle into MyApplication_1.3.2.0_Debug_Test. Sideload your application by running the Powershell script Add-AppDevPackage.ps1 (that can be found in the same directory as your appxbundle).

Note that this is still not entirely the same as what your customers will get from the Windows Store. Their downloaded application will have been compiled to native code by the Windows Store. It is not likely for there to be discrepancies between the managed IL and unmanaged native assemblies, but there are still some things that are not handled properly by the .NET Native compiler; Microsoft recommends testing the native code version of your application. If you think that this discrepancy is a problem for you, then you should seriously consider Method 1.