有关在加载地址空间中加载DLL的问题

那么,我读了几个Matt Pietrek关于可移植可执行文件(PE)文件的文章,例如:

  • 深入了解Win32可移植可执行文件格式, 第1 部分和第2部分
  • MSJ关于连接器的文章
  • MSJ关于COFF格式的文章

另外,我已经读了一些关于这个问题的其他资料。 这是要么我忽略了一些部分,或者这些问题没有在那里回答。

所以,这里是问题:

众所周知,在加载EXE时,Windows Loader会从Importa地址表(IAT)中读取导入的DLL列表,并将它们加载到进程地址空间中。

  1. 进程地址空间是一个虚拟空间。 该DLL可能已经加载到一些物理空间。 这发生在像KERNEL32.dllUSER32.dll这样的DLL上。 物理和虚拟地址之间的关系是什么? 加载器是只分配页面并复制DLL,还是它引用?

  2. 如果没有加载DLL,Loader是加载整个DLL,还是只加载所需的函数? 例如,如果您使用bar.dll函数foo() ,则加载器是否将整个bar.dll加载到进程地址空间中? 或者,它只是加载foo的代码到进程地址空间?

  3. 假设您的EXE文件使用驻留在%WINDIR%\system32\user32.dll USER32.DLL函数MessageBox() 。 你能开发一个自定义的USER32.DLL ,把它放在你的EXE文件所在的目录下,并且期望你的自定义的MessageBox被你的应用程序调用,而不是系统默认的MessageBox

Solutions Collecting From Web of "有关在加载地址空间中加载DLL的问题"

回复1:物理地址不起作用,这里涉及的所有内容都是虚拟内存。 物理地址只有当虚拟内存页面被映射到RAM时才会被建立,由页面错误触发。 许多基本DLL出现在几个进程的相同的虚拟内存地址,如kernel32.dll。 这些过程只是共享相同的代码页面(而不是数据)。

Re 2:没有发生实际的“加载”,使用的功能与支持内存映射文件的功能相同。 这些页面的支持是DLL文件本身,而不是页面文件。 直到页面错误迫使Windows从文件读取页面到RAM中,才会加载任何内容。 但是,是的,DLL的整个代码部分被映射。

回答3:是的,这将工作。 但是在实践中几乎不可能实现,因为你必须为程序使用的所有 user32输出编写替换函数。 包括其他Win32函数使用的那些,你不知道。 API挂钩是使用的典型技术,来自Microsoft Labs的Detours是一个不错的选择。

Windows内部版本5是一个很好的书,了解更多关于管道。

1)当你创建新进程时,NT内核加载程序为进程分配空间并映射指定位置上的所有PE节。 然后NT加载程序通过导入表来查找,在进程内存中加载DLL并在必要时更正指针(称为重定位)。

2)Loader在进程地址空间中加载整个DLL。

3)是的,它将使用EXE所在的目录下的user32.dll 。 看到这个链接 。 但是作为位于user32.dll的大多数WinAPI函数,您的自定义dll必须导出它们中的大部分。