当dumpbin出现在大于文件本身的文件偏移量时,它是如何读取导出表的?

时间:2009-10-15 01:47:05

标签: c# .net bytearray pe-exports dumpbin

我正在编写一个小型PE阅读器,因此我在我的测试应用程序旁边运行dumpbin以确认正确读取了值。到目前为止它所做的一切,除了出口表。

我正在测试的文件是DLL。我的应用程序以字节数组的形式读取文件,并将其传递给我的PE读取器类。这些值与dumpbin输出的值一致,包括RVA和导出数据目录的大小。

        E000 [     362] RVA [size] of Export Directory

问题是,字节数组的大小只有42,496。你可以想象,当我的PE读者试图在E000(57,344)阅读时,我得到一个IndexOutOfRangeException。但是,dumpbin没有这样的问题,并且读取导出目录就好了。是的,整个文件确实被读入字节数组。

这怎么可能?

1 个答案:

答案 0 :(得分:6)

PE文件包含“sections”,这些部分具有独立的基址。 PE不是连续的内存映像。每个部分都是一个连续的记忆图像。

首先,您必须阅读部分信息并制作其布局的内存映射。然后,您将能够将截面偏移与基于文件的偏移对齐。

顺便说一下,考虑一下OllyDbg,它是Windows的免费软件,开源调试器和反汇编程序。它可能会帮助您测试自己的软件,并可能通过“自己动手”来满足您的目的。

来自dumpbin /all输出的示例:

SECTION HEADER #1
   .text name
    BC14 virtual size
    1000 virtual address (00401000 to 0040CC13)
    BE00 size of raw data
     400 file pointer to raw data (00000400 to 0000C1FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         Execute Read

在这种情况下,我的.text部分从RVA 1000开始并扩展到RVA CE00。指向此部分的文件指针是400.我可以通过减去600的工作将1000-CDFF范围内的任何RVAs转换为文件指针。(所有数值都是十六进制的。)

每当遇到“RVA”(相对虚拟地址)时,使用此方法将其解析为文件偏移量(或字节数组的索引):

  1. 确定RVA属于哪个部分。每个部分包含其虚拟地址及其大小的RVAs。部分不重叠。
  2. 从RVA中减去部分虚拟地址 - 这将为您提供相对于该部分的偏移量。
  3. 将部分的PointerToRawData添加到您在步骤(2)中获得的偏移量。这是与RVA对应的文件偏移量。
  4. 您可以使用的另一种方法是使用 dwDesiredAccess 参数中设置的标记MapViewOfFileEx()来调用FILE_MAP_EXECUTE。此API将解析PE文件中的节头,并将这些节的内容读入相对于“模块库”的位置。

    模块库是加载PE头的基地址。使用LoadLibrary()函数加载DLL时,可以通过GetModuleInformation()函数的MODULEINFO成员 lpBaseOfDll 获取。

    使用MapViewOfFileEx()时,模块库只是MapViewOfFileEx()的返回值。

    在以这些方式加载模块的设置中,将RVA解析为正常指针值是一个问题:

    1. 将模块基地址存储在char *
    2. 将RVA添加到char *
    3. char *转换为实际数据类型并取消引用。
    4. 让OS按照这些方法映射文件的一个缺点是,如果您使用此工具调查某些可疑文件,并且不确定开发人员是否对部分标题采取了奇怪的自由,那么您可能会错过让操作系统处理这部分解析的一些有价值的信息。