Wednesday, October 22, 2014

WinDbg and PE II

Import Address Table (IAT)

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.
So the flow is like this: The function name is fetched using Export Names Table and the corresponding entry in the Export Ordinals Table is looked up to get the index or offset. This index is used to parse the Export Address Table and fetch the Function address.
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