How to obfuscate .NET applications in Visual Studio Code

C# obfuscation in Visual Studio Code

Contents

Visual Studio Code (not Visual Studio!) is an open-source IDE from Microsoft that supports many programming languages. It can work as a standalone application on Windows, Linux, macOS, and even the Web. With extensions, Visual Studio Code turns into a powerful application used to develop and debug programs. Of course, Visual Studio Code fully supports .NET and C#.

ArmDot is a modern cross-platform .NET obfuscator that runs on Windows, Linux, and macOS. It provides names obfuscation, control flow obfuscation, and code virtualization. ArmDot supports .NET Framework as well as .NET Core.

This guide will teach you to enable .NET obfuscation without leaving Visual Studio Code.

Prerequisites

Ensure that Visual Studio Code is installed. Also, you need C# extension.

Finally, install .NET 6 SDK:
Instal C# extension to Visual Studio Code

Create a sample application

Let’s create a C# console application project named “ObfuscationTest”. Start Visual Studio Code. Click to FileOpen Folder from the main menu.

In the Open Folder dialog, create a new directory, “ObfuscationTest”, select it and click Select Folder. If Visual Studio Code asks Do you trust the authors of the files in this folder?, select Yes:
Create sample application

The folder name ObfuscationTest defines the project name and the default namespace name. Currently, the folder is empty as we will add the code later, but now we are going to create a skeleton of the application.

Click to View – Terminal to open the Terminal window. Type the following command:

dotnet new console --framework net6.0

The standard initial code is added:
Initial code

Replace the generated code in Program.cs with the following one:

namespace ObfuscationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Run the debugging; ensure it displays Hello World! as expected:
The sample application runs well

Enable obfuscation

To use ArmDot, you need to add two packages: ArmDot.Client and ArmDot.Engine.MSBuildTasks. ArmDot.Client provides obfuscation attributes. ArmDot.Engine.MSBuildTasks contains an obfuscation task.

Use the following commands: dotnet add package ArmDot.Client and dotnet add package ArmDot.Engine.MSBuildTasks:
Add .NET packages

To add obfuscation to the building process you need to add a new target that is executed after compilation. Open ObfuscationTest.csproj and insert the following code right before </Project>:

<Target Name="Protect" AfterTargets="Build">
  <ItemGroup>
     <Assemblies Include="$(TargetDir)$(TargetFileName)" />
  </ItemGroup>
  <ArmDot.Engine.MSBuildTasks.ObfuscateTask
    Inputs="@(Assemblies)"
    ReferencePaths="@(_ResolveAssemblyReferenceResolvedFiles->'%(RootDir)%(Directory)')"
  />
</Target>

Now the project contains the target Protect:
Add .NET obfuscation target

Click to RunStart Debugging; the project is rebuilt and started. Switch to Terminal, and you will see the following warning:

C:\Users\Artem\Documents\ObfuscationTest\ObfuscationTest.csproj(103: No methods to protect in the assembly C:\Users\Artem\DocumentationTest.dll

Indeed, we have not told ArmDot what exactly we want to obfuscate. ArmDot provides different options, including names obfuscation, control flow obfuscation, and others. A developer can control ArmDot obfuscation options using ArmDot attributes.

Let’s enable names obfuscation for the entire application by adding ArmDot.Client.ObfuscateNamesAttribute to the assembly:

using System.Reflection;

[assembly:ArmDot.Client.ObfuscateNamesAttribute]

namespace ObfuscationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Start debugging. Switch to Terminal, you will see:

  [ArmDot] Names obfuscation started
  [ArmDot] Names obfuscation finished

Great! ArmDot did its job.

We can obfuscate a particular method. To do that, add an obfuscation attribute to a method:

using System.Reflection;

[assembly:ArmDot.Client.ObfuscateNamesAttribute]

namespace ObfuscationTest
{
    class Program
    {
        [ArmDot.Client.VirtualizeCode]
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Start debugging again and switch to Terminal:

  [ArmDot] Conversion started for method System.Void ObfuscationTest.Program::Main(System.String[])
  [ArmDot] Conversion finished for method System.Void ObfuscationTest.Program::Main(System.String[])

Conclusion

It’s very easy to add a .NET obfuscator in Visual Studio Code:

  1. Add ArmDot packages to a project.
  2. Then enable the obfuscation task in a project file.
  3. Finally, specify obfuscation options using ArmDot obfuscation attributes for an entire assembly or particular types or methods.