Post

Obfuscar: Question on Local Variables

It is not a surprise that many people would like to try out Obfuscar, one of the most popular .NET obfuscation tools, and they have various questions on the obfuscation results. Thus, I might post from time to time on what you should expect from such a tool, and help you better understand C#, .NET, as well as Obfuscar.

Today, let’s start with a recent issue on GitHub regarding local variables in C# methods.

The Sample Code

So, we will use the simplest C# sample below as our test case,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Security.Cryptography.X509Certificates;

namespace C_
{
    class Program
    {
        static void Main(string[] args) 
        {
            var test = Int32.MinValue;
            Console.WriteLine(test);

            var test2 = new X509Certificate2();
            Console.WriteLine(test2);
        }
    }
}

If you use dotnet new console to create a test project and replace the content of Program.cs with the snippet above, you can then easily compile everything to an assembly, such as bin/Debug/net7.0/testconsole.dll.

If variable names are kept after compilation, we should be able to see them in MSIL format.

Disassembling MSIL

You might want to find a disassembler somewhere, and I just published a new global tool for .NET SDK here,

1
$ dotnet tool install --global dotnet-ildasm2

With this tool installed, you can easily run the following command to disassemble the Main method from the assembly,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ildasm testconsole.dll -i Program::Main


.class private auto ansi beforefieldinit C_.Program extends [System.Runtime]System.Object
{

  .method private hidebysig static default void Main(string[] args) cil managed
  {
    // Method begins at Relative Virtual Address (RVA) 0x2050
    .entrypoint
    // Code size 28 (0x1C)
    .maxstack 1
    .locals init(int32 V_0, class [System.Security.Cryptography.X509Certificates]System.Security.Cryptography.X509Certificates.X509Certificate2 V_1)
    IL_0000: nop
    IL_0001: ldc.i4 -2147483648
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: call void class [System.Console]System.Console::WriteLine(int32)
    IL_000d: nop
    IL_000e: newobj instance void class [System.Security.Cryptography.X509Certificates]System.Security.Cryptography.X509Certificates.X509Certificate2::.ctor()
    IL_0013: stloc.1
    IL_0014: ldloc.1
    IL_0015: call void class [System.Console]System.Console::WriteLine([System.Runtime]System.Object)
    IL_001a: nop
    IL_001b: ret
  } // End of method System.Void C_.Program::Main(System.String[])
} // End of class C_.Program

As you can see, the original variable names test and test2 are nowhere to find. As we are currently working on a debug build assembly, we can see that C# compiler left hints for local variables in .locals. But even there names like V_0 and V_1 are not related to the original variable names.

If we disassemble the corresponding release build, we will see

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.class private auto ansi beforefieldinit C_.Program extends [System.Runtime]System.Object
{

  .method private hidebysig static default void Main(string[] args) cil managed
  {
    // Method begins at Relative Virtual Address (RVA) 0x2050
    .entrypoint
    // Code size 21 (0x15)
    .maxstack 8
    IL_0000: ldc.i4 -2147483648
    IL_0005: call void class [System.Console]System.Console::WriteLine(int32)
    IL_000a: newobj instance void class [System.Security.Cryptography.X509Certificates]System.Security.Cryptography.X509Certificates.X509Certificate2::.ctor()
    IL_000f: call void class [System.Console]System.Console::WriteLine([System.Runtime]System.Object)
    IL_0014: ret
  } // End of method System.Void C_.Program::Main(System.String[])
} // End of class C_.Program

which does not even have .locals any more.

Conclusion

Thus, now you know that local variable names are lost during C# compilation, so that any obfuscation tool needn’t to perform anything else on them.

Stay tuned for more.

© Lex Li. All rights reserved. The code included is licensed under CC BY 4.0 unless otherwise noted.
Advertisement

© - Lex Li. All rights reserved.

Using the Chirpy theme for Jekyll.

Last updated on April 14, 2024