SlideShare une entreprise Scribd logo
1  sur  62
Télécharger pour lire hors ligne
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 soufianetahiri@gmail.com
Website http://www.itsecurity.ma - http://www.marw0rm.com
LinkedIn http://ma.linkedin.com/in/soufianetahiri
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.
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.
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.
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.
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:
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…
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.
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:
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
…
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)
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
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
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
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
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
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 :
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:
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.
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.
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
{
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
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 FilesMicrosoft Visual
Studio 8SDKv2.0Bin
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:
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:
Demystifying dot NET reverse engineering
Page 24
Then double click on our concerned method (Form1_Load…) to get the IL code and corresponding bytes:
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
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
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:
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:
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:
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:
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)
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”:
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:
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
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
}
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
Demystifying dot NET reverse engineering
Page 37
This way you can get Reflexil panel under the source code or IL code shown by Reflector
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:
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:
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…
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:
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.
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 FilesMicrosoft Visual Studio
8SDKv2.0Bin, ILASM the assembler can be found under
C:WINDOWSMicrosoft.NETFrameworkvx.x (depending on the version of frameworks used to
produce the assembly which we want to modify)
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:
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:
CommonLanguageRuntime
Execution
Engine
Source Code Managed
Compiler
Managed module
METADATA
IL Code
LOADER
Just-in-Time
Compiler
Native Code
Internal Data
Structure
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:
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:
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:
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:WINDOWSMicrosoft.NETFrameworkv4.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:WINDOWSMicrosoft.NETFrameworkv4.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:
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)
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!
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:
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 !)
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
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:
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)
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:
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:
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:WindowsMicrosoft.NETFrameworkv4.0.30319>ilasm C:UsersSoufianeDesktopround-
tcrackme3.il -res=C:UsersSoufianeDesktopround-tcrackme3.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:
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”.
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

Contenu connexe

Similaire à Demystifying dot NET reverse engineering - Part1

Safetty systems intro_embedded_c
Safetty systems intro_embedded_cSafetty systems intro_embedded_c
Safetty systems intro_embedded_cMaria Cida Rosa
 
Introduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning SimpleIntroduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning SimpleSandeep Hijam
 
Introducing small basic
Introducing small basicIntroducing small basic
Introducing small basicAn I
 
Cs121 Unit Test
Cs121 Unit TestCs121 Unit Test
Cs121 Unit TestJill Bell
 
The seven pillars of aspnet
The seven pillars of aspnetThe seven pillars of aspnet
The seven pillars of aspnetNethaji Naidu
 
1. Introduction Original - To Print
1. Introduction Original - To Print1. Introduction Original - To Print
1. Introduction Original - To PrintChinthaka Fernando
 
How I ended up contributing to Magento core
How I ended up contributing to Magento coreHow I ended up contributing to Magento core
How I ended up contributing to Magento coreAlessandro Ronchi
 
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdfCLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdfssuserbe139c
 
Programming Without Coding Technology (PWCT) Features - Framework & Extension
Programming Without Coding Technology (PWCT) Features - Framework & ExtensionProgramming Without Coding Technology (PWCT) Features - Framework & Extension
Programming Without Coding Technology (PWCT) Features - Framework & ExtensionMahmoud Samir Fayed
 
Introducing small basic
Introducing small basicIntroducing small basic
Introducing small basicSara Samol
 
Java Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage EssayJava Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage EssayLiz Sims
 
Procedural Programming Of Programming Languages
Procedural Programming Of Programming LanguagesProcedural Programming Of Programming Languages
Procedural Programming Of Programming LanguagesTammy Moncrief
 
Automatic answer checker
Automatic answer checkerAutomatic answer checker
Automatic answer checkerYesu Raj
 
Software design.edited (1)
Software design.edited (1)Software design.edited (1)
Software design.edited (1)FarjanaAhmed3
 

Similaire à Demystifying dot NET reverse engineering - Part1 (20)

Safetty systems intro_embedded_c
Safetty systems intro_embedded_cSafetty systems intro_embedded_c
Safetty systems intro_embedded_c
 
Introduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning SimpleIntroduction to Docker and Containers- Learning Simple
Introduction to Docker and Containers- Learning Simple
 
Intro To AOP
Intro To AOPIntro To AOP
Intro To AOP
 
The Seven Pillars Of Asp.Net
The Seven Pillars Of Asp.NetThe Seven Pillars Of Asp.Net
The Seven Pillars Of Asp.Net
 
Introducing small basic
Introducing small basicIntroducing small basic
Introducing small basic
 
Cs121 Unit Test
Cs121 Unit TestCs121 Unit Test
Cs121 Unit Test
 
The seven pillars of aspnet
The seven pillars of aspnetThe seven pillars of aspnet
The seven pillars of aspnet
 
Teamwork Presentation
Teamwork PresentationTeamwork Presentation
Teamwork Presentation
 
1. Introduction Original - To Print
1. Introduction Original - To Print1. Introduction Original - To Print
1. Introduction Original - To Print
 
How I ended up contributing to Magento core
How I ended up contributing to Magento coreHow I ended up contributing to Magento core
How I ended up contributing to Magento core
 
Introducing Small Basic.pdf
Introducing Small Basic.pdfIntroducing Small Basic.pdf
Introducing Small Basic.pdf
 
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdfCLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
CLR_via_CSharp_(Jeffrey_Richter_4th_Edition).pdf
 
Part i
Part iPart i
Part i
 
Programming Without Coding Technology (PWCT) Features - Framework & Extension
Programming Without Coding Technology (PWCT) Features - Framework & ExtensionProgramming Without Coding Technology (PWCT) Features - Framework & Extension
Programming Without Coding Technology (PWCT) Features - Framework & Extension
 
Introducing small basic
Introducing small basicIntroducing small basic
Introducing small basic
 
Java Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage EssayJava Is A Programming Dialect And Registering Stage Essay
Java Is A Programming Dialect And Registering Stage Essay
 
Part1
Part1Part1
Part1
 
Procedural Programming Of Programming Languages
Procedural Programming Of Programming LanguagesProcedural Programming Of Programming Languages
Procedural Programming Of Programming Languages
 
Automatic answer checker
Automatic answer checkerAutomatic answer checker
Automatic answer checker
 
Software design.edited (1)
Software design.edited (1)Software design.edited (1)
Software design.edited (1)
 

Demystifying dot NET reverse engineering - Part1

  • 1. 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 soufianetahiri@gmail.com Website http://www.itsecurity.ma - http://www.marw0rm.com LinkedIn http://ma.linkedin.com/in/soufianetahiri
  • 2. 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.
  • 3. 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.
  • 4. 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.
  • 5. 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.
  • 6. 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:
  • 7. 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…
  • 8. 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.
  • 9. 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:
  • 10. 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 …
  • 11. 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)
  • 12. 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
  • 13. 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
  • 14. 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
  • 15. 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
  • 16. 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
  • 17. 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 :
  • 18. 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:
  • 19. 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.
  • 20. 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.
  • 21. 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 {
  • 22. 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
  • 23. 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 FilesMicrosoft Visual Studio 8SDKv2.0Bin 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:
  • 24. 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:
  • 25. Demystifying dot NET reverse engineering Page 24 Then double click on our concerned method (Form1_Load…) to get the IL code and corresponding bytes:
  • 26. 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
  • 27. 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
  • 28. 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:
  • 29. 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:
  • 30. 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:
  • 31. 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:
  • 32. 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)
  • 33. 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”:
  • 34. 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:
  • 35. 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
  • 36. 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 }
  • 37. 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
  • 38. Demystifying dot NET reverse engineering Page 37 This way you can get Reflexil panel under the source code or IL code shown by Reflector
  • 39. 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:
  • 40. 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:
  • 41. 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…
  • 42. 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:
  • 43. 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.
  • 44. 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 FilesMicrosoft Visual Studio 8SDKv2.0Bin, ILASM the assembler can be found under C:WINDOWSMicrosoft.NETFrameworkvx.x (depending on the version of frameworks used to produce the assembly which we want to modify)
  • 45. 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:
  • 46. 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: CommonLanguageRuntime Execution Engine Source Code Managed Compiler Managed module METADATA IL Code LOADER Just-in-Time Compiler Native Code Internal Data Structure
  • 47. 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:
  • 48. 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:
  • 49. 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:
  • 50. 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:WINDOWSMicrosoft.NETFrameworkv4.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:WINDOWSMicrosoft.NETFrameworkv4.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:
  • 51. 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)
  • 52. 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!
  • 53. 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:
  • 54. 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 !)
  • 55. 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
  • 56. 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:
  • 57. 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)
  • 58. 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:
  • 59. 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:
  • 60. 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:WindowsMicrosoft.NETFrameworkv4.0.30319>ilasm C:UsersSoufianeDesktopround- tcrackme3.il -res=C:UsersSoufianeDesktopround-tcrackme3.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:
  • 61. 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”.
  • 62. 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