第十九章 DLL基础

来源:互联网 发布:全面战争mac 编辑:程序博客网 时间:2024/04/29 02:57

一、目的

        在应用程序调用DLL中的函数之前、必须把该DLL映射到进程的地址空间中。分两种方式:隐式链接和显示运行时链接。

二、隐式链接

       1、DLL模块显式声明需要导出的函数和变量(dllexport)

       2、DLL模块根据导出的内容生成导出段

             rodinal(函数编号:GetProcAddress可以用此得到函数地址)

             hint(索引:便于查找提高性能) 

             RVA(相对地址:DLL基地址确定后,加上此地址就是函数or变量进程地址空间中的地址了) 

             name(函数名称:GetProcAddress可以用此得到函数地址)

      3、DLL同时在链接阶段生成.lib文件,里面仅仅包含dll导出的符号,用于链接可执行文件时确定导入符号源自哪个DLL

            (注:DLL在导出函数时会对函数进行重命名,如果不想改编函数名,有两个办法

                        1、创建.def文件,包含导出函数名即可;

                        2、利用如#pragma comment(linker,"/export:MyFunc=_MyFunc@8") 导出函数名

              )

      4、可执行文件或者其他DLL包含DLL头文件(此时头文件被声明为dllimport),引用导出函数或者变量(可显式声明extern 或者dllimport,略微提升性能)

      5、可执行文件或者DLL根据引用的外部符号创建导入段;导入段包含dll名称,以及从此dll导入的符号的名称和地址。

      6、启动可执行文件时 :

            首先为进程创建虚拟地址空间,将可执行文件映射到地址空间;

            然后扫描导入段,将其他DLL映射到地址空间;(可预生成基地址,减少DLL基地址重定位,在程序安装阶段)

            最后根据DLL基地址和DLL导出段导出符号相对地址相加得到最终符号地址,修复可执行文件导入段导入符号地址。线程最终使用的就是导入符号地址;(可使用DLL绑定技术,预生成导入符号地址,在程序安装阶段)

三、显式链接

       1、LoadLibrary 显式将DLL映射到地址空间中(GetModuleHandle只是获取已映射的DLL)。

       2、FreeLibrary 显式卸载DLL(有时候某DLL创建了一个线程,如果该线程Free此DLL后,则FreeLibrary后面的代码就不存在了,因此有FreeLibraryAndExitThread函数)。

       3、GetProcAddress 获取某DLL的一个导出函数(通过函数编号,或者是名字)。

       4、DLL入口点DllMain(映射DLL时,卸载DLL时,创建线程时和销毁线程时都会进入,如果调用了DisableThreadLibraryCalls则在创建线程时和销毁线程时不会进入) 。

 四、延迟载入DLL技术

       1、使用/Lib:DelayImp.lib 将_delayLoadHelper2嵌入到代码中(此函数调用LoadLibrary 和GetProcAddress )。

       2、使用/DelayLoad:MyDll.dll 将MyDll.dll从导入段中去掉,增加一个延迟段,对延迟载入DLL的函数的调用实际上调用的就是_delayLoadHelper2。

       3、使用/Delay:unload 则可以使用_FUnloadDelayLoadedDLL2 来卸载延迟载入DLL,这样它会清空延迟段的函数地址。

       4、_delayLoadHelper2 可以调用挂钩函数

五、其他

       1、函数转发器:#pragma comment(linker,"/export:MyFunc=OtherDLL._MyFunc") 导出名为MyFunc的函数,但是此函数的入口点在OtherDLL中的_MyFunc

       2、已知的DLL:LoadLibrary(L"SomeLib") 会通过正常规则搜索,LoadLibrary(L"SomeLib.dll") 会去掉后缀,然后在KnownDLLs 注册表项查找相同键值得到真正的DLL名称,然后在DllDirectory路径下搜索DLL,如果找不到则返回失败。

       3、DLL重定位:为了强制系统优先从应用程序目录开始查找,可以在应用程序目录创建一个名为xx.exe.load的文件来告诉LoadLibrary 从此应用程序目录开始搜索。    

0 0
原创粉丝点击