Objective Remove the 'Trial protection' from an obfuscated .NET application
  • WinDbg
  • CFF Explorer
Target audience Advanced users

The second part of the article discusses how to modify binaries that are obfuscated. For simplicity and clarity, I will not use obfuscated binaries. Doing this, allows the reader to understand what is actually happening. In the demo I will completely ignore the name of the methods or the actual, non-obfuscated, code.

I recommend reading the first part, if you didn't already. It provides some information that might be needed to understand theis second part.

The same 'TrialApp.exe' binary is used. The current approach, as opposed the the former one, is:

  1. Load the application in debugger and break the execution when the trial message is displayed.
  2. Get the call stack
  3. Find the address of the trial check method
  4. Remove the call

1. Load the application in debugger and break the execution when the trial message is displayed

WinDbg can be obtained for free from Windows SDK (see the Microsoft Downloads website). If you are running a 64 bit OS, make sure you start the 32bit version of WinDbg (should be in Program Files (x86)).

Load 'TrialApp.exe' in WinDbg by clicking File -> Load Executable. In order to run it you have 3 options:

  1. Type 'g' and press ENTER
  2. Press F5
  3. Click Debug -> Go

The application will start and the execution will stop when the message box is displayed. Is actually waiting for the user to click OK. At this point break the execution by pressing Debug -> Break.

Before being able to debug the .NET application, 2 DLLs needs to be loaded. They help the debugger 'understand' the .NET internals. The actual paths might differ on your configuration. Anyway, make sure you load the 32 bit version of these files (the 64 bit version are in the Framework64 folder). The .load command loads external libraries.

.load c:\Windows\Microsoft.NET\Framework\v4.0.30319\SOS.dll
.load c:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll

2. Get the call stack

A call stack is associated with a thread. Before getting the stack we need to figure out which is the thread for which we want it. Execute the following command and inspect the output...


There are two thread having IDs 0 and 2. Is quite easy to decide which is the main thread since just one of them is Single Thread Apartment (STA). Switch to the main thread and display the CLR stack using the following commands:


3. Find the address of the trial check method

OK! You're still with me? If yes, then take a look at the result of the last command. It displays the call stack of the main thread. Notice that OnCreateControl calls OnLoad, OnLoad calls From1_Load, etc. In the case of obfuscated code, the name would probably be strange and you would have to analyze each method in depth. Because the code was JIT compiled the call to the trial check was inlined.

Let's take a look at the IL code for Form1_Load. To do this, first we need the address description of the MethodDesc structure of method. The ip2md command returns the structure. The argument is the IP address of the method. After this, just dump the IL for the address specified in MethodDesc. I want to make on observation here: if you look at the MethodDesc structure you can see the mdToken field. This field specified the table and the row in the table for the this method (the row corresponding to this method is the 6th, because the index starts at 0).

!ip2md 003f01f9
!dumpil 00176304

In case of obfuscated code, you would probably see just a call instruction to some cryptic method. It makes no difference. We can see that at IL_0001 (relative to the start of the method) we have a call and this instruction uses 5 bytes in the file (0006-0001 = 0005; in hex)).

Having the size of the instruction, its position and the row of the method in the methods table we can proceed further. Open CFF Explorer and load the assembly.

Navigate to .NET Directory -> MetaData Streams -> #~ -> Tables. Look for the Method table in the new tree and select the entry with number 5. Copy its RVA value.

4. Remove the call

With the RVA in hand (on clipboard :-) ), remove the call just like in the first part of the article. Replace the call bytes with zeros. One observation: we must also remove the instruction before the call (ldarg_0; opcode 02; no arguments). So, zero 6 bytes starting at the first in the method.

In other words, replace:

00 00 0A 02 28 08 00 00 06 2A 1E 02 28 06 00 00
06 2A 66 02 7B 02 00 00 04 2C 10 72 01 00 00 00


00 00 0A 02 28 08 00 00 06 2A 1E 00 00 00 00 00
00 2A 66 02 7B 02 00 00 04 2C 10 72 01 00 00 00

Run the application. The trial check is gone.