0x01 綁定導入表概念程序員
綁定導入表(The Bound Import Directory)。它包含了可讓加載器判斷綁定的地址是否合法的信息。描述它的數據結構是IMAGE_BOUND_IMPORT_DESCRIPTOR,目錄表就是這種結構的數組,每一項都對應一個被綁定過的DLL。windows
每當PE裝載器裝入PE文件時,檢查導入表並將相關DLL映射到進程空間地址。而後經過遍歷IAT裏的IMAGE_THUNK_DATA數組並用導入函數的真實地址替換它,這一步須要不少時間。若是程序員事先能正確預測函數地址,PE裝載器就不用每次裝入PE文件時都去修正IMAGE_THUNK_DATA值了,綁定導入就是這種思想的產物。api
當一個可執行文件被綁定(例如經過綁定程序Visual Studio的Bind.exe)時,IAT中的IMAGE_THUNK_DATA結構被導入函數的實際地址改寫了。磁盤中的可執行文件,他們的IAT裏有的存放的是相關DLL導出函數的實際內存地址。這樣可使應用程序更快的進程初始化,而且使用較少的存儲器。數組
在執行整個進程期間,bind程序作了兩個重要假設:數據結構
©當進程初始化時,須要的DLL實際加載到了它們的首選基地址中。函數
©自從綁定操做執行以來,DLL導出表中引用的符號位置一直沒有改變。工具
固然,若是上面的兩個假設中有一個是假的,IAT中全部地址均是無效的,加載器會檢查這種狀況並作出相應反應,加載器從INT表裏得到所須要的信息來解決導入API的地址問題。對於一個可執行文件的裝入,INT是不須要的。可是,若是沒有,可執行文件是不能被綁定的。微軟的連接器彷佛老是生成一個INT,可是在很長一段時間裏,Borland 的連接器(TLINK)沒有這樣作, 由Borland生成的文件是不能被綁定的。spa
因爲不知用戶運行的是Windows 2000仍是Windows XP,沒法將系統DLL綁定起來,所以程序安裝時是綁定程序的最佳時機。Windows 安裝器的BindImage將作這些工做。另外,IMAGEHLP.DLL提供了BindImageEx函數。無論用什麼方式,綁定都是一個好主意。若是加載器肯定綁定信息是當前的,可執行文件的裝入會更快,若是綁定信息已經變得陳舊了,也不會影響程序的運行。code
對於加載器來講,使綁定變得有效的一個關鍵步驟是肯定在IAT表中的綁定信息是不是當前的。當一個可執行文件被綁定時,被參考的DLL信息放入了文件中,加載器檢查這些信息來作一個快速的綁定有效性驗證。blog
數據目錄表( DataDirectory )的第11個成員指向綁定輸入。綁定輸入以一個IMAGE_BOUND_IMPORT_DESCRIPTOR結構的數組開始,一個綁定可執行文件包含一系列這樣的結構,每一個IBID結構都指出了一個已經被綁定輸入DLL的時間/日期戳。IBID 的結構以下:
typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { DWORD TimeDateStamp; WORD OffsetModuleName; WORD NumberOfModuleForwarderRefs; } IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
TimeDateStamp。包含一個被導入的DLL的時間/日期戳;容許加載器快速斷定綁定是否是新的。這個成員必須和要引用的DLL的文件頭信息相吻合,不然就會加載器去手動計算新IAT,這種狀況通常發生在DLL版本不一樣時或者DLL映像被重定位時。
OffsetModuleName。包含了以第一個IMAGE_BOUND_IMPORT_DESCRIPTOR爲基址,DLL名稱字符串(ASCII且以null結束)的偏移(非RVA)。
NumberOfModuleForwarderRefs。是緊接着本結構後的另外一個IMAGE_BOUND_FORWARDER_REF結構數組的元素個數。
typedef struct _IMAGE_BOUND_FORWARDER_REF { DWORD TimeDateStamp; WORD OffsetModuleName; WORD Reserved; } IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;
這個結構數組幹什麼用的?注意到Forwarder這個詞,咱們在導出表中的函數的轉發,就是一個函數本身不實現而是把調用請求轉發給另外一個DLL中的函數。這裏的IMAGE_BOUND_FORWARDER_REF結構就是用來記錄接受轉發的另外一個DLL的校驗信息,若是這個DLL還有導出轉發,那麼在該DLL中也有IMAGE_BOUND_FORWARDER_REF結構描述第三個DLL的校驗信息。
當綁定一個API被轉發到另外一個DLL時,被轉發到的DLL的有效性也要被檢查。這樣,IMAGE_BOUND_FORWARDER_REF和IMAGE_BOUND_IMPORT_DESCRIPTOR結構是交叉存取的。例如連接到HeapAlloc,它被轉向到NTDLL中的RtlAllocateHeap,而後對可執行文件運行BIND。在EXE裏,已經有一個針對KERNEL32.DLL 的IBID, 它後面跟着一個針對NTDLL.DLL 的IMAGE_BOUND_FORWARDER_REF。緊跟在後面多是另外的你輸入並綁定的針對其餘DLL的IBID。Windows目錄裏的應用程序就是典型的綁定輸入結構程序,其IAT已指向相關DLL的函數。
爲了方便實現,Microsoft 的一些編譯器( 如Visual Studio)都提供了bind.exe 這樣的工具,由它檢查PE文件的導入表,並用導入函數的真實地址替換IAT裏的IMAGE_THUNK_DATA值。當文件裝入時,PE裝載器一定檢查地址的有效性。若是DLL版本不一樣於PE文件存放的相關信息,或DLE須要重定位那麼裝載器認爲原先計算的地址是無效的,它一定遍歷OriginalFirstThunk 指向的數組以獲取輸入函數新地址,產生一個新的IAT,綁定輸入表去除是不會影響程序正常運行的,去除方法是將圖10.19中的綁定數據清零,而後再將目錄表中的Bound import的RVA與大小清零便可。
總結:
此數據項兩個做用:
一、根據TimeDateStamp和OffsetModuleName字段的值咱們就能夠判斷IAT表中的信息是否已通過期。
二、解決DLL轉發問題
0x02 綁定導入表分析
以win7x86 下記事本程序爲例:
*** wait with pending attach Symbol search path is: srv* Executable search path is: ModLoad: 00120000 00150000 C:\Windows\system32\notepad.exe ModLoad: 77a10000 77b4c000 C:\Windows\SYSTEM32\ntdll.dll ModLoad: 765f0000 766c4000 C:\Windows\system32\kernel32.dll ModLoad: 75a70000 75abb000 C:\Windows\system32\KERNELBASE.dll ModLoad: 761b0000 76250000 C:\Windows\system32\ADVAPI32.dll ModLoad: 76540000 765ec000 C:\Windows\system32\msvcrt.dll ModLoad: 77ba0000 77bb9000 C:\Windows\SYSTEM32\sechost.dll ModLoad: 76d10000 76db1000 C:\Windows\system32\RPCRT4.dll ModLoad: 75fc0000 7600e000 C:\Windows\system32\GDI32.dll ModLoad: 76c00000 76cc9000 C:\Windows\system32\USER32.dll ModLoad: 77b80000 77b8a000 C:\Windows\system32\LPK.dll ModLoad: 766d0000 7676d000 C:\Windows\system32\USP10.dll ModLoad: 76770000 767eb000 C:\Windows\system32\COMDLG32.dll ModLoad: 76250000 762a7000 C:\Windows\system32\SHLWAPI.dll ModLoad: 74800000 7499e000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\COMCTL32.dll ModLoad: 76dc0000 77a0a000 C:\Windows\system32\SHELL32.dll ModLoad: 6fd90000 6fde1000 C:\Windows\system32\WINSPOOL.DRV ModLoad: 76aa0000 76bfc000 C:\Windows\system32\ole32.dll ModLoad: 76a10000 76a9f000 C:\Windows\system32\OLEAUT32.dll ModLoad: 74d70000 74d79000 C:\Windows\system32\VERSION.dll ModLoad: 77c20000 77c3f000 C:\Windows\system32\IMM32.DLL ModLoad: 767f0000 768bc000 C:\Windows\system32\MSCTF.dll ModLoad: 75920000 7592c000 C:\Windows\system32\CRYPTBASE.dll ModLoad: 74560000 745a0000 C:\Windows\system32\uxtheme.dll ModLoad: 74270000 74283000 C:\Windows\system32\dwmapi.dll (a70.f44): Break instruction exception - code 80000003 (first chance) eax=7ffdd000 ebx=00000000 ecx=00000000 edx=77aaf1d3 esi=00000000 edi=00000000 eip=77a44108 esp=0143fc94 ebp=0143fcc0 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint: 77a44108 cc int 3 0:001> dt 00120000 _IMAGE_DOS_HEADER ntdll!_IMAGE_DOS_HEADER +0x000 e_magic : 0x5a4d +0x002 e_cblp : 0x90 +0x004 e_cp : 3 +0x006 e_crlc : 0 +0x008 e_cparhdr : 4 +0x00a e_minalloc : 0 +0x00c e_maxalloc : 0xffff +0x00e e_ss : 0 +0x010 e_sp : 0xb8 +0x012 e_csum : 0 +0x014 e_ip : 0 +0x016 e_cs : 0 +0x018 e_lfarlc : 0x40 +0x01a e_ovno : 0 +0x01c e_res : [4] 0 +0x024 e_oemid : 0 +0x026 e_oeminfo : 0 +0x028 e_res2 : [10] 0 +0x03c e_lfanew : 0n224 0:001> dt 00120000+e0 _IMAGE_NT_HEADERS ntdll!_IMAGE_NT_HEADERS +0x000 Signature : 0x4550 +0x004 FileHeader : _IMAGE_FILE_HEADER +0x018 OptionalHeader : _IMAGE_OPTIONAL_HEADER 0:001> dt 1200f8 _IMAGE_OPTIONAL_HEADER ntdll!_IMAGE_OPTIONAL_HEADER +0x000 Magic : 0x10b +0x002 MajorLinkerVersion : 0x9 '' +0x003 MinorLinkerVersion : 0 '' +0x004 SizeOfCode : 0xa800 +0x008 SizeOfInitializedData : 0x22400 +0x00c SizeOfUninitializedData : 0 +0x010 AddressOfEntryPoint : 0x3689 +0x014 BaseOfCode : 0x1000 +0x018 BaseOfData : 0xc000 +0x01c ImageBase : 0x120000 +0x020 SectionAlignment : 0x1000 +0x024 FileAlignment : 0x200 +0x028 MajorOperatingSystemVersion : 6 +0x02a MinorOperatingSystemVersion : 1 +0x02c MajorImageVersion : 6 +0x02e MinorImageVersion : 1 +0x030 MajorSubsystemVersion : 6 +0x032 MinorSubsystemVersion : 1 +0x034 Win32VersionValue : 0 +0x038 SizeOfImage : 0x30000 +0x03c SizeOfHeaders : 0x400 +0x040 CheckSum : 0x39741 +0x044 Subsystem : 2 +0x046 DllCharacteristics : 0x8140 +0x048 SizeOfStackReserve : 0x40000 +0x04c SizeOfStackCommit : 0x11000 +0x050 SizeOfHeapReserve : 0x100000 +0x054 SizeOfHeapCommit : 0x1000 +0x058 LoaderFlags : 0 +0x05c NumberOfRvaAndSizes : 0x10 +0x060 DataDirectory : [16] _IMAGE_DATA_DIRECTORY 0:001> dt 0x120158+0x58 _IMAGE_DATA_DIRECTORY ntdll!_IMAGE_DATA_DIRECTORY +0x000 VirtualAddress : 0x278 +0x004 Size : 0x128 0:001> db 00120000 +0x278 l 130 00120278 7e d9 5b 4a 80 00 00 00-ad da 5b 4a 8d 00 01 00 ~.[J......[J.... 00120288 db da 5b 4a 9a 00 00 00-dd d9 5b 4a a4 00 00 00 ..[J......[J.... 00120298 2f db 5b 4a ae 00 00 00-6f da 5b 4a b9 00 00 00 /.[J....o.[J.... 001202a8 25 da 5b 4a c4 00 00 00-01 db 5b 4a d1 00 00 00 %.[J......[J.... 001202b8 4b db 5b 4a dd 00 00 00-c7 da 5b 4a ea 00 00 00 K.[J......[J.... 001202c8 05 db 5b 4a f4 00 00 00-76 d9 5b 4a 00 01 00 00 ..[J....v.[J.... 001202d8 ca da 5b 4a 0d 01 00 00-db da 5b 4a 9a 00 00 00 ..[J......[J.... 001202e8 2b db 5b 4a 1a 01 00 00-00 00 00 00 00 00 00 00 +.[J............ 001202f8 41 44 56 41 50 49 33 32-2e 64 6c 6c 00 4b 45 52 ADVAPI32.dll.KER 00120308 4e 45 4c 33 32 2e 64 6c-6c 00 4e 54 44 4c 4c 2e NEL32.dll.NTDLL. 00120318 44 4c 4c 00 47 44 49 33-32 2e 64 6c 6c 00 55 53 DLL.GDI32.dll.US 00120328 45 52 33 32 2e 64 6c 6c-00 6d 73 76 63 72 74 2e ER32.dll.msvcrt. 00120338 64 6c 6c 00 43 4f 4d 44-4c 47 33 32 2e 64 6c 6c dll.COMDLG32.dll 00120348 00 53 48 45 4c 4c 33 32-2e 64 6c 6c 00 57 49 4e .SHELL32.dll.WIN 00120358 53 50 4f 4f 4c 2e 44 52-56 00 6f 6c 65 33 32 2e SPOOL.DRV.ole32. 00120368 64 6c 6c 00 53 48 4c 57-41 50 49 2e 64 6c 6c 00 dll.SHLWAPI.dll. 00120378 43 4f 4d 43 54 4c 33 32-2e 64 6c 6c 00 4f 4c 45 COMCTL32.dll.OLE 00120388 41 55 54 33 32 2e 64 6c-6c 00 56 45 52 53 49 4f AUT32.dll.VERSIO 00120398 4e 2e 64 6c 6c 00 00 00-00 00 00 00 00 00 00 00 N.dll...........
分析一下,第一行4a5bd97eh爲TimeDateStamp值,80h爲當前綁定dll名的相對偏移,00h表示當前dll轉發dll個數爲0,因此也就不存在IMAGE_BOUND_FORWARDER_REF結構。
0:001> db 00120278+80 001202f8 41 44 56 41 50 49 33 32-2e 64 6c 6c 00 4b 45 52 ADVAPI32.dll.KER
第一行,右半部分,4a5bdaad爲TimeDateStamp值,8dh爲當前綁定dll名的相對偏移,01h表示當前dll轉發dll個數爲1,因此後面跟着的8個字節,爲IMAGE_BOUND_FORWARDER_REF結構。
0:001> db 00120278+8d 00120305 4b 45 52 4e 45 4c 33 32-2e 64 6c 6c 00 4e 54 44 KERNEL32.dll.NTD
能夠看到在IMAGE_BOUND_FORWARDER_REF結構中,4a5bdadbh爲TimeDateStamp值,轉發dll名字偏移爲9d,查看內存發現時ntdll,也就是說調用kernel32.dll中函數時,會轉發到ntdll中。
0:001> db 00120278+9a 00120312 4e 54 44 4c 4c 2e 44 4c-4c 00 47 44 49 33 32 2e NTDLL.DLL.GDI32.
觀察當前保定導出表內存,發現大部分dll都沒有轉發,只有kernel32.dll轉發到ntdll.dll。
咱們接着再以加載的Kernel32.dll爲例:
0:001> dt 765f0000 _IMAGE_DOS_HEADER ntdll!_IMAGE_DOS_HEADER +0x000 e_magic : 0x5a4d +0x002 e_cblp : 0x90 +0x004 e_cp : 3 +0x006 e_crlc : 0 +0x008 e_cparhdr : 4 +0x00a e_minalloc : 0 +0x00c e_maxalloc : 0xffff +0x00e e_ss : 0 +0x010 e_sp : 0xb8 +0x012 e_csum : 0 +0x014 e_ip : 0 +0x016 e_cs : 0 +0x018 e_lfarlc : 0x40 +0x01a e_ovno : 0 +0x01c e_res : [4] 0 +0x024 e_oemid : 0 +0x026 e_oeminfo : 0 +0x028 e_res2 : [10] 0 +0x03c e_lfanew : 0n240 0:001> dt 765f00f0 _IMAGE_NT_HEADERS ntdll!_IMAGE_NT_HEADERS +0x000 Signature : 0x4550 +0x004 FileHeader : _IMAGE_FILE_HEADER +0x018 OptionalHeader : _IMAGE_OPTIONAL_HEADER 0:001> dt 765F0108 _IMAGE_OPTIONAL_HEADER ntdll!_IMAGE_OPTIONAL_HEADER +0x000 Magic : 0x10b +0x002 MajorLinkerVersion : 0x9 '' +0x003 MinorLinkerVersion : 0 '' +0x004 SizeOfCode : 0xc5000 +0x008 SizeOfInitializedData : 0xe000 +0x00c SizeOfUninitializedData : 0 +0x010 AddressOfEntryPoint : 0x4cd6f +0x014 BaseOfCode : 0x1000 +0x018 BaseOfData : 0xc0000 +0x01c ImageBase : 0x765f0000 +0x020 SectionAlignment : 0x1000 +0x024 FileAlignment : 0x1000 +0x028 MajorOperatingSystemVersion : 6 +0x02a MinorOperatingSystemVersion : 1 +0x02c MajorImageVersion : 6 +0x02e MinorImageVersion : 1 +0x030 MajorSubsystemVersion : 6 +0x032 MinorSubsystemVersion : 1 +0x034 Win32VersionValue : 0 +0x038 SizeOfImage : 0xd4000 +0x03c SizeOfHeaders : 0x1000 +0x040 CheckSum : 0xdca19 +0x044 Subsystem : 3 +0x046 DllCharacteristics : 0x140 +0x048 SizeOfStackReserve : 0x40000 +0x04c SizeOfStackCommit : 0x1000 +0x050 SizeOfHeapReserve : 0x100000 +0x054 SizeOfHeapCommit : 0x1000 +0x058 LoaderFlags : 0 +0x05c NumberOfRvaAndSizes : 0x10 +0x060 DataDirectory : [16] _IMAGE_DATA_DIRECTORY 0:001> dt 765F0168+58 _IMAGE_DATA_DIRECTORY ntdll!_IMAGE_DATA_DIRECTORY +0x000 VirtualAddress : 0x288 +0x004 Size : 0x408 0:001> db 77a10000 +0x288 77a10288 00 00 00 00 40 00 00 42-00 00 00 00 00 00 00 00 ....@..B........ 77a10298 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102a8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102b8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102c8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102d8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102e8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102f8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 0:001> db 77a10288+40 77a102c8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102d8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102e8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a102f8 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a10308 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a10318 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a10328 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 77a10338 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
能夠發現,加載的kernel32.dll中,雖然存在綁定導入表,可是內容卻未空,意味着當前模塊沒有綁定其餘模塊。