一个PE文件如何映射到内存?

所以我在过去的几天里一直在研究PE格式,我还有一些问题

  1. 数据部分是否被映射到进程的内存中,或程序是否从磁盘读取?

  2. 如果它确实被映射到它的内存中,那么该过程如何能够得到该部分的偏移? (和其他部分)

  3. 有没有办法获得已经映射到内存中的进程的入口点,而不用接触磁盘上的文件?

Solutions Collecting From Web of "一个PE文件如何映射到内存?"

数据部分是否被映射到进程的内存中?

是。 这是不可能长期存活下来的,该程序容易写入该部分。 这会触发写入时复制页面副本,从而获取页面文件而不是PE文件所支持的页面。

该过程如何能够抵消该部分的偏移量?

链接器已经计算了该部分中变量的偏移量。 它可能会被重新定位,对于那些在加载DLL时已经使用的具有尴尬基址的DLL是很常见的。 在这种情况下,PE文件中的重定位表被加载器用来修补代码中的地址。 包含修补代码的页面与数据段的处理方式相同,不再由PE文件支持,不能在进程之间共享。

有什么方法可以获得进程的入口点吗?

整个 PE文件被映射到内存,包括它的头文件。 所以你当然可以在不读取文件的情况下从内存中读取IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint。 请记住,如果您为另一个进程执行此操作会很痛苦,因为您无法直接访问其虚拟地址空间。 你将不得不使用ReadProcessMemory(),这是相当少的喜悦,不太可能比阅读文件更快。 该文件很可能存在于文件系统缓存中。 地址空间布局随机化功能很容易让你头痛,目的是使这种事情很难做到。

数据部分是否被映射到进程的内存中,或程序是否从磁盘读取?

它被映射到进程的内存中。

如果它确实被映射到它的内存中,那么该过程如何能够得到该部分的偏移? (和其他部分)

通过一个重定位表:从使用直接寻址的可执行代码引用全局对象(数据或函数),在这个表中有一个条目,以便装载器打补丁码,修正原始偏移量。 请注意,您可以创建不带重定位部分的PE文件,在这种情况下,所有数据和代码部分都有固定的偏移量,并且可执行文件具有固定的入口点。

有没有办法获得已经映射到内存中的进程的入口点,而不用接触磁盘上的文件?

不确定,但如果“不触摸”你的意思是甚至没有阅读文件,那么你可以通过走上堆栈来弄清楚。

  1. 是的,PE标题中描述的所有部分都被映射到内存中。 IMAGE_SECTION_HEADER结构告诉加载器如何映射它(例如,内存段可以比内存中的磁盘大得多)。

  2. 我不太清楚,如果我明白你在问什么。 你的意思是如何从代码部分的代码知道在哪里访问数据部分中的数据? 如果模块在首选加载地址加载,那么由链接器静态生成的地址是正确的,否则加载程序会用重定位信息修复地址。

  3. 是的,窗口加载器也将PE头载入模块基址的内存中。 在那里,你可以将文件PE头中的所有信息(也是入口点)归档。

我可以推荐这篇文章的一切关于PE格式,特别是在重定位。