10101010101010
010101010101000010100
10100101
10101010100101010
10101000010010110
00101000101000010

-Crudd's eMesreveR-
solution and keygen of the reverseme
~by tank_~

10101000100011111001
101000110010101100
1000100001111111011
10001000011111101010
1000111000101100100
1001111110001000100

The Matrix has you, Neo!

Section:
Contents:
1.Tools used

SoftIce (for tracing/debugging)
IDA / W32Dasm (for dead-listings)
Hiew (for modifying the exe's instructions/opcodes)
PeBuild (for modifying the exe's sections and writing strings)
Sadd (by NeuRaL_NoiSe, for adding sections to a PE file)
OpGen (by NeuraL_NoiSe, for getting the right calls/jmps in the exe)
Api reference (for the coding part of the reverseme)

2.Initial approach (Introduction)

Okie, a few first words about the beginning.
This is a great reverseme for the newbies, and for those who have a little experience in reversing also, so if you haven't tried to reverse it yet but would rather do it the 'easy' way (by reading my tut), I say to you: 'Your way is awfully wrong!'. You should try first to reverse it yourself and ONLY if you fail take a peek in this tutorial. Now that we have that clear, let's go on with the fun.
So, we have to reverse a crackme. Funny task we say. Okie, first things first. Read the assignment. We have got to add a few labels, edit boxes and a button. When the button is clicked it has to do something (not important atm). Now, disassemble the exe in IDA, then run it a couple of times in Sice, just to get its feeling. Notice how things run, it is rather easy considering that the source was written in asm. Now, we need to 'do' a few things to the exe before we continue. I have first tried to add my code in the .rsrc section but then found out the space was not enough... :) So we will add a section from the very start. Launch Sadd (SADD.EXE eMesreveR.exe .tank), and use a RAW size of 0x600. We have plenty of space where we will play now. We also need some of our strings in the exe. We will add them where the program stores its own (the .data section). So, we will add (using PE Builder):
403150: "Name:'
403160: "Serial number:"
403170: "HDD serial:"
Now take a look at the disassembly, near the entry point. At 401011 we see:
.text:00401011 E8 E0 02 00 00 call sub_4012F6
Full of curiosity, we take a look at 4012F6, and we discover:
.text:004012F6 sub_4012F6 proc near ; CODE XREF: start+11p
.text:004012F6 push 0
.text:004012F8 push 0
.text:004012FA push 0
.text:004012FC push 0
.text:004012FE push offset dword_403370 ;HDD serial
.text:00401303 push 0
.text:00401305 push 0
.text:00401307 push 0
.text:00401309 call j_GetVolumeInformationA
.text:0040130E mov esi, dword_403370
.text:00401314 push esi
.text:00401315 push offset unk_403000
.text:0040131A push offset dword_403370
.text:0040131F call j_wsprintfA ;store HDD serial in 403370
.text:00401324 add esp, 0Ch
.text:00401327 retn
.text:00401327 sub_4012F6 endp
Taking a look at the api ref we see:
BOOL GetVolumeInformation(
LPCTSTR lpRootPathName, // address of root directory of the file system
LPTSTR lpVolumeNameBuffer, // address of name of the volume
DWORD nVolumeNameSize, // length of lpVolumeNameBuffer
LPDWORD lpVolumeSerialNumber, // address of volume serial number
LPDWORD lpMaximumComponentLength, // address of system's maximum filename length LPDWORD lpFileSystemFlags, // address of file system flags
LPTSTR lpFileSystemNameBuffer, // address of name of file system
DWORD nFileSystemNameSize // length of lpFileSystemNameBuffer
);

So Crudd wanted to help us, therefore we do not need to get the HDD serial ourselves, we have it ready stored in 403370 when we will need it.
Also notice two strings:"Congrats. Now if you're really..." and "Invalid serial. Please ...". If you will look around the place where they are used (in IDA) you will see that there is a proc that reads text from two textboxes (via GetWindowTextA), encodes the data, also encodes the name with the HDD serial, compares the 2 values and pops a messagebox according to the equality of the 2. You have guessed it, it's our crackme code we will have to call when the user clicks the 'CHECK IT' button (Yes, that's right, Crudd made it easier once more by including the code that checks for the serial). We also take a look at GetWindowText:
int GetWindowText(
HWND hWnd, // handle of window or control with text
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum number of characters to copy
);
So, look carefully and write down the values being pushed right before the api calls (403158 and 40315C), those are the textbox handle addresses, so that's where we will need to put the handles when we create the textboxes. Also note the address where the crackme algorithm starts (4011C6, we will need to call that address later).

3.Essay
(steps)

The essay will be divided into 3 parts: one concerning the creation of the controls, the second the button click intrepretation, and the third coding a keygen for the new crackme.

PART I
We start by looking at the api ref for a func that displays a control. We find that CreateWindowEx does the trick. That api call should be followed by ShowWindow and UpdateWindow in order for the control to be displayed properly. Note the addresses for the 3 funcs (in IDA, using the names window):
CreateWindowEx - 40132E; ShowWindow - 401376; UpdateWindow - 401382
Now we need a place to jump to our code that will add the controls. We will do that between the call to the CreateWindowEx and ShowWindow of the main window. So, at 4010E5 we modify:
.text:004010E5 jmp 405002
We are all set then, let's add the necessary code. Oops, almost forgot: back to the api ref:
HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu, or child-window identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data
);

BOOL ShowWindow(
HWND hWnd, // handle of window
int nCmdShow // show state of window
);

BOOL UpdateWindow(
HWND hWnd // handle of window
);

Now we can start coding(better watch out coz there's a big snippet coming, and I mean big):
--------------this is where it starts--------------
00405002 push 0
00405004 push dword_40314C ;look in IDA at 401007, that's where i got this value from
0040500A push 4000h ;resource ID
0040500F push eax ;main window handle (eax=[ebp-50])
00405010 push 15h ;values
00405012 push 7Fh ;refering
00405014 push 10h ;to size
00405016 push 6Fh ;and positioning
00405018 push 40800000h ;window(control) style
0040501D push 0 ;window(control) text
0040501F push offset aEdit ; "edit"
00405024 push 100h ;window(control) extended style
00405029 call j_CreateWindowExA
0040502E push 1 ;SW_SHOWNORMAL
00405030 push eax ;control handle
00405031 mov dword_403158, eax ;store eax for safe keeping
00405036 call j_ShowWindow ;show the window(control)
0040503B push dword_403158 ;restore the control handle
00405041 call j_UpdateWindow ;update the window(control)
00405046 push 0
00405048 push dword_40314C
0040504E push 4001h
00405053 push dword ptr [ebp-50h]
00405056 push 15h
00405058 push 7Fh
0040505A push 30h
0040505C push 6Fh
0040505E push 40800000h
00405063 push 0
00405065 push offset aEdit ; "edit"
0040506A push 100h
0040506F call j_CreateWindowExA
00405074 push 1
00405076 push eax
00405077 mov dword_40315C, eax
0040507C call j_ShowWindow
00405081 push dword_40315C
00405087 call j_UpdateWindow
0040508C push 0
0040508E push dword_40314C
00405094 push 4002h
00405099 push dword ptr [ebp-50h]
0040509C push 15h
0040509E push 7Fh
004050A0 push 50h
004050A2 push 6Fh
004050A4 push 48800001h
004050A9 push offset dword_403370
004050AE nop
004050AF push offset aEdit ; "edit"
004050B4 push 20000h
004050B9 call j_CreateWindowExA
004050BE push 1
004050C0 push eax
004050C1 mov dword_403470, eax
004050C6 call j_ShowWindow
004050CB push dword_403470
004050D1 call j_UpdateWindow
004050D6 push 0
004050D8 push dword_40314C
004050DE push 4003h
004050E3 push dword ptr [ebp-50h]
004050E6 push 15h
004050E8 push 60h
004050EA push 10h
004050EC push 5
004050EE push 50000000h
004050F3 push offset dword_403150
004050F8 push offset aStatic ; "static"
004050FD push 0
004050FF call j_CreateWindowExA
00405104 push 1
00405106 push eax
00405107 mov dword_403470, eax
0040510C call j_ShowWindow
00405111 push dword_403470
00405117 call j_UpdateWindow
0040511C push 0
0040511E push dword_40314C
00405124 push 4004h
00405129 push dword ptr [ebp-50h]
0040512C push 15h
0040512E push 60h
00405130 push 30h
00405132 push 5
00405134 push 50000000h
00405139 push offset aSerialNumber ; "Serial number:"
0040513E push offset aStatic ; "static"
00405143 push 0
00405145 call j_CreateWindowExA
0040514A push 1
0040514C push eax
0040514D mov dword_403470, eax
00405152 call j_ShowWindow
00405157 push dword_403470
0040515D call j_UpdateWindow
00405162 push 0
00405164 push dword_40314C
0040516A push 4005h
0040516F push dword ptr [ebp-50h]
00405172 push 15h
00405174 push 5Ah
00405176 push 50h
00405178 push 5
0040517A push 50000000h
0040517F push offset aHddSerial ; "HDD serial:"
00405184 push offset aStatic ; "static"
00405189 push 0
0040518B call j_CreateWindowExA
00405190 push 1
00405192 push eax
00405193 mov dword_403470, eax
00405198 call j_ShowWindow
0040519D push dword_403470
004051A3 call j_UpdateWindow
004051A8 push 0
004051AA push dword_40314C
004051B0 push 4006h
004051B5 push dword ptr [ebp-50h]
004051B8 push 20h
004051BA push 60h
004051BC push 6Ah
004051BE push 50h
004051C0 push 50000001h
004051C5 push offset aCheckIt ; "Check It"
004051CA push offset aButton ; "button"
004051CF push 0
004051D1 call j_CreateWindowExA
004051D6 push 1
004051D8 push eax
004051D9 mov dword_403470, eax
004051DE call j_ShowWindow
004051E3 push dword_403470
004051E9 call j_UpdateWindow
004051EE jmp loc_4010F7 ;go back to program flow

--------------this is where it ends--------------
Allthough the code is rather lenghty, it's simple and it can be resumed like this:
int no_of_controls=7
while (no_of_controls>0) {
CreateControl
ShowControl
UpdateControl
no_of_controls--
}
That's like all for the first part.


PART II
What do we have to do in this part? Simply add code to the messageloop so that our button triggers some action when it is clicked. Since the exe was rather small I have found it easy to locate the code that checks for the messages the program receives. I have searched for the strings the program uses in the messageboxes of the 2 menu-items. Just open the names window and type "aread..." it will guide you to the string def, see where it is called from, press ENTER and you will arrive somewhere around the message handling routines (just scroll up a few lines). We see:
00401125 push ebp
00401126 mov ebp, esp ;structure holding the message info
00401128 cmp [ebp+arg_4], 2 ;([ebp+arg_4]=message) is WM_DESTROY?
0040112C jnz short loc_40113A
0040112E push 0
00401130 call j_PostQuitMessage
00401135 jmp loc_4011C0
0040113A cmp [ebp+arg_4], 1 ;is WM_CREATE?
0040113E jnz short loc_401142
00401140 jmp short loc_4011C0
00401142 cmp [ebp+arg_4], 111h ;is WM_COMMAND
00401149 jnz short loc_4011AB
0040114B mov eax, [ebp+arg_8] ;if WM_COMMAND check the control ID ([esp+arg_8])
0040114E cmp [ebp+arg_C], 0
00401152 jnz short loc_401196
00401154 cmp ax, 1 ;is it the About menu?
00401158 jnz short loc_401170
Now I thought we could easily jump to our code at 401142, so just modify at that address:
00401142 jmp 405201 ;followed by 2 nops
And, at 405021, assemble:
00405201 cmp dword ptr [ebp+0Ch], 111h ;is WM_COMMAND?
00405208 jnz 4011AB ;if not jump to location that processes the rest of messages
0040520E mov eax, [ebp+10h] ;if it is, put in eax the ID of the control that issued the msg
00405211 cmp eax, 4006h ; is it our control (the button)?
00405216 jnz 40114E ;if not continue with the program flow
0040521C call 4011C6 ;if yes call the proc that checks the serial (i told u to remember this address :) )
00405221 jmp 4011C0 ;go back to the message loop
This should be it! Run it, it should work. The reverseme stops here, but since we like keygens, we will build one. So:
PART III (optional)
We know that the serial check algorithm starts at 4011C6. Going there, we see:
004011C7 push 28h
004011C9 push offset unk_403398
004011CE push dword_403158
004011D4 call j_GetWindowTextA ;read name into 403398
004011D9 push 28h
004011DB push offset unk_4033C0
004011E0 push dword_40315C
004011E6 call j_GetWindowTextA ;read serial into 4033C0
004011EB lea eax, ds:403398h ;put name in eax
004011F1 cmp byte ptr [eax], 0 ;see if there is user input
004011F4 jz short loc_401215 ;if not pop error messagebox
004011F6 lea ebx, ds:403370h ;if yes put HDD serial in ebx
004011FC xor ecx, ecx ;ecx=0

----------algorithm starts here----------
004011FE movzx edx, byte ptr [eax]
00401201 movzx esi, byte ptr [ebx]
00401204 cmp esi, 0
00401207 jz short loc_40122A
00401209 xor edx, esi
0040120B add ecx, edx
0040120D xor esi, ecx
0040120F add ecx, esi
00401211 inc eax
00401212 inc ebx
00401213 jmp short loc_4011FE ;jmp to comparison routine

----------algorithm ends here--------------
It is rather easy, but I will let it to you to figure it out. I will only give you the proc from the keygen (in Delphi):
procedure TForm1.SpeedButton1Click(Sender: TObject);
var volinfo:dword; a:boolean; doi:cardinal; serial,nume,val1,val2:string; esi,edx,ecx,i,j:longint;
begin
ecx:=0;
if edit1.text='' then showmessage('You must enter a name!') else
begin
a:=windows.GetVolumeInformation(0,0,0,@volinfo,doi,doi,0,0); serial:=Format('%d',[volinfo]);
nume:=edit1.text;
for i:=1 to length(serial) do
begin
val1:=serial[i];
if i<=length(nume) then edx:=ord(nume[i]) else edx:=0;
esi:=ord(serial[i]);
edx:= edx xor esi;
ecx:=ecx+edx;
esi:= esi xor ecx;
ecx:=ecx+esi;
end;
str(ecx,serial);
edit2.text:=serial;
end;
end;

This is the end of the actual essay, snif snif ;)

4.Final words
This has been a cool assignment by Crudd, I love your reversemes. I decided to do a little more than the initial assignment, because I really wanted to code a keygen. You will have to decide on the result.

5.Greets
(Acknowledgements)

Greets go to:
Crudd, for writing the reverseme, and also
extasy, amante4, SantMat, vissie. Also thanks to Iczelion, nchanta, Dawai for various tips, the guys at #Cracking4Newbies, #win32asm, the guys in ID (your database is really great), and everyone else I forgot.
6.Contact me
You can mail me with questions/problems/queries and so on at tank__@hotmail.com