由于每个IMAGE_IMPORT_DESCRIPTOR已经指向解析的虚拟地址的RVA,因此IAT似乎是多余的。为什么要包含此数据目录?如果我覆盖IAT数据目录的RVA /大小,则二进制文件仍然可以正常运行。

我遗漏了什么吗?是否存在IAT数据目录对二进制文件运行至关重要的情况?

评论

我已经很长时间没有使用PE格式了。但是,如果我没记错的话,IAT目录会将RVA保存到导入地址表中。该表包含每个导入函数的地址。假定DLL加载在其首选地址处,则可以用函数的RVA填充它。但是,如果两个DLL具有重叠的虚拟地址,则系统可能必须将DLL加载到其他地址,在这种情况下,它将对其进行重新定位,并且IAT中的地址将是错误的。我认为在这种情况下,加载的PE会在加载时覆盖IAT。

请不要在评论中回答,谢谢。

#1 楼

首先,有几点说明
导入地址表是仅由导入函数的地址组成的表。与Import Table(由IMAGE_IMPORT_DESCRIPTOR组成)不同,IMAGE_IMPORT_DESCRIPTORS也包含在哪里查找这些导入的详细信息。
重申一下:(这有点过分简化了)Import Address Table是导入函数在内存中实际地址的数组。当前的过程。不分为模块,没有其他信息(如序数或名称)。只是所有导入函数的地址的数组。
Characteristics的结构,清理和分区方式更加合理。它们使加载程序能够找到所需的功能。您所称的“已解析虚拟地址的RVA”(在FirstThunk结构中实际上有两个IMAGE_IMPORT_DESCRIPTORIMAGE_IMPORT_DESCRIPTOR)不是指向远程DLL中的实际导入功能,而是指向导入地址表中的位置该IMAGE_IMPORT_DESCRIPTOR中的第一项。相同的IMPORT_TABLE中的后续项目也是导入地址表中的以下项目。表格位置。 IMAGE_IMPORT_DESCRIPTOR是加载程序如何知道FirstThunk s中描述的函数的导入地址表位置的原因。为什么? (又是回答您的问题)
因此,如您所见,IMAGE_IMPORT_DESCRIPTOR仅为多个导入功能保存一个地址,并且仅指向该地址(而不是如您的问题所暗示的那样直接保存该地址),因此我们可以轻松地“使用thunk”而不是“导入地址表”。
至于为什么您可以覆盖磁盘上PE的IAT中的实际内容,而所有内容仍然可以工作-隐式回答,但我也将明确回答。磁盘上的数据与FirstThunk结构中的数据相同,指针相同。但是,永远不要根据Microsoft自己的文档实际读取数据,IAT通常是在PE加载过程中填充的。我想用相关数据初始化它的原因有点像是开发人员的想法。
但是,为什么呢?您应该问一个类似的问题(实际上,这就是该问题的大致含义):
该结构仍然比以前复杂得多,这是在压缩方式(而不是作为地址包含在不同的Characteristics或其他类似结构中)实际上是一种优化。
很高兴您问到! ;)我会解释。
您可能知道,DLL被有效地加载到相同的地址中,并使用称为写入时复制的Windows机制来实际上仅具有大多数模块的单个副本。当模块映射到不同的虚拟地址时,也是如此。但是,当需要为模块填充导入的功能时,则需要写入PE结构。无论您在哪里存放地址,都必须更改。导入地址表仅用于触发尽可能少的页面写时复制(即实际的“导入地址表”页面本身)。
这部分是由于存在额外的级别PE中的间接访问从此开始。