Protect Your App
Protecting your entire app is as simple as adding a few lines to the app's Visual Studio project file (e.g., MyExecutable.csproj
).
Once integrated, Dotfuscator Professional will protect all of your assemblies - whether from the app's project or other projects in your solution - automatically, with every Release
build.
Integrate into Your Visual Studio Project
To integrate Dotfuscator into a project, edit the project file (.csproj
) in Visual Studio and make the changes shown below.
Only make these changes to your main project (which is probably your startup project).
.NET Framework
To protect a .NET Framework project, copy the new XML elements shown below (<PropertyGroup>
, etc.) and paste them into your project file immediately before the closing </Project>
tag.
Note that the order of the elements is important.
If you are using an SDK-style project see the .NET Core instructions.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<!-- ...existing tags... -->
<!-- Set build properties for Dotfuscator -->
<PropertyGroup>
<!-- Set the location of the Dotfuscator MSBuild targets to import -->
<!-- Defaults to install location, but can be overridden when calling MSBuild -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) -->
<!-- TODO: Set this to false after the file is generated by the first local build -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release builds -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets last -->
<Import Project="$(DotfuscatorMSBuildDir)\PreEmptive.Dotfuscator.Common.targets" />
</Project>
.NET Core or .NET Standard
By default, .NET Core and .NET Standard projects use SDK-style projects.
To protect an SDK-style project, you must ensure that the Dotfuscator targets file is imported last. This can be done by using explicit SDK imports.
First remove the Sdk
attribute from the project's root <Project>
tag. Then, copy the new elements shown below (replacing the SDK name if necessary) into the appropriate positions in your project file.
While Visual Studio and MSBuild on Windows will work with Dotfuscator to protect such projects, the .NET Core commands (dotnet build
/ dotnet msbuild
/ dotnet publish
) are not currently supported.
<!-- ORIGINALLY WAS: <Project Sdk="Microsoft.NET.Sdk"> OR <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> OR similar -->
<Project>
<!-- The Sdk attribute has been replaced with explicit <Import> tags to ensure Dotfuscator's targets are imported after "Sdk.targets" -->
<!-- Import SDK properties -->
<!-- (before any existing tags) -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<!-- UPDATE THE "Sdk" PROPERTY TO MATCH THE VALUE ORIGINALLY IN THE <Project> TAG -->
<!-- ...existing tags... -->
<!-- Import SDK targets -->
<!-- (after any existing tags but before Dotfuscator targets) -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<!-- UPDATE THE "Sdk" PROPERTY TO MATCH THE VALUE ORIGINALLY IN THE <Project> TAG -->
<!-- Set build properties for Dotfuscator -->
<PropertyGroup>
<!-- Set the location of the Dotfuscator MSBuild targets to import -->
<!-- Defaults to install location, but can be overridden when calling MSBuild -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) -->
<!-- TODO: Set this to false after the file is generated by the first local build -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release builds -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets last -->
<Import Project="$(DotfuscatorMSBuildDir)\PreEmptive.Dotfuscator.Common.targets" />
</Project>
Xamarin
Dotfuscator integrates with Xamarin applications as part of the regular Xamarin build process, using the same approach as other .NET platforms. However, there are some unique aspects to the Xamarin integration that you should understand before you begin. You can get started with the instructions here, but for more detail, please see the Xamarin page.
To protect your Xamarin app you must integrate Dotfuscator into each of your output projects (Android, iOS, and UWP). Dotfuscator will protect all assemblies in the project's output directory that originated from the project's solution.
To protect a Xamarin project (we suggest starting with Android), copy the new elements shown below into the appropriate positions in your project file immediately before the closing </Project>
tag.
Note that the order of the elements is important.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- ...existing tags... -->
<!-- Set build properties for Dotfuscator -->
<PropertyGroup>
<!-- Set the location of the Dotfuscator MSBuild targets to import -->
<!-- Defaults to install location, but can be overridden when calling MSBuild -->
<DotfuscatorMSBuildDir Condition="'$(DotfuscatorMSBuildDir)' == ''">$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4</DotfuscatorMSBuildDir>
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) -->
<!-- TODO: Set this to false after the file is generated by the first local build -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
<!-- Enable Dotfuscator for Release -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Release'">true</DotfuscatorEnabled>
<!-- Enable Dotfuscator for Ad-Hoc (only needed for iOS) -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'Ad-Hoc'">true</DotfuscatorEnabled>
<!-- Enable Dotfuscator for AppStore (only needed for iOS) -->
<DotfuscatorEnabled Condition="'$(Configuration)' == 'AppStore'">true</DotfuscatorEnabled>
<!-- Only needed when using Tamper Checks for Android -->
<!-- TODO: If using Tamper Checks for Android, set this to the SHA-1 fingerprint of the certificate used to sign the app -->
<DotfuscatorAndroidSigningCertFingerprint></DotfuscatorAndroidSigningCertFingerprint>
</PropertyGroup>
<!-- Import the Dotfuscator MSBuild targets last -->
<Import Project="$(DotfuscatorMSBuildDir)\PreEmptive.Dotfuscator.Common.targets" />
</Project>
Unity
Integrating Dotfuscator into a Unity project requires special configuration that is not covered by the instructions on this page.
Please see the Unity page to get started.
Build the Project
In Visual Studio, save your changes to the project file, close the tab, and reload the project.
To get a protected app, build the project just as you normally would, in the Release
configuration.
As part of this initial build, Dotfuscator will generate a config file, DotfuscatorConfig.xml
, with default protection settings.
The build will emit a warning to this effect (seen in the screenshot above), which you can ignore for this first build.
Check the generated file into version control.
The build will then call Dotfuscator to protect the solution's assemblies (.exe
and .dll
files) in the project's output directory (e.g., bin\Release
).
Dotfuscator will also produce report files in a new DotfuscatorReports
directory; you should exclude this directory from version control.
Once the build completes, congratulations! Your app is now protected by Dotfuscator!
Note: For help diagnosing build or runtime issues, see Troubleshooting.
Disable Config File Generation
During the first build, Dotfuscator generated a config file, DotfuscatorConfig.xml
, with default protection settings.
This feature is helpful when getting set up, but once the file exists (and is tracked by version control) you should disable this feature because it can mask a certain kind of build error.
To disable config file generation, edit your project file (.csproj
) again and replace the following lines:
<!-- Generate a default Dotfuscator config file (DotfuscatorConfig.xml) -->
<!-- TODO: Set this to false after this file is generated by the first local build -->
<DotfuscatorGenerateConfigFileIfMissing>true</DotfuscatorGenerateConfigFileIfMissing>
with:
<!-- Error if the Dotfuscator config file (DotfuscatorConfig.xml) is missing -->
<DotfuscatorGenerateConfigFileIfMissing>false</DotfuscatorGenerateConfigFileIfMissing>
Examine the Protected Assemblies
After integrating Dotfuscator into your project, you should verify that the integration is operating correctly. You might also be curious about what kind of protection Dotfuscator is applying by default.
The easiest way to answer these questions is to use reverse engineering tools on your project's assemblies, decompiling them back into high-level C# code.
You can decompile assemblies built locally (e.g., in bin\Release
) as well as those laid down by your app's installer.
For full details of how to decompile assemblies, see Decompiling.
As an example, consider decompiling a method in the GettingStarted
sample app before and after integrating Dotfuscator:
Unprotected | Default protection (excerpt) |
---|---|
We can clearly see what the unprotected method is doing, as well as its name, just as if we had the source code.
However, with Dotfuscator's default protection, the simple for
loop has been converted into a confusing mess of switch
and goto
statements by Control Flow obfuscation.
Additionally, the name of the method and its defining type have been replaced with short, meaningless names thanks to Renaming obfuscation.
Note that this is just the default protection Dotfuscator provides. With some additional configuration, Dotfuscator can cause decompilation tools to outright crash when processing your assemblies:
Default protection (excerpt) | Enhanced protection |
---|---|
Dotfuscator can also inject Checks into your app, which detect and respond to unauthorized usage at runtime. For instance, a Debugging Check can detect if a debugger is attached to your production app and, if so, terminate the app.
For details on configuring these and other stronger forms of protection, see Enhance Protection.
Build on Build Agents
In addition to local builds in Visual Studio, Dotfuscator also protects your app during automated builds. For details on setting up Dotfuscator on your build agents, see Build Agent Considerations.
Archive Report Files
As part of the build, Dotfuscator produces report files (in the DotfuscatorReports
directory).
These reports contain information that can be useful when testing, releasing, and supporting a protected app.
For instance, the renaming map file (Renaming.xml
) enables you to decode obfuscated stack traces produced by the app.
You should archive these reports, especially for builds you release. This way, if you later run into an issue with a certain version of your app, you will have the corresponding report files to assist you.
If your team uses a continuous integration and delivery (CI/CD) pipeline or other automated build system, configure it to archive the contents of the DotfuscatorReports
after every build.
Otherwise, make a note in your release process or checklist to manually archive this directory when releasing the app.
Be sure to store the reports in a secure, versioned location so you can refer to them later.
Note: These report files can undo parts of Dotfuscator's protection. Never distribute them outside of your organization.
Enhance Protection
Dotfuscator offers default protection settings when you first integrate it into a Visual Studio project, as demonstrated earlier. These settings are chosen to give your app reasonably-strong protection without requiring you to perform additional configuration, and to reduce the risk of protection interfering with your app's normal operation.
However, Dotfuscator offers much stronger protection than these defaults. For details, see the Enhance Protection page.
Alternative Approaches
This page demonstrated a recommended approach for using Dotfuscator, where the protection is applied by Dotfuscator's MSBuild targets. For some scenarios, this approach may not be suitable. An alternative approach may be better if any of the following are true:
- You need to protect assemblies that don't originate from your solution.
- You need to use Dotfuscator's Linking feature.
- You need Dotfuscator to run after the MSBuild packaging steps.
- Your project is built by a build system other than Visual Studio or MSBuild.
- You don't have access to the Visual Studio project itself, just the already-compiled assemblies (i.e.,
.exe
and.dll
files) or app package (e.g.,.appx
).
In these cases, you will need to have Dotfuscator run after the normal compilation step to create protected versions of the assemblies (.exe
and .dll
files) that were compiled.
The general procedure is as follows:
Use the Dotfuscator Config Editor to create a Config File which specifies the assemblies Dotfuscator will protect and where the protected versions will be written. You can test your configuration locally by building it in the Config Editor. For details, see Working with Configs.
If you use an automated build system, install Dotfuscator onto your build agents.
Call Dotfuscator during your build, after your Visual Studio project has compiled your code into .NET assemblies. You will need to pass the path to the Config File you created as an argument to Dotfuscator.
There are a number of ways to call Dotfuscator, listed below. Note that if you are using the Dotfuscator NuGet package to install Dotfuscator on your build agents, you will need to adjust these examples; see Using the NuGet Package.
The
Dotfuscate
MSBuild task. This is a good choice if you are familiar with MSBuild and have customized your Visual Studio project file to have additional targets or are running a separate MSBuild project. For instance, run Dotfuscator in the well-knownAfterBuild
target:<UsingTask TaskName="PreEmptive.Tasks.Dotfuscate" AssemblyFile="$(MSBuildExtensionsPath)\PreEmptive\Dotfuscator\4\PreEmptive.Dotfuscator.Tasks.dll" /> <Target Name="AfterBuild"> <Dotfuscate ConfigPath="path\to\your\DotfuscatorConfig.xml" /> </Target>
Dotfuscator's Command Line Interface. This can be called from any script or build system which can execute regular Windows programs, so it's a good fit for all scenarios that Dotfuscator supports. For instance, to call Dotfuscator from a Windows batch file:
"%DOTFUSCATOR_HOME%\dotfuscator.exe" path\to\your\DotfuscatorConfig.xml
The Dotfuscator Azure Pipelines Extension. This extension, available in the Visual Studio Marketplace, can be installed into an Azure Pipelines organization to provide the Dotfuscator Professional Command Line task. You can then add the task to your pipeline in the UI and specify the path to your config file in the Path To Config File field. Or, if you use the YAML pipeline syntax, here's an example of an added Dotfuscator step:
- task: DotfuscatorCLI@1 displayName: 'Dotfuscator Professional Command Line using DotfuscatorConfig.xml' inputs: configFile: DotfuscatorConfig.xml
You will need to preserve the report files Dotfuscator produces, at least with every release, but preferably with every build. If your team uses an automated build system, configure it to archive the reports after every build. Otherwise, make a note in your release process or checklist to manually archive this directory when releasing the app. Be sure to store the reports in a secure, versioned location so you can refer to them later.