An Easy Windows Crackme
Posted on Sat 02 August 2014 in Reverse Engineering
Here I'm going to show you how to crack this crackme. We'll use some basic reversing techniques to figure out how it works and how to break or bypass its copy protection.
Some knowledge of IA-32 assembly would be beneficial to understand what is going on but I'll try to explain it in enough detail that you should be able to follow anyway.
Prerequisites
If you want to follow along the setup is:
- 32bit Windows 7 Home Edition installed inside a VMware virtual machine
- OllyDBG installed
- Microsoft Visual Studio Express 2013 for Windows Desktop installed and 'VC/bin/' in the PATH variable
Initial Look
After you download the zip file and look inside it you should seee this:
Drag the folder they are sitting in to the desktop and run SomeCrypto~01.exe
by double clicking on it.
You should see a rather intimidating window with no explaination like this:
Try to put some junk input in the 2 fields but nothing happens:
Let's close this, it tells us nothing, and have a closer look at the binary itself.
One of the first things you should always look at is the imports section of the binary, it tells you what functions are being imported by the application from other libraries (.dll files).
This tells you a lot about the application and there are nearly always imports because the application has to communicate with the OS.
dumpbin
is an application that comes with Microsoft Visual Studio Express 2013 for Windows Desktop
and on my test machine resides in C:\Program Files\Microsoft Visual Studio 12\VC\bin\
.
It can be used to look at some of the sections in PE executables.
Open up a command prompt with admin privileges:
And run the command dumpbin /imports "C:\Users\user\Desktop\SomeCrypto~01\SomeCrypto~01.exe"
.
The location of the crackme file might be different depending on what your local username is for Windows (mine is user
) and if you extracted it to somewhere other than the desktop.
You should see an output like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
This shows us the functions that are being imported and which dll file each function is in.
The first thing that stands out to me is the call to MessageBoxA
on line 25.
These challenges normally create a message box saying "Success" or something when you have done it so a call to this might be where in the application we want to get to.
And once we are there we should be able to trace back through the code to see where the check was done.
The second thing I notice is the call to GetDlgItemTextA
on line 33.
This function looks like it could be responsible for getting our input, if this is true we could follow the code from that point and find the code that checks our input and the success code.
Digging A Little Deeper
We can ignore the rest for now and go straight to opening the application in OllyDBG. Open Olly with administrator privileges:
Click File->Open and choose the SomeCrypto~01.exe
file:
You should then see this:
The big section in the top left is the main disassembly window, this shows the disassembly of the application from the entry point of the application (004012DE
), this is where execution of the application starts and these are the CPU instructions that are going to run.
We can check this using dumpbin
with the following command: dumpbin /headers "C:\Users\user\Desktop\SomeCrypto~01\SomeCrypto~01.exe" | find /i "entry point"
1 |
|
The columns are from left to right, the memory address of the instruction, the hex representation of the instruction, the ia-32 assembly representation and finally notes that Olly puts there for us.
The top right section contains the values of the CPU registers, these are used primarily as storage for the CPU while it is running instructions. There are a couple of special ones which I'll explain if I need to.
The format is: [CPU register name] [value] [Olly notes]
The bottom right section is the stack window and shows the current status of the stack, the stack is used to store function arguments and local variables as well as a few other things.
The columns are from left to right, memory address, 4 byte hex value at that memory address, Olly notes
The bottom left section is the dump window and can be used to dump certain bits of memory to see what is there.
The dump window has titles for its columns.
Let's see if there are any interesting strings in here, right click anywhere and click on Search for->All referenced text strings:
You should see the strings window with 4 entries:
The third entry down looks promising (Success).
Let's have a look where in the application this is, right click on it and click Follow in Disassembler:
You should see something like this:
As you can see the function call is to MessageBoxA
, this is where we want to end up.
Just above the function call are the instructions that decide whether or not the bit of code that calls MessageBoxA
is run (I've highlighted the relevant rows).
Understanding The Authentication Logic
This is basically just calling some internal function at 00401000
then using the return value to decide whether or not to jump to 004012CA
. If the return value is 0
the jump happens.
This is the code at 004012CA
:
1 2 3 4 5 6 7 |
|
It just exits so we don't want to end up here, this is the fail case.
Let's look inside this function to see what it does, right click on the function call (at 0040129D
) and click Follow:
You should see this:
This is the function that decides if our name and/or serial are correct. Here is the full disassembly:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
|
Here I will go over this code in detail and try to understand what it is doing.
First it starts with the function prologue:
1 2 |
|
This is common among all stdcall and cdecl functions, it just sets up the stack frame (for more information about stack frames check out the "Stack Frames" section of my post on basic binary auditing).
The next instruction is interesting:
1 |
|
This is using the ECX register before anything has been done to it in this function. This means that whatever is stored in ECX was stored there in the calling function and it was passed as an argument to this current function.
The reason it was passed in a register instead of on the stack (how arguments are normally passed) is because the compiler knew it was in control of all points of entry into this function.
The most likely way that the compiler would have known this is if the function was explicitly defined with the static keyword. This means that only functions inside the same source file can call this function.
To figure out what is stored in ECX at this point in the application without running it, we will need to look back through the code that called this function, here is that code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
As you can see there are 2 calls to GetDlgItemTextA
and we have 2 fields (Name and Serial). But at this time we don't know which field is which however we do have their ID's.
The prototype for GetDlgItemTextA
is:
1 2 3 4 5 6 |
|
And from the manual page for it:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
So the second argument is the ID of the field and the third is the buffer that the text is going to be stored in.
This means that we are looking for the control with ID 3EA. Line 16 (on the disassembly of the 2 calls to GetDlgItemTextA
above) shows that ECX is being loaded with the address of ESP+84, just before ESP+84 is loaded as the buffer argument to GetDlgItemTextA
with an ID of 3EA.
If you remember back to when we used dumpbin
to list all of the imported functions, there was also a function called SetDlgItemTextA
being imported.
This function is likely used to set the values to "Enter you name..." and "Enter your serial...". We can use this to figure out which of these ID's (3E9
or 3EA
) is the serial field and which is the name field; and ultimately which is being passed to our checking function in ECX.
We could use the strings window again and find out where "Enter you name..." and "Enter your serial..." are referenced but I'll show you a different way to find them using the function name (SetDlgItemTextA
).
First close OllyDBG, open it again and open the crackme again so that you get to this point again:
Right click anywhere and click Search for->All intermodular calls:
After that, this window should pop up:
You can see the second and third entries are calls to SetDlgItemTextA
, looking at the addresses on the left these calls are right next to each other.
Right click on 1 of them and click Follow in Disassembler or press Enter:
You should see this:
Here is the disassembly of these calls:
1 2 3 4 5 6 7 8 9 |
|
The prototype for this function is:
1 2 3 4 5 |
|
Looking at this its obvious that the control with ID 3EA is the serial number field because it is being set to "Enter your serial...".
We can verify this by setting a breakpoint at the top of the serial checking function, running the application and checking the value of the ECX register.
First go to the check function again:
Then right click on the top instruction (at address 00401000
) and click Breakpoint->Toggle or press F2:
You should then see the background of the address section (on the far left) turn red:
Then run the application by clicking Debug->Run or pressing F9:
You should see this after the breakpoint is hit (it shouldn't take long for the breakpoint to hit):
As you can see in the registers window (in the top right), the value of ECX is the address that contains the string "Enter your serial..." so our static analysis of the code was correct.
Now we can get back to analysing the code in this serial checking function.
The following is the start of the function excluding the prologue:
1 2 3 4 5 6 7 8 |
|
The first line loads the first byte of our serial into the AL register (The lower byte of the EAX register).
Some space is then reserved on the stack for a local variable. On line 3 the value of the ESI register is saved on the stack and zero'ed out (xor'ing anything with itself makes the result 0).
The byte in the AL register (at this point in time the first character in our serial) is checked for 0 on line 5 and if it is 0 execution jumps to 004010C6
.
Let's look at the code at 004010C6
:
1 2 3 4 5 |
|
This clearly just sets the return value to 0
and returns, we already know that we don't want a return value of 0
so this is our failure case.
Following the jump we have an LEA instruction, which loads the value of our local variable, and a SUB command, which calculates the distance from the local variable to where our serial is in memory.
The result of these 2 instructions (the distance from the local variable to where our serial is in memory) is stored in the EDX register.
Next we have the following loop:
1 2 3 4 5 6 7 8 9 10 |
|
This is checking if the value in AL is below 61 (lines 1 and 2) or above 7A (lines 3 and 4) and jumping to 004010C6
if it is.
Looking at the ascii table 61 is a and 7A is z.
So if the first character is not a lowercase letter, execution will jump to the same failure case as before.
If the jumps aren't taken the byte is moved to the address pointed to by EDX+ECX
on line 5. This will point to the right position in the local variable due to the earlier SUB
command.
Then (on line 6) the next byte in the serial is moved into AL, both ECX and ESI are incremented. Lastly, on lines 9 and 10, AL is checked for 0 and the jump to 00401018
is only taken if AL is 0.
This is clearly just making sure only lowercase letters are part of the serial, so at least we now know the possible different characters that are allowed in the serial.
Another thing to notice here is that ESI is being used as a counter and at the end will contain the number of characters in the serial.
Let's look at the 2 lines following this loop:
1 2 |
|
If you'll remember, ESI contains the number of characters in the serial and here its being checked against 1A
(or 26 in decimal). If ESI isn't equal to 26 then our failure case is taken again (004010C6
).
We then zero out EAX and onto the next loop:
1 2 3 4 5 |
|
This is simply moving a string from 403010
to 403140
and only stops once it hits a 0
.
The data at 403010
we can see by right clicking on the line (line 1 here) and click Follow in Dump -> Address constant:
You should see this:
It will show the following in the dump window:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
This is everything before and including the first 0
.
Once this loop has completed we have the following:
1 2 3 4 |
|
This zero's out ECX and checks the value at 403140
against CL (0
) and if they match jumps to 00401088
, otherwise jumps to 00401060
.
Let's see what happens if you jump on line 3 is taken:
1 2 3 4 |
|
Another jump is taken if ECX is 0
and we know it will at this point. Here is the code at that location:
1 2 3 4 5 6 7 8 9 10 |
|
This is the end of the function.
Its pretty obvious that this function creates a checksum of a modified version of the string we found earlier and checks it against F891B218
, if it is equal the function returns 1, otherwise it return 0.
At this point I remember that there are no rules to this crackme so patching is allowed.
Exit OllyDBG completely and make a copy of the application like this:
This isn't needed, I just do it to be careful.
Ope the copy and go to the serial checking function and the line under CMP AL,61
, where it says JL SomeCryp.004010C6
at 0040101A
, double click, type je 4010A2
and click Assemble.
The little window should have stayed open, type jmp 4010C6
and click Assemble again.
You should see the following:
This should check if the first character in the serial is a and if it is jump to 4010A2
, otherwise jump to 4010C6
which is the failure case.
Click Cancel and scroll down the the memory address 4010A2
. Double click there, type mov eax, 0xf891b218
and click Assemble.
You should see this:
Now just fill the rest with NOP's until the cmp
at 004010AF
like this:
This should ensure that if the serial contains an a at the start it should set the value of EAX accordingly.
Save these modifications to the application file by right clicking anywhere and clicking Copy to exe->All modifications:
It should open this window:
Click Copy all and you should see something like this:
Click the close button in the top right corner of this window and you should get the following dialog:
Now if you browse to the directory with the crackme files in you should see a new file:
The file ending in .bak is the backup created by Olly, and the 1 named SomeCrypto~01 - Copy.exe
is our patched file.
Just run it and put anything as the name and any serial starting with an a:
CRACKED!!! :-)
Conclusion
You don't need to fully understand every part of an application while reverse engineering it, it depends on what you are trying to achieve and the complexity of the application.
Try to concentrate as much as possible on the important areas and ignore everything else.
When beating a protection mechanism sometimes its easiest to just bypass the protection as opposed to trying to break it.
Further Reading
The best book I've read on this topic is Reversing: Secrets of Reverse Engineering by Eldad Eilam.
Happy Hacking :-)