程序员的自我修养: Windows下的动态链接
2010-03-08 13:01
302 查看
一 DLL
Windows下的DLL文件和exe文件实际上是一个概念,他们都是有PE格式的二进制文件,有些不同的是:PE文件头部中有个符号位表示该文件是EXE或是DLL.
每个进程有一份私有的数据副本, 由于在ELF文件中, 代码段是地址无关的, 所以可以在多个进程之间共享一份代码. 但是DLL的代码并不是地址无关的, 所以他只是在某种情况下可以被多个进程间共享.
1. DLL共享数据段与进程间通信
在win32下,可以采用DLL共享数据段的方法实现进程间通信.正常情况下,每个DLL的数据段在各个进程中都是独立的,每个进程都拥有自己的副本.但是windows允许将DLL的数据段设置成共享的,即任何进程都可以共享该DLL的同一份数据段.(可以将其分离出来放到另外一个数据段,然后将这个数据段设置成进程间可共享的.也就是说一个DLL中有两个数据段,一个进程间共享,另一个私有.)
但是也产生了一个安全漏洞, 这用利用DLL共享数据段来实现进程间通信的方法应该尽量避免.
2. lib文件, dll文件, obj文件, exp文件的联系
当使用MSVC的编译器cl进程编译时:
可见,总计生成了Math.obj, Math.exp, Math.dll, Math.lib四个文件.
当查看Math.lib文件的导出时,
导出分别为: _add _sub _mul, 并且可知Math.lib中的段有:
当查看Math.dll时,
可知, dll文件可以导出的函数有: add, sub, mul, 我们还可以看到他们的相对地址RVA.
Math.dll文件中的段有:
使用cl /c TestMath.c 编译产生TestMath.obj文件.
当链接时,使用命令link TestMath.obj Math.lib产生TestMath.exe文件.
当查看TestMath.obj的.drectve段时,
可见, 没有要求导出的函数(供链接时使用).
整个过程如下:
Math.lib中并不真正包含Math.c的代码和数据,他用来描述Math.dll的导出符号,他包含了TestMath.obj链接Math.dll时所需要的导入符号以及一部分"桩"代码(胶水代码),以便于将程序与DLL粘在一起. Math.lib又叫"导入库".
Math.exp是链接器在创建DLL时的临时存放导出表的文件.
3.模块定义文件.def
__stdcall调用规范也是大多数windows下的编程语言所支持的通用调用规范, 那么作为一个能过广泛使用的DLL最好采用__stdcall的函数规范.而MSVC默认采用__cdecl调用规范,否则他就会使用符号修饰,经过修饰的符号不便于维护和使用,于是采用.def文件对导出符号进行重命名就是一个很好的方案. windows中的WINAPI实际上就是__stdcall, 所以DLL也是采用了导出函数重名名的方法.
关于导出符号, math.c文件修改如下:
结果如下:
add sub经过名字修饰,mul不变.
当我们用如下的def文件时:
结果如下:
4. 导出重定向
EXPROTS
HeapAlloc = NTDLL.RtlAllocHeap
实现机制: 正常情况下,导出表的地址数组中包含的是函数RVA, 但是如果这RVA指向的位置位于导出表中,那么表示这个符号被重定向了.被重定向了的RVA并不代表该函数的地址,而是指向一个ASCII的字符串,这个字符串在导出表中,它是符号重定向后的DLL文件名和符号名.
二 导入导出表
1. 导出表
PE头文件有一个叫DataDirectory的结构数组, 这个数组共有16个元素, 每个元素中保存的是一个地址和一个长度. 其中第一个元素就是导出表的结构的地址和长度. 导出表是一个IMAGE_EXPORT_DIRECTORY的结构体. 他被定义在WINNT.h中:
IMAGE_DATA_DIRECTORY结构如下:
映证了"每个元素中保存的是一个地址和一个长度"的说法.那么就可以说明, 其中第一个元素就是导出表的结构的地址和长度.
导出表的结构如下:
对于链接器来说, 它在链接输出DLL时需要知道哪些函数和变量是要被导出的.
因为对于PE文件来说,默认全局函数和变量是不导出的.
指定要导出的符号的一种方法是: 使用MSVC的__declspec(dllexport)拓展,它
实际上是通过目标文件的编译器指示来实现的
(对于math.obj来说, 它在.drectve段保存了四个/EXPORT参数, 用于传递给
链接器,告知链接器导出相应的函数).
5. 导入表
当PE文件加载时, windows加载器的其中一个任务就是将所有需要导入的函数地址确定并且将导入表中的元素调到正确的地址, 以实现动态链接.
在PE文件中, 导入表是一个IMAGE_IMPORT_DESCRIPTOR的结构体数组, 每一个这个结构对应一个被导入的DLL.
FirstThunk指向一个导入地址数组IAT.
在动态链接器刚完成映射,还没有开始重定位和符号解析的时候, IAT中的元素表示相对应的导入符号的序号或符号名;
当windows的动态链接器在完成该模块的链接时,元素值会被动态链接器改写成符号的真正地址.
那么怎么判断导入地址数组的元素是导入符号的序号还是名字?
如果最高位是1, 低31位就是导入符号的序号值;
如果是0, 低31位就指向一个叫IMAGE_IMPORT_BY_NAME的RVA, IMAGE_IMPORT_BY_NAME由一个WORD和一个字符串组成.那个WORD就表示Hint,即导入符号最有可能的序号值, 后面的字符串是一个符号名. 当使用符号名导入时, 动态链接器先使用Hint值去定位该符号在目标导入表中的位置, 如果是就命中; 否则就按照正常的二分查表进行符号查表.
IMAGE_IMPORT_DESCRIPTOR的OrginalFistThunk指向一个数组叫做导入名称表INT(Import Name Table).
延迟载入(Delayed Load):
当延迟载入的API第一次被调用时, 由链接器添加的特殊的桩代码就会启动, 这个桩代码负责对DLL的装载工作. 然后这个桩代码通过GetProcAddress来找被掉用API的地址.
6. 导入函数的调用
在PE模块中, 需要调用一个导入函数时, 就是使用一个间接调用指令:
CALL DWORD PTR [0x0040D11C]
0x0040D11C对应于IAT中的某一项, 也就是0x0040D11C开始取4个字节作为目标地址.
我们可以看到,0x0040D11C是做个目标地址的地址的常数被写入在指令中的. 可以说, PE DLL的代码段并不是地址无关的.所以要使用重定基地址的方法.
对于编译器来说, 他无法判断一个函数是本模块内部的, 还是从外部导入的.因为对于普通模块内部函数调用来说, 编译器产生的指令是这样的:
CALL XXXXXXXX
XXXXXXXX是模块内部的函数地址.
MSVC引入 __declspec(dllexport)属性, 一段一个函数有被声明为 __declspec(dllexport), 那么编译器就知道它是外部导入的, 以便产生相对应的指令形式.
三 DLL的优化技术
1. 重定基地址(Rebasing)
对DLL文件的基地址进行装载时重定位.
从上面的分析中我们可以注意到DLL文件有一个段叫.reloc.存放的是重定位信息. 我们同样可以从DataDirectory数组里面得到重定位信息.
这样就导致如果一个DLL被多个进程共享, 且该DLL被这些进程装载到不同的位置, 那么每个进程都需要有一份单独的DLL代码段的副本.
2. 导入函数绑定
还可以将DLL导出函数的地址保存到模块的导入表中,就可以省去每次启动时符号解析的过程.这叫导入函数绑定.
用一种检验机制来知道是否DLL导出函数地址发生变化, 即链接器把DLL的时间戳和校验和保存到被绑定的PE文件的导入表中. 运行时,核对版本是否相同.
可以看到绑定的信息.
四 DLL HELL
windows缺乏一种很有效的DLL版本控制机制.
解决方法:
1. 静态链接
2. 防止DLL覆盖(DLL Stomping)
3. 防止DLL冲突(放到应用程序的文件夹中)
4. .NET下DLL HELL的解决方案
用一个叫Manifest的清单文件描述程序集.
Windows下的DLL文件和exe文件实际上是一个概念,他们都是有PE格式的二进制文件,有些不同的是:PE文件头部中有个符号位表示该文件是EXE或是DLL.
每个进程有一份私有的数据副本, 由于在ELF文件中, 代码段是地址无关的, 所以可以在多个进程之间共享一份代码. 但是DLL的代码并不是地址无关的, 所以他只是在某种情况下可以被多个进程间共享.
1. DLL共享数据段与进程间通信
在win32下,可以采用DLL共享数据段的方法实现进程间通信.正常情况下,每个DLL的数据段在各个进程中都是独立的,每个进程都拥有自己的副本.但是windows允许将DLL的数据段设置成共享的,即任何进程都可以共享该DLL的同一份数据段.(可以将其分离出来放到另外一个数据段,然后将这个数据段设置成进程间可共享的.也就是说一个DLL中有两个数据段,一个进程间共享,另一个私有.)
但是也产生了一个安全漏洞, 这用利用DLL共享数据段来实现进程间通信的方法应该尽量避免.
2. lib文件, dll文件, obj文件, exp文件的联系
//Math.c __declspec(dllexport) double add(double a, double b) { return a+b; } __declspec(dllexport) double sub(double a, double b) { return a-b; } __declspec(dllexport) double mul(double a, double b) { return a+b; }
当使用MSVC的编译器cl进程编译时:
F:/ProgrammingSpace/TempForever/TempForever>cl /LDd Math.c 用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 15.00.21022.08 版 版权所有(C) Microsoft Corporation。保留所有权利。 Math.c Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /out:Math.dll /dll /implib:Math.lib Math.obj 正在创建库 Math.lib 和对象 Math.exp
可见,总计生成了Math.obj, Math.exp, Math.dll, Math.lib四个文件.
当查看Math.lib文件的导出时,
F:/ProgrammingSpace/TempForever/TempForever>dumpbin /EXPORTS Math.lib Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file Math.lib File Type: LIBRARY Exports ordinal name _add _mul _sub Summary BA .debug$S 14 .idata$2 14 .idata$3 4 .idata$4 4 .idata$5 A .idata$6
导出分别为: _add _sub _mul, 并且可知Math.lib中的段有:
BA .debug$S 14 .idata$2 14 .idata$3 4 .idata$4 4 .idata$5 A .idata$6
当查看Math.dll时,
F:/ProgrammingSpace/TempForever/TempForever>dumpbin /EXPORTS Math.dll Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file Math.dll File Type: DLL Section contains the following exports for Math.dll 00000000 characteristics 4B99E326 time date stamp Fri Mar 12 14:45:58 2010 0.00 version 1 ordinal base 3 number of functions 3 number of names ordinal hint RVA name 1 0 00001000 add 2 1 00001020 mul 3 2 00001010 sub Summary 3000 .data 9000 .rdata 4000 .reloc 1F000 .text
可知, dll文件可以导出的函数有: add, sub, mul, 我们还可以看到他们的相对地址RVA.
Math.dll文件中的段有:
Summary 3000 .data 9000 .rdata 4000 .reloc 1F000 .text
//TestMath.c #include <stdio.h> __declspec(dllimport) double sub(double a, double b); int main() { double ret = sub(3.0, 2.0); printf("RET: %f/n", ret); return 0; }
使用cl /c TestMath.c 编译产生TestMath.obj文件.
当链接时,使用命令link TestMath.obj Math.lib产生TestMath.exe文件.
当查看TestMath.obj的.drectve段时,
F:/ProgrammingSpace/TempForever/TempForever>dumpbin /DIRECTIVES TestMath.obj Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file TestMath.obj File Type: COFF OBJECT Linker Directives ----------------- /DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" Summary 9 .data 8C .debug$S 2F .drectve 10 .rdata 46 .text
可见, 没有要求导出的函数(供链接时使用).
整个过程如下:
Math.lib------------------------------------ Math.c->Math.dll | Math.exp | |--->TestMath.exe | TestMath.c->TestMath.obj-------------------------|
Math.lib中并不真正包含Math.c的代码和数据,他用来描述Math.dll的导出符号,他包含了TestMath.obj链接Math.dll时所需要的导入符号以及一部分"桩"代码(胶水代码),以便于将程序与DLL粘在一起. Math.lib又叫"导入库".
Math.exp是链接器在创建DLL时的临时存放导出表的文件.
3.模块定义文件.def
__stdcall调用规范也是大多数windows下的编程语言所支持的通用调用规范, 那么作为一个能过广泛使用的DLL最好采用__stdcall的函数规范.而MSVC默认采用__cdecl调用规范,否则他就会使用符号修饰,经过修饰的符号不便于维护和使用,于是采用.def文件对导出符号进行重命名就是一个很好的方案. windows中的WINAPI实际上就是__stdcall, 所以DLL也是采用了导出函数重名名的方法.
关于导出符号, math.c文件修改如下:
__declspec(dllexport) double __stdcall add(double a, double b) { return a+b; } __declspec(dllexport) double __stdcall sub(double a, double b) { return a-b; } __declspec(dllexport) double __cdecl mul(double a, double b) { return a+b; } double __cdecl div(double a, double b) { return a/b; }
结果如下:
F:/ProgrammingSpace/TempForever/TempForever/new>dumpbin /exports math.dll Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file math.dll File Type: DLL Section contains the following exports for Math.dll 00000000 characteristics 4B99FE0D time date stamp Fri Mar 12 16:40:45 2010 0.00 version 1 ordinal base 3 number of functions 3 number of names ordinal hint RVA name 1 0 00001000 _add@16 3 1 00001010 _sub@16 2 2 00001020 mul Summary 3000 .data 9000 .rdata 4000 .reloc 1F000 .text
add sub经过名字修饰,mul不变.
当我们用如下的def文件时:
LIBRARY Math EXPORTS add = _add@16 sub = _sub@16 mul div
结果如下:
F:/ProgrammingSpace/TempForever/TempForever/new>dumpbin /exports math.dll Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file math.dll File Type: DLL Section contains the following exports for Math.dll 00000000 characteristics 4B99FF08 time date stamp Fri Mar 12 16:44:56 2010 0.00 version 1 ordinal base 6 number of functions 6 number of names ordinal hint RVA name 1 0 00001000 _add@16 4 1 00001010 _sub@16 5 2 00001000 add 2 3 00001030 div 3 4 00001020 mul 6 5 00001010 sub Summary 2000 .data 2000 .rdata 1000 .reloc A000 .text
4. 导出重定向
EXPROTS
HeapAlloc = NTDLL.RtlAllocHeap
实现机制: 正常情况下,导出表的地址数组中包含的是函数RVA, 但是如果这RVA指向的位置位于导出表中,那么表示这个符号被重定向了.被重定向了的RVA并不代表该函数的地址,而是指向一个ASCII的字符串,这个字符串在导出表中,它是符号重定向后的DLL文件名和符号名.
二 导入导出表
1. 导出表
PE头文件有一个叫DataDirectory的结构数组, 这个数组共有16个元素, 每个元素中保存的是一个地址和一个长度. 其中第一个元素就是导出表的结构的地址和长度. 导出表是一个IMAGE_EXPORT_DIRECTORY的结构体. 他被定义在WINNT.h中:
IMAGE_DATA_DIRECTORY DataDirectory IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
IMAGE_DATA_DIRECTORY结构如下:
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
映证了"每个元素中保存的是一个地址和一个长度"的说法.那么就可以说明, 其中第一个元素就是导出表的结构的地址和长度.
导出表的结构如下:
typedef struct _IMAGE_EXPORT_DIRECTORY{ DWORD Characteristics; DOWRD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctons; //导出地址表(EAT,Export Address Table) //存放的是各个导出函数的RVA(相对虚拟地址, Relative Virtual Address) DWORD AddressOfNames; //符号名表(Name Table) //函数名表,它保存的是导出的函数名字,其中的所有的函数名是按照ASCII顺序 //排序的,以便于动态连接器在查找函数名字时可以速度更快 DWORD AddressOrdinals; //名字序号表(Name-Orinal Table) }IMAGE_EXPORT_DIRECTORY; //上面三个表的关系是: //符号名表顺序排列, 名字序号表记录他的序号, 以寻找它在导出地址表中的索引 //RVA(相对虚拟地址,Relative Virtual Address): //它是相对于PE文件的装载基地址(Base Address)的一个偏移地址 /**********************************************************/
对于链接器来说, 它在链接输出DLL时需要知道哪些函数和变量是要被导出的.
因为对于PE文件来说,默认全局函数和变量是不导出的.
指定要导出的符号的一种方法是: 使用MSVC的__declspec(dllexport)拓展,它
实际上是通过目标文件的编译器指示来实现的
(对于math.obj来说, 它在.drectve段保存了四个/EXPORT参数, 用于传递给
链接器,告知链接器导出相应的函数).
F:/ProgrammingSpace/TempForever/TempForever>dumpbin /DIRECTIVES math.obj Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file math.obj File Type: COFF OBJECT Linker Directives ----------------- /DEFAULTLIB:"LIBCMTD" /DEFAULTLIB:"OLDNAMES" /EXPORT:_add /EXPORT:_sub /EXPORT:_mul Summary 88 .debug$S 57 .drectve 2B .text
5. 导入表
当PE文件加载时, windows加载器的其中一个任务就是将所有需要导入的函数地址确定并且将导入表中的元素调到正确的地址, 以实现动态链接.
在PE文件中, 导入表是一个IMAGE_IMPORT_DESCRIPTOR的结构体数组, 每一个这个结构对应一个被导入的DLL.
typedef struct { DWORD OrginalFistThunk; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DOWRD FirstThunk; //指向一个导入地址数组IAT(Import Address Table) }IMAGE_IMPORT_DESCRIPTOR;
FirstThunk指向一个导入地址数组IAT.
在动态链接器刚完成映射,还没有开始重定位和符号解析的时候, IAT中的元素表示相对应的导入符号的序号或符号名;
当windows的动态链接器在完成该模块的链接时,元素值会被动态链接器改写成符号的真正地址.
那么怎么判断导入地址数组的元素是导入符号的序号还是名字?
如果最高位是1, 低31位就是导入符号的序号值;
如果是0, 低31位就指向一个叫IMAGE_IMPORT_BY_NAME的RVA, IMAGE_IMPORT_BY_NAME由一个WORD和一个字符串组成.那个WORD就表示Hint,即导入符号最有可能的序号值, 后面的字符串是一个符号名. 当使用符号名导入时, 动态链接器先使用Hint值去定位该符号在目标导入表中的位置, 如果是就命中; 否则就按照正常的二分查表进行符号查表.
IMAGE_IMPORT_DESCRIPTOR的OrginalFistThunk指向一个数组叫做导入名称表INT(Import Name Table).
延迟载入(Delayed Load):
当延迟载入的API第一次被调用时, 由链接器添加的特殊的桩代码就会启动, 这个桩代码负责对DLL的装载工作. 然后这个桩代码通过GetProcAddress来找被掉用API的地址.
6. 导入函数的调用
在PE模块中, 需要调用一个导入函数时, 就是使用一个间接调用指令:
CALL DWORD PTR [0x0040D11C]
0x0040D11C对应于IAT中的某一项, 也就是0x0040D11C开始取4个字节作为目标地址.
我们可以看到,0x0040D11C是做个目标地址的地址的常数被写入在指令中的. 可以说, PE DLL的代码段并不是地址无关的.所以要使用重定基地址的方法.
对于编译器来说, 他无法判断一个函数是本模块内部的, 还是从外部导入的.因为对于普通模块内部函数调用来说, 编译器产生的指令是这样的:
CALL XXXXXXXX
XXXXXXXX是模块内部的函数地址.
MSVC引入 __declspec(dllexport)属性, 一段一个函数有被声明为 __declspec(dllexport), 那么编译器就知道它是外部导入的, 以便产生相对应的指令形式.
三 DLL的优化技术
1. 重定基地址(Rebasing)
对DLL文件的基地址进行装载时重定位.
从上面的分析中我们可以注意到DLL文件有一个段叫.reloc.存放的是重定位信息. 我们同样可以从DataDirectory数组里面得到重定位信息.
F:/ProgrammingSpace/TempForever/TempForever/new>dumpbin /relocations math.dll > new.txt //部分内容 Microsoft (R) COFF/PE Dumper Version Dump of file math.dll File Type: DLL BASE RELOCATIONS #4 1000 RVA, 90 SizeOfBlock 3C HIGHLOW 10001E4B 41 HIGHLOW 1000D008 47 HIGHLOW 1000D00C 4B HIGHLOW 10001532 51 HIGHLOW 1000D010 55 HIGHLOW 100014E6 5B HIGHLOW 1000D014 5F HIGHLOW 1000151F 65 HIGHLOW 1000D018 69 HIGHLOW 10001488 6E HIGHLOW 1000D01C 74 HIGHLOW 1000D020 78 HIGHLOW 10001DC3 7E HIGHLOW 1000D024 82 HIGHLOW 100014A4 88 HIGHLOW 1000D028 8C HIGHLOW 10001406 92 HIGHLOW 1000D02C 96 HIGHLOW 10001393 AF HIGHLOW 1000DF84 F6 HIGHLOW 1000B004 FB HIGHLOW 1000EB34 105 HIGHLOW 1000DF8C 139 HIGHLOW 1000DF88 151 HIGHLOW 1000DF88 159 HIGHLOW 1000DF88 15F HIGHLOW 1000DFDC 1A5 HIGHLOW 1000D030 1AB HIGHLOW 1000DFA4 1C6 HIGHLOW 1000B000 1F6 HIGHLOW 1000C340 212 HIGHLOW 1000DF88 22A HIGHLOW 1000B12C 27D HIGHLOW 1000B12C 2AA HIGHLOW 1000B12C 336 HIGHLOW 1000D6A8 33E HIGHLOW 1000D5C4 353 HIGHLOW 1000D4C8 35E HIGHLOW 1000D5C4 620 HIGHLOW 1000B130 685 HIGHLOW 1000E13C 6BD HIGHLOW 1000D830 C17 HIGHLOW 1000D830 CD2 HIGHLOW 1000D830 E76 HIGHLOW 1000D008 EC4 HIGHLOW 1000B140 ECD HIGHLOW 1000B138 EF9 HIGHLOW 1000B164 EFF HIGHLOW 1000B00C F08 HIGHLOW 1000B148 F0F HIGHLOW 1000B008 F29 HIGHLOW 1000D034 F2F HIGHLOW 1000B014 F3A HIGHLOW 1000D030 F46 HIGHLOW 1000D034 F5B HIGHLOW 1000B180 F62 HIGHLOW 1000B010 F76 HIGHLOW 1000B170 F7D HIGHLOW 1000B008 FA4 HIGHLOW 1000D034 FAA HIGHLOW 1000B014 FB5 HIGHLOW 1000D030 FC1 HIGHLOW 1000D034 FD6 HIGHLOW 1000B180 FDD HIGHLOW 1000B010 FF1 HIGHLOW 1000B19C FF8 HIGHLOW 1000B008 0 ABS 2000 RVA, 160 SizeOfBlock 10 HIGHLOW 1000B018 1C HIGHLOW 1000D034 22 HIGHLOW 1000B014 2E HIGHLOW 1000DFA0 3D HIGHLOW 1000D034 43 HIGHLOW 1000B01C 4C HIGHLOW 1000D030 58 HIGHLOW 1000DFA8 66 HIGHLOW 1000D030 6C HIGHLOW 1000D034 78 HIGHLOW 1000B020 7E HIGHLOW 1000D034 8B HIGHLOW 1000C360 95 HIGHLOW 1000B180 9C HIGHLOW 1000B010 B4 HIGHLOW 1000B200 C3 HIGHLOW 1000B170 CA HIGHLOW 1000B008 D7 HIGHLOW 1000B19C FA HIGHLOW 1000D0A0 10F HIGHLOW 1000B024 135 HIGHLOW 1000D6A8 175 HIGHLOW 1000B02C 17B HIGHLOW 1000D030 1A5 HIGHLOW 1000D030 1AB HIGHLOW 1000DFA4 1C7 HIGHLOW 1000B000 1DF HIGHLOW 1000B028 205 HIGHLOW 1000C388 27F HIGHLOW 1000B200 2A2 HIGHLOW 1000B030 2AC HIGHLOW 1000D0A0 2E4 HIGHLOW 1000D6A8 2EC HIGHLOW 1000D5D0 338 HIGHLOW 1000D030 348 HIGHLOW 1000D034 34E HIGHLOW 1000B014 35A HIGHLOW 1000D030 360 HIGHLOW 1000D034 370 HIGHLOW 1000D030 376 HIGHLOW 1000DFA4 38B HIGHLOW 1000D034 399 HIGHLOW 1000B01C 3A4 HIGHLOW 1000B180 3AB HIGHLOW 1000B010 3C6 HIGHLOW 1000B008 3CB HIGHLOW 1000B1CC 3D3 HIGHLOW 1000B1C0 3D9 HIGHLOW 1000DF9C 3E0 HIGHLOW 1000B1B4 3E6 HIGHLOW 1000DFA0 3ED HIGHLOW 1000B1AC 3F3 HIGHLOW 1000DFA4 3FB HIGHLOW 1000DF9C 402 HIGHLOW 1000B01C 407 HIGHLOW 1000DFA8 40F HIGHLOW 1000DFA0 418 HIGHLOW 1000DFA4 424 HIGHLOW 1000B014 429 HIGHLOW 1000DFA0 42E HIGHLOW 1000B020 434 HIGHLOW 1000DF9C 438 HIGHLOW 1000200E 43E HIGHLOW 1000DFA4 443 HIGHLOW 1000DFA8 449 HIGHLOW 1000B018 44E HIGHLOW 1000D034 45D HIGHLOW 1000DFA0 473 HIGHLOW 1000DF9C 47E HIGHLOW 1000DFA0 483 HIGHLOW 1000DF9C 48E HIGHLOW 1000DFA4 493 HIGHLOW 1000DFA0 49E HIGHLOW 1000DFA8 4A3 HIGHLOW 1000DFA4 4B0 HIGHLOW 1000DFA8 4BE HIGHLOW 10002202 4C4 HIGHLOW 1000DF9C 4D1 HIGHLOW 1000D030 4F1 HIGHLOW 1000D030 4F7 HIGHLOW 1000DFA4 513 HIGHLOW 1000B000 52F HIGHLOW 1000C3B0 541 HIGHLOW 1000EA04 590 HIGHLOW 1000E0F4 596 HIGHLOW 1000B034 5A7 HIGHLOW 1000B02C 5D4 HIGHLOW 1000DFAC 5DD HIGHLOW 1000B038 5E9 HIGHLOW 1000DFAC 620 HIGHLOW 1000DFAC 629 HIGHLOW 1000B038 635 HIGHLOW 1000DFAC 66E HIGHLOW 1000DFAC 677 HIGHLOW 1000B038 683 HIGHLOW 1000DFAC 6A7 HIGHLOW 1000B038 6B0 HIGHLOW 1000B010 6DD HIGHLOW 1000D038 6F8 HIGHLOW 1000B1E8 6FE HIGHLOW 1000B010 707 HIGHLOW 1000B1D8 70E HIGHLOW 1000B008 730 HIGHLOW 1000B03C 78F HIGHLOW 1000B120 797 HIGHLOW 1000B120 7AA HIGHLOW 1000B120 7B5 HIGHLOW 1000B108 7BA HIGHLOW 1000B0F8 7CA HIGHLOW 100030DE 7D4 HIGHLOW 1000B0F0 7DB HIGHLOW 1000B0F4 7E6 HIGHLOW 1000EB30 7EF HIGHLOW 1000EB30 805 HIGHLOW 1000EB30 810 HIGHLOW 1000C3D0 82A HIGHLOW 1000DFE0 836 HIGHLOW 1000DFDC 83E HIGHLOW 1000DFD8 84E HIGHLOW 1000EB28 863 HIGHLOW 1000EB24 8A3 HIGHLOW 1000EB28 8B0 HIGHLOW 1000EB24 8DA HIGHLOW 1000B110 8DF HIGHLOW 1000B10C 8EA HIGHLOW 1000B118 8EF HIGHLOW 1000B114 90D HIGHLOW 1000DFE0 999 HIGHLOW 10002939 9A6 HIGHLOW 1000D038 9AF HIGHLOW 1000C3F0 9C3 HIGHLOW 1000B04C 9E4 HIGHLOW 1000EA20 9EA HIGHLOW 1000EA08 A1C HIGHLOW 1000EA20 A73 HIGHLOW 1000EA20 A7B HIGHLOW 1000EA08 ABB HIGHLOW 1000EA08 AC5 HIGHLOW 1000EA08 AED HIGHLOW 1000B048 B06 HIGHLOW 1000EA20 B47 HIGHLOW 1000EA20 B77 HIGHLOW 1000B044 B89 HIGHLOW 1000B048 BDB HIGHLOW 1000EA08 BE1 HIGHLOW 1000B040 C05 HIGHLOW 1000EA20 C23 HIGHLOW 1000B050 C45 HIGHLOW 1000EB20 C50 HIGHLOW 1000EB2C C5F HIGHLOW 1000DF8C C97 HIGHLOW 1000DFC0 CA1 HIGHLOW 1000DF8C CF1 HIGHLOW 1000DF8C CFC HIGHLOW 1000DF8C D06 HIGHLOW 1000EB20 D17 HIGHLOW 1000DFC0 D22 HIGHLOW 1000DFC0 ED5 HIGHLOW 1000EB2C EE6 HIGHLOW 1000DFE8 EEE HIGHLOW 1000E0EC EF4 HIGHLOW 1000B054 EF9 HIGHLOW 1000EB34 EFF HIGHLOW 1000DFD0 F6B HIGHLOW 1000DFB4 F71 HIGHLOW 1000DFB8 F87 HIGHLOW 1000E0F0 F92 HIGHLOW 1000B068 FA9 HIGHLOW 1000E0F0 FB5 HIGHLOW 1000B02C FC2 HIGHLOW 1000E0F0 FC9 HIGHLOW 1000E0F0 3000 RVA, D4 SizeOfBlock 0 HIGHLOW 1000B064 4F HIGHLOW 1000B060 62 HIGHLOW 1000B05C 94 HIGHLOW 1000B058
这样就导致如果一个DLL被多个进程共享, 且该DLL被这些进程装载到不同的位置, 那么每个进程都需要有一份单独的DLL代码段的副本.
2. 导入函数绑定
还可以将DLL导出函数的地址保存到模块的导入表中,就可以省去每次启动时符号解析的过程.这叫导入函数绑定.
用一种检验机制来知道是否DLL导出函数地址发生变化, 即链接器把DLL的时间戳和校验和保存到被绑定的PE文件的导入表中. 运行时,核对版本是否相同.
F:/ProgrammingSpace/TempForever/TempForever/new>dumpbin /imports c:/windows/note pad.exe Microsoft (R) COFF/PE Dumper Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file c:/windows/notepad.exe File Type: EXECUTABLE IMAGE Section contains the following imports: comdlg32.dll 10012C4 Import Address Table 1007990 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 76344906 F PageSetupDlgW 763385CE 6 FindTextW 76349D84 12 PrintDlgExW 7633C3E1 3 ChooseFontW 76322306 8 GetFileTitleW 76337B9D A GetOpenFileNameW 76338602 15 ReplaceTextW 76330036 4 CommDlgExtendedError 76337C2B C GetSaveFileNameW SHELL32.dll 1001174 Import Address Table 1007840 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 7D647C18 1F DragFinish 7D5E18CE 23 DragQueryFileW 7D5FB1A9 1E DragAcceptFiles 7D632E6F 103 ShellAboutW WINSPOOL.DRV 10012B4 Import Address Table 1007980 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 72F7643C 78 GetPrinterDriverW 72F74D40 1B ClosePrinter 72F75091 7E OpenPrinterW COMCTL32.dll 1001020 Import Address Table 10076EC Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 7718D270 8 CreateStatusWindowW msvcrt.dll 10012EC Import Address Table 10079B8 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 4CFB2DAE 4E _XcptFilter 4CFB9E9A F6 _exit 4CFB9ECE C5 _c_exit 4CFCAECF 317 time 4CFCAB69 2D4 localtime 4CFB9EB6 C8 _cexit 4CF9D036 2C6 iswctype 4CFB5C94 ED _except_handler3 4CF9CE77 274 _wtol 4CFC802F 32F wcsncmp 4CFBFB0C 1E4 _snwprintf 4CFB9E7E 290 exit 4CFE17AC A8 _acmdln 4CF9EEEB 6D __getmainargs 4CFB9D67 13B _initterm 4CFCD695 9A __setusermatherr 4CFE23D8 B6 _adjust_fdiv 4CF9F1A4 80 __p__commode 4CF9F1DB 85 __p__fmode 4CFB537C 98 __set_app_type 4CFCEE4F D6 _controlfp 4CFC806B 330 wcsncpy ADVAPI32.dll 1001000 Import Address Table 10076CC Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 77DA6FEF 1EF RegQueryValueExW 77DA6C17 1CA RegCloseKey 77DCBA25 1D0 RegCreateKeyW 77DCBD05 139 IsTextUnicode 77DA7AAB 1EE RegQueryValueExA 77DA7842 1E4 RegOpenKeyExA 77DAD757 1FC RegSetValueExW KERNEL32.dll 100108C Import Address Table 1007758 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 7C8097B8 13E GetCurrentThreadId 7C80932E 1D4 GetTickCount 7C80A4B7 294 QueryPerformanceCounter 7C80A864 16A GetLocalTime 7C809FA0 1D8 GetUserDefaultLCID 7C83378D 140 GetDateFormatW 7C833FEB 1D6 GetTimeFormatW 7C80FFA9 1F8 GlobalLock 7C80FF12 1FF GlobalUnlock 7C810CFD 15A GetFileInformationByHandle 7C809420 51 CreateFileMappingW 7C8017E9 1C0 GetSystemTimeAsFileTime 7C801E1A 34A TerminateProcess 7C80DE85 13B GetCurrentProcess 7C8449FD 336 SetUnhandledExceptionFilter 7C801D7B 244 LoadLibraryA 7C80B731 176 GetModuleHandleA 7C801EF2 1AE GetStartupInfoA 7C80FCBF 1F4 GlobalFree 7C8115F2 16C GetLocaleInfoW 7C8099BF 24E LocalFree 7C809A1D 24A LocalAlloc 7C809A99 3B8 lstrlenW 7C832EC9 254 LocalUnlock 7C80A3EE 38 CompareStringW 7C832E35 250 LocalLock 7C87A656 EA FoldStringW 7C809BD7 31 CloseHandle 7C80BAF4 3B2 lstrcpyW 7C801812 2A6 ReadFile 7C8107F0 52 CreateFileW 7C80AA26 3AF lstrcmpiW 7C8099B0 13C GetCurrentProcessId 7C80AE30 198 GetProcAddress 7C817013 10A GetCommandLineW 7C810FC2 3A9 lstrcatW 7C80EE67 CC FindClose 7C80EF71 D3 FindFirstFileW 7C80B7DC 159 GetFileAttributesW 7C80AA5C 3AC lstrcmpW 7C809856 266 MulDiv 7C80BA7F 3B5 lstrcpynW 7C8325D4 253 LocalSize 7C92FE01 168 GetLastError 7C810E17 38F WriteFile 7C92FE10 316 SetLastError 7C80A164 382 WideCharToMultiByte 7C830917 251 LocalReAlloc 7C834BA7 EC FormatMessageW 7C813100 1DA GetUserDefaultUILanguage 7C83205E 300 SetEndOfFile 7C831F4B 82 DeleteFileW 7C8099A5 F6 GetACP 7C80BA04 35E UnmapViewOfFile 7C809C88 267 MultiByteToWideChar 7C80B995 25A MapViewOfFile 7C863E6A 35B UnhandledExceptionFilter GDI32.dll 1001028 Import Address Table 10076F4 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 77F0DC19 98 EndPage 77F24A05 0 AbortDoc 77F0DEA9 96 EndDoc 77EF6E5F 8C DeleteDC 77F0F456 249 StartPage 77EF7F9D 1B6 GetTextExtentPoint32W 77EFBE28 2F CreateDCW 77F24B25 211 SetAbortProc 77EFA5BB 1BC GetTextFaceW 77EF7EAC 250 TextOutW 77F25695 247 StartDocW 77F1FB22 CE EnumFontsW 77EF61C1 1A6 GetStockObject 77EF83B3 198 GetObjectW 77EF5A69 16C GetDeviceCaps 77EF938F 3D CreateFontIndirectW 77EF6BFA 8F DeleteObject 77EF7DB9 1BE GetTextMetricsW 77EF5EDB 217 SetBkMode 77EFD4B7 1CC LPtoDP 77F03A05 243 SetWindowExtEx 77F03AAE 23F SetViewportExtEx 77EF9410 22C SetMapMode 77EF5B70 20F SelectObject USER32.dll 1001188 Import Address Table 1007854 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 77D2908E FF GetClientRect 77D29930 24D SetCursor 77D1869D 22A ReleaseDC 77D186C7 10C GetDC 77D247AB 9F DialogBoxParamW 77D27822 243 SetActiveWindow 77D29BF6 122 GetKeyboardLayout 77D28D20 8F DefWindowProcW 77D2B19C 99 DestroyWindow 77D31F7B 1DB MessageBeep 77D2AF56 292 ShowWindow 77D29823 117 GetForegroundWindow 77D297FF 1A6 IsIconic 77D303C7 173 GetWindowPlacement 77D190D2 37 CharUpperW 77D19E36 1C9 LoadStringW 77D2EE76 1B4 LoadAcceleratorsW 77D2B222 15C GetSystemMenu 77D1AF7F 218 RegisterClassExW 77D27B97 1BE LoadImageW 77D19D69 1BA LoadCursorW 77D1DE46 282 SetWindowPlacement 77D2D0A3 61 CreateWindowExW 77D2D1D2 10E GetDesktopWindow 77D298C8 116 GetFocus 77D2E8BC 1BC LoadIconW 77D2960E 287 SetWindowTextW 77D2CA5A 201 PostQuitMessage 77D1AF34 228 RegisterWindowMessageW 77D2AEAB 2BB UpdateWindow 77D2F750 26F SetScrollPos 77D2B24C 29 CharLowerW 77D1929B 1FE PeekMessageW 77D29849 C4 EnableWindow 77D2B415 BE DrawTextExW 77D1EA3B 56 CreateDialogParamW 77D2A5CD 17A GetWindowTextW 77D18F9C 15D GetSystemMetrics 77D2B29E 1E9 MoveWindow 77D28FD5 193 InvalidateRect 77D61BD4 2D3 WinHelpW 77D2AF1B 110 GetDlgCtrlID 77D2201F 3C ChildWindowFromPoint 77D297A0 231 ScreenToClient 77D2974E 10B GetCursorPos 77D273CC 237 SendDlgItemMessageW 77D2929A 240 SendMessageW 77D2B1B0 2C CharNextW 77D31ABD 39 CheckMenuItem 77D30265 42 CloseClipboard 77D2F166 19F IsClipboardFormatAvailable 77D30277 1F3 OpenClipboard 77D1F967 137 GetMenuState 77D2D2C4 C2 EnableMenuItem 77D2D896 159 GetSubMenu 77D314BA 12C GetMenu 77D66534 1E3 MessageBoxW 77D2C2BB 281 SetWindowLongW 77D188A6 16F GetWindowLongW 77D2436E 111 GetDlgItem 77D2B112 256 SetFocus 77D2736C 254 SetDlgItemTextW 77D1A9B6 2D9 wsprintfW 77D24305 114 GetDlgItemTextW 77D24A4E C6 EndDialog 77D2910F 145 GetParent 77D318AC 2AC UnhookWinEvent 77D18A01 A2 DispatchMessageW 77D18BF6 2AA TranslateMessage 77D1941E 2A8 TranslateAcceleratorW 77D27424 1A2 IsDialogMessageW 77D18CCB 200 PostMessageW 77D191C6 13E GetMessageW 77D317F7 27E SetWinEventHook Header contains the following bound import information: Bound to comdlg32.dll [4802BDA2] Mon Apr 14 10:12:50 2008 Bound to SHELL32.dll [4802BDB6] Mon Apr 14 10:13:10 2008 Bound to WINSPOOL.DRV [4802BDCA] Mon Apr 14 10:13:30 2008 Bound to COMCTL32.dll [4802BD6C] Mon Apr 14 10:11:56 2008 Bound to msvcrt.dll [4802BD6C] Mon Apr 14 10:11:56 2008 Bound to ADVAPI32.dll [4802BD89] Mon Apr 14 10:12:25 2008 Bound to KERNEL32.dll [4802BDC6] Mon Apr 14 10:13:26 2008 Contained forwarders bound to NTDLL.DLL [4802BDC5] Mon Apr 14 10:13:25 200 8 Bound to GDI32.dll [4802BD81] Mon Apr 14 10:12:17 2008 Bound to USER32.dll [4802BDBD] Mon Apr 14 10:13:17 2008 Summary 2000 .data 8000 .rsrc 8000 .text
可以看到绑定的信息.
四 DLL HELL
windows缺乏一种很有效的DLL版本控制机制.
解决方法:
1. 静态链接
2. 防止DLL覆盖(DLL Stomping)
3. 防止DLL冲突(放到应用程序的文件夹中)
4. .NET下DLL HELL的解决方案
用一个叫Manifest的清单文件描述程序集.
相关文章推荐
- 程序员的自我修养——Windows下的动态链接
- 程序员的自我修养——第八、九章——windows下的动态链接
- 程序员的自我修养: Windows下的动态链接
- 程序员的自我修养之Windows下的动态链接
- 【程序员的自我修养】第9章 Windows下的动态链接
- 程序员的自我修养第七章读书笔记-动态链接2
- Windows下动态链接之三:DLL Hell !
- Qt项目打包发布流程(Windows平台&动态链接)
- Windows下用Codeblocks建立一个最简单的DLL动态链接库
- 动态链接的一点小总结 《程序员的自我修养》·笔记
- 初识windows编程之动态链接库
- 动态链接库中分配内存引起的问题-- windows已在XX.exe中触发一个断点
- Visual Studio Express 2013 for Windows Desktop 将c文件生成.dll动态链接库
- linux&Windows动态链接库技术实现和设计程序常用的技术
- windows编程之动态链接库的使用
- Windows与Linux动态链接库技术的对比
- windows程序设计之调用动态链接库DLL DLL的调用约定 GlobalMemoryStatusEx
- Windows下动态链接之一:DLL插件机制的装载和使用
- windows下的动态链接问题(.dll文件的编写与调用)
- 【PE】Windows平台全局变量动态链接问题