gpt4 book ai didi

c++ - 加载程序如何将 DLL 映射到进程地址空间

转载 作者:可可西里 更新时间:2023-11-01 17:08:42 27 4
gpt4 key购买 nike

我很想知道加载程序如何将 DLL 映射到进程地址空间。 loader 是如何做到这一点的。高度赞赏示例。

提前致谢。

最佳答案

好吧,我假设这里的事情是 Windows 方面的。加载 PE 文件时发生的事情是加载程序(包含在 NTDLL 中)将执行以下操作:

  1. 使用 DLL 搜索语义(系统和补丁级别特定)定位每个 DLL,众所周知的 DLL 可以免于此
  2. 将文件映射到内存 (MMF),其中页面是写时复制 (CoW)
  3. 遍历导入目录并在点 1 处(递归地)开始每个导入。
  4. 解决重定位问题,大多数情况下这只是非常有限数量的实体,因为代码本身是位置无关代码 (PIC)
  5. (IIRC) 将 EAT 从 RVA(相对虚拟地址)修补到 VA(当前进程内存空间内的虚拟地址)
  6. 修补 IAT(导入地址表)以使用进程内存空间中的实际地址引用导入
  7. 对于 EXE 的 DLL 调用 DLLMain() 创建一个线程,其起始地址位于 PE 文件的入口点(这也被过度简化了,因为实际的起始地址在 kernel32.h 中)。 Win32 进程的 dll)

现在,当您编译代码时,它取决于链接器如何引用外部函数。一些链接器创建 stub ,以便 - 理论上 - 尝试检查函数地址是否为 NULL 总是会说它不是 NULL。这是一个怪癖,您必须知道链接器是否以及何时受到影响。其他人直接引用 IAT 条目,在这种情况下,未引用的函数(想想延迟加载的 DLL)地址可以为 NULL,然后 SEH 处理程序将调用延迟加载助手并(尝试)解析函数地址,然后在点失败。

上述过程中涉及很多繁文缛节,我简化了。

您想知道的要点是映射到进程中是作为 MMF 发生的,尽管您可以人为地模仿堆空间的行为。但是,如果您还记得有关 CoW 的要点,那就是 DLL 概念的关键。实际上,(大部分)DLL 页面的相同拷贝将在加载特定 DLL 的进程之间共享。未共享的页面是我们写入的页面,例如在解决重定位和类似问题时。在这种情况下,每个进程都有一个(现在已修改)原始页面的拷贝。

关于 DLL 上的 EXE 加壳器的警告。它们完全击败了我描述的这种 CoW 机制,因为它们在加载 DLL 的进程的堆上为 DLL 的解压缩内容分配空间。因此,虽然实际文件内容仍被映射为 MMF 并共享,但解压后的内容对于加载 DLL 的每个进程占用相同数量的内存,而不是共享它。

关于c++ - 加载程序如何将 DLL 映射到进程地址空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/336759/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com