62
DEMYSTIFYING DOT NET REVERSE ENGINEERING PART 1 27/01/2013 About the Author Soufiane Tahiri is an InfoSec Institute contributor and computer security researcher, specializing in reverse code engineering and software security. He is also founder of www.itsecurity.ma and practiced reversing for more than 8 years. Dynamic and very involved, Soufiane is ready to catch any opportunity to be part of a workgroup. Email [email protected] Website http://www.itsecurity.ma - http://www.marw0rm.com LinkedIn http://ma.linkedin.com/in/soufianetahiri

Demystifying dot NET reverse engineering - Part1

Embed Size (px)

Citation preview

Page 1: Demystifying  dot NET reverse engineering - Part1

DEMYSTIFYING DOT NET REVERSE ENGINEERING – PART 1

27/01/2013 About the Author

Soufiane Tahiri is an InfoSec Institute contributor and computer security researcher, specializing in reverse code engineering and software security. He is also founder of www.itsecurity.ma and practiced reversing for more than 8 years. Dynamic and very involved, Soufiane is ready to catch any opportunity to be part of a workgroup.

Email [email protected] Website http://www.itsecurity.ma - http://www.marw0rm.com

LinkedIn http://ma.linkedin.com/in/soufianetahiri

Page 2: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 1

Demystifying dot NET reverse engineering

This, and all upcoming parts, is 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.

Page 3: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 2

Introducing dot NET reverse engineering 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 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 others that

would explain some basics and clarifying dot NET architecture to the extent of making some few

concepts clearer for reverse engineers.

Before starting, I strongly recommend you to take few hours teaching and learning yourself at least one

of the dot NET languages and I recommend either Visual Basic .NET or C#, it may seems to some that

reversing dot NET programs is way easier then reversing “traditional” programs which is in my point of

view wrong.

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 of traditional programming languages like C/C++,

application 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,

then 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.

Page 4: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 3

FIGURE 1 VISUAL OVERVIEW OF THE COMMON LANGUAGE INFRASTRUCTURE (CLI) / WIKIPEDIA

W H A T T H I S M E A N S T O A R E V E R S E E N G I N E E R ?

Basically every compiled dot NET application is not more than its Common Intermediate Language

representation which stills 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… with all parameters and arguments, we can also get all interfaces,

structures …

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.

Page 5: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 4

W H A T W I L L Y O U L E A R N F R O M T H I S ?

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 (thing that will

come via 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.

Page 6: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 5

IMAGE 1 CHOOSING THE MAIN LANGUAGE

Load this Crack Me up into it (File > Open menu) and look 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:

IMAGE 2 OUR CRACK ME IS LOADED UP

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

Page 7: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 6

Keep on developing tree and see what is inside of this Crack Me :

Now we can see that our Crack Me is composed by 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 this 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 pretty easier to us and let us guess what everything is supposed to do, for example, the

function btn_Chk_Click(Object, EventArgs) that seems to be trigged when the button “btn_Chk” is clicked,

btn_About_Click(Object, EventArgs) which is presumably called when button “btn_About” is clicked…

Page 8: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 7

Since this is an application to practice, it has not lot of forms and functions, which makes things more

easiest to 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 image 1).

To see actual source code, double click on the function name, Reflector show 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 basics 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 you complex explanations regarding dot NET application and decided not to flood you

in this first part by information that may discourage you, I’ll try to introduce you more in-depth

knowledge about how dot NET programs really works, I tried to show you the clearest way how to deal

with a very basic protection, hopefully this taught you few more things that matter while reversing dot

NET programs.

Page 9: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 8

Demystifying dot NET reverse engineering - 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 bypassing 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 when we talk especially 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 event 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, finding in the program the right place and figuring out

what bytes to change, by what changing them is not usually a simple thing.

In this paper and upcoming one, we will try to practice some byte changing (commonly said patching)

practices using different homemade targets, we will re use 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 full application using nothing but only MSIL but this is not a

interesting thing by a point of view of “dot NET developer” but may be more helpful the way this 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 firstly compiled (if we can permit saying

this) to a IL or MSIL language and is executed in a runtime environment: Common Language Runtime (CLR)

then is secondly recompiled or converted on its execution, to a local native instructions like x86 or x86-

64… which are set depending on what type of processor is currently used, thing 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 dot NET

code is portable.

The figure below demonstrates this process:

Page 10: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 9

UNDERSTANDING MSIL The aim of this paper is introducing you 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 programs security systems weakness.

Before going ahead, it’s wise to say that CLR executes the IL code allowing this way making operations

and manipulating data, 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:

Dot NET

Compile

r

Microsoft Intermediate Language source

(MSIL or IL)

MSIL

Compiler

CPU specific native code

0110101101010010101011010010100101110010101010001010101001010

10

Dot NET source : VB.NET, C#, Cobol.NET

Page 11: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 10

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 accepting all wrong passwords by only changing some bytes.

Let’s go back to our Crack ME #1 opened into Reflector, we got the original source code that checks the

password typed:

private void btn.Chk.Click(object sender, EventArgs e)

{

if (this.txt.Pwd.Text == "p@55w0rd!")

{

Interaction.MsgBox("Congratulations !", MsgBoxStyle.Information,

"Correct!");

}

else

{

Interaction.MsgBox("Invalid password", MsgBoxStyle.Critical, "Error!");

}

}

And by switching to IL code view we get this:

.method private instance void btn.Chk.Click(object sender, 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

InfoSecInstitute.dotNET.Reversing.Form1::get.txt.Pwd()

L.0006: callvirt instance string

[System.Windows.Forms]System.Windows.Forms.TextBox::get.Text()

L.000b: ldstr "p@55w0rd!"

L.0010: ldc.i4.0

L.0011: call int32

[Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::Compare

String(string, string, bool)

L.0016: ldc.i4.0

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

L.0019: ldstr "Congratulations !"

L.001e: ldc.i4.s 0x40

L.0020: ldstr "Correct!"

L.0025: call valuetype

[Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

L.002a: pop

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

L.002d: ldstr "Invalid password"

L.0032: ldc.i4.s 0x10

L.0034: ldstr "Error!"

L.0039: call valuetype

[Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

Page 12: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 11

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, and as said above, dot NET is essentially a stack machine, and

we will need some references the understand what this IL code means, we can find a listing of all IL

assembly instruction and their use, I’ll try to expose and explain the most important ones relative to

reverse engineering uses.

IL Instructions start right after “.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 hexadecimal

editor we will find a series of byte codes from 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 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 way 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 works. To locate 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 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

Page 13: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 12

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

Page 14: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 13

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

Page 15: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 14

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 the

evaluation stack and stores it in a the local variable list at a

specified index.

FE 0E

Page 16: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 15

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 quit 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 void btn_Chk_Click(object sender, EventArgs e)

{

if (this.txt_Pwd.Text == "p@55w0rd!")

{

Interaction.MsgBox("Congratulations !", MsgBoxStyle.Information,

"Correct!");

Is just translated to this:

L_0010: ldc.i4.0

L_0011: call int32

[Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::Compare

String(string, string, bool)

L_0016: ldc.i4.0

L_0017: bne.un.s L_002d

L_0019: ldstr "Congratulations !"

L_001e: ldc.i4.s 0x40

L_0020: ldstr "Correct!"

L_0025: call valuetype

[Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

Page 17: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 16

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

Using the IL instructions reference we get:

1. Call: Calls the method indicated by the passed method descriptor, which in this case calls string

comparison method

2. ldc.i4.0: Pushes the integer value of 0 onto the evaluation stack as an int32.

3. bne.un.s: Transfers control to a target instruction (short form) when two unsigned integer values or

unordered float values are not equal.

4. Ldstr: Pushes a new object reference to a string literal stored in the metadata.

At this point only bne.un.s seems interesting and worth more explanation, if statements are in Intermediate

Language is translated to a branch instruction, so bne stands for brach if not equal (BranchNotEqual) and

its used if the two values on the top of a stack are not equal than it jumps to line L_002d as you can see

from:

L_0016: ldc.i4.0

L_0017: bne.un.s L_002d

L_0019: ldstr "Congratulations !"

This starts making sense, and let us thinking about how we can bypass typing in a valid password ,

instead of showing “Congratulations !” if password is correct, we can reverse it and force the program

showing us this message if 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 actual offset of the instruction to go there directly in a

hexadecimal editor.

Solutions:

Referring the list above we see that bne.un.s = 0x33 and Beq.s = 0x2E; to find the location in file

where we have to make changes, we have to translate 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 = 0x16, bne.un.s L_002d = 0x33 and 0x?? Value representing the L_002d and ldstr = 0x72

So our searching sting will look like 1633??72 of course using “??” means the use of regular expression

when doing search and means the use of 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 :

Page 18: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 17

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 what inside Reflector:

And by switching to IL view mode we can see:

Page 19: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 18

This stills very 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 next chapter some advanced byte patching

techniques and how to deal with them.

Page 20: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 19

Demystifying dot NET reverse engineering - Advanced Byte Patching INTRODUCTION In first parts we saw some basics that would let you reverse some dot NET application; we covered the

concepts of dot NET compilation, we presented Microsoft Common Intermediate Language, we analyzed

some low level code using code reflection, we saw a non exhaustive list of IL instructions their functions

and their byte representation.

We covered as well the basics of byte patching, how to find the location of bytes we want to change in

a hexadecimal editor, and by what changing them.

In this part of our dot NET reverse engineering series I will introduce you 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 tried to respond to few questions and suggestions regarding the two first parts, so 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:

So basically we have to enable the first button having “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 trigged later in this article.

Page 21: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 20

Let’s disassemble our target using ILSpy which is very similar to Reflector so we will not need to present it

(link to download it is in the References), once analyzed our Crack Me is placed on a very similar to

Reflector tree structure and by expanding nodes we notice 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 the way we get this:

If you have any coding background you can guess with ease that “this.btnEnableMe.Enabled = false;” is

responsible of disabling the component “btnEnableMe” which is in our case a button. 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

{

Page 22: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 21

// 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(b

ool)

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 instruction worth of being explained (in the order they appear):

1. ldarg.0 Pushes the value 0 to the method 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 32bits 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 to “False” when programming, 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 previous chapter we knew that byte representation is important in order to know the exact location of

the IL instruction to change and by what changing it, 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 Call a method associated with an object. 6F

Ldarg.0 Load argument 0 onto the stack. 02

Page 23: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 22

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 representation and make a byte

search in a hexadecimal editor.

Referring the list above we get: 166F??026F??, the “??” means that we do not know neither

instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool) (at IL_0007)

bytes representation nor 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 be easily an alternative tool to Reflector or ILSpy except the fact of having a bit less user

friendly interface and no high level code translation feature. Anyway, once located open it and load our

Crack Me into it (File -> Open) and expand trees as following:

Page 24: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 23

ILDasm does not show byte representation by default, to show IL corresponding bytes you have to select

View -> Show Bytes:

Page 25: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 24

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

Page 26: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 25

FIGURE 2 ILDASM IL + BYTES REPRESENTATIONS ENCODED FORM1_LOAD() METHOD

We have more information about IL instructions and their Bytes representations now, in order to use this

amount of 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 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; we may face an annoying problem which is finding more than one occurrence of our sequence. In

this situation, instead of searching for bytes sequence we search for (or to better say “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 Figure1, ILDasm and ILSpy

indicate the Relative Virtual Address (RVA) at the line // Method begins at RVA 0x1b44c and in order to

translate this to an offset or file location, we have to determinate 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

Page 27: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 26

introduce you a tool that comes with Microsoft Visual C++ to view PE sections called “dumpbin” (If you do

not have it, please referrer to links on “References” section).

Dumpbin is a command line utility, so via 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 0x2000 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’s calculator or any other calculator that support hexadecimal operations we get:

(1B44C – 2000) + 400 = 1984C

Page 28: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 27

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 and what we want change is few bytes after this offset considering the

method header.

Going back to the sequence of bytes we got a bit ago 166F4000000A026F22000006 and going to the

offset calculated before we get:

Page 29: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 28

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 reproduces (before doing any byte changes think always to make a backup of the

original file).

And yes our first problem is solved; we still have “Unregistered Crack Me” caption and 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.

By giving it a try something bad happened:

Page 30: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 29

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

process.

Protecting a program depends always on developer’s way of thinking, there is as mush ways to protect

software as mush ways to break them. We can nevertheless store protections in “types” or “kinds” of

protections, among this, there is what we call “license check” protections. Depending on how developer

imagined how 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 trigged when we press the button “Enable Me” we saw this,

btn_About_Click() is for showing the message box when cliquing on “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:

Page 31: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 30

By clicking on the button save, instead of saving directly, the Crack Me checks the “registration stat” of

the program, this may be a kind of “extra protection”, which means, 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, well click on

“checkRegStat()” to see its content:

FIGURE 3 ORIGINAL SOURCE CODE OF CHECKRESTAT() METHOD

Here is clear that there is a Boolean variable that changes, which is isRegistered and till now we made no

changes regarding this. So if isReistered 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:

Page 32: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 31

FIGURE 4 .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 5 METHOD CHCEKLICENSE()

This is for sure 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 if 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 remove the same way the main feature which is

saving, since it is done only once the checking is done (Figure 2)

Page 33: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 32

If we force the isRegistered variable taking the value True by changing its initialization (Figure3), we will

lose the call to checkLicense() method that itself calls the main feature (“saving”) as its only called if

isRegistered is equal to false as seen here (refer to Figure2):

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, Figure4) the 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 considered time.

We will sewitch 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 editing

and manipulating 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”:

Page 34: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 33

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

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

Page 35: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 34

FIGURE 6

Well basically we want to modify the Crack Me a way we get “File saved!”, Switch the view to see 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 0x10

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

Page 36: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 35

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

}

Page 37: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 36

I marked interesting instructions that need some explanations, so 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

TABLEAU 1 IL INSTRUCTIONS

The Crack Me makes a Boolean test regarding the license file presence (Figure 4), if file 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 the 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

Page 38: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 37

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

Page 39: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 38

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 I’ll introduce for now 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” by “if found” which

means changing brtrue.s (Tableau 1) by 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:

Page 40: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 39

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

Remove “brtrue.s” and type the new instruction “brfalse.s” then click “Update”, you see your modification

done:

Page 41: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 40

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

then Save as…

Page 42: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 41

This way we have a modified copy of our Crack Me, we have the “Enable Me” button enabled, by

clicking on it we enable “Save as…” button and by clicking on this last we get our “File Saved!”

message:

Page 43: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 42

This third part is at her end, it take 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 with no doubt be able to bypass the

software protection. In upcoming parts I’ll try to introduce you disassembling and reassembling dot NET

application and see how this can be exploitable in reversing dot NET software.

Page 44: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 43

Introducing Round-trip engineering INTRODUCTION

After covering the basics of dot NET reverse engineering in first articles (refer to references) , it’s time to

go more in depth of the dot NET MSIL assembly language, this article has not the purpose of teaching

you programming using this language, I’ll try to clarify more the IL code you saw until now, how to deal

with it using some “new” tools, but also presenting the technique of “round trip engineering” which is not

dot NET specified technique and see how we can be creative and use this in our reverser’s point of view

advantages.

In this article I’ll present you IL assembly mush more in depth and how we can deal with two synchronized

tools to remove the first protection of a Crack Me I made for this purpose, once you can handle these

tools and know the “basics” of round trip engineering I will present you second article on advanced round

trip engineering to perform some more advanced manipulation on the same Crack Me to remove the

second protection so take a long breath and here we go!

DEFINITION OF “ROUND TRIP ENGINEERING” IL assembler and disassembler were first made as strict internal tools used to facilitate the development

of the Common Language Runtime. When both tools became synchronized enough, third party dot NET

oriented compilers based on ILAsm started to appear along with dot NET Frameworks class library,

compilers and tools was released to the developers’ community.

Technically, round trip engineering is the ability of two or more software development tools to be

synchronized, when talking about round trip engineering in dot NET context, we are talking about the

fact of taking a managed assembly, generated from any high level programming language such as

Microsof Visual C# or Microsoft Visual Basic .NET or any low level programming like ILAsm, but using a

dot NET oriented compilers; disassemble it, modify the code by adding, removing or changing the IL code,

then reassembling it back into new modified and working assembly / module.

Note: Managed dot NET application is called “assembly” and Manage dot NET executable is called

“module”.

THE SUBJECT’S CORE

In this article we will work exclusively with two tools officially released by Microsoft within Windows SDK

tools: the IL assembler (ILASM) and the IL disassemble (ILDASM that was presented in previous parts of

“Demystifying dot NET reverse engineering”, please refer to references section). Theoretically, we can

reverse engineer every dot NET based assembly / module using only these two tools.

ILDASM, the disassemble can be found under the folder C:\Program Files\Microsoft Visual Studio

8\SDK\v2.0\Bin, ILASM the assembler can be found under

C:\WINDOWS\Microsoft.NET\Framework\vx.x (depending on the version of frameworks used to

produce the assembly which we want to modify)

Page 45: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 44

Before starting the analysis of our target (not yet presented) I will clarify and in depth some dot NET

aspects starting by the Common Language Runtime.

Common Language Runtime is a layer between dot NET assemblies and the operating system in which it’s

supposed to run; as you know now (hopefully) every dot NET assembly is “translated” into a low level

intermediate language (Common Intermediate Language – CIL which was earlier called Microsoft

Intermediate Language – MSIL ) despite of the high level language in which it was developed with; and

independent of the target platform, this kind of “abstraction” lead to the possibility of interoperation

between different development languages.

The Common Intermediate Language is based on a set of specifications guaranteeing the interoperation;

this set of specifications is known as the Common Language Specification – CLS as defined in the Common

Language Infrastructure standard of Ecma International and the International Organization for

Standardization – ISO (link to download Partition I is listed in references section)

Dot NET assemblies and modules which are designed to run under the Common Language Runtime – CLR

are composed essentially by Metadata and Managed Code.

Managed code is the set of instructions that makes the “core” of the assembly / module functionality, and

represents the application’s functions, methods … encoded into the abstract and standardized form

known as MSIL or CIL, and this is a Microsoft’s nomination to identify the managed source code running

exclusively under CLR.

On the other side, Metadata is a way too ambiguous term, and can be called to simplify things “data

that describes data” and in our context, very simply, metadata is a system of descriptors concerning the

“content” of the assembly, and refers to a data structure embedded within the low level CIL and

describing the high level structure of the code. It describes the relationship between classes, their

members, the return types, global items, methods parameters and so on… To generalize (and always

consider the context of the common language runtime), metadata describes all items that are declared or

referenced in a module.

Basing on this we can say that the two principal components of a module are metadata and IL code; the

CLR system is subdivided to two major subsystems which are “loader” and the just-in-time compiler.

The loader parses the metadata and makes in memory a kind of layout / pattern representation of the

inner structure of the module, then depending on the result of this last, the just-in-time compiler (also

called jitter) compiles the Intermediate Language code into the native code of the concerned platform.

The figure below describes how a managed module is created and executed:

Page 46: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 45

Our target which is a managed module is “CrackMe3-InfoSecInstitute-dotNET-Reversing.exe” (link to

download in references section), this Crack Me is presented like this:

A nag screen that we have to remove and a windows form asking for a serial number, and we will

discover together how we can use some creative round trip engineering to remove all protections present

on this Crack Me.

Step 1: Disassembling

First of all, let’s disassemble our Crack Me using ILDASM and see the IL code embedded in our managed

module. To avoid getting lost let’s just focus on two nodes:

Com

mon L

anguage R

untim

e

Execution

Engine

Source Code Managed

Compiler

Managed module

METADATA

IL Code

LOADER

Just-in-Time

Compiler

Native Code

Internal Data

Structure

Page 47: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 46

Our managed module has only one form called Form1 as seen in the picture above and an appealing

class name “GenSerial”, let’s develop the first node and see:

Double click on the Form1_Load method to see actual IL code:

.method private instance void Form1_Load(object sender, class [mscorlib]System.EventArgs e) cil

managed

{

// Code size 19 (0x13)

.maxstack 8

IL_0000: ldstr "I'm a nag screen, remove me."

IL_0005: ldc.i4.s 16

IL_0007: ldstr "Nagging you!"

IL_000c: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

IL_0011: pop

IL_0012: ret

} // end of method Form1::Form1_Load

All ILAsm keywords are marked in bold to increase code readability; I’ll take you through this piece of

code line by line to clarify what it does and what we will have to do.

Understanding Form_Load() Method:

Page 48: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 47

.method private instance void Form1_Load(…) cil managed defines the metadata item Method

Definition.

The keywords private and instance define the flags of Method Definition item. The keyword public means

that the method Frm1_Load() can be accessed by all members for whom the mother class of

Form1_Load() is visible. The keyword instance is here to tell that the method is associated with an object

rather than a class.

The keyword void defines explicitly the return type of the current method which is the default return type.

Void means that this method does not return any value.

The keywords cil and managed indicate that the method body is presented in Intermediate Language (IL)

and define implementation flags of Method Definition

.maxstack 8 is the directive that presents the maximum number of items /elements that can be present

at any time during method execution on the evaluation stack .

IL_0000: is a label and won’t occupy anything in the memory, ILDASM marks every line (instruction) with

a label, labels are not compiled and are exclusively used to identify some offsets within IL code at

compile time.

As you know IL is strictly a stack based language, everything MUST pass through the evaluation stack,

and every instruction puts or takes something (or nothing) from the top of the evaluation stack, when we

talk about pushing /pulling elements onto / from the stack we are talking in term of items regardless

their sizes.

Ldstr "I'm a nag screen, remove me." Creates an object of type string from the given string constant and

loads a reference to this object onto the evaluation stack, this kind of constants are stored in the

metadata, and this common language runtime string constant or metadata string constant is always stored

in Unicode (UTF-16) format.

ldc.i4.s 16 is the short form (notice de “.s”) of the instruction that loads the value 16 of type int32 onto

the evaluation stack and in this sample, it loads the message box style that displays critical message icon.

call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object), valuetype is used before the

object we want to create and we provide the full signature of the class including library name, so we call

a (non virtual?) method , valuetype is obligatory in generic type instantiations since these lasts are

represented in metadata as TypeSpecs.

The instruction pop removes the string “Nagging you!” from the stack.

The return instruction ret, returns immediately to the call site, depending on the called method, ret returns

one value of a certain type and this type have to be on the evaluation stack, in the case the method

concerned returns void type, the evaluation stack must be empty at the moment of return (as in this case).

Well, now we know that this method (which is Form1_Load) does only one and only one thing: preparing

and showing the nag screen and we have to get rid of it.

Technically we have to generate an .il file from our module/assembly (by dumping it from ILDasm),

manipulate it and reassemble it, but before doing this we have to know the version of our assembly so

we can recompile it (using ILASM) without getting problems.

We can use ILDasm to get this kind of information by viewing the assembly manifest content:

Page 49: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 48

.ver directive specifies the version number of the assembly:

IMAGE 3 ASSEMBLY VERSION

Now let’s dump our assembly by clicking File->Dump->Ok (or Ctrl+D), chooses a directory and saves,

you should get something like this:

The file with .il extension contain every IL instruction present on the managed module, open it using your

favorite text editor and try to find the Form1_Load method:

Page 50: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 49

At this point many possibilities are available to us; we can remove all instruction inside our method or

remove to whole method, force a ret at the beginning of this last… I prefer to remove the content of this

method, which means, transforming the method Form1_Load() to a method that does nothing!

Remove from line number 1192 to line number 1201 and save modifications:

Now we need to reassemble our modified .il file, and we will use ILAsm assembler; a tool provided as

well with Visual Studio and Windows SDK and able to generate portable executables from Microsoft

Intermediate Language.

Step 2: Reassembling

You still remember the version of our assembly which is 4.0.30319 (image1), the version of ILASM we are

going to use is under C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319.

We have to pass trough Microsoft Windows Command (CMD) or Visual Studio Command Prompt ,

anyway the result remains the same.

So Start->Run->CMD

CD C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319

ilasm filename.il –res=filename.res

Filename = full path to the .il file, the -res parameter is optional and is used to keep resources within the

original assembly (like icons)

If compilation process was successful you will get:

Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved

Writing PE file

Operation completed successfully

And you get your new modified working and without nag screen file:

Page 51: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 50

Note: You can change texts that appear on the message box by changing strings loaded onto the stack,

changing the style of the message box:

Member Value Description

OKOnly 0 Displays OK button only.

OKCancel 1 Displays OK and Cancel buttons.

AbortRetryIgnore 2 Displays Abort, Retry, and Ignore buttons.

YesNoCancel 3 Displays Yes, No, and Cancel buttons.

YesNo 4 Displays Yes and No buttons.

RetryCancel 5 Displays Retry and Cancel buttons.

Critical 16 Displays Critical Message icon.

Question 32 Displays Warning Query icon.

Exclamation 48 Displays Warning Message icon.

Information 64 Displays Information Message icon.

DefaultButton1 0 First button is default.

DefaultButton2 256 Second button is default.

DefaultButton3 512 Third button is default.

ApplicationModal 0 Application is modal. The user must respond to the message box

before continuing work in the current application.

SystemModal 4096 System is modal. All applications are suspended until the user responds

to the message box.

MsgBoxSetForeground 65536 Specifies the message box window as the foreground window.

MsgBoxRight 524288 Text is right-aligned.

MsgBoxRtlReading 1048576 Specifies text should appear as right-to-left reading on Hebrew and

Arabic systems.

TABLEAU 2 VISUAL BASIC MSGBOXSTYLE ENUMERATION VALUES (SOURCE: MICROSOFT MSDN)

Page 52: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 51

The second problem we are facing is way mush complicated, if you want to bypass the serial validation

or want to calculate the correct serial this may be relatively easy, I want to show you how we can take

advantage of some “creative” round trip engineering and let the Crack Me do something that it was not

supposed to do like telling us the correct serial number!

Page 53: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 52

Advanced Round-trip engineering

SUMMARY This article is a part of a whole, and pretends to go more in depth of IL assembly language exploited in

reversing non-obfuscated (until now) dot NET assemblies and modules. (Managed dot NET applications

are called assemblies and managed dot NET executables are called modules; a managed dot NET

application -assembly- can be a single module assembly or multi-modules assembly)

As previously presented, the fact of disassembling and reassembling a managed executable is called

round tripping, the round tripping in our cases which concerns managed portable executable files is

divided into two main steps:

1. Disassembling the PE file into an .il file (which contains ILAsm source code) and into managed and

unmanaged resource files; task done using ILDASM.

2. Reassembling files got in step 1 into a new PE file using ILASM compiler.

Settle for simply disassembling and reassembling is not that interesting task unless modifying / altering

the ILAsm source code before reassembling it. Round tripping (as most of reverse engineering techniques)

is not “breaking software protections” specific, but we will focus only on this in our upcoming studies as

we saw in the article “Demystifying dot NET reverse engineering- Introducing Round-trip engineering”.

Last thing we did is removing the Crack Me’s nag screen and still facing serial number protection which

we will analyze in upcoming paragraphs.

SERIAL CHECK ANALYSIS Get back to ILDASM and let’s reconsider the tree structure we’ve got:

Each node represents a namespace once expanded we can explore class objects which once expanded

deliver their methods and properties, and here we have an interesting class name “GenSerial” which

contain a very interesting method:

Page 54: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 53

With this IL assembly content:

.method public instance object CalculSerial() cil managed

{

// Code size 43 (0x2b)

.maxstack 4

.locals init (object V_0)

IL_0000: ldarg.0

IL_0001: call class CrackMe3_InfoSecInstitute_dotNET_Reversing.My.MyComputer

CrackMe3_InfoSecInstitute_dotNET_Reversing.My.MyProject::get_Computer()

IL_0006: callvirt instance class

[Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ComputerInfo

[Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ServerComputer::get_Info()

IL_000b: callvirt instance string

[Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ComputerInfo::get_OSVersion()

IL_0010: ldstr "."

IL_0015: ldstr ""

IL_001a: callvirt instance string [mscorlib]System.String::Replace(string, string)

IL_001f: stfld string

CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::SerialNumber

IL_0024: ldarg.0

IL_0025: ldfld string

CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::SerialNumber

IL_002a: ret

} // end of method GenSerial::CalculSerial

Things get a bit more complicated and need clarification, interested things will be explained:

.method public instance object CalculSerial() cil managed , as seen in article 4 (Demystifying dot NET

reverse engineering- Introducing Round-trip engineering) this is the MethodDef metadata item, the only

difference is that this method has a return type which is object.

.maxstack directive is described in article 4 (please refer to background section)

.locals init (object V_0) as in any development language, variables are very important, and ILAsm as

every language has its way of declaration, .locals init (object V_0) defines a local variable called

objectV_0, the init keyword indicates to the Just-in-Time compiler that it must initialize all local variables

to zero on entry to the method.

ldarg.0 is the instruction that loads argument 0 on the stack, but instance methods like the one we have,

has the “this” (used in high level languages) instance references as the first argument of the method

signature, so ldarg.0 here loads instance pointer on the stack

call class CrackMe3_InfoSecInstitute_dotNET_Reversing.My.MyComputer

CrackMe3_InfoSecInstitute_dotNET_Reversing.My.MyProject::get_Computer(), MyComputer here is

inheriting from a base class defined in Microsoft.VisualBasic namespace, call here invokes the static

method get_Computer() which resides in the class MyProject under the namespace “My” and will return an

instance of CrackMe3_InfoSecInstitute_dotNET_Reversing.My.MyComputer, this property “get_Computer”

(like in most high level languages getters and setters)will lead to access an instance of

Microsoft.VisualBasic.Devices.Computer object (entering in details will multiply the size of this article !)

Page 55: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 54

callvirt instance class [Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ComputerInfo

[Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ServerComputer::get_Info() calls the virtual

method/property (getter) get_Info() and the use of the keyword instance means that the we are dealing

with instance methods instead of static ones, and referring to Microsoft MSDN ComputerInfo class

Pprovides properties for getting information about the computer's memory, loaded assemblies, name,

and operating system; ServerComputer class provides properties for manipulating computer components

with an inheritance hierarchy like this:

System.Object

Microsoft.VisualBasic.Devices.ServerComputer

MICROSOFT.VISUALBASIC.DEVICES.COMPUTER

callvirt instance string

[Microsoft.VisualBasic]Microsoft.VisualBasic.Devices.ComputerInfo::get_OSVersion() this calls the virtual

method get_OSVersion() from the dot NET Frameworks class library ComputerInfo. As a result of this call

a string is put onto the evaluation stack and from the method name we can guess that our program

accesses to the operating system version.

The instruction ldstr "." and ldstr "" creates respectively a string object from the string constant “.” (dot)

then loads a reference to it onto the stack and does the same thing to the string constant “” (empty

string)

Call instance string [mscorlib]System.String::Replace(string, string) this instruction calls the

Replace(string,string) function from the dot NET Frameworks class library, parameters / method

Page 56: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 55

arguments are taken from the stack (“.” And “”) and the result is pushed back onto the stack. This means it

takes computer version, replace every dot “.” by nothing then puts back the result onto the stack.

stfld string CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::SerialNumber this instruction sets

the result of the function Replace(string, string) on the field SerialNumber which is previously declared as

private and is equivalent to a private variable in high level languages

ldarg.0 loads the reference of the object itself (equivalent to this in high level languages) then using ldfld

string CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::SerialNumber takes the instance from the

stack and loads the value of the instance field SerialNumber on it.

Ret is –as you probably guessed it- the instruction that returns from a called method to a call site and

since our method returns an object, one value of type object is on the evaluation stack of the calling

method.

At this point we should know that the field SerialNumber contains the version of our operating system

without dots, we can retrieve easily full OS version which is in my case 6.1.7601.65536 and by applying

Replace() function I get 61760165536 which was a successful serial number:

This was fun let’s now move to serious things because until now we did not alter the code and we did not

use ILASM assembler! We want to let the Crack Me telling us the right serial number instead of showing

up “Wrong serial number” message box.

Let’s have a look again into ILDASM then expand the second node:

Page 57: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 56

By verifying methods Form1 class contains we can find easily the method called once we click on the

button “Register”:

The actual method’s IL code should be (hopefully) clearer and I won’t explain again the code line by line:

.method private instance void reg_Btn_Click(object sender, class [mscorlib]System.EventArgs e) cil

managed

{

// Code size 69 (0x45)

.maxstack 3

IL_0000: ldarg.0

IL_0001: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox

CrackMe3_InfoSecInstitute_dotNET_Reversing.Form1::get_txt_Serial()

IL_0006: callvirt instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text()

IL_000b: ldarg.0

IL_000c: ldfld class CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial

CrackMe3_InfoSecInstitute_dotNET_Reversing.Form1::cGenSerial

IL_0011: callvirt instance object

CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::CalculSerial()

IL_0016: ldc.i4.0

IL_0017: call bool

[Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Operators::ConditionalCompareObjectEqua

l(object, object, bool)

IL_001c: brfalse.s IL_0032

IL_001e: ldstr "Serial is correct!"

IL_0023: ldc.i4.s 64

IL_0025: ldstr "Congratulation"

IL_002a: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object,

valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

IL_002f: pop

IL_0030: br.s IL_0044

IL_0032: ldstr "Wrong serial number."

IL_0037: ldc.i4.s 16

IL_0039: ldstr "Error"

IL_003e: call valuetype [Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxResult

[Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::MsgBox(object, valuetype

[Microsoft.VisualBasic]Microsoft.VisualBasic.MsgBoxStyle, object)

Page 58: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 57

IL_0043: pop

IL_0044: ret

} // end of method Form1::reg_Btn_Click

If you followed all articles about Demystifying dot NET Reverse Engineering you should be able to

understand what this method does exactly (and by the way please remark System.EventArgs which

means that we are under an event which is “click” the click on button “Register” flags the method

reg_Btn_Click(…)).

We can split this code into blocks:

1. First, the Crack Me gets the text we typed as serial number using method get_text()

2. Then, it calls an instance of the class which calculates the correct serial number using CalculSerial()

3. At this point, we have three items on the top of the evaluation stack as expected using the the

directive .maxstack 3, which are two objects: serial number typed by the user retrieved using

get_text() method and the correct serial number calculated via the function CalculSerial() and

four byte zero loaded by the instruction ldc.i4.0 to let the Crack Me correctly uses the API

ConditionalCompareObjectEqual(…) which represents the overloaded Visual Basic equals (=)

operator with a Boolean return type. The loading of zero as TextCompare parameter means that

the comparison is not case sensitive, but this is not mush important in this case since our serial

number is numeric.

4. If comparison returns false, this means that objects loaded as parameters are not equal which

means serial number given by the user is not correct so brfalse.s braches / jumps to IL_0032

which loads a reference to the string “Wrong serial number” and prepares the message box to

show after what it clears the evaluation stack using pop instruction, otherwise, it prepares the

“Serial is correct!” message box and clears the evaluation stack using pop instruction before

unconditionally transfers the program to ret instruction (the end of the method) using br.s IL_0044

instruction.

We know what this method does exactly, we have to use some “creative” round tripping to let the Crack

Me changes its behavior and instead of showing the wrong serial message box it shows the correct serial

number, so basically we need to change this portions of the code:

And:

But by what! Obviously we have to call the function that calculates and returns the correct serial number,

remove the “Wrong serial number” and show the correct serial number.

Let’s imagine how the evaluation stack should look like after changes and manage to do so:

Page 59: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 58

0 “The serial number is: ”

1 #SERIAL#

2 Message box style

3 Message box title

First thing we should notice is that we are going to load 4 items onto the stack, the directive .maxstack

was previously established to prepare the just in time compiler to reserve only 3 slots for this method, so

the first change we have to do is changing the .maxstack value:

1. .maxstack 4

Second thing is removing the line IL_0032: ldstr "Wrong serial number." And prepare the string we want

to load, the use of labels is optional but we need to use at least one label to mark the offset at which we

started modifications:

2. IL_Patch: ldstr "The serial number is: "

Now we have to call an instance of the class that has the function witch calculates the correct serial

number, we will simply take the same instructions used by the Crack Me to perform comparison:

3. IL_Patch0: ldarg.0

4. IL_Patch1: ldfld class CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial

CrackMe3_InfoSecInstitute_dotNET_Reversing.Form1::cGenSerial

5. IL_Patch2: callvirt instance object

CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::CalculSerial()

Technically our serial is “ready” but we cannot show an “object” in a text box, we have to get the string

value from the serial number object, in dot NET Frameworks the method which can return a boxed copy

of an object is RuntimeHelpers.GetObjectValue and we have to give its full signature:

6. IL_Patch3: call object

[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)

Now the evaluation stack contains two values: “The serial number is:” string and the serial number string,

we need to concatenate them t produce one value / item, by browsing Microsoft MSDN we find

String.Concat (object,…) method, so by giving its full signature we get:

7. IL_Patch4: call string [mscorlib]System.String::Concat(object, object)

We are almost done, but we still have to do one more change regarding the branch brfalse.s

Instead of jumping to the offset at label IL_0032 the Crack Me should go to our patch:

8. IL_001c: brfalse.s IL_Patch

Now we are done! After these changes the modified code must look like this:

Page 60: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 59

Save you .il file and let’s reassemble it using ILASM assembler to test what we did (if you have troubles

with this step please refer to http://resources.infosecinstitute.com/demystifying-dot-net-reverse-

engineering-introducing-round-trip-engineering/):

C:\Windows\Microsoft.NET\Framework\v4.0.30319>ilasm C:\Users\Soufiane\Desktop\round-

t\crackme3.il -res=C:\Users\Soufiane\Desktop\round-t\crackme3.res

The compilation process was successful:

Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved

Writing PE file

Operation completed successfully

And the result was successful as well:

We can continue by customizing this message box to have nicer result by changing the title and the

message box style:

Page 61: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 60

We can go more in depth in our Crack Me tweaking and make changes the way it writes the correct

serial in the text box area instead of showing it in a message box:

IL_Patch0:

ldarg.0

callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox

CrackMe3_InfoSecInstitute_dotNET_Reversing.Form1::get_txt_Serial()

ldarg.0

ldfld class CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial

CrackMe3_InfoSecInstitute_dotNET_Reversing.Form1::cGenSerial

callvirt instance object CrackMe3_InfoSecInstitute_dotNET_Reversing.GenSerial::CalculSerial()

call string [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToString(object)

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

IL_0044:

ret

And the result is quite nice:

Clicking once, the crack me write the serial number, clicking twice it shows you “Serial is correct”.

Page 62: Demystifying  dot NET reverse engineering - Part1

Demystifying dot NET reverse engineering

Page 61

References

Reflexi l - http://sourceforge.net/projects/reflexil/

Dumpbin - ftp://www.fpc.org/fpc32/VS6Disk1/VC98/BIN/DUMPBIN.EXE

LINK.exe - ftp://www.fpc.org/fpc32/VS6Disk1/VC98/BIN/LINK.EXE

http://en.wikipedia.org/wiki/List_of_CIL_instructions

Google for WinHex

http://en.wikipedia.org/wiki/.NET_Framework

Google for Reflector!

ECMA Partition I : http://www.ecma-international.org/publications/standards/Ecma-

335.htm

MSIL Disassembler: http://msdn.microsoft.com/en-us/library/ceats605.aspx

MSIL Assembler: http://msdn.microsoft.com/en-us/library/496e4ekx.aspx

http://msdn.microsoft.com/en-

us/library/microsoft.visualbasic.compilerservices.operators.conditionalcompareobjectequal

.aspx

http://msdn.microsoft.com/en-

us/library/system.runtime.compilerservices.runtimehelpers.getobjectvalue.aspx

http://resources.infosecinstitute.com/demystifying-dot-net-reverse-engineering-

introducing-round-trip-engineering/

Crack-Mes

Crack Me#1 http://www.mediafire.com/?yjoh2f6bv4d6n4i

Crack Me #2 - http://www.mediafire.com/?42vml4flc6yj097

Crack Me#3 - http://www.mediafire.com/?r73aumddbt06b7d