Protection, software licensing tool, and obfuscator
for C# and .Net
with support of serial keys and files embedding

3 Reasons To Use ArmDot

1 ArmDot obfuscates .Net code by converting to a virtual machine so it is almost impossible to restore the original code.

2 It's easy to use comprehensive API to issue, block and check serial keys.

3 Embed any kind of files including managed and unmanaged DLLs, data files and other assets into a .Net assembly.

Get Demo Version

Please enter the correct e-mail to get a demo version.

If you have not received a letter please contact us.

Why problems of existing solutions?

Obfuscation by renaming...

Most of protection solutions use a classic approach: obfuscation by renaming classes, methods and properties. It is supposed that in case of hacking much more time will be wasted. It sounds reasonable, but the problem is that instructions are the same, and it is so easy to patch it. undocumented features

Another popular way to protect applications is to use undocumented features of .Net runtime. That could work but, as soon as a new .net runtime version is released, this method stops working.

...or by debugging interface

The third idea is to use unmanaged CLR debugging interface that injects real .Net code at runtime. Unfortunately, a hacker can get this code after injecting, then remove unmanaged part or replace original code with modified one.

What does ArmDot offer?

Virtual Machine that makes code completely incomprehensible. The goal is to convert the original code into an illegible form. ArmDot has a proven approach that is widely used for the unmanaged code: the original code is converted into an array of bytes that is interpreted by special virtual machine. Each time you apply ArmDot, it creates a new version of virtual machine and uses a new set of instructions to represent the original code.

Mix Code is a technique that makes extracting license code checking very complicated. The license key checking code is mixed with the original code and it's really hard to separate one code from another one cause both use the same variables and their instructions overlap.

Let's consider a small sample

In this code a license key is checked at the beginning and then the main form is displayed:

static void Main()
    // Firstly load serial key from registry (you can load it from any source)
    RegistryKey licenseKey = Registry.CurrentUser.OpenSubKey(@"Software\ArmDotSamples\NagScreen\License");
    if (null != licenseKey)

    if (!ArmDot.Client.Api.IsCodeProtected())
        MessageBox.Show("WARNING: the code in not protected");

    if (ArmDot.Client.Api.LicenseKeyState.Valid != ArmDot.Client.Api.GetLicenseState())
        MessageBox.Show("This program is not registered");

    Application.Run(new Form1());

Let's look at the IL code of this method. The code is really obvious:

IL_0000:  nop
IL_0001:  ldsfld     class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.Registry::CurrentUser
IL_0006:  ldstr      "Software\\ArmDotSamples\\NagScreen\\License"
IL_000b:  callvirt   instance class [mscorlib]Microsoft.Win32.RegistryKey [mscorlib]Microsoft.Win32.RegistryKey::OpenSubKey(string)
IL_0010:  stloc.0
IL_0011:  ldnull
IL_0012:  ldloc.0
IL_0013:  ceq
IL_0015:  stloc.1
IL_0016:  ldloc.1
IL_0017:  brtrue.s   IL_002f
IL_0019:  ldloc.0
IL_001a:  ldstr      "key"
IL_001f:  callvirt   instance object [mscorlib]Microsoft.Win32.RegistryKey::GetValue(string)
IL_0024:  castclass  [mscorlib]System.String
IL_0029:  call       void [ArmDot.Client]ArmDot.Client.Api::PutKey(string)
IL_002e:  nop
IL_002f:  call       bool [ArmDot.Client]ArmDot.Client.Api::IsCodeProtected()
IL_0034:  stloc.1
IL_0035:  ldloc.1
IL_0036:  brtrue.s   IL_0045
IL_0038:  nop
IL_0039:  ldstr      "WARNING: the code in not protected"
IL_003e:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
IL_0043:  pop
IL_0044:  nop
IL_0045:  ldc.i4.1
IL_0046:  call       int32 [ArmDot.Client]ArmDot.Client.Api::GetLicenseState()
IL_004b:  ceq
IL_004d:  stloc.1
IL_004e:  ldloc.1
IL_004f:  brtrue.s   IL_005e
IL_0051:  nop
IL_0052:  ldstr      "This program is not registered"
IL_0057:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
IL_005c:  pop
IL_005d:  nop
IL_005e:  call       void [System.Windows.Forms]System.Windows.Forms.Application::EnableVisualStyles()
IL_0063:  nop
IL_0064:  ldc.i4.0
IL_0065:  call       void [System.Windows.Forms]System.Windows.Forms.Application::SetCompatibleTextRenderingDefault(bool)
IL_006a:  nop
IL_006b:  newobj     instance void NagScreen.Form1::.ctor()
IL_0070:  call       void [System.Windows.Forms]System.Windows.Forms.Application::Run(class [System.Windows.Forms]System.Windows.Forms.Form)
IL_0075:  nop
IL_0076:  ret

And this way it looks like after applying ArmDot (only part is shown). How does it work?

      IL_3001:  ldloc      V_11
      IL_3005:  stloc      V_46
      IL_3009:  br         IL_35e4

      IL_300e:  nop
      IL_300f:  ldloc      V_94
      IL_3013:  ldc.i4     0x1
      IL_3018:  ldelem.ref
      IL_3019:  castclass  [mscorlib_4]System.Reflection.FieldInfo
      IL_301e:  stloc      V_270
      IL_3022:  ldloc      V_94
      IL_3026:  ldc.i4     0x2
      IL_302b:  ldelem.ref
      IL_302c:  stloc      V_25
      IL_3030:  ldloc      V_270
      IL_3034:  ldloc      V_25
      IL_3038:  callvirt   instance object [mscorlib_4]System.Reflection.FieldInfo::GetValue(object)
      IL_303d:  stloc      V_59
      IL_3041:  ldloc      V_21
      IL_3045:  ldloc      V_270
      IL_3049:  callvirt   instance class [mscorlib_4]System.Type [mscorlib_4]System.Reflection.MemberInfo::get_DeclaringType()
      IL_304e:  ldloc      V_59
      IL_3052:  ldc.i4     0x0
      IL_3057:  stloc      V_173
      IL_305b:  stloc      V_112
      IL_305f:  stloc      V_241
      IL_3063:  stloc      V_235
      IL_3067:  nop
      IL_3068:  ldloc      V_173
      IL_306c:  brtrue     IL_307b
      IL_3071:  ldstr      ""
      IL_3076:  br         IL_3080
      IL_307b:  ldstr      "&"
      IL_3080:  nop
      IL_3081:  stloc      V_247
      IL_3085:  ldloc      V_235
      IL_3089:  stloc      V_168
      IL_308d:  ldloc      V_168
      IL_3091:  switch     ( 
      IL_30aa:  br         IL_3241
      IL_30af:  nop


If you have not received a letter please contact us.

Embed files with the help of ArmDot

It's easy to add dependencies: managed and unmanaged DLLs, data files and other assets to the output .Net assembly.

If a .Net code requires an unmanaged DLL, just add the DLL to Assembly Directory and build a project.

After building the project, the output .net assembly will work as if the embedded DLL really exists.

In other cases one may need to hide assets: videos, images and other files. Embedded files are not stored on a disk, but in the process memory instead, therefor it's hard to extract them.

More Screenshots

Main Window

Main Window

License Key Generation

License Key Generation

License Keys

License Key Generation