我如何计算导出table的内存虚拟地址的文件偏移量?

How can i calculate the file offset of the memory virtual address of the export table?

所以,我试图读取一个 DLL 文件,一切正常,直到我到达可选 Header 数据目录,特别是它的第一个成员,导出 Table.

我的问题是我无法移动 reader 的偏移量,因为虚拟地址成员基于内存 VA,而我的 reader 基于文件偏移量。一个直观的例子可能会有所帮助:

如您所见,此 PE 查看器在数据目录的导出 Table 地址(可选 Header)处读取的加载虚拟地址的值为 0x00002630(我们将其称为hex1 从现在开始)。

然而,当我点击导出 Table 查看实际内容时,程序将这个地址从内存转换为文件偏移量,结果将我重定向到这个地址:

它重定向到我的地址是0x00001a30(从现在开始我们称它为hex2)。

我自己做了一些测试,比如将 hex1 除以 8,因为我认为这可能是从 4096 的内存对齐到 512 的文件对齐的转换,但它没有给我相同的结果十六进制2。我也做了一些奇怪的事情来尝试得到那个公式,但它给了我更奇怪的结果。

所以,我的问题是,如果我只知道数据目录 (hex1) 的内存偏移量,我怎么能 get/calculate 那个文件偏移量 (hex2)?

假设您使用的是 MSVC C/C++,您首先需要在 Optional Header 之后找到 IMAGE_SECTION_HEADER 结构的数组。 SDK 有一个名为 IMAGE_FIRST_SECTION(pNtHeaders) 的宏,您只需在其中传递 PE 的指针 header 即可简化此过程。它基本上只是跳过内存中可选的 header,这是 headers 部分开始的地方。此宏也适用于 32 位或 64 位 Windows PE 文件。

一旦获得 IMAGE_SECTION_HEADER 数组的地址,就可以使用指针数学循环遍历结构直到 FileHeader.NumberOfSections。每个结构都描述了每个命名 PE 部分的内存地址 (VirtualAddress) 的相对起始位置,以及您加载的文件中该部分的文件偏移量 (PointerToRawData)。

文件中部分的大小为 SizeOfRawData。此时,您现在拥有将任何给定 RVA 转换为文件偏移量所需的一切。第一个范围用您正在查找的 RVA 检查每个 IMAGE_SECTION_HEADER 的 VirtualAddress。即:

if (uRva >= pSect->VirtualAddress && (uRva < (pSect->VirtualAddress + pSect->SizeOfRawData))
{
    //found
}

如果找到匹配部分,则从查找 RVA 中减去 VirtualAddress,然后添加 PointerToRawData 偏移量:

uFileOffset = uRva - pSect->VirtualAddress + pSect->PointerToRawData

这导致从对应于该 RVA 的文件的开头开始偏移。此时您已将 RVA 转换为文件偏移量。

注意:由于填充、不正确的 PE 文件等原因,您可能会发现并非所有 RVA 都会映射到文件中的某个位置,此时您可能会显示错误消息。