W32Dasm Disassembled
Part4:
A Quick little Byte Editor by Harlequin December 2000
|
|
|
About Quick Edit |
Ever get one of those sillly little programs which require only a
simple mov al,01 or changing a je to jne etc. You have to fire up
your hex editor find the location, change the bytes, save it, search
the file on disk and run it. Well Quick edit makes this process
somewhat easier.
It is very simple to use.
Enter the RVA of the bytes you wish to edit as shown in the W32Dasm
Deadlisting. You must enter leading zeros so that the value is 8
digits long.
Clicking 'GoTo' will then open the file and display the bytes at this address.
You should note that if a file Pfilename exists Quick edit will open
this instead of the filename. This does mean that the bytes may not
be the same as those in your W32Dasm listing but does mean that you
can add to already existing patches. If the file Pfilename does not
exist then Quick Edit opens the actual program (filename).
The two edit boxes are then updated with the bytes found at the RVA
in the file. The top edit box is read only and will not change. This
is here simply in case you make a mistake in your editing, you can
then see what the original bytes were.
The lower editbox is where you make your changes. Note that you can
only change bytes, you should not add them, if you do they will be
written and the file will be corrupt.
When the bytes are loaded the 'Run' button becomes enabled. Clicking
this will run the program as it is, unedited!
Clicking the 'Save' button saves your changes into the file Pfilename.
Once you have clicked the 'Save' button the 'Run' button will now run
the modified file Pfilename not the original.
You can make several changes at a time by simply changing the RVA and
pressing 'GoTo' again. Note that the file is loaded each time you do
this so if you make a change then click the GoTo button again with
the same address the displayed original bytes will be updated with
your changed bytes.
As I said it's pretty simple really.
Have fun
Introduction |
This series is not intended to increase in difficulty rather it is
just a reflection of my ideas and their implementation as and when I
execute them. This essay is pretty simple, the 'Quick Edit' code I
wrote separately and most of it was just a case of copy and paste
from the W32Patch Part1 code. I created the dialog box in BRW, I
tested it using another little program I wrote for this purpose. It
was very simple and was written as a tool for my own use, however if
I find it useful there is always the chance someone else might so
here it is :-)
I wanted this Part to be completely independent of the previous
Parts. So to do this I thought I would keep well away from any of the
code we created in Parts1-3. In order to keep away from previous code
I considered it was better to replace an existing function rather
than create a brand new one. I decided to replace the useless and
ugly About box function. Implementing the whole thing was also very
simple and quick so in order to (have something to write ;-)
demonstrate something different I made it all more complicated for myself.
I decided to use an approach I learned from an excellent essay by Extasy, a method of implementing your dll and functions without having the LoadLibrary or GetProcAddress API's to lean on.
Preliminaries |
I am using W32Dasm v8.93 currently and have been since I started
reversing so all references in this essay will be to this version.
Before starting I made a copy of W32Dasm called Target which is the
file on which I will be working and making changes, as I will be
using W32dasm in the making of many of the changes I will refer to
the new W32Dasm as Target and W32Dasm as itself.
So first of all you should disassemble Target.exe using W32Dasm and
save the deadlisting.
The Essay |
Objectives:
Add our own DLL and Procedure to the import table
#1
To my knowledge there are only four ways to achieve our objective #1 it is always useful to have all these at our disposal though as often one way may not be possible within a specific target. The other three ways are:
Load the DLL and procedure using the LoadLibrary and GetProcAddress which already are made available by the target program. This is the method I used in parts 1-3 of W32Dasm Disassembled.
Use the snippet of code provided by NeuRaL_NoiSE in his Hnotepad essay pack. This snippet was created by Jack Qwerty of the virus group (29A). It is basically a replacement for the LoadLibrary and GetProcAddress functions. Compiled it produces a very small procedure which can be pasted into your target. This procedure accepts the DLL name and Procedure name as parameters the opens and searches the DLL retrieving a handle to the Procedure. Ingenious! There are some very clever people about.Where there is a problem there is always somebody capable of a solution, such is the nature of the human race.
Extasy's method. This adds our dll name and function name to the import names list then prepends the relevant addresses to the import directory and subtracts the number of bytes added from the import table address.
Unfortunately Extasy's method does not work with every target and as
you may have guessed it doesn't work with target.exe. This is because
the import directory in target.exe begins at the .idata section
boundary. If we prepend data to the import directory we are then
placing this data in the .INIT section. This is obviously not
favorable, I tried this method and then shrinking the .INIT section
and expanding the .idata section etc etc but I could not get it to work.
My next thought was to append the info to the import directory but as
you can see there is no space for this in target.exe. So next I tried
inserting the number of bytes needed (14h) into .idata and deleting
the same number of bytes from the end of .idata. As the array tables
are in the same section I had to adjust all the RVA's by 14h. This
didn't work either, although I am not sure why, I may spend more time
on this one day.
So next I thought, if I cannot get data before the directory and I cannot get data after the directory why not just move the whole directory to a place where I can?
Here goes.........................
The first thing we need is the address of the import table, this you
can find manually by reading through the PE header should you so
desire but with so many tools which will do it for us why bother, I
used procdump. You should know how to find it manually though, and
indeed you should read a few of the many PE header descriptions
available until you are familiar with PE files. This sort of stuff
becomes a lot easier when you know what is going on.
In target.exe we find the Import table at RVA 4D4000. Now as we are
going to be using a lot of RVA values and converting them to file
offsets I would suggest using one of the excellent tools for doing
this, check out protools.
So if we convert the RVA to an offset we get D1C00h the beginning of
the import table.
The import directory layout has the following format:
typedef struct tagImportDirectory
{
DWORD dwRVAFunctionNameList; --- 004D408Ch
DWORD dwUseless1;
DWORD dwUseless2;
DWORD dwRVAModuleName; --- 004D2000h
DWORD dwRVAFunctionAddressList; --- 004D45E4h
}IMAGE_IMPORT_MODULE_DIRECTORY,
* PIMAGE_IMPORT_MODULE_DIRECTORY;
The values shown in yellow are the RVA's for the first DLL (Kernel32)
in target.exe. This format is then repeated for each dll included in
the application.
The table is terminated with a complete entry (5 DWORDS) all of
'00000000' bytes.
So our table begins at offset D1C00h and ends at D1C8Bh a total of
140 bytes, lets move it. I use Uedit32 for this, selecting all 140
bytes, copy, then at offset D1B00h paste. This of course adds 140
bytes to your file so place the cursor at D1B00h then menu -
Edit\Hex\ insert/delete
Select delete, set to 140 and click ok, and there they are gone.
Now if we want to make this our new import directory we need to
change the pointer to it in the PE header you can use procdump or
something if you like, I prefer to do it manually. We find the import
directory address at offset 180h.
As we are crossing section boundaries we cannot just subtract
100bytes from this value, it is easier to use your offset calculator
to convert offset D1B00h to RVA 4D3700h, insert this value at 180h
and we are ready.
So we want to add our DLL name to the list. It is probably not
a good idea to add the name to the beginning of the names list as
this list starts at offset D0400h. As this is a nice round number it
could well be a section boundary, I don't know I didn't check.
Instead I decide to place my dll name in the nice little bit of space
preceding the import table and just after the existing procedure list.
So at offset D1A90h edit in our dll name W32Patch.dll.
Now the directory structure uses five DWORDS for each dll so ours
will start at offset D1B78h and the pointer to our dll name will be
the fourth Dword at offset D1B84h. So edit in the RVA to our new dll
name 90360D00h and we have a pointer to our dll. Note we do not add
the image address (400000h) this is added at runtime. Next we need to
point to our procedure.
The remaining two addresses in the directory don't actually point to
our procedure name they point to two arrays of addresses, each of
which points to the procedure name. So we not only need to insert out
name we also have to create these arrays. The two arrays are
identical on disk and you might think to cut corners and make only
one array for your new functions. Don't do this! the first array will
always remain as you see it on disk, this serves as a reference
during runtime should a problem occur with the loaded data. The
second array becomes the loaded data. When the program loads, the
RVA's in this array are replaced with VA's to the actual procedure
list. This information is then placed in the data section of your
program so the procedures can be accessed.
Firstly lets enter our procedure name 'ByteEd'. Remember that your
dll name must terminate with a '00' byte as per a normal string, you
should also know that each procedure name is proceeded by two '00'
bytes. This I believe is where the procedure ordinal value is stored
at runtime, although I am not sure. It is important to include them
though and you should also note that these two preceding bytes are
the start of the procedure name as far as addressing is concerned,
they are not just surplus. So we leave three bytes at the end of our
dll name and insert our procedure name at offset D1A9Fh.
Now to create the arrays to point to the name. Leaving two '00' bytes
at the end of the name insert our procedure RVA 000D369Dh (including
the two '00' bytes remember) reversed (9D360D00h) at offset D1AA8h (I
start them here because it is neater and often better to start on a
Dword boundary where possible). This is our first array. The
application knows it has reached the end of an array when it
encounters a zero value, so to terminate this array we must leave a
'00000000' Dword before starting array 2 at offset D1AB0h. This of
course is the same value as array 1.
Good we are done now we have to update the import directory to point
to these arrays.
So the first DWORD of our directory entries at offset D1B78h becomes
A8360D00h to point to the RVA of our array1. The fifth DWORD at
offset D1B88h becomes B0360D00h to point to the RVA of our array2.
That is all there is to it we have added our dll and function to the
import table.
Our final table should look like this:
000d1a90h: 57 33 32 50 61 74 63 68 2E 64 6C 6C 00 00 00 42 ; W32Patch.dll...B 000d1aa0h: 79 74 65 45 64 00 00 00 9D 36 0D 00 00 00 00 00 ; yteEd...6...... 000d1ab0h: 9D 36 0D 00 00 00 00 00 00 00 00 00 00 00 00 00 ; 6.............. ......... 000d1b70h: 3C 20 0D 00 2C 4B 0D 00 A8 36 0D 00 00 00 00 00 ; 000d1b80h: 00 00 00 00 90 36 0D 00 B0 36 0D 00 00 00 00 00 ;
To call this new procedure from within the target.exe you simply call the address of the variable in array2 which points to its name. So for our procedure we would use:
Call dword ptr [004D36B0]
So lets make use of our new procedure and insert Quick Edit into target.exe.
#2
Open target in Resource Hacker and change the menu item 'About' to
'Quick Edit' then save it.
Now we need to locate the about box function. In your deadlisting use
the dialog references to bring you here:
:0045258B 55 push ebp
:0045258C 8BEC mov ebp, esp
:0045258E 81C430FFFFFF add esp, FFFFFF30
:00452594 53 push ebx
:00452595 8B5D08 mov ebx, dword ptr [ebp+08]
:00452598 B81C134B00 mov eax, 004B131C
:0045259D E866580500 call 004A7E08
:004525A2 66C78540FFFFFF0800 mov word ptr [ebp+FFFFFF40], 0008
:004525AB 6A00 push 00000000
:004525AD 83C4FC add esp, FFFFFFFC
* Possible Reference to Dialog: DialogID_55F0
|
:004525B0 C70424F0550000 mov dword ptr [esp], 000055F0
:004525B7 8B5333 mov edx, dword ptr [ebx+33]
W32Dasm gives us no idea how we came here but who cares this is our function lets patch :-)
The first thing we need to do is to find a memory address with the current filename and file directory as these will be passed as parameters to Quick Edit. To do this I ran W32Dasm, opened target.exe, loaded it, put a breakpoint on 0045458Bh and loaded a file into target.exe. I then clicked the About menu item and we break. Now I had an advantage here as I didn't have to search for the filename in memory, I recognized the base address from part1 stored in EDI. So I checked my part1 essay and added the required values to the base address and bingo, sure enough there were the filename and directory name I was looking for. So armed with all I need lets go, in W32Dasm's Patch window I enter the following:
:0045258B 60 pushad --- Save all registers as normal
:0045258C 81C14F066400 add ecx, 0064064F --- Base address already in ecx, Lucky eh?
:00452592 51 push ecx --- Push pointer to filename
:00452593 89F9 mov ecx, edi --- Base address into ecx again
:00452595 81C131016F00 add ecx, 006F0131 --- Directory string
:0045259B 51 push ecx --- Push it
:0045259C FF15B0364D00 call dword ptr [004D36B0] --- Call our function
:004525A2 61 popad --- Reset registers
:004525A3 C3 ret --- Break out the beer
and that is all there is to it we now have our Quick Edit function.
In Conclusion |
As you can see this procedure was very very simple, all you really need is an understanding of the PE file structure. It shows that there are usually several options to achieve our objective and if your first line of attack does not work on a target don't give up, get imaginative, there is invariably an alternative.
This little adaption functions completely independent of any of the previous parts of the W32Dasm disassembled essays. It will also not effect any other patches, such as dreads VB string patch. You do get my little bitmap in the patch though, you can allow me that surely ;-)
Final Notes |
Don't even know if anybody is reading any of these essays? Some
feedback would be nice! I shall stop writing them if they are of no
use to anyone :-(
Mail me at: Mail @ Harlequin00 . cjb . net
Thanks go to: +Tsehp for posting my essays.
Everybody out there writing essays! I wouldn't be
here without them. Peter Urbanik for such a great tool
|
Essay
by: Harlequin
Page
Created: 20th December 2000