Windows Loader

Windows Loader

ID:39991646

大小:321.69 KB

页数:19页

时间:2019-07-16

Windows Loader_第1页
Windows Loader_第2页
Windows Loader_第3页
Windows Loader_第4页
Windows Loader_第5页
资源描述:

《Windows Loader》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库

1、Windows加载器与模块初始化作者:MattPietrek在最近的MSJ专栏(1999年六月)中,我讨论了COM类型库和数据库访问层,例如ActiveX®数据对象(ADO)和OLEDB。MSJ专栏的长期读者可能认为我已经不行了(写不出技术层次比较高的文章了)。为了重振雄风,这个月我要讲解一部分WindowsNT®加载器代码,它是操作系统和你的代码接合的地方。同时,我也会向你演示一些获取加载器状态信息的高超技巧,以及可以用在DeveloperStudio®调试器中的相关技巧。考虑一下你对EXE、DLL以及它们是如何被

2、加载的和初始化的到底知道多少。你可能知道当一个用C++写成的DLL被加载时,它的DllMain函数会被调用。想一想当你的EXE隐含链接到一些DLL(例如,KERNEL32.DLL和USER32.DLL)时到底发生了什么。这些DLL是以什么顺序被初始化的?某个DLL将要被初始化,而它所依赖的其它DLL还未被初始化,这可能吗?PlatformSDK在“DynamicLinkLibraryEntryPointFunction(动态链接库入口点函数)”一节中对此描述如下:“你的函数应该仅进行一些简单的初始化任务,例如设置线程

3、局部存储(TLS),创建同步对象和打开文件等。它绝对不能调用LoadLibrary函数,因为这可能在DLL加载顺序上造成循环依赖。这可能导致即将使用一个DLL但是系统还未对它进行初始化。同样,你也不能在入口点函数中调用FreeLibrary函数,因为这可能导致即将使用一个DLL但是系统已经执行完了它的终止代码。”“调用除TLS函数、同步函数和文件函数之外的Win32®函数也可能引起很难诊断的问题。例如,调用User函数、Shell函数和COM函数可能引起访问违规,因为这些DLL中一些函数调用LoadLibrary加载

4、其它系统组件。”看了上述文档后我的第一反应是它太含糊了。例如你想在自己的DllMain函数中读取注册表是再正常不过的事了,它当然可以作为初始化的一部分。但不幸的是,在你的DllMain代码开始执行时ADVAPI32.DLL还没有初始化。这样,对注册表API的调用将会失败。在上述文档中对使用LoadLibrary给出了严厉的警告。但非常有趣的是,WindowsNT的USER32.DLL却明确地忽略前面的忠告。你可能知道WidnowsNT上的一个注册表键AppInit_Dlls,它用来加载一系列DLL到每个进程。事实表明

5、,是USER32在初始化时加载这些DLL的。USER32在它的DllMain代码中查看这个注册表键并调用LoadLibrary加载这些DLL。稍微思考一下就会知道,如果你的应用程序不使用USER32.DLL的话,AppInit_Dlls这个技巧就不能发挥作用。不过,这有点跑题了。我之所以要讲解这方面的内容是因为DLL的加载与初始化还是一片盲区。在大多数情况下,对操作系统加载器是如何工作的有一个简单的印象就足够了。然而,在极少数情况下,除非你对操作系统加载器的行为方式有比较详细的了解,否则就会陷入困境之中。加载器醒来!

6、大多数程序员所认为的模块加载过程实际上分为两个截然不同的步骤。第一步是把EXE或DLL映射进内存。此时加载器查看模块的导入地址表(IAT)来判断这个模块是否依赖于其它DLL。如果它依赖的DLL还未被加载进那个进程,加载器也将它们映射进内存。这个过程递归进行,直到所有依赖的模块都被映射进内存。要查看一个可执行文件隐含依赖的所有DLL,最好的方法是使用PlatformSDK附带的DEPENDS程序。第二步是初始化所有DLL。在第一步中,当操作系统把EXE和DLL映射进内存时,它并不调用相应的初始化例程。初始化例程是在所有

7、模块都被映射进内存之后才被调用的。关键是:DLL被映射进内存的顺序并不需要与它们被初始化的顺序一样。我曾经见到有人看到DeveloperStudio调试器中对DLL映射时的通知而误认为DLL是以相同的顺序被初始化的。在WindowsNT中,调用EXE和DLL入口点代码的例程被称为LdrpRunInitializeRoutines。在平常的工作中,我已经多次跟踪到LdrpRunIntializeRoutines的汇编代码中。但是,看着大堆的汇编代码并不是理解它的好方法。因此,我用类似C++的伪代码重写了WindowsN

8、T4.0SP3的LdrpRunInitializeRoutines函数,如图1所示。实际上,在NTDLL.DBG中这个例程的名字按__stdcall调用约定被粉碎成了_LdrpRunInitializeRoutines@4。在伪代码中,除了那些名字前面加了下划线的,其余的都是我起的名字。在WindowsNT加载器代码中,LdrpRunIniti

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。