Patching .NET Binary Code with CFF Explorer
Abstract
The purpose of this article is to show how to bypass various security checks by modifying binary code directly, rather than source code, through the use of CFF Explorer. We have already looked at the diverse ways of circumventing IL code earlier. There we have accomplished such crucial tasks by playing with IL byte code instruction. This article basically teaches you how to identify the corresponding binary code instructions using the IL disassembler; then you will learn how to modify such binary code (hex code) using an editor such as CFF Explorer.
Become a certified reverse engineer!
Prerequisites
It is presumed that the user has a thorough understanding and knowledge of binary coding manipulation and that you have installed a fresh copy of CFF Explorer software in order to edit the binary code instructions. Apart from that, the user should have a deep understanding of MSIL code instruction as well.
The Cracking .NET Application
Here, we are developing a demo C#.net application in order to illustrate how to bypass the security constraints of a program that performs a calculation or conversion of Centigrade to Fahrenheit. The code for the implementation of trial expiration is:
[cpp]
public partial class Conversion : Form
{
public Conversion()
{
InitializeComponent();
private void TrialExpiredCheck()
{
if (isTrialExpired)
{
MessageBox.Show(@"Trial Duration has expired!
Installed Freh copy","!!!!Alert Message!!!!");
Application.Exit();
}
}
private void Conversion_Load(object sender, EventArgs e)
{
TrialExpiredCheck();
#region Calculation code
private void button1_Click(object sender, EventArgs e)
{
double c = Convert.ToDouble(textBox1.Text);
double f = (c * 9 / 5) + 32;
label3.Text = f.ToString();
}
#endregion
}
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 about the calculation conversion code and others.
After successfully compiling this source code, the CLR produces its executable file. During the trial duration, the user interface prototype of this product would look like this:
But the vendor of this product releases its beta version and provides only a free trial version in the market that works for a specific duration. Once this duration is complete, it will expire automatically and an alert message will flash on the screen. After the OK button is clicked, it automatically unloads the application. The alert message looks like this:
Now, there are two options that will allow you to keep using the product. Either buy the product key (full version), which, of course, requires some money, or reverse-engineer the logic implementation in order to bypass the security checks. But we don't have the source code, so how can we do this? 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, we are provided with the executable version. All we have to do is modify the binary code of this product in order to bypass the security restrictions by using the .NET shipped ILDASM.exe; we have already seen couple of examples of manipulation using ILDASM in the previous articles of this reverse-engineering series but, from the point of view of this article, the ILDASM role is slightly different. This time, we will dump the executable file in search of RVA (relative virtual address) instruction, which is obtained when we compile with the corresponding line number option. So first open the target assembly in ILASM:
The IL Disassembler will reveal all the statements for each method in line-by-line format. The RVA column typically allows the runtime to calculate the starting memory address of the MSIL, defining 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 amount of raw IL code but our main concern is to find TrialExpireCheck() method corresponding code, as follows:
[cpp]
.method private hidebysig instance void TrialExpiredCheck() cil managed
{
// Method begins at RVA 0x2134
.maxstack 2
.line 16,16 : 9,10 ''
IL_0000: /* 00 */ nop
.line 17,17 : 13,32 ''
IL_0001: /* 02 */ ldarg.0
IL_0002: /* 7B (04)000004 */ ldfld bool Fahrenheit.Conversion::isTrialExpired
IL_0007: /* 16 */ ldc.i4.0
IL_0008: /* FE01 */ ceq
IL_000a: /* 0A */ stloc.0
IL_000b: /* 06 */ ldloc.0
IL_000e: /* 00 */ nop
.line 19,20 : 17,81 ''
IL_000f: /* 72 | (70)000041 */ ldstr "Trial Duration has expired!”
IL_0014: /* 72 | (70)0000EA*/ ldstr "!!!!Alert Message!!!!"
IL_001e: /* 26 */ pop
.line 21,21 : 17,36 ''
IL_001f: /* 28 | (0A)000021*/ call void [System.Windows.Forms]System.Windows.Forms.Application::Exit()
IL_0024: /* 00 */ nop
.line 22,22 : 13,14 ''
IL_0025: /* 00 */ nop
.line 23,23 : 9,10 ''
IL_0026: /* 2A */ ret
} // 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 perform C/C++/VC++ PE file modification. The CFF Explorer, however, was designed for PE editing with full support for the .NET binary file, but without losing sight of the portable executable internal structure. This wonderful tool encapsulates bundles of tools that might help reverse-engineering. 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. Open CFF Explorer (this is a free utility that can be downloaded from www.ntcore.com). Open the target .NET executable file (Fahrenheit.exe) and it will decompile it and then load all of the associated binary code.
As you can see in the following image, CFF Explorer reveals almost 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, including resource modification, hex editing, disassembling, address conversion, and finally rebuilding or rewriting the file.
Our main interest is "Address Converter," which is located in the middle left panel. Just open it and you will find the executable file in the form of binary code. One of the sophisticated and complex tasks is to directly manipulate or modify the binary instruction because we don't have any information 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, which points out the real source code line number and sequence of bytes. Basically, RVA represent the segment address for method (TrialExpiredCheck), which includes all the logic for the security constraints. This instruction indicates that this method body starts from the address 0x2134 in the raw hex bytes.
// Method begins at RVA 0x2134
We have to perform two tasks in order to bypass the trial version expiration restrictions;
- Stop or divert the call of Application.Exit() method in account of carting on the execution.
- Remove the "Trial version expired" alert message box.
So, by using this value 0x2134, we can directly jump into the security constraint logic code, as shown below;
Divert or Remove the Call to Application.Exit() method
We have to first identify the associated bytes in the hex code that are responsible for executing Application.Exit() method. After carefully scrutinizing the IL code defined earlier, we can figure out that opcode IL_001f is key code as;
IL_001f: /* 28 | (0A)000021*/ call void [System.Windows.Forms]System.Windows.Forms.Application::Exit()
IL_0024: /* 00 */ nop
IL_0025: /* 00 */ nop
IL_0026: /* 2A */ ret
The associated byte values are shown in red; we have to align them in proper sequence. This is normally done right to left as following;
28 21 00 00 0A 00 00 2A
You can also spot such a byte sequence in the CFF hex code editor, as shown below;
So, if we change the bytes between 26 and 2A to nop (00), then we can stop or remove the call of Applicaton.Exit method:
We have now successfully removed the call to Exit() method.
Remove the Call to Alert Message Box
If we examine the IL code thoroughly, we can easily see that there is Boolean variable, isTrialExpired, which is configured to be True by default and, in the TrialExpiredcheck() method, its value is checked in a condition. Because the Boolean variable value is true, if condition construct execution always true and an alert message box will be flashed.
IL_0002: /* 7B (04)000004 */ ldfld bool Fahrenheit.Conversion::isTrialExpired 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 follows;
So, this is the hack: If we remove this if condition check by replacing the IL_00c instruction value 2D with 2C, then the if construct is never executed and no alert message box shows up.
Finally, save the modification that you have made to the binary code file because it is also provides the functionality of rebuilding the executable file. Now test the executable: The message box does not appear and the executable file loads successfully.
Bingo! We have successfully removed all the security restriction.
Summary
This article showed how to edit or patch the binary code instructions without having the actual source code. We employed a third-party tool, CFF Explorer, which 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 understanding how this works, we can easily reverse-engineer the .NET binary code as per our requirement.
Disclaimer: I, Ajay Kumar, have no intent to teach any offensive tactics and I don't support any Black Hat activities. The reason for this article is to provide white hat or defensive knowledge for study or testing.