Virtualization in NETGuard.IO

NETGuard.IO uses virtualization protection in its code flow protection in order to offer the maximal protection.

Standard approach on managed security / obfuscation is about adding entropy to the source code in the MSIL format. This enable code flow obfuscation and other obfuscation feature. However it is quite easy to remove the added code by coding de-obfuscation software, like DE4DOT to name the most famous de-obfuscation tools.

What is not virtualization ?

To exemplify how virtualization works, let’s take a very simple method :

static int test (int a){
 int b = a + 1336;
 return b;

This simple method takes one int parameter and add 1336 to it and return the result, so if the parameter is 1 it will return 1337. Here is the MSIL view of that same simple method :

.method private hidebysig static 
	int32 test (
		int32 a
	) cil managed 
	// Method begins at RVA 0x2052
	// Code size 8 (0x8)
	.maxstack 8

        // grab the parameter's value and push it to the stack
	IL_0000: ldarg.0 
        // add 1336 to the stack
	IL_0001: ldc.i4 1336
        // add up the values on the stack and push result
	IL_0006: add
        // return value on the stack
	IL_0007: ret
} // end of method test

Here is the native machine code of that same method once it’s compiled at runtime :

L0000: mov eax, ecx
L0002: add eax, 0x538// decimal : 1336
L0007: ret

As you can see, it’s fairly easy to guess what the code does, and it’s easier to modify the MSIL code before it gets compiled in native code at runtime by using decompilers, such as DNSPY, or free library that allow you to modify the .NET metadata / bytes of the compiled assembly.

What is virtualization ?

Starting from that, we needed a way to complexify the decompilation / modification process to keep your files safe from potentialy malicious usages. Virtualization is a trendy thing according to the research environment today, especially in the field of software security, more and more virtualization-based security are popping out.

We decided to develop a custom programming language and a custom compiler / interpreter to execute the custom programming language’s code. Not only that, but in order to reduce the possibility for our custom programming language to get mastered by hackers, we decided to add a dynamic parameter to the equation.

Our custom programming language has, like every programming language out there, opcodes, or instructions. Those instructions are instantiated and the source code of the virtualized method is parsed so each time an instruction is detected, the custom programming language interpreter will execute the instruction’s code.

Standard MSIL also has instructions, such as ldarg.0, ldc.i4.0, add, ret etc. You can use a debugger to see how the .NET program’s instructions got executed one after the other, line after line. That is exactly the same thing for our custom programming language’s instructions. Here is a not-so-real preview of what could our custom programming language looks like :

NG_0000: grab 
NG_0001: 0
NG_0002: push 
NG_0003: 1336
NG_0004: tot
NG_0005: end

The syntax has been simplified for demonstration purposes. But you can understand how we created a custom programming language using MSIL as a model.

What makes NETGuard.IO virtualization protection different ?

As you can see above, even the custom programming language can be understood easily. However it cannot be decompiled, because it is not compiled as MSIL.

Yet, there already exists scripts to de-virtualizes famous commercial virtualization protection tools such as VMProtect. To prevent this scenario we decided to go one step further.

Dynamic instruction handlers : every time you obfuscate your file, a new set of instructions is generated, with its respective freshly-generated instruction codes.
Virtualization mutations : we complexify the custom programming language source code by adding mutations and new branches every time you obfuscate a file, so every output is unique.

With time our virtualization protection will improve, because currently it might impact your software performence a little, and with enough dedicated time and skills a hacker could still dump the virtualization handler’s code and puzzle to decode the virtualized code for the given software. But since every obfuscation task generates a unique virtualization output this hacker shall do the same time-consuming process for every file since the virtualization is different each time.