The files for this tutorial are available here (2k).
This is going to be my first tutorial. I hope it is worthy reading for you all. I like the ReverseMe's .... but, wouldn't it be very easy to just do the thing we're asked for : make the exit-button work?. Yes, indeed it would, therefore here I'll reverse a bit further...
A tutorial where all the changes are directly made with HIEW. W32Dasm may be of assistance.
1. Make the MessageBox let you prompt for "Wan't to see my AboutBox before exiting?" with "Yes/No" buttons and a Question mark Icon.
2. Exit the program on "No" or show the AboutBox on "Yes" with a special Icon and our own Text. Exit on klicking "OK".
Let's get started. The first thing we notice when we deadlist is that Shell32.dll (where the AboutBox-Function is located) isn't loaded. This means it has to be loaded by our code, otherwise we can't execute the Functions we need. We can use "GetProcAddress" to dynamically retreive the address of the functions we need. We will type the "GetProcAddress" over "GetModuleHandleA" in the import table (Virtual Address 402084, Offset 684). But now how do we get the handle to "KERNEL32.DLL"?. There goes "ExitProcess", overwritten by "LoadLibrary" at Address 402076, Offset 676. Now we have 2 functions to get dynamically all the Handles and Functions we need!. You can even see those changes when deadlisting the Exe-file. ExitProcess is now gone forever, but the EndDialog-function will do the Exit-Job just fine.
Next step :- make a list of all the functions we need :-
· ShellAboutA - Shell32.dll
· ExtractIconA - Shell32.dll
We now need the String "SHELL32.DLL" for the LoadLibrary function and others too :-
· The strings of the 2 needed Functions "ShellAboutA"
· The Title of our AboutBox: "See what you can do!!".
· The first Textline in the AboutBox: "By CaptRE".
Lets see what our Win32.hlp file has to say about ShellAboutA? - "Points to text that the function displays in the title bar of the Shell About dialog box and on the first line of the dialog box after the text "Microsoft Windows" or "Microsoft Windows NT." If the text contains a "#" separator, dividing it into two parts, the function displays the first part in the title bar, and the second part on the first line after the text "Microsoft Windows" or "Microsoft Windows NT". So we'll make it one String then :
"See what you can do!!#By CaptRE"
· The Title of our MessageBox: "WannaSeeAbout?".
· The Text of our MessageBox: "Do you want to see my AboutBox before you leave?".
Now lets find a place to insert those Strings. I decided to use the .data section. I calculated (F8/F6 in Hiew) offset+VirtSize=800+3C=83C. That's free space .. after some trial and error I found out that I had to leave a few spaces (that's Zero's in Hex!), otherwise at execution my first String was beeing crippled. I started at 00403041 (Offset 841) and inserted my Strings. Notice you have to leave a space (thats NOT a Spacebar, but 2 Zero's in Hex!) between each String.
Change the MessageBox into our own Title and Text with a YesNo button and a Question mark Icon.
1. Search in the appropriate header file or API viewer the
values for MB_YESNO + MB_ICONQUESTION (Public Const MB_YESNO =
&H4&, Public Const MB_ICONQUESTION = &H20&). So
the value needed is 20h+4h=24h.
2. Change the Push at Offset 43E into PUSH 024.
3. Change the Push at Offset 440h into PUSH 403075 = ""WannaSeeAbout?" (Don't know how to get this Address?, very simple : in Hiew change to Hex-Mode (F4/F2) then search for the text we've just added. Put the cursor on the first Character of the String and read the Address in the title bar).
4. Change the Push at Offset 445 into PUSH 403084 (Text : "Do you want...").
5. Save with F9.
Redirect the original call to GetModuleHandleA :-
1. Let's see where we can put our new code. In Hiew: F8/F6.
In the .text section we can insert it at Offset+VirtSize=400+8A=48A.
2. Jump from original to new code. A good place to do this is where the call to the MessageBox is made.
3. Change the call at offset 402 into the call to "LoadLibrary". See your Win32.hlp file : the two functions are almost identical!.
4. At the new code location : call the MessageboxA function.
5. Yes/No clicks are saved in EAX. Check if "Yes" or "No" is pushed.
6. If No : stop the program.
7. Push string "Shell32.dll".
8. LoadLibrary "Shell32.dll". The handle of Shell32.dll will be returned in EAX.
9. Push string "ExtractIconA".
10. Push the pointer of Shell32.dll (=EAX).
11. Call GetProcAddress. The return value will be in EAX, that's the pointer to the function "ExtractIconA".
12. Push index number of the icon. Let's take number 35 (map with tools). The hex-value has to be pushed, i.e. 23.
13. Push string "Shell32.dll".
14. Push instance handle. Let it be 0.
15. Call ExtractIconA. That is : call EAX (remember?).
16. The return value will be in EAX. Save the return value (Handle of the Icon) into a Buffer, otherwise it will be overwritten when calling the ShellAboutA Function. Which buffer?, we'll use the buffer in the original code. Look at Offset 407.
17. Push String "Shell32.dll" again.
18. Call "LoadLibrary" again. The return value will be in EAX.
19. Push the string "ShellAboutA"
20. Push the pointer of Shell32.dll (=EAX).
21. Call "GetProcAddress".
22. Push the icon handle. We saved it into a buffer in pt.15, so: push this buffer!.
23. Push the string with my name. I use this string twice (see pt 23).
24. Push the string with the title and first line of text.
25. Push the handle of the parent window. Let it be 0.
26. Call "ShellAboutA" (=EAX).
27. Jump to original code to stop the program.
At Offset 402 : CALL 00000046C :-
0000048A: E8F5FFFFFF CALL 000000484 ; MessageBoxA.
0000048F: 50 PUSH EAX ; Save result of the click.
00000490: 83F807 CMP EAX,007 ; Is it NO?.
00000493: 74C5 JE 00000045A : It is! Exit!.
00000495: 68B6304000 PUSH 0004030B6 ; "LoadLibraryA".
0000049F: 68C2304000 PUSH 0004030C2 ; "ExtractIconA".
000004A4: 50 PUSH EAX ; Pointer shell32.dll.
000004A5: E8C8FFFFFF CALL 000000472 ; GetProcAddress.
000004AA: 6A23 PUSH 23 ; Index Icon handle in Shell32.dll.
000004AC: 68B6304000 PUSH 0004030B6 ; "Shell32.dll".
000004B1: 6A00 PUSH 00 ; InstanceHandle.
000004B3: FFD0 CALL EAX ; ExtractIconA.
000004B5: A338304000 MOV ,EAX ; Save Icon handle in buffer.
000004BA: 68B6304000 PUSH 0004030B6 ; "Shell32.dll".
000004BF: E8A8FFFFFF CALL 00000046C ; LoadLibrary.
000004C4: 6841304000 PUSH 000403041 ; "ShellAboutA".
000004C9: 50 PUSH EAX ; Pointer Shell32.dll.
000004CA: E8A3FFFFFF CALL 000000472 ; GetProcAddress.
000004CF: FF3538304000 PUSH D, ; Icon handle.
000004D5: 6866304000 PUSH 000403066 ; My Name-string.
000004DA: 684D304000 PUSH 00040304D ; Title & First line-String.
000004DF: 6A00 PUSH 00 ; ParentWindow Handle.
000004E1: FFD0 CALL EAX ; ShellAboutA.
000004E3: E972FFFFFF JMP 00000045A ; Exit!.
I know I could have made some JUMPS so that the repeated code for getting the pointer to Shell32.dll isn't redundant, but I kept it simple for educational purposes. The same thing is also true for the strings used in the MessageBox: I could have overwritten the original strings to keep the amount of space needed minimized. Also I could have loaded the ExitProcess function to make a clean exit.
Look at the code ... Think ... Right!, I've got total control of every program when implementing this dynamic calling of functions!. Have Fun and Learn ...