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

Dav*_*own 4 .net c# bytearray pe-exports dumpbin

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

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

        E000 [     362] RVA [size] of Export Directory
Run Code Online (Sandbox Code Playgroud)

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

这怎么可能?

Hea*_*utt 6

PE文件包含"部分",并且这些部分具有独立的基址.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对应的文件偏移量.

您可能使用的另一种方法是使用dwDesiredAccess参数中设置MapViewOfFileEx()的标志进行调用.此API将解析PE文件中的节头,并将这些节的内容读入相对于"模块库"的位置.FILE_MAP_EXECUTE

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

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

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

  1. 将模块基地址存储在a中 char *
  2. 将RVA添加到 char *
  3. char *实际数据类型和反引用这一点.

像这些方法一样让操作系统映射文件的一个缺点是,如果你使用这个工具调查一些可疑文件,并且不确定开发人员是否对部分标题采取了奇怪的自由,那么你可能会错过一些有价值的信息通过让操作系统处理这部分解析.