Reversing
"dihux's ReverseMe #1"
-
by Sunshine
|
Target : | dihux's
ReverseMe #1 File : dhx.reme.1.exe (23 kb) |
Downloaded from : | New2Cracking |
Author of target: | dihux |
Tools used : | Ollydbg
(I used 1.09), Hex Editor, PEditor or LordPE |
Download whole package here! (includes original & reversed file and this tut)
Introduction:
Hi, today we wanna reverse dihux's
ReverseMe #1. It's a nice target and not too difficult cause he has already
done some things for us.
Note for Ollydbg: After every change you make, right click on the changed line(s)
and choose copy to executable. A new window with the diassembly of our file
including our changes pops up. When you try to close it, Ollydbg asks you to
save the changes. Choose "Yes" and all changes are saved to file!
Ok let's have a look at our target. Start it and we see two edit fields, a 'Do'-button
which is disabled and a close button. That's all. So open readme.txt to see
what to do (listed below).
-Tasks- 1. Enable the "Do" button 2. Make it compare the text that is taken from the first edit box with 0xA, and if above then message the user that max is 10 characters 3. When you have enabled the "Do" button you have to make it set the generated serial to the second edit box 4. Make the second edit box locked so that the user can't modify its contents but the user should be able to copy it 5. Write a tutorial and give it to me |
Let's begin...
First of all we should get an overview over the file. So open the file in Ollydbg, we land at the entrypoint (4013D5), set a breakpoint on the next line (4013D7) with F2, start the reverseme with F9 and go on tracing with F8.
004013D5 .
6A 60 PUSH 60 004013D7 . 68 18524000 PUSH dhx_reme.00405218 . . 00401554 . 56 PUSH ESI 00401555 . FFD7 CALL EDI 00401557 . 50 PUSH EAX ; Arg1 00401558 . E8 03FDFFFF CALL dhx_reme.00401260 ; dhx_reme.00401260 <- step into this call with F7 |
Perhaps you've noticed it.... we just trace the stuff generated by the c++ compiler. Step into that call at 401558 with F7 to get to the reverseme itself. Well, looks much better, doesn't it. We see that icons are loaded, the main window is registered and created, we also see the message loop (GetMessage, TranslateMessage) and so on... But where are the edits created? Where are the messages processed? We need to find the window procedure where these things are done. Cause the file is so small, we could just look around and we'll find it immediately. But let's do it the 'right way'. Look here:
00401265 .
8B35 C8504000 MOV ESI,DWORD PTR DS:[<&USER32.LoadIconA>]
; USER32.LoadIconA 0040126B . 57 PUSH EDI 0040126C . 8B7C24 5C MOV EDI,DWORD PTR SS:[ESP+5C] 00401270 . 33DB XOR EBX,EBX 00401272 . 68 007F0000 PUSH 7F00 ; /RsrcName = IDI_APPLICATION 00401277 . 53 PUSH EBX ; |hInst => NULL 00401278 . C74424 30 3000>MOV DWORD PTR SS:[ESP+30],30 ; 00401280 . 895C24 34 MOV DWORD PTR SS:[ESP+34],EBX ; 00401284 . C74424 38 0010>MOV DWORD PTR SS:[ESP+38],dhx_reme.00401000 ;<- WndProc 0040128C . 895C24 3C MOV DWORD PTR SS:[ESP+3C],EBX ; . . 004012CE . 8D4424 28 LEA EAX,DWORD PTR SS:[ESP+28] 004012D2 . 50 PUSH EAX ; /pWndClassEx 004012D3 . FF15 D0504000 CALL DWORD PTR DS:[<&USER32.RegisterClassExA>] ; \RegisterClassExA |
Every
main window which is created with CreateWindow or CreateWindowEx must be registered
with RegisterClass or RegisterClassEx. Both functions take as parameter a structure
called WNDCLASS for RegisterClass or WNDCLASSEX for RegisterClassEx. One member
of this structure (called lpfnWndProc) is a pointer to the window procedure.
Here in our file it's 401000. So let's scroll up there in Ollydbg. We see the
well-known case-loop where the messages are checked (Ollydbg
even points it out, what a great tool!).
Task 1 - Enable the
Do Button
Let's go to the WM_CREATE branch cause there the edits and buttons must be created
there. We see this:
004010D4 >
53 PUSH EBX ; Case 1
(WM_CREATE) of switch 00401008 004010D5 . 57 PUSH EDI 004010D6 . 6A 00 PUSH 0 ; /pModule = NULL 004010D8 . FF15 50504000 CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleA>] ; \GetModuleHandleA . . 004011AC > 6A 00 PUSH 0 004011AE . 57 PUSH EDI 004011AF . 6A 68 PUSH 68 004011B1 . 56 PUSH ESI 004011B2 . 6A 14 PUSH 14 004011B4 . 6A 50 PUSH 50 004011B6 . 6A 41 PUSH 41 004011B8 . 6A 0A PUSH 0A 004011BA . 68 00000050 PUSH 50000000 004011BF . 68 3C514000 PUSH dhx_reme.0040513C ; ASCII "Do" 004011C4 . 68 60514000 PUSH dhx_reme.00405160 ; ASCII "BUTTON" 004011C9 . 68 00000200 PUSH 20000 004011CE . FFD3 CALL EBX ; call CreateWindowEx 004011D0 . 85C0 TEST EAX,EAX ; check if CreateWindowEx failed 004011D2 . 5F POP EDI ; restore edi 004011D3 . A3 60744000 MOV DWORD PTR DS:[407460],EAX ; save handle of Do button at 407460 004011D8 . 5B POP EBX ; restore ebx 004011D9 . 75 17 JNZ SHORT dhx_reme.004011F2 ; if CreateWindowEx succeeded then jump over error message 004011DB . 50 PUSH EAX ; /Style ; 004011DC . 68 B4514000 PUSH dhx_reme.004051B4 ; |Title = "Error." 004011E1 . 68 1C514000 PUSH dhx_reme.0040511C ; |Text = "Couldn't create button.hSetd" 004011E6 . 56 PUSH ESI ; |hOwner 004011E7 . FF15 00514000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>] ; \MessageBoxA 004011ED . A1 60744000 MOV EAX,DWORD PTR DS:[407460] mov handle of Do button in eax 004011F2 > 6A 00 PUSH 0 ; /Enable = FALSE 004011F4 . 50 PUSH EAX ; |hWnd 004011F5 . FF15 04514000 CALL DWORD PTR DS:[<&USER32.EnableWindow>] ; \EnableWindow |
Ok, here is our button
created. All necessary parameters are pushed on the stack before calling CreateWindowEx
(because of the ascii "Do" & "Button" we know we are
dealing with the right button). and what we see after this? dihux helped us
really a lot. He disabled the button using the API function EnableWindow. To
enable the button, we simply replace at 4011F2 the "push 0" (false)
with "push 1" (true).
Click on this line in Ollydbg, hit space, type in "push 1", press
return to assemble, press esc to get back, mark this line again, right click
and choose "copy to executable file". You could also use a Hex Editor
and change at offset 5F2 this 6A00 to 6A01. Then you should use a copy of our
file, otherwise you'll get an error cause it's already opened in Ollydbg. Ok
first task is solved.
Task 2 - compare text and message user if too long
Ok we have to react when the Do-Button is pressed. So we have to check to WM_COMMAND branch and we see this:
00401036 >
0FB745 10 MOVZX EAX,WORD PTR SS:[EBP+10] ;
Case 111 (WM_COMMAND) of switch 00401008 0040103A . 83E8 67 SUB EAX,67 ; Switch (cases 67..68) 0040103D . 74 7E JE SHORT dhx_reme.004010BD 0040103F . 48 DEC EAX 00401040 . 0F85 0F020000 JNZ dhx_reme.00401255 00401046 . 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8] ; Case 68 ('h') of switch 0040103A 00401049 . 6A 0C PUSH 0C ; /Count = C (12.) 0040104B . 68 7C744000 PUSH dhx_reme.0040747C ; |Buffer = dhx_reme.0040747C 00401050 . 6A 65 PUSH 65 ; |ControlID = 65 (101.) 00401052 . 51 PUSH ECX ; |hWnd 00401053 . FF15 EC504000 CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>] ; \GetDlgItemTextA 00401059 . 90 NOP 0040105A . 90 NOP 0040105B . 90 NOP 0040105C . 90 NOP 0040105D . 90 NOP 0040105E . 90 NOP 0040105F . 90 NOP 00401060 . 33C9 XOR ECX,ECX |
Very good the text is already
taken from the edit and dihux give us with the nops some space so we don't have
to overwrite code. It's not that much of space but enough for inserting a jump
to an empty space.
We need space to insert our code but also to store the strings for our messagebox.
Let's check the section table:
Section | Virtual Size | Virtual Offset | Raw Size | Raw Offset |
.text | 00003D48 | 00001000 | 00003E00 | 00000400 |
.rdata | 0000124A | 00005000 | 00001400 | 00004200 |
.data | 00000818 | 00007000 | 00000400 | 00005600 |
Ok, our strings we'll insert in the .rdata section. We can insert
them from offset 4200h + 124Ah = 544Ah. We have room for 1400h - 124Ah = 1B6h
bytes (that's more than enough).
Open you hex editor, go to offset 544A and insert you strings like this (perhaps
you have to close our file in Ollydbg in order to save the changes):
00005430 7973
7465 6D49 6E66 6F00 5D03 5669 7274 ystemInfo.].Virt
00005440 7561 6C51 7565 7279 0000 4D61 7869 6D75 ualQuery..Maximu
00005450 6D20 6973 2031 3020 6368 6172 6163 7465
m is 10 characte
00005460 7273 2100
4572 726F 7221 0000 0000 0000 rs!.Error!......
00005470 0000 0000 0000 0000 0000 0000 0000 0000 ................
We remember : caption is at offset 544A = 40624A virtual
address; caption at offset 5464 = 406264.
Our code we can insert from raw offset 400h + 3D48h = 4148h (virtual address
404D48).
So back in Ollydbg we insert at 401059 our jump to our "code cave":
00401053
. FF15 EC504000 CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>];
\GetDlgItemTextA 00401059 E9 EA3C0000 JMP dhx_reme.00404D48 0040105E . 90 NOP 0040105F . 90 NOP 00401060 . 33C9 XOR ECX,ECX |
There we insert the following code (don't forget to hit "copy to executable file" after this):
00404D48
83F8 0A CMP EAX,0A ;
compare eax with 10 00404D4B 77 05 JA SHORT dhx_reme.00404D52 ; if so jump to 404D52 (to the messagebox) 00404D4D E9 0EC3FFFF JMP dhx_reme.00401060 ; jump back 00404D52 6A 00 PUSH 0 ; from here on show messagebox with error message 00404D54 68 64624000 PUSH dhx_reme.00406264 ; ASCII "Error!" 00404D59 68 4A624000 PUSH dhx_reme.0040624A ; ASCII "Maximum is 10 characters!" 00404D5E 6A 00 PUSH 0 00404D60 FF15 00514000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; USER32.MessageBoxA 00404D66 E9 4BC3FFFF JMP dhx_reme.004010B6 ; jump back to 4010B6 |
Directly after the call to GetDlgItemTextA we jump here. In eax is stored the length of text which the function GetDlgItemTextA has read into its buffer. If it's 10 or less, we jump back where we came from. If it's larger than 10, we display a messagebox with our inserted strings and jump to 4010B6. Why 4010B6? It's the end of the "Do-button routine"; if we have more than 10 chararcters we don't want any serial calculation and that stuff... just go out of the routine.
Task 3 - set the generated serial to the second edit box
After we checked the text, the serial calculation follows which I don't discuss here (it's a very simple algo) and then we come to this:
0040108A
> 890D 70744000 MOV DWORD PTR DS:[407470],ECX 00401090 . 8B15 70744000 MOV EDX,DWORD PTR DS:[407470] 00401096 . 52 PUSH EDX ; /<%X> => 0 00401097 . 68 C4514000 PUSH dhx_reme.004051C4 ; |Format = "%X" 0040109C . 68 74744000 PUSH dhx_reme.00407474 ; |s = dhx_reme.00407474 <- our serial is string 004010A1 . FF15 F0504000 CALL DWORD PTR DS:[<&USER32.wsprintfA>] ; \wsprintfA 004010A7 . 83C4 0C ADD ESP,0C 004010AA . 6A 00 PUSH 0 ; /Text = NULL; <- have to change this 004010AC . 6A 00 PUSH 0 ; |ControlID = 0;<- and this 004010AE . 6A 00 PUSH 0 ; |hWnd = NULL ;<- and this 004010B0 . FF15 F4504000 CALL DWORD PTR DS:[<&USER32.SetDlgItemTextA>] ; \SetDlgItemTextA |
The serial is converted to a hexadecimal string using wsprintfA. Dihux has already implemented the SetDlgItemTextA function for us at the right place, we have just to push the right parameters. But the room is a bit small, for every parameter pushed we have just 2 bytes. But for example push [ebp+8] is FF7508, that means 3 bytes. So we jump down again to the end of the section where we have room. So we change it into this:
004010A7
83C4 0C ADD ESP,0C 004010AA E9 BC3C0000 JMP dhx_reme.00404D6B ; jump down to inserted code 004010AF 90 NOP ; cause jump instruction is only 5 bytes long, fill last byte with a nop 004010B0 FF15 F4504000 CALL DWORD PTR DS:[<&USER32.SetDlgItemTextA>] ; \SetDlgItemTextA |
At 404D6B we insert this:
00404D6B
68 74744000 PUSH dhx_reme.00407474 ; push
serial string 00404D70 6A 66 PUSH 66 ; push ID of serial edit 00404D72 FF75 08 PUSH DWORD PTR SS:[EBP+8] ; push handle of main window 00404D75 E9 36C3FFFF JMP dhx_reme.004010B0 ; jump to SetDlgItemTextA |
The 407474 I get from the last argument pushed for the function wsprintf. To find out the control ID, you can use a tool, for example "The Customizer" or you go back to the place where the edit is created to find where the ID is pushed. (here: 0040112E . 6A 66 PUSH 66). The handle of the main window is nearly always at [ebp+8] stored.
Task 4 - lock second edit box
What dihux mean is not to disable the edit box, we should just make it readonly. So let's go back where the edit box is created:
0040112B
> 6A 00 PUSH 0 0040112D . 57 PUSH EDI 0040112E . 6A 66 PUSH 66 00401130 . 56 PUSH ESI 00401131 . 6A 14 PUSH 14 00401133 . 68 AA000000 PUSH 0AA 00401138 . 6A 23 PUSH 23 0040113A . 6A 0A PUSH 0A 0040113C . 68 00000050 PUSH 50000000 ; <- our window style 00401141 . 68 C1514000 PUSH dhx_reme.004051C1 00401146 . 68 BC514000 PUSH dhx_reme.004051BC ; ASCII "EDIT" 0040114B . 68 00000200 PUSH 20000 00401150 . FFD3 CALL EBX ; call CreateWindowEx |
This is how the second edit box is created. The 4th last argument pushed before calling CreateWindowEx is "window style". Here it is 50000000. Now we have to add the atrribut ES_READONLY. The constant for ES_READONLY is 800h. We know that the styles are combined to one using a "logical or". So we have to calculate: 50000000h or 00000800h = 50000800h. Just change push 50000000 to push 50000800 and that's all!
We have successfully reversed dihux's ReverseMe #1. Was
quite funny and not too difficult! Hope c u soon again in my next tut!
Questions, criticism? Mail me!
Sunshine, July 2003
This site is part of Sunshine's Homepage