【问题标题】:How can i calculate the file offset of the memory virtual address of the export table?如何计算导出表的内存虚拟地址的文件偏移量?
【发布时间】:2020-06-19 23:37:47
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

    标签: portable-executable


    【解决方案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 转换为文件偏移量所需的一切。第一个范围检查每个 IMAGE_SECTION_HEADER 的 VirtualAddress 与您正在查找的 RVA。即:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      相关资源
      最近更新 更多