It consists of the mapping between the absolute virtual address and the function names which are exported from different loaded modules. As we saw in the last post, there are various DLLs which are loaded along with notepad.exe. IAT gives us a list of function names which are imported from these loaded modules. Let's examine ITA:
0:000> dps 00681000 L348/4
00681000 77251456 ADVAPI32!RegSetValueExWStub
00681004 7725462d ADVAPI32!RegQueryValueExWStub
00681008 7725461d ADVAPI32!RegCloseKeyStub
0068100c 77251494 ADVAPI32!RegCreateKeyW
00681010 7725460d ADVAPI32!RegOpenKeyExWStub
00681014 7725440e ADVAPI32!IsTextUnicode
00681018 7725361c ADVAPI32!CloseServiceHandleStub
0068101c 7724b4d7 ADVAPI32!QueryServiceConfigWStub
00681020 7724c9ec ADVAPI32!OpenServiceWStub
00681024 7724ca04 ADVAPI32!OpenSCManagerWStub
00681028 00000000
0068102c 76d75696 kernel32!FindNLSStringStub
00681030 76d5a235 kernel32!GlobalAllocStub
...
00681330 770d2804 msvcrt!__set_app_type
00681334 00000000
00681338 7731ad24 COMDLG32!ReplaceTextW
0068133c 772f2694 COMDLG32!PageSetupDlgW
00681340 772f4b96 COMDLG32!PrintDlgExW
00681344 7731acf0 COMDLG32!FindTextW
It is good to know how to fetch an IAT of a PE image because we can use this output to detect any sort of IAT hooks. IAT hooking is a technique used by rootkits to take control of the functions in a DLL by overwriting the function pointers in the IAT.
Discussion:
How did the IAT get filled up with these values at run time?
When the OS loader starts the PE, it will fill the IAT with function pointers to the imported functions from various loaded modules. We will try to find out how it got to know these function pointers.
Export Directory
PE image imports the functions from (<-) kernel32.dll
kernel32.dll exports the functions to (->) our PE image.
Each loaded module will have its own Export Directory:
0:000> dt IMAGE_EXPORT_DIRECTORY
ole32!IMAGE_EXPORT_DIRECTORY
+0x000 Characteristics : Uint4B
+0x004 TimeDateStamp : Uint4B
+0x008 MajorVersion : Uint2B
+0x00a MinorVersion : Uint2B
+0x00c Name : Uint4B
+0x010 Base : Uint4B
+0x014 NumberOfFunctions : Uint4B
+0x018 NumberOfNames : Uint4B
+0x01c AddressOfFunctions : Uint4B
+0x020 AddressOfNames : Uint4B
+0x024 AddressOfNameOrdinals : Uint4B
- AddressOfFunctions: an array of RVAs of the functions in the module
- AddressOfNames: an array of RVAs each corresponding to the function name strings of exported functions.
- AddressOfNameOrdinals: This array is in sync with the AddressOfNames array and there is a one to one correspondence between the two. It gives an index or an offset into the AddressOfFunctions array to get the Address of the Function Name.
Export Names Table -> Export Ordinal Table -> Export Address Table (Function Address, VA)
This should make it clear how the OS loader gets to know the addresses of Functions which are imported by the main module from these loaded modules.
Now, we want to view all the functions exported by the GDI32.dll module. We need to first view its the data directory:
0:000> !dh gdi32 -f
File Type: DLL
FILE HEADER VALUES
14C machine (i386)
4 number of sections
53F7F199 time date stamp Fri Aug 22 18:42:49 2014
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
2102 characteristics
Executable
32 bit word machine
DLL
OPTIONAL HEADER VALUES
10B magic #
9.00 linker version
47800 size of code
3000 size of initialized data
0 size of uninitialized data
9C09 address of entry point
1000 base of code
----- new -----
75c10000 image base
1000 section alignment
200 file alignment
3 subsystem (Windows CUI)
6.01 operating system version
6.01 image version
6.01 subsystem version
4E000 size of image
400 size of headers
4AE2C checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
140 DLL characteristics
Dynamic base
NX compatible
1240 [ 4B88] address [size] of Export Directory
4798C [ 8C] address [size] of Import Directory
4B000 [ 3D8] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
4C000 [ 1984] address [size] of Base Relocation Directory
4871C [ 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
2B420 [ 40] address [size] of Load Configuration Directory
278 [ B8] address [size] of Bound Import Directory
1000 [ 240] 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
So, the offset of the Export Directory is 1240 relative to the Image Base Address. Let's view it:
0:000> dt IMAGE_EXPORT_DIRECTORY 75c10000+1240
ole32!IMAGE_EXPORT_DIRECTORY
+0x000 Characteristics : 0
+0x004 TimeDateStamp : 0x53f7e330
+0x008 MajorVersion : 0
+0x00a MinorVersion : 0
+0x00c Name : 0x2e86
+0x010 Base : 0x3e8
+0x014 NumberOfFunctions : 0x2d7
+0x018 NumberOfNames : 0x2cb
+0x01c AddressOfFunctions : 0x1268
+0x020 AddressOfNames : 0x1dc4
+0x024 AddressOfNameOrdinals : 0x28f0
You know how to find the image base address (75c10000) of gdi32.dll in the virtual address space of notepad.exe right?
Let's check addresses of names first:
0:000> dd 75c10000+1dc4
75c11dc4 00002e90 00002e99 00002ea3 00002eb8
75c11dd4 00002ec9 00002edc 00002eef 00002f07
75c11de4 00002f18 00002f21 00002f30 00002f3f
So, we got a list of RVAs now. Each of them when added to the base address of gdi32.dll will point to the Function Name string. Let's check by taking the first two RVA from the list:
0:000> da gdi32+00002e90
75c12e90 "AbortDoc"
0:000> da gdi32+00002e99
75c12e99 "AbortPath"
The NumberOfNames filed in the IMAGE_EXPORT_DIRECTORY had a value of 0x2cb, which means there are so many function names exported by gdi32.dll. We can use:
x gdi32!*
to list all exported symbols.
No comments:
Post a Comment