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

问题描述 投票:1回答:1

所以,我试图读取DLL文件,直到到达可选头数据目录,特别是它的第一个成员,导出表,一切都很好。

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

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

但是,当我单击“导出表”以查看实际内容时,程序会将该地址从内存转换为文件偏移,结果将我重定向到该地址:

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

我自己进行了一些测试,例如将hex1划分为8,因为我认为这可能是从内存对齐方式4096和文件对齐方式512过渡的结果,但是它给我的结果与hex2不同。我也做了一些奇怪的事情来尝试得出该公式,但是它给了我更奇怪的结果。

所以,我的问题是,如果我只知道数据目录(hex1)的内存偏移,我如何获取/计算文件偏移(hex2)?

portable-executable
1个回答
1
投票

假设您正在使用MSVC C / C ++,首先需要在“可选标头”之后找到IMAGE_SECTION_HEADER结构的数组。 SDK包含一个名为IMAGE_FIRST_SECTION(pNtHeaders)的宏,您只需在其中传递PE标头的指针即可简化此过程。它基本上只是跳过节头开始的内存中的可选头。此宏也可以在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都将映射到文件中的某个位置,此时您可能会显示错误消息。

© www.soinside.com 2019 - 2024. All rights reserved.