Solution to Extasy's OpenMe
by Lord Rhesus (27/11/2000)
Difficulty Level
Intermediate
Target
This is a reverseme that has been coded by Extasy of the Immortal Descendants.
What Needs to be Done
The program is a small program which contains a series of check boxes in a three by three grid. The checkboxes are checked and unchecked by clicking on them and when the user presses the save button a file is created called 'save.sav' which contains the details of whether each box is checked or not. The challenge here is to implement an open function in the program without patching any part of the program except the PE header. Writing to the process in memory however is allowed!
Tools Used
Ida Pro Resource Editor (not really necessary but useful for exploring)
Iczelion's Code Snippet Creator (only used for testing and compiling. Cheat!!!)
Hex Editor
Masm
TRW 2000 (to debug our code)
The Essay
You will need to download some of my source code from here in order to understand fully what is going on.
Method of Approach
Before we jump in at the deep end it is a good idea to plan how we are going
to achieve the reverseme's objectives. As suggested by Extasy it would be a
good idea to write a dll containing the code to open the saved file. The reason
why we would do this is because the imports which we need aren't in the main
program. Actually this isn't true, I gave it some thought and realised this
after I had solved the reverseme. We could implement the code because the main
program contains the LoadLibrary and GetProcAddress imports which we will use
anyway to get to our own dll functions. After we have written the dll we need
to find a zero padded space in OpenMe.exe where we can place our code. The steps
we need to take are as follows:
Step 1 (Poking around)
Have a look at the program in a resource editor and find out what ID the open button has. I found it out to 117 (or 75h). Disassemble the file OpenMe.exe in Ida Pro or something else, it should only take about 3 seconds to disassemble as the program is so small. If you scroll down you will get to an interesting section of code as shown below:
00401088 cmp ax, 75h ; Hmm, is that the ID of the Open Button? 0040108C jnz short loc_401093 ; Jump to see if other button pressed 0040108E jmp loc_401184 ; Skip to end if button pressed 00401093 ; --------------------------------------------------------------------------- 00401093 00401093 loc_401093: ; CODE XREF: sub_401040+4Cj 00401093 cmp ax, 76h ; ID of the Save button 00401097 jnz short loc_4010E0 ; Skip if save not pressed
We have now found out where the check is to see if the Open button has been selected. If Extasy hadn't included this check in the program then we could have just redirected the program from here and done the check ourselves. That would have been a bit tedious, but it's worth noting for other reversemes and programs.
Anyway. If we look further down the code we come to the next section of interest:
004010E0 ; --------------------------------------------------------------------------- 004010E0 004010E0 loc_4010E0: ; CODE XREF: sub_401040+57j 004010E0 cmp ax, 65h ; 65h = ID of first checkbox 004010E4 jnz short loc_4010F2 ; Jump if box not clicked 004010E6 xor dword_4020A8, 1 ; Reverse value at 4020A8, hmm 004010ED jmp loc_401184 ; Jump to end 004010F2 ; --------------------------------------------------------------------------- 004010F2 004010F2 loc_4010F2: ; CODE XREF: sub_401040+A4j 004010F2 cmp ax, 66h ; ID or second checkbox 004010F6 jnz short loc_401104 004010F8 xor dword_4020AC, 1 ; hmm, location is now a dwords length away 004010FF jmp loc_401184 00401104 ; ---------------------------------------------------------------------------
Code exactly like the above occurs 9 times! The same number of times as the number of checkboxes! From this we can see that the current state of the checkboxes is stored at location 4020A8 in memory and a dword is used to store the state of each checkbox, highly efficient usage of memory by Extasy there ;-). We should make a note of the location where this information is kept I think.
Now we have to find the handle of the dialog box. We need this so we can change the states of the checkboxes after we've opened and processed the file. This is fairly straight forward, all we have to do is look in our disassembled listing for the call to CreateDialogParam. Take a note of the address that is pushed onto the stack 4 pushes before the call (at memory location 401013). This is the call to the dialog procedure which handles all api calls to do with the dialog box. Ida Pro will show you the local variables (arguments) passed to the procedure as below:
00401040 sub_401040 proc near ; DATA XREF: start+13o 00401040 00401040 arg_0 = dword ptr 8 00401040 arg_4 = dword ptr 0Ch 00401040 arg_8 = dword ptr 10h
The first variable is what we want as it points to the dialogs handle when combined with ebp. Therefore provided no more procedures are called [EBP+8] will point to the dialog's handle.
Step 2 (Finding a zero padded area)
Some rules when looking for zero padded areas in a file:
(quick amendment by the author here: the two rules above are not the best way to find a usable zero padded area, the correct method is described in other parts of this web site, or alternatively look at SantMat's solution as he uses a better method)
Just open up the program in a hex editor (I use Cygnus Hex Editor but everyone else seems to think it's lame!). Have a look for a section filled with lots of zeros. If it has a bunch of strings above it then it is probably the data section. Check this location now in Ida to see if it is being used at all. The zeros from memory location 4020CC seem to be ok. A good place to put the code would be 4020D0 as it is a nice round number. Funnily enough I was reading through SantMat's essay on this reverseme and 4020D0 is exactly the same place where he chose to place his code! You know what they say about great minds and thinking alike, although my mind is probably superior ;-).
Step 3 (Writing the dll)
I won't bother explaining this much as you can just look at the source code. The below pseudo code will show the stages taken:
Open the file for reading
if file not found then
Messagebox with "File not found" message
else
Read 36 bytes (24h) from file save.sav and store them in mem location 4020A8
Close the file
Update checkbox display
end if
Step 4 (Writing code to call the dll)
I won't bother explaining this as well as you can see from the source code below how to call the program. I cheated a bit and when testing hard patched the code into the executable to see if it worked using Iczelion's Snippet Creator. Here is the code as pasted into the creator's text box:
@top:
jmp @start
LibName db "open.dll",0
FunctionName db "OpenSavedFile",0
DllNotFound db "open.dll not found",0
AppName db "OpenMe",0
FunctionNotFound db "OpenSavedFile function not found",0
hLib dd ?
FunctionAddr dd ?
@start:
invoke LoadLibrary,addr LibName
.IF eax==NULL
invoke MessageBox,NULL,addr DllNotFound,addr AppName,MB_OK
.ELSE
mov hLib,eax
invoke GetProcAddress,hLib,addr FunctionName
.IF eax==NULL
invoke MessageBox,NULL,addr FunctionNotFound,addr AppName,MB_OK
.ELSE
mov FunctionAddr,eax
mov eax, [ebp+8] ;[ebp+8] contains the handle of the main dialog. It
;is moved into eax so it can be passed to the dll
call [FunctionAddr]
.ENDIF
.ENDIF
jmp @top ;jump put here so it can be edited later to point to
;memory location 401184 which it returns to
For the snippet creator to insert the code where we want it, we have to tell it to place the code in an existing section at location 4020D0. When this is done we have to redirect the jumps. The first jump we have to redirect to is the link to the code which calls our dll. If you look at the first disassembly snippet in Step 1 then the jump we need to change is the jump from 40108E. Here is the calculation for working out the jump:
4020d0 - 401093 = 103d
So in hex we change the jump at file location (just for testing) 48e to e93d100000. Now we have to jump back from the end of our code snippet to memory location 401184. We can work out the hex of our code by the method below:
NOT((402190 - 401184) - 1) = ffffeff4
In hex we patch file location 78B to E9F4EFFFFF.
If we run the program and now save a pattern like below:
X
X
XXX
Then change it to something else and click on Open the pattern above will be retrieved from the file.
Step 5 (Write a loader to insert code)
After cheating and writing a hard patch we can easily take the hex bytes it was compiled to and stick them in the data section of a loader, and then use them to patch the main program at run time. Again I'm not going to explain the loader so just look at the source code. There we go, we're finished and we didn't have to edit the PE file.
Step 6 (Watching democracy in action, the American style)
I would write something witty and clever here about the state
of American politics but I lack a sense of humor, Volatility would probably
kick my arse and American politics is too fucking boring.
Final Notes
That was easy enough wasn't it.
Greetings
Everyone in the reversing scene, no one in the warez scene coz they are no better than the lusers who make the porn sites they advertise and Adolf Hitler, for failing to take over the world.
If you wish to contact me my e-mail address is: lordrhesus@yahoo.co.uk
As an end note I would like to make a brief statement explaining why reversing papers are more interesting than the boring papers you have to write in industry and university:
In industry you can't end your paper with the word fuck!!!