WinDbg : Trying To Find The Export Address Table (EAT) Of A Binary
In the last article we learnt how to use the basic WinDbg commands we had learnt, to find out useful information within the loaded binary images. That article taught us how to parse the import address table (IAT) of a loaded binary. We will extend that study here, to try and learn one can parse the export address table (EAT) of a loaded binary image.
Commands used in this article are:
Before we begin, a brief introduction about the EAT is desirable. The EAT works in the same way as the IAT, apart from the fact that the library will be exporting the functions to the image executable, in which the program will import into the IAT. The key data structure that is used by Windows to map the EAT is _IMAGE_EXPORT_DIRECTORY. Now, we know from our previous learning that to see the types created by us, we can use the dt command. A quick recall of that exercise can be found here. Unfortunately, WinDbg(atleast the current version) cannot find this type! So we need to calculate the offsets manually. the structure is defined in the header file WinNt.H. I am copying the same here for convenience.
//
// Export Format
//
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
The AddressOfFunctions is the field we are interested in. the comment says that the array contains Relative virtual Addresses (RVAs) from the base of the image. It is the the PE loaders responsibility to translate these to real addresses for the binary using it in the IAT.
The AddressOfNames and AddressOfNameOrdinals are loaded alongside each other, to provide a linkage between the address of the function and the name of the function. The AddressOfNames is a pointer to a array of function names, and the AddressOfNameOrdinals is a pointer to a array used to index into the AddressOfFunctions to obtain the addresses for the function names. Now, lets try to use this knowledge to see if we can actually find the names of the functions which a particular binary exports. Not all binaries will necessarily export, in such cases the number of entries in the EAT will be zero.
kd> !dh lsass.exe -f
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
4 number of sections
4A5BBF3E time date stamp Tue Jul 14 04:41:58 2009
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
122 characteristics
Executable
App can handle >2gb addresses
32 bit word machine
OPTIONAL HEADER VALUES
10B magic #
9.00 linker version
4200 size of code
1000 size of initialized data
0 size of uninitialized data
2F3D address of entry point
1000 base of code
----- new -----
00d90000 image base
1000 section alignment
200 file alignment
2 subsystem (Windows GUI)
6.01 operating system version
6.01 image version
6.01 subsystem version
9000 size of image
600 size of headers
6193 checksum
00040000 size of stack reserve
00006000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
8140 DLL characteristics
Dynamic base
NX compatible
Terminal server aware
1EC4 [ 6B] address [size] of Export Directory
4478 [ 154] address [size] of Import Directory
7000 [ 700] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
8000 [ 368] address [size] of Base Relocation Directory
5080 [ 38] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
3F90 [ 40] address [size] of Load Configuration Directory
280 [ 294] address [size] of Bound Import Directory
1000 [ 1AC] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
Ok, now lets dump the contents at the offset of 0x1EC4 to see what they contain.
kd> dd 1EC4+lsass
00d91ec4 00000000 4a5bbf3e 00000000 00001f00
00d91ed4 00000001 00000002 00000002 00001eec
00d91ee4 00001ef4 00001efc 00002ef6 000023c9
00d91ef4 00001f0a 00001f1a 00010000 7361736c
00d91f04 78652e73 734c0065 74654761 65746e49
00d91f14 63616672 734c0065 67655261 65747369
00d91f24 74784572 69736e65 90006e6f 90909090
00d91f34 8b55ff8b 565351ec 57ff3357 00008a68
This is the _IMAGE_EXPORT_DIRECTORY structure. The three highlighted fields are the following:
00001f00 : Name
00001ef4 : AddressOfFunctions
00001efc : AddressOfNames
00002ef6 : AddressOfNameOrdinals
To verify whether we have indeed the right offsets, lets dump out the contents of the 'Name' to see if it is indeed lsass.exe.
kd> da 00001f00+lsass
00d91f00 "lsass.exe"
Looks like we did get he right members. Then lets use the other addresses to find the names of all the functions exported. Lets use the dd command to dump the addresses first.
kd> dd 00001ef4+lsass
00d91ef4 00001f0a 00001f1a 00010000 7361736c
00d91f04 78652e73 734c0065 74654761 65746e49
00d91f14 63616672 734c0065 67655261 65747369
00d91f24 74784572 69736e65 90006e6f 90909090
00d91f34 8b55ff8b 565351ec 57ff3357 00008a68
00d91f44 20206800 7fe800d9 33000009 ff5343db
00d91f54 d910fc15 41186800 15ff00d9 00d910f8
00d91f64 ff535753 d9108415 0cc48300 458d046a
Now we can use the da command to dump the name of each function that is exported. it is a manual process to walk the arrays or we can write scripts for it. Scripts are a slightly advanced topic, which will be covered in future posts, we can revisit the problem at that time.
kd> da 00001f0a+lsass
00d91f0a "LsaGetInterface"
Your RVA locations are off by 4; the actual offsets in your case are:
ReplyDelete00001f00 : Name
00001eec : AddressOfFunctions
00001ef4 : AddressOfNames
00001efc : AddressOfNameOrdinals
That's why using 0x1ef4 you get to a function name, not function body.
An easy way to check your work is to use !dh -e
ReplyDelete