Reversing "dihux's ReverseMe #1" - by Sunshine
File : dhx.reme.1.exe (23 kb)
|Downloaded from :||New2Cracking|
|Author of target:||dihux|
|Tools used :||
(I used 1.09), Hex Editor, PEditor or LordPE
Download whole package here! (includes original & reversed file and this tut)
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).
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
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.
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:
8B35 C8504000 MOV ESI,DWORD PTR DS:[<&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
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:
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:,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: 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:
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|
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):
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":
. FF15 EC504000 CALL DWORD PTR DS:[<&USER32.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):
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:
> 890D 70744000 MOV DWORD PTR DS:,ECX
00401090 . 8B15 70744000 MOV EDX,DWORD PTR DS:
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:
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:
68 74744000 PUSH dhx_reme.00407474 ; push
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:
> 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