Search
Blog Index

Navigation
Tuesday
Dec252012

.NET Reversing

 

reblogged from :

 

Demystifying Dot NET Reverse Engineering, Part 1: Big Introduction

This, and all upcoming parts, are made with a strict and pure educational purpose just to gain insights into dot NET programs. What you’re going to do with this and all upcoming parts is your own responsibility. I will not be held responsible for your eventual action and use of this.

All techniques used in this and all upcoming parts have been used only to demonstrate theories and methods described. The scope of this paper and all upcoming parts as well as any other paper written by me (Soufiane Tahiri) is of sharing knowledge and improving reverse engineering techniques.
And please note that disassembling and / or reversing software is prohibited by almost all international laws, if you like software then please BUY IT.

Introduction

This will be a kind of “saga” of papers that will talk essentially talk about dot NET oriented reverse engineering. We are already on the stable version 4.5 (4.5.50709) / 15 August 2012 of Microsoft .NET Frameworks for Visual Studio 2012 and distributed with Windows 8, Windows Server 2012, but we are still not seeing enough papers about reversing applications developed using dot NET technology.

I’ll try to fill this lack of papers, and this first article is supposed to be a part of an upcoming series that would explain some basics and clarify dot NET architecture to the extent of making a few concepts clearer for reverse engineers.

Before starting, I strongly recommend you take a few hours to teach yourself at least one of the dot NET languages, and I recommend either Visual Basic .NET or C#. It may seem to some that reversing dot NET programs is way easier then reversing “traditional” programs, which is wrong in my point of view.

The concept of dot NET can be easily compared to the concept of JAVA and Java Virtual Machine, at least when talking about compilation. Unlike most traditional programming languages like C/C++, applications developed using dot NET frameworks are compiled to a Common Intermediate Language (CIL or Microsoft Common Intermediate Language MSIL) – which can be compared to bytecode when talking about Java programs – instead of being compiled directly the native machine executable code, the Dot Net Common Language Runtime (CLR) will translate the CIL to the machine code at runtime.

This will definitely increase execution speed, but has some advantages since every dot NET program will keep all classes’ names, functions’ names variables and routines’ names in the compiled program, and this, from a programmer’s point of view, is such a great thing since we can make different parts of a program using different programming languages available and supported by frameworks.


Figure 1. Visual overview of the Common Language Infrastructure (CLI) / Wikipedia

What does this mean to a reverse engineer?

Basically every compiled dot NET application is not more than its Common Intermediate Language representation, which still has all the pre-coded identifiers just the way they were typed by the programmer.

Technically, knowing this Common Intermediate Language will simply lead to identifying high level language instructions and structure, which means that from a compiled dot NET program we can reconstitute back the original dot NET source code, with even the possibility of choosing to which dot NET programming language you want this translation to be made and this is a pretty annoying thing!

When talking about dot NET applications, we talk about “reflection” rather than “decompilation”, this is a technique which lets us discover class information or assembly at runtime, this way we can get all properties, methods, functions, etc. with all parameters and arguments, we can also get all interfaces, structures, etc.

Nowadays there are plenty of tools that can “reflect” the source code of a dot NET compiled executable; a good and really widely used one is “Reflector” with which you can browse classes, decompile and analyze dot NET programs and components. It allows browsing and searching CIL instructions, resources and XML documentation stored in a dot NET assembly. But this is not the only tool we will need when reversing dot NET applications. I’ll try to introduce each one every time we are in need of it.

What will you learn from this first paper?

This first essay will show you how to deal with Reflector to reverse a very simple practice oriented Crack-ME I did the very basic way, and it does not pretend to explain real software protection (that will come via the next articles).

Let’s practice

Our Crack-ME is a simple one form dot NET application that asks us for a password. I made it to show you some very basics about dot NET reverse engineering, usually we start by looking at the target and see its behavior, this way we can determinate what should we look for!

This displays a nasty message box when filling in a bad password:

Let us now see why this piece of compiled code shows us “Invalid password”. Open up Reflector, at this point we can configure Reflector via the language’s drop down box in the main toolbar, and select whatever language you may be familiar with. I’ll choose Visual Basic, but the decision is up to you of course.


Figure 2. Choosing the main language

Load this Crack-ME up into it (File > Open menu) and look for anything that would be interest us.
Technically, the Crack-ME is analyzed and placed in a tree structure. We will develop nodes that interest us:

Figure 3. Our Crack-ME is loaded up

You can expand the target by clicking the “+” sign:

Keep on developing the tree and see what is inside of this Crack-ME:

Now we can see that our Crack-ME is composed of References, Code and Resources.

  1. Code: this part contains the interesting things, and everything we will need at this point is inside of InfoSecInstitute_dotNET_Reversing (which is a Namespace).
  2. References: is similar to “imports”, “includes” used in other PE files.
  3. Resources: for now this is irrelevant to us, but it is similar to ones in other Windows programs.

By expanding the code node we will see the following tree:

Reflector detects the only form our Crack-ME has called Form1, with all variables, procedures, functions and Graphical User Interface elements, and as explained above it recognized original names, which makes things easier for us and lets us guess what everything is supposed to do. For example, the function btn_Chk_Click(Object, EventArgs) that seems to be triggered when the button “btn_Chk” is clicked, btn_About_Click(Object, EventArgs) which is presumably called when button “btn_About” is clicked…

Since this is an application to practice, it has not a lot of forms and functions, which makes things easier for us; we can now say that what interests us is what the function btn_Chk_Click () has to say. We want to know what our Crack-ME actually does once we click on btn_Chk, and this can be translated to the language we choose (refer to Figure 2).

To see actual source code, double click on the function name. Reflector shows us the decompiled source code in the language chosen, in this example we will get:

Nothing magical, we can see clearly as sun what this function does, everyone with very basic knowledge in any programming language can see that this function / procedure tests if the password typed is “p@55w0rd!”, and by checking this we get:

This is pretty easy! We can explore more abilities like patching this Crack-ME to accept all typed passwords, which will be certainly the next part of this course.

I tried to avoid giving you complex explanations regarding dot NET application and decided not to flood you in this first part with information that may discourage you. I tried to show you the clearest way to deal with a very basic protection, hopefully this taught you few more things that matter while reversing dot NET programs. In the next parts, I’ll try to introduce more in-depth knowledge about how dot NET programs really work

References

 

 

Demystifying dot NET reverse engineering – PART 2: Introducing Byte Patching

Introduction

We covered in the first part the very basics regarding dot NET programs, how they are compiled (which we will see again a little bit more in depth) and how we can see inside them using Reflector. We saw how easy is to bypass protections based on hardcoded serials or passwords, this was really very basic and almost always we have to do more to go in depth of real programs protections.

Practicing reverse engineering in general, and not only when we talk about reversing dot NET programs, is not only about getting serials or passwords; reverse engineering is the art of playing with bytes, it’s about changing bytes to alter functionalities, to disable or to enable some of them, in some cases it’s used to add some entire functionalities, and this is not always a simple task. To do this, mastering assembly is a must, and not only this, but finding in the program the right place and figuring out what bytes to change. This is not usually a simple thing.

In this paper and the upcoming one, we will try to practice some byte changing (commonly called “patching”) practices using different homemade targets. We will reuse the first file, which is “CrackMe#1-InfoSecInstitute-dotNET-Reversing”, and a second target that will be “ReverseMe#1-InfoSecInstitute-dotNET-Reversing”.

Compiling dot NET

As seen in the first part, every dot NET program is coded using some high level dot NET programming language (vb.NET, C#…) and when compiling, this high level programming language is taken to a low level one which is Microsoft Intermediate Language (MSIL) and can be considered as the lowest common denominator for dot NET. We can build a full application using nothing but only MSIL, and though this is not interesting from a point of view of a “dot NET developer”, it may be more helpful as it gives an insight into how Common Language Runtime (CLR) actually works and runs our high level code.

Just like Java and Java Virtual Machine, any dot NET program is first compiled (if we can permit saying this) to a IL or MSIL language and is executed in a runtime environment: Common Language Runtime (CLR), and then is recompiled or converted on its execution to local native instructions like x86 or x86-64, which are set depending on what type of processor is currently used. This is done by Just In Time (JIT) compilation used by the CLR.

To recapitulate, the CRL uses a JIT compiler to compile the IL (or MSIL) code which is stored in a Portable Executable (our compiled dot NET high level code) into platform specific code, and then the native code is executed. This means that dot NET is never interpreted, and the use of IL and JIT is to ensure the dot NET code is portable.

The figure below demonstrates this process:

Understanding MSIL

The aim of this paper is to introduce you to some new IL instructions. Beyond the obvious curiosity factor, understanding IL and how to manipulate it will just open the doors of playing around with any dot NET programs and in our case, figuring out our program’s security systems weakness.

Before going ahead, it’s wise to say that CLR executes the IL code. Allowing this way of making operations and manipulating data, the CRL does not handle directly the memory, it uses instead a stack, which is an abstract data structure which works according to the “last in first out” basis. We can do two important things when talking about the stack: pushing and pulling data. By pushing data or items into the stack, any already present items just go further down in this stack. By pulling data or items from the stack, all present items move upward toward the beginning of it. We can handle only the topmost element of the stack.

Well, let’s return back to our “CrackMe#1-InfoSecInstitute-dotNET-Reversing”. By typing in a wrong password, the Crack ME shows us this message box:

We got in the first part of “Demystifying dot NET reverse engineering” the hard coded password, now we will see how to force this Crack Me into accepting all wrong passwords by only changing some bytes.

Let’s go back to our Crack ME #1 opened into Reflector. We have the original source code that checks the password typed:

private
btn.Chk.Click({


if (this.
Text == “p@55w0rd!”)

{


“Congratulations !”
, “Correct!”);

}


else

{


MsgBox(“Invalid password”, “Error!”);

}

}

And by switching to IL code view we get this:

.method
private
instance
btn.Chk.Click(class [mscorlib]System.EventArgs e) cil managed

{


.maxstack 3

L.0000: ldarg.0

L.0001: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.TextBox
get.txt.Pwd()

L.0006: callvirt instance
System.Windows.Forms]System.Windows.Forms.TextBox::get.Text()

L.000b: ldstr “p@55w0rd!”

L.0010: ldc.i4.0

L.0011: call Microsoft.VisualBasic] L.0016: ldc.i4.0

L.0017: bne.un.s L.002d

L.0019: ldstr “Congratulations !”

L.001e: ldc.i4.s 0×40

L.0020: ldstr “Correct!”

L.0025: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, L.002a: pop

L.002b: br.s L.003f

L.002d: ldstr “Invalid password”

L.0032: ldc.i4.s 0×10

L.0034: ldstr “Error!”

L.0039: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, L.003e: pop

L.003f: ret

}

This is the direct representation of the internal Intermediate Language, and this is the level we will be prompted to deal with to make changes. As said above, dot NET is essentially a stack machine, and we will need some references to understand what this IL code means. We can find a listing of all IL assembly instructions and their use. I’ll try to expose and explain the most important ones relative to reverse engineering uses.

IL Instructions start right after the “.maxstack #” line, the first line is L.0000: ldarg.0 which loads argument 0 onto the stack, and this may be easily compared to NOP instruction in traditional assembly code, but its actual byte code is “00″, not “90″ as in x86 assembly. If we open any program using the hexadecimal editor, we will find a series of byte codes from the first line to the last one, which is byte code representing every IL instruction composing our program, and this is what we can change to let the program do things which are not “supposed” to be done when we want to invert some tests or jumps or alter any part of the code.

The use of a hexadecimal editor is in some ways the traditional “dirty” way to replace actual bytes; we will discover how to do it this way and we’ll see how other more “clean” ways work. To locate the offset of bytes we want to change in our hexadecimal editor, we have to look for these bytes to locate the series of bytes we are willing to change.

Every IL instruction has its specific byte representation. I’ll try to introduce to you a non-exhaustive list of most important IL instructions, their functions and the actual bytes representation, and you are not supposed to learn them but use this list as a kind of reference:

 

IL Instruction Function Byte representation
And Computes the bitwise AND of two values and pushes the result onto the evaluation stack. 5F
Beq Transfers control to a target instruction if two values are equal. 3B
Beq.s Transfers control to a target instruction (short form) if two values are equal. 2E
Bge Transfers control to a target instruction if the first value is greater than or equal to the second value. 3C
Bge.s Transfers control to a target instruction (short form) if the first value is greater than or equal to the second value. 2F
Bge.Un Transfers control to a target instruction if the first value is greater than the second value, when comparing unsigned integer values or unordered float values. 41
Bge.Un.s Transfers control to a target instruction (short form) if the first value is greater than the second value, when comparing unsigned integer values or unordered float values. 34
Bgt Transfers control to a target instruction if the first value is greater than the second value. 3D
Bgt.s Transfers control to a target instruction (short form) if the first value is greater than the second value. 30
Bgt.Un Transfers control to a target instruction if the first value is greater than the second value, when comparing unsigned integer values or unordered float values. 42
Bgt.Un.s Transfers control to a target instruction (short form) if the first value is greater than the second value, when comparing unsigned integer values or unordered float values. 35
Ble Transfers control to a target instruction if the first value is less than or equal to the second value. 3E
Ble.s Transfers control to a target instruction (short form) if the first value is less than or equal to the second value. 31
Ble.Un Transfers control to a target instruction if the first value is less than or equal to the second value, when comparing unsigned integer values or unordered float values. 43
Ble.Un.s Transfers control to a target instruction (short form) if the first value is less than or equal to the second value, when comparing unsigned integer values or unordered float values. 36
Blt Transfers control to a target instruction if the first value is less than the second value. 3F
Blt.s Transfers control to a target instruction (short form) if the first value is less than the second value. 32
Blt.Un Transfers control to a target instruction if the first value is less than the second value, when comparing unsigned integer values or unordered float values. 44
Blt.Un.s Transfers control to a target instruction (short form) if the first value is less than the second value, when comparing unsigned integer values or unordered float values. 37
Bne.Un Transfers control to a target instruction when two unsigned integer values or unordered float values are not equal. 40
Bne.Un.s Transfers control to a target instruction (short form) when two unsigned integer values or unordered float values are not equal. 33
Br Unconditionally transfers control to a target instruction. 38
Brfalse Transfers control to a target instruction if value is false, a null reference (Nothing in Visual Basic), or zero. 39
Brfalse.s Transfers control to a target instruction if value is false, a null reference, or zero. 2C
Brtrue Transfers control to a target instruction if value is true, not null, or non-zero. 3A
Brtrue.s Transfers control to a target instruction (short form) if value is true, not null, or non-zero. 2D
Br.s Unconditionally transfers control to a target instruction (short form). 2B
Call Calls the method indicated by the passed method descriptor. 28
Clt Compares two values. If the first value is less than the second, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack. FE 04
Clt.Un Compares the unsigned or unordered values value1 and value2. If value1 is less than value2, then the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack. FE 03
Jmp Exits current method and jumps to specified method. 27
Ldarg Loads an argument (referenced by a specified index value) onto the stack. FE 09
Ldarga Load an argument address onto the evaluation stack. FE 0A
Ldarga.s Load an argument address, in short form, onto the evaluation stack. 0F
Ldarg.0 Loads the argument at index 0 onto the evaluation stack. 02
Ldarg.1 Loads the argument at index 1 onto the evaluation stack. 03
Ldarg.2 Loads the argument at index 2 onto the evaluation stack. 04
Ldarg.3 Loads the argument at index 3 onto the evaluation stack. 05
Ldarg.s Loads the argument (referenced by a specified short form index) onto the evaluation stack. 0E
Ldc.I4 Pushes a supplied value of type int32 onto the evaluation stack as an int32. 20
Ldc.I4.0 Pushes the integer value of 0 onto the evaluation stack as an int32. 16
Ldc.I4.1 Pushes the integer value of 1 onto the evaluation stack as an int32. 17
Ldc.I4.M1 Pushes the integer value of -1 onto the evaluation stack as an int32. 15
Ldc.I4.s Pushes the supplied int8 value onto the evaluation stack as an int32, short form. 1F
Ldstr Pushes a new object reference to a string literal stored in the metadata. 72
Leave Exits a protected region of code, unconditionally transferring control to a specific target instruction. DD
Leave.s Exits a protected region of code, unconditionally transferring control to a target instruction (short form). DE
Mul Multiplies two values and pushes the result on the evaluation stack. 5A
Mul.Ovf Multiplies two integer values, performs an overflow check, and pushes the result onto the evaluation stack. D8
Mul.Ovf.Un Multiplies two unsigned integer values, performs an overflow check, and pushes the result onto the evaluation stack. D9
Neg Negates a value and pushes the result onto the evaluation stack. 65
Newobj Creates a new object or a new instance of a value type, pushing an object reference (type O) onto the evaluation stack. 73
Not Computes the bitwise complement of the integer value on top of the stack and pushes the result onto the evaluation stack as the same type. 66
Or Compute the bitwise complement of the two integer values on top of the stack and pushes the result onto the evaluation stack. 60
Pop Removes the value currently on top of the evaluation stack. 26
Rem Divides two values and pushes the remainder onto the evaluation stack. 5D
Rem.Un Divides two unsigned values and pushes the remainder onto the evaluation stack. 5E
Ret Returns from the current method, pushing a return value (if present) from the caller’s evaluation stack onto the caller’s evaluation stack. 2A
Rethrow Re throws the current exception. FE 1A
Stind.I1 Stores a value of type int8 at a supplied address. 52
Stind.I2 Stores a value of type int16 at a supplied address. 53
Stind.I4 Stores a value of type int32 at a supplied address. 54
Stloc Pops the current value from the top of theevaluation stack and stores it in a the local variable list at a specified index. FE 0E
Sub Subtracts one value from another and pushes the result onto the evaluation stack. 59
Sub.Ovf Subtracts one integer value from another, performs an overflow check, and pushes the result onto the evaluation stack. DA
Sub.Ovf.Un Subtracts one unsigned integer value from another, performs an overflow check, and pushes the result onto the evaluation stack. DB
Switch Implements a jump table. 45
Throw Throws the exception object currently on the evaluation stack. 7A
Xor Computes the bitwise XOR of the top two values on the evaluation stack, pushing the result onto the evaluation stack. 61

 

Now that we have a quite good IL instructions reference, we can get back to Reflector and our Crack Me to start imagining how we can get rid of its protection:

We can see from the picture above that the portion of code:

private
btn_Chk_Click({


if (this.
“p@55w0rd!”)

{


“Congratulations !”, “Correct!”);

Is just translated to this:

L_0010: ldc.i4.0

L_0011: call Microsoft.VisualBasic] L_0016: ldc.i4.0

L_0017: bne.un.s L_002d

L_0019: ldstr “Congratulations !”

L_001e: ldc.i4.s 0×40

L_0020: ldstr “Correct!”

L_0025: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic]valuetype [Microsoft.VisualBasic]L_002d as you can see:

L_0016: ldc.i4.0

L_0017: bne.un.s L_002d

L_0019: ldstr “Congratulations !”

This starts making sense, and lets us think about how we can bypass typing in a valid password. Instead of showing “Congratulations!” if the password is correct, we can reverse it and force the program into showing us this message if a password is not correct. The instruction that does this is Beq.s which is, “Transfers control to a target instruction (short form) if two values are equal” (refer to the reference list above).

Problems:

Technically we have two problems. First, we need to find out byte representation of the IL instruction we want to change. Second we do not have an actual offset of the instruction to go there directly in a hexadecimal editor.

Solutions:

Referring the list above we see that bne.un.s = 0×33 and Beq.s = 0x2E; to find the location in file where we have to make changes, we have to translate a few instructions to make a long enough searching string to find what we are looking for.

Always referring to the list above we get:

ldc.i4.0 = 0×16, bne.un.s L_002d = 0×33 and 0x?? Value representing the L_002d and ldstr = 0×72

So our searching string will look like 1633??72. Of course, using “??” means the use of regular expressions when doing search and means the use of a wildcard, and this depends on which hexadecimal editor you use. I’ll use WinHex but you are free to use whatever hexadecimal editor you want:

Here we have to edit 16331472 to 162E1472. Always think about making backups before doing any changes just in case.

Testing our change

Let’s now run our modified / patched version of our Crack Me and see if what we did is right:

Seems all right, but let’s just see what our byte changing actually looks like inside Reflector:

And by switching to IL view mode we can see:

This still is a basic dot NET byte patching process, but is necessary to start from basics before dealing with many more relatively complicated things. We will see in the next chapter some advanced byte patching techniques and how to deal with them.

References

 

 

Demystifying dot NET reverse engineering – PART 3: Advanced Byte Patching

In the first two parts, we saw some basics that will let you reverse-engineer some dot NET applications; we covered the concepts of dot NET compilation, we presented Microsoft Common Intermediate Language, we analyzed some low-level code using code reflection, and we saw a nonexhaustive list of IL instructions with their functions and their byte representations.

We also covered the basics of byte patching, how to find the location of bytes we want to change in a hexadecimal editor, and how to change them.

In this part of our dot NET reverse engineering series I will introduce you to some advanced byte patching as well as a concept of a basic aspect of license check protection and how we can reverse-engineer it (as requested by readers). We will introduce new tools as well, and see how we can deal with them.

The deal

In this practice, I have tried to respond to a few questions and suggestions regarding the two first parts. I tried to simulate in this second Crack Me a “real” software protection with disabled button, disabled feature, and license check protection; our third practice looks like this:

So basically we have to enable the first button, which has the “Enable Me” caption; by clicking it we will get the “Save as…” button enabled, which will let us simulate a file-saving feature. We will see where the license check protection is triggered later in this article.

Let’s disassemble our target using ILSpy, which is very similar to Reflector so we will not need to present it (a link to download it is in the References). Once analyzed, our Crack Me is placed on a tree structure very similar to Reflector’s. By expanding nodes we see the following:

We can already clearly see some interesting methods with their original names, which is great. We have only one form in this practice, so let’s see what “Form1_Load(object, EventArgs) : void” has to say. We can see actual code just by clicking on the method’s name, and we get this:

If you have any coding background you can easily guess that “this.btnEnableMe.Enabled = false;” is responsible for disabling the component “btnEnableMe” which is a button, in our case. At this point, it’s important to see the IL and the byte representation of the code we are seeing. Let’s switch to IL view and see:

.method private
instance void Form1_Load (
object sender,
class [mscorlib]System.EventArgs e
) cil managed
{
// Method begins at RVA 0x1b44c
// Code size 29 (0x1d)
.maxstack 2
.locals init (
[0] valuetype [System.Drawing]System.Drawing.Color
)

IL_0000: ldarg.0
IL_0001: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Button CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnEnableMe()
IL_0006: ldc.i4.0
IL_0007: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
IL_000c: ldarg.0
IL_000d: callvirt instance class [System.Windows.Forms]System.Windows.Forms.Label CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()
IL_0012: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Red()
IL_0017: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)
IL_001c: ret
} // end of method MainForm::Form1_Load

In the code above we can see some IL instructions that should be explained (in the order in which they appear):

  1. ldarg.0 Pushes the value 0 onto the evaluation stack.
  2. callvirt Calls the method get() associated with the object btnEnableMe.
  3. ldc.i4.0 Pushes 0 onto the stack as a 32-bit integer.
  4. callvirt Calls the method set() associated with the object btnEnableMe.

This says that the stack got the value 0 before calling the method set_Enabled(bool); 0 is in general associated with “False” when programming, so we will have to change this 0 to 1 in order to pass “True” as parameter to the method set_Enabled(bool). The IL instruction that pushes 1 onto the stack is ldc.i4.1

In the previous chapter, we saw that byte representation is important in order to know the exact location of the IL instruction to change and to what it should be changed, so by referring to the IL byte representation reference we have:

 

IL Instruction Function Byte representation
Ldc.I4.0 Pushes the integer value of 0 onto the evaluation stack as an int32. 16
Ldc.I4.1 Pushes the integer value of 1 onto the evaluation stack as an int32. 17
Callvirt Calls a method associated with an object. 6F
Ldarg.0 Loads argument 0 onto the stack. 02

 

We have to make a big sequence of bytes to search the IL instruction we want to change; we have to translate ldc.i4.0,
callvirt
, ldarg.0,
and callvirt to their respective byte representations and make a byte search in a hexadecimal editor.

Referring the list above, we get: 166F??026F??; the “??” means that we do not know either the instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool) (at IL_0007) bytes representation or the bytes representation of instance class [System.Windows.Forms]System.Windows.Forms.Label CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat() (at IL_000d)

Things are getting more complicated and we will use some extra tools. I’m calling ILDasm! This tool is provided with dot NET Framework SDK, if you have installed Microsoft Visual Studio, you can find it in Microsoft Windows SDK folder; in my system ILDasm is located at C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

ILDasm can easily be an alternative tool to Reflector or ILSpy except for the fact that its interface is a bit less user-friendly and it has no high-level code translation feature. Anyway, once you’ve located it, open it and load our Crack Me into it (File -> Open) and expand trees as follows:

ILDasm does not show byte representation by default. To show the IL corresponding bytes you have to select View -> Show Bytes:

Then double click on our concerned method (Form1_Load…) to get the IL code and corresponding bytes:

Figure 1 ILDasm IL + bytes representations encoded Form1_Load() method

Figure 1 ILDasm IL + bytes representations encoded Form1_Load() method

We now have more information about the IL instructions and their bytes representations now. In order to use this new information, you have to know that after “|” the low-order byte of the number is stored in the PE file at the lowest address, and the high-order byte is stored at the highest address. This order is called “Little Endian.”

What does this mean?

When looking inside the Form1_Load( ) method using ILDasm, we have this:

IL_0006: /* 16 |
IL_0007: /* 6F | (0A)000040
IL_000c: /* 02 |
IL_000d: /* 6F | (06)000022

These Bytes are stored in the file this way: 166F4000000A026F22000006

Back to our target

This sequence of bytes is quite good for making a byte search in a hexadecimal editor. In a real situation study, e may face the annoying problem of finding more than one occurrence of our sequence. In this situation, instead of searching for a bytes sequence we search for (or, better, go to) an offset which can be calculated.

An offset, also called relative address, is used to get to a specific absolute address. We have to calculate an offset where the instruction we want to change is located. Referring to Figure 1, ILDasm and ILSpy indicate the Relative Virtual Address (RVA) at the line // Method begins at RVA 0x1b44c. In order to translate this to an offset or file location, we have to determine the layout of our target to see different sections and different offsets / sizes. We can use PEiD or any other PE Tool, but I prefer to introduce you to a tool that comes with Microsoft Visual C++ to view PE sections called “dumpbin” (If you do not have it, please refer to links in the “References” section).

Dumpbin is a command line utility, so we use the command line type “dumpbin -headers target_name.exe”


By scrolling down we find interesting information:

SECTION HEADER #1
.text name
1C024 virtual size
2000 virtual address
1C200 size of raw data
400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read

Notice that the method Form1_Load() begins at RVA 0x1b44c (refer to Figure 1) and here the .text section has a virtual size of 0x1c024
with a virtual address indicated as 0×2000 so our method must be within this section. The section containing our method starts from 0X400
in the main executable file. Using these addresses and sizes we can calculate the offset of our method this way:

(Method RVA – Section Virtual Address) + File pointer to raw data; all values are in hexadecimal, so using the Windows calculator or any other calculator that supports hexadecimal operations, we get: (1B44C – 2000) + 400 = 1984C

So 0x1984C is the offset of the start of our method in our main executable. Using any hexadecimal editor we can go directly to this location. What we want to change is a few bytes after this offset considering the method header.

Going back to the sequence of bytes we got a little while ago, 166F4000000A026F22000006, and going to the offset calculated before, we get:

We want to change ldc.i4.0, which is equal to 16, by ldc.i4.1, which is equal to 17. Let’s make this change and see what it produces (before doing any byte changes remember always to make a backup of the original file).

And yes, our first problem is solved; we still have the “Unregistered Crack Me” caption and the still not tested “Save as…” button. Once we click on the button “Enable Me,” we get the second one enabled, which is supposed to be the main program feature.

But, in giving it a try, something bad happen:

Before saving, the program checks for a license; if the license is not found, it disables everything and aborts the saving process.

Protecting a program depends always on the developer’s way of thinking. There are as many ways to protect software as there are to break it. We can nevertheless store protections in “types” or “kinds” of protections. Among these is what we call “license check” protections. Depending on how the developer imagined that the protection must behave and how the license must be checked, the protection’s difficulty changes.

Let’s see again inside our target:

The method btn_EnableMe_Click _1() is triggered when we press the button “Enable Me,” as we saw this; btn_About_Click() is for showing the message box when clicking on the “About” button. Then we still have two methods, btn_EnableMe_Click () and checkLicence() which seems to be interesting.

Let’s go inside the method btn_EnableMe_Click() and see what it has to tell:

By clicking on the “Save” button, instead of saving directly, the Crack Me checks the “registration status” of the program. This may be a kind of “extra protection,” which means that the main feature, which is “saving file,” is protected against “forced clicks”; the Crack Me checks if it is correctly registered before saving even if the “Save as…” button is enabled when the button “Enable Me” is clicked. Click on “checkRegStat()” to see its content:

Figure 2 Original source code of checkReStat() method

Figure 2 Original source code of checkReStat() method

It is clear that there is a Boolean variable that changes, which is isRegistered, and we have made no changes to this. So if isRegistered is false (if (!this.isRegistered)…) the Crack Me makes a call to the checkLicense() method. We can see how isRegistered is initialized by clicking on .ctor() method:

Figure 3 .ctor() method

Figure 3 .ctor() method

.ctor() is the default constructor where any member variables are initialized to their default values.

Let’s go back and see what the method checkLicense() does exactly:

Figure 4 Method chcekLicense()

Figure 4 Method chcekLicense()

This is surely a simple simulation of software “license check” protection. The Crack Me checks for the presence of a “lic.dat” file in the same directory of the application startup path; in other words, the Crack Me verifies that there is any “lic.dat” file in the same directory as the main executable file.

Well, technically, at this point, we can figure out many solutions to make our program run fully. If we remove the call to the checkLicense() method, we will also remove the main feature, which is saving, since it is done only once the checking is done (Figure 2).

If we force the isRegistered variable to take the value True by changing its initialization (Figure 3), we will lose the call to checkLicense() method that itself calls the main feature (“saving“), as it is only called if isRegistered is equal to false, as seen here (refer to Figure 2):

public void checkRegStat()
{
this.LblStat.ForeColor = Color.Green;
this.LblStat.Text = “Saving…”;
if (!this.isRegistered)
{
this.checkLicence();
}
}

We can alter the branch statement (if… else… endif, Figure 4). This way we can save only if the license file is not found.

We saw how to perform byte patching the “classical” way using offsets and hexadecimal editor. I’ll introduce you an easy way which is less technical and can save us considerable time.

We will switch again to Reflector (please refer to previous parts of this series for further information). This tool can be extended using plug-ins; we will use Reflexil,
a Reflector add-In that will allow us to editing and manipulate IL code, then saving the modifications to disk. After downloading Reflexil you need to install it; Open Reflector and go to Tools -> Add-ins (in some versions View -> Add-ins)

A window will appear. Click on “Add…” and select “Reflexil.Reflector.dll“:

Once you are done you can see your plug-in added to the Add-ins window, which you can close:

Let’s load our modified Crack-Me on Reflector, and go to checkLicence() method:

Figure 5

Figure 5

Basically, we want to modify the Crack Me so that we get “File saved!” Switch the view to see the IL code representation of this C# code:

.method
public
instance
void
checkLicence() cil managed

{


.maxstack 3


.locals
init (

[0] string
str,

[1] valuetype [System.Drawing]System.Drawing.Color
color)

L_0000: call string [System.Windows.Forms]System.Windows.Forms.Application::get_StartupPath()

L_0005: ldstr “\\lic.dat”

L_000a: call string [mscorlib]System.String::Concat(string, string)

L_000f: stloc.0

L_0010: ldloc.0


L_0011: call bool [mscorlib]System.IO.File::Exists(string)


L_0016: brtrue.s L_006b


L_0018: ldstr “license file missing. Cannot save file.”

L_001d: ldc.i4.s 0×10

L_001f: ldstr “License not found”

L_0024: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object, valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

L_0029: pop

L_002a: ldarg.0

L_002b: ldc.i4.0

L_002c: stfld bool
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::isRegistered

L_0031: ldarg.0

L_0032: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()

L_0037: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Red()

L_003c: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)

L_0041: ldarg.0

L_0042: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()

L_0047: ldstr “Unregistered Crack Me”

L_004c: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)

L_0051: ldarg.0

L_0052: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Button
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnEnableMe()

L_0057: ldc.i4.0

L_0058: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)

L_005d: ldarg.0

L_005e: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Button
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_btnSaveAs()

L_0063: ldc.i4.0

L_0064: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)


L_0069: br.s L_0092


L_006b: ldarg.0

L_006c: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()

L_0071: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Green()

L_0076: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)

L_007b: ldarg.0

L_007c: callvirt instance
class [System.Windows.Forms]System.Windows.Forms.Label
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::get_LblStat()


L_0081: ldstr “File saved !”

L_0086: callvirt instance
void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)

L_008b: ldarg.0

L_008c: ldc.i4.1

L_008d: stfld bool
CrackMe2_InfoSecInstitute_dotNET_Reversing.MainForm::isRegistered


L_0092: ret

}

I marked interesting instructions that need some explanations. Basically we have this:

.method
public
instance
void
checkLicence() cil managed

{


.maxstack 3

//

(…)

L_0011: call bool [mscorlib]System.IO.File::Exists(string)


L_0016: brtrue.s L_006b


L_0018: ldstr “license file missing. Cannot save file.”

(…)

L_0069: br.s L_0092


L_006b: ldarg.0

(…)

L_0081: ldstr “File saved !”

(…)

L_0092: ret
}

By referring to our IL instructions reference we have:

 

IL Instruction Function Byte representation
Call Calls the method indicated by the passed method descriptor. 28
Brtrue.s Transfers control to a target instruction (short form) if value is true, not null, or non-zero. 2D
Br.s Unconditionally transfers control to a target instruction (short form). 2B
Ret Returns from the current method, pushing a return value (if present) from the caller’s evaluation stack onto the caller’s evaluation stack. 2A

 

Table 1 IL Instructions

The Crack Me makes a Boolean test on the license file presence (Figure 4); if the file is found, it returns True, which means brtrue.s will jump to the line L_006b and the Crack Me will load “File saved!” string. Otherwise it will go to the unconditional transfer control br.s that will transfer control to the instruction ret to get out from the whole method.

Remember, we want our Crack Me to check for license file absence; that way, it returns True if file not found, so it loads “File saved!” string.

Let’s get back to Reflector. Now we have found the section of code we want to change (Figure 5); here comes the role of our add-in Reflexil. On the menu go to Tool -> Reflexil v1.x:

This way you can get the Reflexil panel under the source code or IL code shown by Reflector.

This is the IL code instruction panel of Reflexil. As you can see, there are two ways you can make changes using this add-in, but for now I’ll introduce only one. We will see how to edit instructions using IL code.

After analyzing the IL code above, we know that we have to change the “if not found” to “if found” which means changing brtrue.s (Table 1) to its opposite. By returning to the IL code reference we find
brfalse.s
: Branch to target if value is zero (false), short form.

This said, on Reflexil’s panel, find out where is the line we want to change:

Right click on the selected line -> Edit… Now you get a window that looks like this:

Remove “brtrue.s” and type the new instruction “brfalse.s,” then click “Update.” You see your modification has been made:

To “physically “save this change, right click on the root of the disassembled Crack Me select Reflexilv1.x, then Save as…


This way we have a modified copy of our Crack Me. We have the “Enable Me” button enabled; by clicking on it, we enable the “Save as…” button and by clicking on that, we get our “File Saved!” message:

This is the end of the third part. It takes more time with more complex algorithms and protections, but if you are able to get the IL code and can read it clearly you will undoubtedly be able to bypass the software protection. In upcoming parts I’ll introduce you disassembling and reassembling dot NET application and see how this can be exploitable in reversing dot NET software.

References:

 

 

 

 

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>
« Pentest VMware with VASTO! | Main | The SIM-card filesystem in details »