Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 12

Solution to douby's ReverseMe 1

by Dracon (DREAD)

Tools used:
-----------
* IDA 3.85 (Disassembler)
* HIEW (hexeditor which can generate Opcodes)
* SoftIce (to debug my new code)
* Win32 Api reference
* alphabetic list of important Api constants (very handy)

Also usefull are:


* SAdd (add new sections of any size to an exe)
* ProcDump (has an integrated PE-Editor)
* OpGen (Opcode Generator to create the opcodes for jumps from one virtual
address to another AND it can retrieve the addresses of all imported
windows-functions)

First of all I must say that douby's idea of a "ReverseMe" is great. Adding new
functions this way makes your best tools and programs even better. It's not easy
though. You must know something about the PE file-format and of course win32asm.
I also recommend that you read the essay about adding functions to Notepad by
NeuRaL_NoiSE.

The challenge was (sorted, easiest first):


1) Add a scrollbar to the editbox
2) Add the exit option to the program
3) Add the loading option to the program
4) Add the saving option to the program (easy if you solved #3)

Let's start!

1. Scrollbar
============

This one is easy. CreateWindowEx or CreateWindow are used to create an edit


control, the one used in the ReverseMe. This is the snippet from IDA (in WDasm
it looks the same, but without the ".text:", only the address is shown):

.text:0040116D mov edx, [esp+8+HWND] ; move HWND to edx


.text:00401171 push 0 ; pointer to some data
.text:00401173 mov ecx, [eax+4]
.text:00401176 push ecx ; hInstance
.text:00401177 push 1 ; child ID
.text:00401179 push edx ; parent window
.text:0040117A push 0 ; initial height
.text:0040117C push 0 ; initial width
.text:0040117E push 0 ; initial y position
.text:00401180 push 0 ; initial x position
.text:00401182 push 508000C4h ; window style !!!
.text:00401187 push 0 ; window name
.text:00401189 push offset aEdit ; "EDIT" - class name
.text:0040118E push 0 ; extended styles
.text:00401190 call ds:CreateWindowExA ; Create the window

Remember, all parameters are pushed in reverse order, the last one first. To get
the scrollbars we must modify the style parameter - all styles are combined by a
logical OR. I have already looked up the values for WS_HSCROLL (0x100000) and
WS_VSCROLL (0x200000) for you, so we calculate:
0x508000C4 OR 0x100000 OR 0x200000 = 50B000C4

file-offset 0x1182: 68 C4 00 80 50
change to: 68 C4 00 B0 50

Short test, okay, works. ;-)

All constants can be found in the include files (win32.inc, user32.inc, ...) and
someone has created html-pages with all important constants in alphabetic order
which is VERY handy.

2. Exit menu entry


==================

Now it's getting more difficult. If you click on a menu-entry the program will
get a WM_COMMAND message with the id in the low-order word of WPARAM.
Fortunately, douby decided to show us a messagebox "Nope, doesn't work yet!".
Fine. Look for this error string and examine the code above it. I have already
renamed some of the location and variables to make the code clearer. Other
comments are inserted by IDA, e.g. for the switch jump:

.text:004011CE WM_COMMAND_msg: ; CODE XREF: WindowProc+12


.text:004011CE cmp esi, 7
.text:004011D1 jz short WM_SETFOCUS_msg
.text:004011D3 cmp esi, 111h
.text:004011D9 jnz short DEFAULT_msg ; default
.text:004011DB push edi
.text:004011DC call ds:GetMenu ; Get the handle of the
; menu assigned to the
; given window
.text:004011E2 mov eax, ebx
.text:004011E4 and eax, 0FFFFh
.text:004011E9 add eax, 0FFFF63BFh ; switch 5 cases
.text:004011EE cmp eax, 4
.text:004011F1 ja short DEFAULT_msg ; default

; ----> Important <----


.text:004011F3 jmp ds:off_0_401260[eax*4] ; switch jump for
; Command IDs

.text:004011FA loc_0_4011FA: ; case 0x9c41


.text:004011FA push 0
.text:004011FC push offset a3rr0r ; "3rr0r!"
.text:00401201 push offset aNopeDoesnTWork ; "Nope doesn't
; work yet"
.text:00401206 push edi
.text:00401207 call ds:MessageBoxA
.text:0040120D pop edi
.text:0040120E pop esi
.text:0040120F xor eax, eax
.text:00401211 pop ebx
.text:00401212 retn 10h

Look at the line that I have marked. The next jump depends on the ID, here is
the table for it (at location 401260):

.text:00401260 dd offset loc_0_4011FA ; IDM_LOAD


.text:00401260 dd offset DEFAULT_msg ; default
.text:00401260 dd offset loc_0_4011FA ; IDM_EXIT
.text:00401260 dd offset IDM_ABOUT ; IDM_ABOUT
.text:00401260 dd offset loc_0_4011FA ; IDM_SAVE

As you can see, 3 jumps go back (4011FA) and display our messagebox, one shows
the Aboutbox and one jumps to DefWinProc. Okay, how can we know WHICH number
belongs to the different IDs? I have already done the whole work for you: you
can modify the jump table in that way that only ONE value will show the error
message (0x4011FA), all others are set do DEFAULT_msg (0x403712). Run the
program and click on the menu items. When you see the messagebox you know which
entry in the jump table belongs to it. Got the idea? Good. Another approach
would be to open the program with BRW (Borland Resource Workshop) and to examine
the menu. The IDs should be right in front of you.

Now you know when the user chooses "Exit" from the menu. How you exit a program?
Very easy, you call PostQuitMessage(0). You could now add some code to do this,
but wait a moment. There should already be a call to this function somewhere.
Found it?

.text:00401159 push 0
.text:0040115B call ds:PostQuitMessage
.text:00401161 pop edi
.text:00401162 pop esi
.text:00401163 xor eax, eax
.text:00401165 pop ebx
.text:00401166 retn 10h

Fine, we store now this offset in the jumptable (3rd entry, file-offset 0x1268):
FA 11 40 00 -----> 59 11 40 00

I hope you know why to store the address this way. On all Intel computers, words
and dwords will be stored with the lowest byte first:
00 40 11 59 -> 59 11 40 00.

That's how these values are read and written from and to memory.

Test it, and it works!

3. File loading
===============

Now we get to the tricky parts. A filedialog should prompt the user for a file
which will then be loaded. The problem is, the necessary API functions aren't
included yet. We will use "GetProcAddress" to get the address of these functions
at runtime. If the dll is already loaded (e.g. kernel32.dll for File I/O) you
can use "GetFileModuleHandleA" to retrieve the handle. If the dll is NOT loaded
(comdlg32.dll for the common dialogs) you will need "LoadLibraryA".

An important question: where do we add our code?

The (executable) code is in the "text" section of the file. Use a tool like IDA,
PE-Browser or ProcDump to check it: Virtual Size = 0x2B3E, Section Size in File:
0x3000. What does this mean? Only 0x2B3E bytes are needed for the code, but
0x3000 bytes are reserved because of the alignment setting. Set the Virtual Size
to 0x3000 and you have 0x4C2 (1218) bytes for your code. This should be more
than enough! How do you change this value? Open the file with a hexeditor and
look for "text" (offset 0x1C9). Read a good doc about the PE file header to find
out more (Microsoft, Iczelion). The first 8 chars are reserved for the name of a
section, after that follows the virtual size (WORD) - change it from 3E2B to
0030.

Some more explanation:


ProcDump is a very good tool which can modify an exe-file in different ways. It
can change the pe-header for you. Run ProcDump, click on "PE Editor" and choose
the ReverseMe. We are interested in the "Sections". You will get a list of all
sections and you can right-click to edit them. The code is in the text-section.
Two values are important: the virtual and the physical size. The physical size
depends on the file alignment setting (Visual C++ uses 1000h, but it can be any
multiply of 200h), the virtual size tells how much space is needed for the code
and is important for the Windows PE-loader which loads the exe into memory and
executes the code. If we set the virtual size to the physical one we can use the
unused bytes for our purpose: in our case the virtual size is 0x2B3E and we can
use the bytes from 0x2B40 (to have a rememberable value) to 0x2FFF (at 0x3000
starts the next section) for our code.

1218 bytes are really a lot, but often you will have less, maybe too less. In
this case you will need the program "SAdd" by NeuRaL_NoiSE. It creates, appends
and zero pads a new section to a dll or exe, you only have to specify a name and
the size. The only problem is that (according to NeuRal_NoiSE in his essay) HIEW
can't assemble a jump to this section, you must use sice to get the opcodes.
There is also a nice program, called "OpGen" by NeuRal_NoiSE himself, who can
calculate the opcodes of every jump: you feed it with the starting and the
ending virtual address and it will give you the opcodes. For jumps within a
section you can use HIEW: enter "jmp xxxxxx" where xxxxxx is the PHYSICAL offset
of the destination, don't use the virtual one here!

Let's return to the ReverseMe. We need to allocate memory for a buffer to hold
the filename and later for the whole file. If you look at the import-table of
the exe you will find 2 functions for this task:

"VirtualAlloc" reserves or commits a region of pages in the virtual address


space of the calling process. Only whole 64k pages are allocated, so if you need
10 bytes you will actually get 64k. Our edit-control is (according to the
helpfile) limited to 0xFFFF bytes (64k-1), but this is NOT true, the limit is
smaller. You can use "EM_GETLIMITTEXT" to get the exact value, I used 60000
which seems to be okay. Nevertheless, we will allocate 64k which are first used
to retrieve the filename from the FileDialog and later to read the file into
memory. The exact parameters for "VirtualAlloc" are:

lpAddress: can be NULL


dwSize: we allocate 64 kBytes
flAllocationType: we choose MEM_COMMIT (0x1000)
flProtect: PAGE_READWRITE (0x4) is okay

When we don't need the memory anymore, it will be freed with "VirtualFree":

lpAddress: the Address of our memory


dwSize: must be 0
dwFreeType: MEM_RELEASE (0x8000)

Now we need some space for the OPENFILENAME structure. Again, we use
VirtualAlloc to allocate the necessary memory (sizeof(OPENFILENAME) = 76 bytes)
and later VirtualFree to free it. It's necessary to initialize the structure.
The allocated memory contains only 0s, this saves us some typing:

- size of the structure (important)


- parent window (can be NULL, or you use [esp+10] which is the current handle,
look below for more about it)
- hInstance (only necessary if we use a custom template, can be 0)
- pointer to a filter (maybe later...)
- pointer for custom filter (not important - NULL)
- size of custom filter (not important - NULL)
- index of current filter (not important - NULL)
- pointer to filename: very important, we will put our pointer here
- size of file-buffer: use 512 bytes (200h), should be enough although we
have allocated 64k
- FileTitle, size of FileTitle, Initial Dir and Title can all be NULL
- Flags: OFN_FILEMUSTEXIST (0x1000) is nice
- the other members are also unimportant

Where do we store the variables? The reference says, that only the registers
EBX, EDI and ESI don't change if you call Win32-Api functions, all others could
be modified. 3 registers are enough for now, but if you need more you should
consider using the stack. We have also another option. The memory of the
OPENFILENAME structure will be used only once, later we can use it to store our
variables in it, e.g. if we save the offset of OPENFILENAME in esi you can use
[esi+xx] to access the memory.

Anything more? Yes, we will need the names of the functions which should be
loaded with "GetProcAddress". I will put these zero-terminated strings at offset
0x3F00, you can also use the data-section for it. Do what we have done with the
text-section: compare the virtual with the physical size, adjust the virtual one
and you are ready to store more data in it. We have enough space, so there is no
need for this.

comdlg32.dll (virtual offset 0x403F00)


kernel32.dll (0x403F0D)
CloseHandle (0x403F1A)
CreateFileA (0x403F26)
GetOpenFileNameA (0x403F32)
ReadFile (0x403F43)
user32.dll (0x403F4C)
GetDlgItem (0x403F57)
SetWindowTextA (0x403F62)

The code starts at offset 0x3B40. You can use HIEW to enter it, but be carefull
with the calls like "VirtualAlloc". The address for these procedures must be
looked up in the disassembled file. Search for the functions and you will see
its addresses:

VirtualAlloc: 0x00404034
VirtualFree: 0x0040408C
LoadLibraryA: 0x00404028
GetProcAddress: 0x0040402C
GetModuleHandleA: 0x00404044

Another way to get these addresses is to use "OpGen" once more. Click on "Lookup
Imports for patching" and the program will give you a list of all imported
functions and its addresses. Now you can use them in HIEW like this:

Function: VirtualAlloc
address: 0x404034
enter in HIEW: call d,[00404034]

HIEW will show you (as a comment) that you actually call VirtualAlloc from
Kernel32.dll. Let's have a look at the asm-code:
; Handle IDM_LOAD
: starting at offset 0x3B40
;
; allocate memory for filename buffer
push 4 ; PAGE_READWRITE
push 1000h ; MEM_COMMIT
push 10000h ; 64k
push 0 ; let Windows decide
call VirtualAlloc
mov edi, eax ; store pointer in edi

; allocate memory for OPENFILENAME


push 4
push 1000h
push 4Ch ; 76 bytes
push 0
call VirtualAlloc
mov esi, eax ; store pointer in esi

; initialize the important members


mov [esi], 4Ch ; size of structure
mov eax, [esp+10h] ; this is the parent HWND
mov [esi+4], eax
mov [esi+1Ch], edi ; pointer to filename buffer
mov [esi+20h], 200h ; size of buffer, 200h is enough
mov [esi+34h], 1000h ; flags: OFN_FILEMUSTEXIST

; load comdlg32.dll
; I don't free it, this should be done at program exit
push 403F00h ; offset "comdlg32.dll"
call LoadLibraryA
mov ebx, eax ; store handle in ebx

; get address of GetOpenFileNameA


push 403F32h ; offset "GetOpenFileNameA"
push ebx ; dll-handle
call GetProcAddress

; call the function, only 1 parameter


push esi ; offset OPENFILENAME structure
call eax ; GetOpenFileNameA

; has the user choosen a file?


or eax, eax ; eax == 0 ?
jz FINISH ; yes, jump to end - use 0x3DA0

Wouldn't it be nice to see the filename in the titlebar? Let's do it. We will
need the handle for "user32.dll" and the address of "SetWindowTextA" also later,
so we store them once they are retrieved. The OPENFILENAME structure won't be
used anymore, so we use this memory, you must only keep track where you put all
your variables.

; get handle to "user32.dll"


push 403F4Ch ; offset "user32.dll"
call GetModuleHandleA
mov [esi+20], eax ; store handle for later use

; get address of SetWindowTextA


push 403F62h ; offet "SetWindowTextA"
push eax
call GetProcAddress
mov [esi+24], eax ; store address for later use

; call function
push edi ; should contain the filename
push [esp+14] ; push HWND
call eax ; SetWindowTextA

The user has choosen a file and we will now open and load it. I use
"CreateFileA" and "ReadFile", please check the doc for the exact parameters. As
mentioned above, only about 60000 bytes will be loaded, because the edit-control
can't show more, and even if you load this amount you won't be able to edit the
file until you delete some text. You can use "EM_SETLIMITTEXT" to increase the
limit to a max. of FFFFh.

; open the file


; get library handle for kernel32.dll
push 403F0D ; offset "kernel32.dll"
call GetModuleHandleA
mov ebx, eax ; store it in ebx

; get address of CreateFileA


push 403F26h ; offset "CreateFileA"
push eax
call GetProcAddress

; call CreateFileA
; check its parameters in the doc
push 0 ; hTemplateFile
push 8000080h ; FILE_ATTRIBUT_NORMAL, FILE_FLAG_SEQUENTIAL_SCAN
push 3h ; OPEN_EXISTING
push 0 ; Security Attributes
push 1 ; FILE_SHARE_READ is allowed
push 80000000h ; GENERIC_READ
push edi ; our file
call eax ; CreateFileA

cmp eax, -1 ; INVALID_HANDLE_VALUE (-1) ?


je FINISH ; yes, do nothing, jump to end

; store handle in memory of OPENFILENAME


mov [esi], eax

; get address of ReadFile


push 403F43h ; offset ReadFile
push ebx ; kernel32.dll handle
call GetProcAddress

; set up parameters
push 0 ; overlapped structure

mov ecx, esi ; next parameter is a pointer for read bytes


add ecx, 4 ; I use esi+4 for it
push ecx

push EA00h ; number of bytes to read (ca. 60000)


push edi ; offset of buffer to receive data
push [esi] ; filehandle
call eax ; ReadFile

; close file, we don't need the handle anymore


push 403F1Ah ; offset CloseHandle
push ebx ; kernel32.dll handle
call GetProcAddress

push [esi] ; filehandle


call eax ; CloseHandle

; now check how many bytes we have read


mov eax, [esi+4]
or eax, eax ; test if 0
jz FINISH ; do nothing if no bytes read

The file is now loaded and we want to display it. It's necessary to know the
windows-handle of the edit-control. Do we know it? Look at the (disassembled)
code for the messagebox "Nope doesn't work yet." The first parameter is HWND
(last one pushed), and we see: it's stored in edi. If you scroll up a little bit
you will find that [esp+10] is the location where the HWND is right now. This is
the handle of the main window though. I have used a spy to get the handle of the
edit-control and it was always HWND+4, but there is a cleaner approach.

You can use "GetDlgItem" to retrieve the windows-handle. You need the HWND of
the parent window and the ID of your child-window or dialog-control. The ID of
the edit-control we can find out if we look at the "CreateWindowEx" code once
more (I have explained every parameter in the Scrollbar-section) - it's 1. If we
have the handle we can use "SetWindowTextA" which actually sends a WM_SETTEXT
message to our control.

; get HWND of edit-control via GetDlgItem


push 403F57h ; offet "GetDlgItem"
push [esi+20] ; handle of "user32.dll"
call GetProcAddress

push 1 ; ID of edit control


push [esp+14] ; parent window is stored in [esp+10]
; but we have already pushed a DWORD, so
; HWND is now in [esp+10+4]
call eax ; GetDlgItem

mov ebx, [esi+24] ; address of "SetWindowTextA"


push edi ; address of filebuffer
push eax ; HWND of edit-control
call ebx ; SetWindowTextA
jmp FINISH

After writing this code I found out that you can also use "SetDlgItemText" to
set the text of the control. This function does exactly the same and is shorter
to code. :) The parameters are almost the same, you need the HWND of the parent
window, the ID of your control and the pointer to the new text. I leave this as
an exercise for you.

Now we are ready. Only some cleanup has to be done: free all memory allocated
with VirtualAlloc, pop the registers edi, esi and ebx, and finally return. This
finishing code starts at offset 0x3DA0, so jmp (je, jz) FINISH means that you
must enter "jmp 03DA0" in HIEW. It will generate the right opcode for this jump.
FINISH:
; free memory
push 8000h ; MEM_RELEASE
push 0
push esi ; OPENFILENAME
call VirtualFree
push 8000h
push 0
push edi ; filename buffer
call VirtualFree

pop edi
pop esi
pop ebx
ret 10h

Puh, that was much code. Does it work? YES!!! Great. I must say that it's much
work to do something like this, you must be very carefull (and concentrated)
while adding the code and the right offsets in HIEW.

4. File saving
==============

Now that we have figured out how to load a file it shouldn't be a problem to
save it. You must (again) allocate memory, initialize the OPENFILENAME
structure, call GetSaveFileNameA, create a file, get the contents of the
edit-control (this time with "GetDlgItemTextA") and save everything with
"WriteFile". Here is the code, starting at offset 0x3C70. Don't forget to set
the entry of the jumptable (0x1270) to 0x403C70! After reading the previous part
you shouldn't have any problems to understand this one as well.

; allocate memory for filename buffer


push 4 ; PAGE_READWRITE
push 1000h ; MEM_COMMIT
push 10000h ; 64k
push 0 ; let Windows decide
call VirtualAlloc
mov edi, eax ; store pointer in edi

; allocate memory for OPENFILENAME


push 4
push 1000h
push 4Ch ; 76 bytes
push 0
call VirtualAlloc
mov esi, eax ; store pointer in esi

; initialize the important members


mov [esi], 4Ch ; size of structure
mov eax, [esp+10h] ; this is the parent HWND
mov [esi+4], eax
mov [esi+1Ch], edi ; pointer to filename buffer
mov [esi+20h], 200h ; size of buffer, 200h is enough

; load comdlg32.dll
push 403F00h ; offset "comdlg32.dll"
call LoadLibraryA
mov ebx, eax ; store handle in ebx
; get address of GetSaveFileNameA
push 403F71h ; offset "GetSaveFileNameA"
push ebx ; dll-handle
call GetProcAddress

; call the function


push esi ; offset OPENFILENAME structure
call eax ; GetSaveFileNameA

; has the user choosen a file?


or eax, eax ; eax == 0 ?
jz FINISH

; get handle to "user32.dll"


push 403F4Ch ; offset "user32.dll"
call GetModuleHandleA
mov ebx, eax ; store handle in ebx

; get address of SetWindowTextA


push 403F62h ; offet "SetWindowTextA"
push eax
call GetProcAddress

; call function
push edi ; should contain the filename
push [esi+4] ; push HWND
call eax ; SetWindowTextA

; get address of GetDlgItemTextA


push 403F82h ; offet "GetDlgItemTextA"
push ebx
call GetProcAddress

; call GetDlgItemTextA
; The text won't be stored in edi because it still contains the filename
; which I will need later. I use edi+100h, no filename is THAT long and
; the buffer is still big enough for the max. 60000 bytes.
push FEFFh ; max. size of string
mov ecx, edi
add ecx, 100h
push ecx ; where to store the string
push 1 ; ID of edit-control
push [esp+1C] ; windows-handle
call eax

or eax, eax ; success?


jz FINISH
mov [esi+10], eax ; store number of bytes retrieved

; open the file


; get library handle for kernel32.dll
push 403F0D ; offset "kernel32.dll"
call GetModuleHandleA
mov ebx, eax ; store it in ebx

; get address of CreateFileA


push 403F26h ; offset "CreateFileA"
push eax
call GetProcAddress
; call CreateFileA
; check its parameters in the doc
push 0 ; hTemplateFile
push 8000080h ; FILE_ATTRIBUT_NORMAL, FILE_FLAG_SEQUENTIAL_SCAN
push 2 ; CREATE_ALWAYS
push 0 ; Security Attributes
push 0 ; no sharing allowed
push 40000000h ; GENERIC_WRITE
push edi ; our file
call eax ; CreateFileA

cmp eax, -1 ; INVALID_HANDLE_VALUE ?


je FINISH ; do nothing, jump to end

; store handle in memory of OPENFILENAME


mov [esi], eax

; get address of WriteFile


; I thought this function was already imported. Deadly wrong!
; My computer crashed several times...
push 403F92h ; offset "WriteFile"
push ebx
call GetProcAddress

; call WriteFile
push 0 ; overlapped structure
mov ecx, esi ; pointer to DWORD for written bytes
add ecx, 8 ; I use [esi+8]
push ecx ; push the address
push [esi+10] ; number of bytes to write
mov ecx, edi ; the buffer starts at edi+100h
add ecx, 100h
push ecx ; push the buffer
push [esi] ; filehandle
call eax ; WriteFile

; close file, we don't need the handle anymore


push 403F1Ah ; offset CloseHandle
push ebx ; kernel32.dll handle
call GetProcAddress

push [esi] ; filehandle


call eax ; CloseHandle

jmp FINISH

The FINISH stuff is the same, starting at physical offset 0x3DA0. Don't use the
virtual offset in HIEW, it will be calculated at runtime. Virtual offsets are
only needed for strings and for the jumps of the jumptable.

5. Conclusion
=============

That's it and I am burnt out. I hope you got the idea HOW to add code to an
unknown target without having the source. The "ReverseMe" is quite small so you
have to use GetProcAddress very often. In a normal application MANY functions
are already imported and ready to use. Read NNs essay how to add new menu-items
and how to handle these messages.
6. Greetings:
=============

Knotty Dread
NeuRaL NoiSE (his essay ROCKS)
douby
s^witz
all DREAD members (you know show you are)

Comments, critics, improvements go to:


andreas.theDragon@gmx.net

finished: 2000-06-01

You might also like