0x01 绑定导入表概念

 

绑定导入表(The Bound Import Directory)。它包含了可以让加载器判断绑定的地址是否合法的信息。描述它的数据结构是IMAGE_BOUND_IMPORT_DESCRIPTOR,目录表就是这种结构的数组,每一项都对应一个被绑定过的DLL。

 

每当PE装载器装入PE文件时,检查导入表并将相关DLL映射到进程空间地址。然后通过遍历IAT里的IMAGE_THUNK_DATA数组并用导入函数的真实地址替换它,这一步需要很多时间。如果程序员事先能正确预测函数地址,PE装载器就不用每次装入PE文件时都去修正IMAGE_THUNK_DATA值了,绑定导入就是这种思想的产物。

 

当一个可执行文件被绑定(例如通过绑定程序Visual Studio的Bind.exe)时,IAT中的IMAGE_THUNK_DATA结构被导入函数的实际地址改写了。磁盘中的可执行文件,他们的IAT里有的存放的是相关DLL导出函数的实际内存地址。这样可以使应用程序更快的进程初始化,并且使用较少的存储器。

 

在执行整个进程期间,bind程序做了两个重要假设:

©当进程初始化时,需要的DLL实际加载到了它们的首选基地址中。

©自从绑定操作执行以来,DLL导出表中引用的符号位置一直没有改变

 

  当然,如果上面的两个假设中有一个是假的,IAT中所有地址均是无效的,加载器会检查这种情况并做出相应反应,加载器从INT表里获得所需要的信息来解决导入API的地址问题。对于一个可执行文件的装入,INT是不需要的。但是,如果没有,可执行文件是不能被绑定的。微软的链接器似乎总是生成一个INT,但是在很长一段时间里,Borland 的链接器(TLINK)没有这样做, 由Borland生成的文件是不能被绑定的。

 

      由于不知用户运行的是Windows 2000还是Windows XP,无法将系统DLL绑定起来,因此程序安装时是绑定程序的最佳时机。Windows 安装器的BindImage将做这些工作。另外,IMAGEHLP.DLL提供了BindImageEx函数。不管用什么方式,绑定都是一个好主意。如果加载器确定绑定信息是当前的,可执行文件的装入会更快,如果绑定信息已经变得陈旧了,也不会影响程序的运行。

 

      对于加载器来说,使绑定变得有效的一个关键步骤是确定在IAT表中的绑定信息是否是当前的。当一个可执行文件被绑定时,被参考的DLL信息放入了文件中,加载器检查这些信息来做一个快速的綁定有效性验证。

 

      数据目录表( 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与大小清零即可。

总结:

此数据项两个作用:

1、根据TimeDateStamp和OffsetModuleName字段的值我们就可以判断IAT表中的信息是否已经过期。

2、解决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中,虽然存在绑定导入表,但是内容却未空,意味着当前模块没有绑定其他模块。

版权声明:本文为huity35原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/huity35/p/10588134.html