Thursday, March 5, 2009

學習Windbg系列:定位Kernel32.dll的方法(1)

相關知識:Windows Knowledge, PE Format, Windbg command, x86 knowledge

     先定義一下問題:如何使用Windbg or KD,藉由Windows的運作法則以及PE的格式,找出一個Process載入的Kernel32.dll的位置。更進一步的推導出Kernel32.dll所export的function。
    就拿記事本為例子吧!打開Windbg,"File->Attach To Process",挑選notepad.exe。 
    接著看存放在fs:[30]PEB data

   1: 0:001> dd fs:[30] L1
   2: 0038:00000030  7ffde000
   3: 0:001> dt _PEB 7ffde000
   4: ntdll!_PEB
   5:    +0x000 InheritedAddressSpace : 0 ''
   6:    +0x001 ReadImageFileExecOptions : 0 ''
   7:    +0x002 BeingDebugged    : 0x1 ''
   8:    +0x003 SpareBool        : 0 ''
   9:    +0x004 Mutant           : 0xffffffff 
  10:    +0x008 ImageBaseAddress : 0x01000000 
  11:    +0x00c Ldr              : 0x001a1e90 _PEB_LDR_DATA
  12:    +0x010 ProcessParameters : 0x00020000 _RTL_USER_PROCESS_PARAMETERS
  13:   ......(略)

PEB的資訊很多,這裡就只列出部分內容。為什麼要找到PEB呢?因為PEB裡面的Ldr欄位存放了一個list,這個list記載了該Process所載入的module資訊,藉此我們就可以找到Kernel32.dll

   1: 0:001> dt _PEB_LDR_DATA 0x001a1e90 
   2: ntdll!_PEB_LDR_DATA
   3:    +0x000 Length           : 0x28
   4:    +0x004 Initialized      : 0x1 ''
   5:    +0x008 SsHandle         : (null) 
   6:    +0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x1a1ec0 - 0x1a3030 ]
   7:    +0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x1a1ec8 - 0x1a3038 ]
   8:    +0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x1a1f28 - 0x1a3040 ]
   9:    +0x024 EntryInProgress  : (null)

InLoadOrderModuleList就是上面提到的List,我們來依著LIST_ENTRY裡的第一個欄位FLink尋訪一下這個list:

   1: 0:001> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x1a1ec0 
   2:    +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x1a1f18 - 0x1a1e9c ]
   3:    +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x1a1f20 - 0x1a1ea4 ]
   4:    +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   5:    +0x018 DllBase          : 0x01000000 
   6:    +0x01c EntryPoint       : 0x0100739d 
   7:    +0x020 SizeOfImage      : 0x14000
   8:    +0x024 FullDllName      : _UNICODE_STRING "C:\WINDOWS\system32\notepad.exe"
   9:    +0x02c BaseDllName      : _UNICODE_STRING "notepad.exe"
  10:    +0x034 Flags            : 0x5000
  11:    +0x038 LoadCount        : 0xffff
  12:    +0x03a TlsIndex         : 0
  13:    +0x03c HashLinks        : _LIST_ENTRY [ 0x1a1f54 - 0x7c97b2c8 ]
  14:    +0x03c SectionPointer   : 0x001a1f54 
  15:    +0x040 CheckSum         : 0x7c97b2c8
  16:    +0x044 TimeDateStamp    : 0x48025287
  17:    +0x044 LoadedImports    : 0x48025287 
  18:    +0x048 EntryPointActivationContext : (null) 
  19:    +0x04c PatchInformation : (null)

List的開頭存放的是notepad.exe本身,我們繼續往下找:

   1: 0:001> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x1a1f18 
   2:    +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x1a1fc0 - 0x1a1ec0 ]
   3:    +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x1a1fc8 - 0x1a1ec8 ]
   4:    +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x1a1fd0 - 0x1a1eac ]
   5:    +0x018 DllBase          : 0x7c900000 
   6:    +0x01c EntryPoint       : 0x7c912c28 
   7:    +0x020 SizeOfImage      : 0xaf000
   8:    +0x024 FullDllName      : _UNICODE_STRING "C:\WINDOWS\system32\ntdll.dll"
   9:    +0x02c BaseDllName      : _UNICODE_STRING "ntdll.dll"
  10:    +0x034 Flags            : 0x80084004
  11:    +0x038 LoadCount        : 0xffff
  12:    +0x03a TlsIndex         : 0
  13:    +0x03c HashLinks        : _LIST_ENTRY [ 0x7c97b2c8 - 0x1a1efc ]
  14:    +0x03c SectionPointer   : 0x7c97b2c8 
  15:    +0x040 CheckSum         : 0x1a1efc
  16:    +0x044 TimeDateStamp    : 0x4802a12c
  17:    +0x044 LoadedImports    : 0x4802a12c 
  18:    +0x048 EntryPointActivationContext : (null) 
  19:    +0x04c PatchInformation : (null) 
  20: 0:001> dt ntdll!_LDR_DATA_TABLE_ENTRY 0x1a1fc0 
  21:    +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x1a2068 - 0x1a1f18 ]
  22:    +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x1a2070 - 0x1a1f20 ]
  23:    +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x1a2260 - 0x1a1f28 ]
  24:    +0x018 DllBase          : 0x7c800000 
  25:    +0x01c EntryPoint       : 0x7c80b63e 
  26:    +0x020 SizeOfImage      : 0xf6000
  27:    +0x024 FullDllName      : _UNICODE_STRING "C:\WINDOWS\system32\kernel32.dll"
  28:    +0x02c BaseDllName      : _UNICODE_STRING "kernel32.dll"
  29:    +0x034 Flags            : 0x80084004
  30:    +0x038 LoadCount        : 0xffff
  31:    +0x03a TlsIndex         : 0
  32:    +0x03c HashLinks        : _LIST_ENTRY [ 0x7c97b2b0 - 0x7c97b2b0 ]
  33:    +0x03c SectionPointer   : 0x7c97b2b0 
  34:    +0x040 CheckSum         : 0x7c97b2b0
  35:    +0x044 TimeDateStamp    : 0x4802a12c
  36:    +0x044 LoadedImports    : 0x4802a12c 
  37:    +0x048 EntryPointActivationContext : (null) 
  38:    +0x04c PatchInformation : (null) 

    賓果!,kernel32.dll的base address是0x7c800000。可不可以請Windbg幫我們自動地解析出list上面module的資訊?可以的,請使用!list這個指令,其格式是:
            !list -t FLink的欄位 -x "要執行的指令" -a "給指令的參數" -e 起始Flink的位置
   下面這個例子是自動去秀出每個module的FullDllName:

   1: 0:001> !list -t ntdll!_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink  -x "dt" -a "+0x24 _UNICODE_STRING" -e 0x1a1ec0 
   2: dt 0x1a1ec0 +0x24 _UNICODE_STRING
   3: ntdll!_UNICODE_STRING
   4:  "C:\WINDOWS\system32\notepad.exe"
   5:    +0x000 Length           : 0x3e
   6:    +0x002 MaximumLength    : 0x40
   7:    +0x004 Buffer           : 0x00020728  "C:\WINDOWS\system32\notepad.exe"
   8:  
   9: dt 0x1a1f18 +0x24 _UNICODE_STRING
  10: ntdll!_UNICODE_STRING
  11:  "C:\WINDOWS\system32\ntdll.dll"
  12:    +0x000 Length           : 0x3a
  13:    +0x002 MaximumLength    : 0x208
  14:    +0x004 Buffer           : 0x7c97d028  "C:\WINDOWS\system32\ntdll.dll"
  15:  
  16: dt 0x1a1fc0 +0x24 _UNICODE_STRING
  17: ntdll!_UNICODE_STRING
  18:  "C:\WINDOWS\system32\kernel32.dll"
  19:    +0x000 Length           : 0x40
  20:    +0x002 MaximumLength    : 0x42
  21:    +0x004 Buffer           : 0x001a1f70  "C:\WINDOWS\system32\kernel32.dll"
  22:  
  23: dt 0x1a2068 +0x24 _UNICODE_STRING
  24: ntdll!_UNICODE_STRING
  25:  "C:\WINDOWS\system32\comdlg32.dll"
  26:    +0x000 Length           : 0x40
  27:    +0x002 MaximumLength    : 0x42
  28:    +0x004 Buffer           : 0x001a2018  "C:\WINDOWS\system32\comdlg32.dll"
  29:  
  30: dt 0x1a2110 +0x24 _UNICODE_STRING
  31: ntdll!_UNICODE_STRING
  32:  "C:\WINDOWS\system32\ADVAPI32.dll"
  33:    +0x000 Length           : 0x40
  34:    +0x002 MaximumLength    : 0x42
  35:    +0x004 Buffer           : 0x001a20c0  "C:\WINDOWS\system32\ADVAPI32.dll"
  36:    ......(略)

上面囉嗦了一串,其實我們大可以使用!peb這個指令,可以輕易的得出kernel32.dll的起始位置,但是辛苦的果實比較甜美,不是嗎

   1: 0:001> !peb
   2: PEB at 7ffde000
   3:     InheritedAddressSpace:    No
   4:     ReadImageFileExecOptions: No
   5:     BeingDebugged:            Yes
   6:     ImageBaseAddress:         01000000
   7:     Ldr                       001a1e90
   8:     Ldr.Initialized:          Yes
   9:     Ldr.InInitializationOrderModuleList: 001a1f28 . 001a3040
  10:     Ldr.InLoadOrderModuleList:           001a1ec0 . 001a3030
  11:     Ldr.InMemoryOrderModuleList:         001a1ec8 . 001a3038
  12:             Base TimeStamp                     Module
  13:          1000000 48025287 Apr 14 02:35:51 2008 C:\WINDOWS\system32\notepad.exe
  14:         7c900000 4802a12c Apr 14 08:11:24 2008 C:\WINDOWS\system32\ntdll.dll
  15:         7c800000 4802a12c Apr 14 08:11:24 2008 C:\WINDOWS\system32\kernel32.dll
  16:         763b0000 4802a0c9 Apr 14 08:09:45 2008 C:\WINDOWS\system32\comdlg32.dll
  17:      ......(略)

    找到起始位置之後,就要來計算kernel32.dll有那些可以使用的function摟。上次我們介紹了幫助解析PE檔頭的!dh,這次改用比較苦工的方式,先以+0x3C、+0x78這兩個offset找到Export table的RVA(或者也可以用!dh得知),然後再以+0x20的offset得到function name table 的RVA :

   1: 0:001> dd 7c800000+0x3c L1
   2: 7c80003c  000000f0
   3: 0:001> dd 7c800000+000000f0+0x78 L1 
   4: 7c800168  0000262c
   5: 0:001> dd 7c800000+0000262c+0x20 L1
   6: 7c80264c  00003538
   7: 0:001> dd 7c800000+00003538
   8: 7c803538  00004b9b 00004baa 00004bb3 00004bbc
   9: 7c803548  00004bcd 00004bde 00004bfd 00004c1c
  10: 7c803558  00004c29 00004c45 00004c52 00004c6c
  11: 7c803568  00004c7c 00004c95 00004ca3 00004cae
  12: 7c803578  00004cb9 00004cc5 00004cdd 00004cf7
  13: 7c803588  00004d18 00004d2f 00004d47 00004d5e
  14: 7c803598  00004d7c 00004d96 00004daa 00004dc3
  15: 7c8035a8  00004de2 00004de7 00004dfc 00004e11
  16: 0:001> da 7c800000+00004b9b 
  17: 7c804b9b  "ActivateActCtx"
  18: 0:001> da 7c800000+00004baa 
  19: 7c804baa  "AddAtomA"
  20: 0:001> da 7c800000+00004bb3 
  21: 7c804bb3  "AddAtomW"
  22: 0:001> da 7c800000+00004bbc
  23: 7c804bbc  "AddConsoleAliasA"

   至於function的address呢?可以用類似的方式得知,相關offset請參考PE 格式。本篇內容可以由程式來實作,是一個相當經典的技巧,網路上可以找到一海票範例。ShellCode尤其喜愛使用(待續)

No comments: