Patching .NET Binary Code by CFF Explorer

This article explains how to edit or patch the binary code instructions without having the actual source code.

Abstract

The triggering point behind this article is to bypass the various security checks by modifying binary code directly rather than source code using the CFF Explorer. We however have already been confronted with the diverse ways of circumventing IL code earlier. There we have accomplished such crucial tasks by playing with IL byte code instructions. This article basically teaches how to identify the corresponding binary code instructions using the IL disassembler then explains how to modify such binary code (hex code) using an editor such as the CFF Explorer.

Prerequisites

It is assumed that the user must have a thorough understanding and knowledge of binary coding manipulation and has an installed fresh copy of the CFF Explorer software in order to edit the binary code instructions. Apart from that, the user is supposed to have a deep understanding of MSIL code instructions as well.

The Victim .NET Application

Here, we are developing a demo C# Demo application to illustrate the bypass of the security constraints that typically perform a calculation or conversion of Centigrades to Fahrenheits. Here, the code for the trial expiration implementation is as in the following:

  1. public partial class Conversion : Form  
  2. {  
  3.     bool isTrailExpired = true;  
  4.   
  5.     public Conversion()  
  6.     {  
  7.         InitializeComponent();  
  8.     }  
  9.   
  10.     private void TrialExpiredCheck()  
  11.     {  
  12.         if (isTrailExpired)  
  13.         {  
  14.             MessageBox.Show(@"Trail Duration has expired!   
  15.                                   Installed Freh copy", "!!!!Alert Message!!!!");  
  16.             Application.Exit();  
  17.         }  
  18.     }  
  19.     private void Conversion_Load(object sender, EventArgs e)  
  20.     {  
  21.         TrialExpiredCheck();  
  22.     }  
  23.  
  24.     #region Calculation code  
  25.     private void button1_Click(object sender, EventArgs e)  
  26.     {  
  27.         double c = Convert.ToDouble(textBox1.Text);  
  28.         double f = (c * 9 / 5) + 32;  
  29.         label3.Text = f.ToString();  
  30.     }  
  31.     #endregion  
  32. }  
Here, after carefully going through the code, we can easily figure out that the TrialExpiredCheck() method is responsible for product expiration. We don't need to bother with the calculation conversion code and others.

After successfully compiling this source code, the CLR produces an executable file. During the trial duration, the user interface prototype of this product would be as in the following:

convert

But, the vendor of this product released its beta version and provides only a free trial version in the market that works for a specific duration and once this duration is complete, it will expire automatically and an alert message will flash on the screen as well as after clicking the OK button it will automatically unload the application file as in the following.

alert message

Now, there are two options to carry out your operation, either buy the product key (full version) but that of course requires some money or reverse-engineer the logic implementation to bypass the security checks. But we don't have the source code, so how to do this? Yes, it is still possible by changing the binary code of the executable using CFF Explorer.

IL code Disassembling

Although we don't have the source code of this product, instead we are only providing the executable version. So, all we need to modify is the binary code of this product in order to alleviate the security restrictions using the .NET shipped ILDASM.exe; we have already seen a couple of manipulations with the ILDASM in the previous articles of the reverse engineering series but at the point of this article view, the ILDASM role is slightly different. We this time dump the executable file in search of the Relative Virtual Address (RVA) instruction that is obtained when we perform the compilation with the corresponding line number option. So first open the target assembly in the ILASM as in the following:

dump option

Opening the target binary in the IL Disassembler will reveal all the statements from each method in line by line format. The RVA column typically allows the runtime to calculate the starting memory address of the MSIL that defines the method that contains the trial check, the bytes for each statement and their position relative to the RVA. The disassembled or decompiled file however, produces a large number of raw IL code but our main concern is the TrailExpireCheck() method corresponding code as in the following:
  1. .method private hidebysig instance void TrialExpiredCheck() cil managed  
  2.   {  
  3.     // Method begins at RVA 0x2134  
  4.     .maxstack  2  
  5.     .locals init ([0] bool CS$4$0000)  
  6.   
  7.     .line 16,16 : 9,10 ''  
  8.     IL_0000:  /* 00 */            nop  
  9.     .line 17,17 : 13,32 ''  
  10.     IL_0001:  /* 02  */          ldarg.0  
  11.     IL_0002:  /* 7B  (04)000004 */     ldfld      bool Fahrenheit.Conversion::isTrailExpired  
  12.     IL_0007:  /* 16 */             ldc.i4.0  
  13.     IL_0008:  /* FE01 */        ceq  
  14.     IL_000a:  /* 0A  */           stloc.0  
  15.     IL_000b:  /* 06  */            ldloc.0  
  16.     IL_000c:  /* 2D  18 */       brtrue.s   IL_0026  
  17.   
  18.     IL_000e:  /* 00  */             nop  
  19.     .line 19,20 : 17,81 ''  
  20.     IL_000f:  /* 72   | (70)000041 */    ldstr      "Trail Duration has expired!”  
  21.     IL_0014:  /* 72   | (70)0000EA*/    ldstr      "!!!!Alert Message!!!!"  
  22.     IL_0019:  /* 28   | (0A)000020*/ call  valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string,string)         
  23.   
  24.     IL_001e:  /* 26  */    pop  
  25.     .line 21,21 : 17,36 ''  
  26.     IL_001f:  /* 28   | (0A)000021*/ call  void [System.Windows.Forms]System.Windows.Forms.Application::Exit()  
  27.     IL_0024:  /* 00   */   nop  
  28.     .line 22,22 : 13,14 ''  
  29.     IL_0025:  /* 00  */    nop  
  30.     .line 23,23 : 9,10 ''  
  31.     IL_0026:  /* 2A */     ret  
  32.   } // end of method Conversion::TrialExpiredCheck  
CFF Explorer

Although there are a couple of Hex editing or binary editing tools available such as Ollydbg and IDApro, they don't support .NET binary code editing, they can only do C/C++/VC++ PE file modification. The CFF Explorer however was designed to allow PE editing with full support for the .NET binary file, but without losing the Portable Executable internal structure. This wonderful tool encapsulates bundles of tools that might assist reverse engineers. The CFF Explorer includes the following features. 
  • Hex Editor
  • Quick Disassembler (x86, x64, MSIL)
  • Full support for PE32/64
  • PE Utilities, PE Rebuilder Process Viewer
  • Drivers Viewer
  • Windows Viewer
  • PE and Memory Dumper
  • View and modification of .NET internal structures
  • Resource Editor
  • Support in the Resource Editor for .NET resources
  • PE integrity checks
  • Dependency Walker
  • Deep Scan method
  • Report generation
  • Signatures Updater
  • Signatures Retriever

Binary code patching

Now it is time for action. First open the CFF Explorer (this is a free utility and can be download from www.ntcore.com). Here, open the target .NET executable file (Fahrenheit.exe) and it will first decompile it and then load the entire associated binary code.

As you can see in the following image, The CFF Explorer yields nearly every detail about this executable file, such as its name, file type, development environment, file size, PE size and hashing format. We can perform bundles of operations using CFF Explorer, such as resource modification, hex editing, disassembling, address conversion and finally rebuild or rewrite the file.

cff explorer

Despite having many features, our main concern is the Address Converter located in the middle left panel. Just open it and you will find the executable file in the form of corresponding binary code. It is one of the sophisticated and complex tasks to directly manipulate or modify the binary instruction. Because we don't have any something about which instruction is responsible for which binary hex value.

That is why we disassembled that executable file into IL code earlier in order to find the RVA value and binary code sequences. The IL code file has each instruction with its exact line number that points out the real source code line number and sequence of bytes. Basically the RVA represents the method (TrialExpiredCheck) segment address that includes all the security constraint logic. This instruction indicates that this method body starts from the address 0x2134 in the hex raw bytes.

// Method begins at RVA 0x2134

We exactly need to perform two tasks to bypass such trial version expiration restrictions as in the following:

  1. Stop or divert the call of the Application.Exit() method in the account of carting on the execution.
  2. Remove the trial version expired alert message box.

So, by using this value 0x2134, we can directly jump in the security constraint logic code as in the following:

address convert

Divert of Remove the Call of Application.Exit() method

We must first identify the associated bytes in the hex code that are responsible for executing the Application.Exit() method. After carefully scrutinizing the IL code defined earlier, we can figure out the opcode IL_001f is the key code as in the following:

Divert of Remove the Call

In the Red color, the associated byte value is given; we must align them in proper sequence. This is normally done right to left as in the following:

28 21 00 00 0A 00 00 2A

You can also spot such byte sequence in the CFF hex code editor also as in the following:

status

So, if we change the bytes between 26 and 2A to a nop (00), then we can stop or remove the call of the Applicaton.Exit method. We have successfully removed the call to the Exit() method as in the following.

ApplicatonExit method

Remove the call of Alert message box

If we examine the IL code thoroughly, we can easily determine that there is a Boolean variable isTrialExpired configured to True by default and in the TrailExpiredcheck() method, its value is checked in a condition. Because the Boolean variable value is true, the if condition construct execution is always true and an alert message box will be flashed.

IL_0002: /* 7B (04)000004 */ ldfld bool Fahrenheit.Conversion::isTrailExpired
IL_0007: /* 16 */ ldc.i4.0
IL_0008: /* FE01 */ ceq
IL_000a: /* 0A */ stloc.0
IL_000b: /* 06 */ ldloc.0
IL_000c: /* 2D 18 */ brtrue.s IL_0026

The real byte sequence would be as in the following:

offset

So, this is the hack, if we remove this if condition checking by replacing the IL_00c instruction value 2D to 2C then the if construct is never executed and no alert message box is shown.

Finally, save the modification that you have done in the binary code file because it is also provides the functionality of rebuilding the executable file. Now test the executable, there is no message box shown and the executable file is successfully loading.

Bingo! We have successfully removed all the security restrictions as in the following.

fahrenheit
Summary

This article taught us how to edit or patch binary code instructions without having the actual source code. We employed a third-party tool CFF Explorer that supports the .NET binary file modification unlike the other hex editors. We have also learned one of the advanced dumping tactics of IL code in order to obtain the real line number and actual corresponding byte sequences. After getting an understanding of how this works, we can easily reverse engineer the .NET binary code as per our requirements.

Disclaimer: I Ajay Kumar do not intend to teach any offensive tactics or don't support any black hat kind of activities. This article motive is to provide white hat or defensive knowledge for study or for testing point purposes.