c# - 当 dumpbin 出现在比文件本身大的文件偏移处时,它如何读取导出表?

标签 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 没有这样的问题,并且可以很好地读取导出目录。是的,整个文件确实被读入了字节数组。

这怎么可能?

最佳答案

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 范围内的任何 RVA 转换为文件指针。(所有数值均为十六进制。)

无论何时遇到“RVA”(相对虚拟地址),您都可以使用以下方法将其解析为文件偏移量(或字节数组的索引):

  1. 确定 RVA 属于哪个部分。每个部分都包含从其虚拟地址到其大小的 RVA。部分不重叠。
  2. 从 RVA 中减去节的虚拟地址——这会得到相对于节的偏移量。
  3. 将节的 PointerToRawData 添加到您在步骤 (2) 中获得的偏移量。这是RVA对应的文件偏移量。

您可能使用的另一种方法是调用 MapViewOfFileEx(),并在 dwDesiredAccess 参数中设置标志 FILE_MAP_EXECUTE。该 API 将从 PE 文件中解析节标题,并将节的内容读入它们相对于“模块库”的位置。

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

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

在以这些方式加载模块的设置中,将RVA解析为普通指针值是:

  1. 将模块基地址存储在char *
  2. 将 RVA 添加到 char *
  3. char * 转换为实际数据类型并取消引用。

在这些方法中让操作系统映射文件的一个缺点是,如果您使用此工具调查一些可疑文件并且不确定开发人员是否对节标题采取了奇怪的自由,您可能会错过通过让操作系统处理这部分解析来获取一些有值(value)的信息。

关于c# - 当 dumpbin 出现在比文件本身大的文件偏移处时,它如何读取导出表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1569900/

相关文章:

c# - 带/不带支持字段的二进制格式化程序和属性

c# - byte[] 到 bool[] 用作标志,反之亦然

c# - 使用 while 循环取消查询永远挂起

c# - 在 VS 2015 中将程序集添加到类库

.net - HTTP 方法 GET、POST、PUT 和 DELETE 之间有什么区别

c# - Entity Framework 代码优先与 T4 模板

c# - 使用反射从 C# 中嵌套类型的 DeclaringType 获取泛型类型

android - java.io.FileNotFoundException :/file/path. jpg 打开失败:ENOENT(没有这样的文件或目录)

.net - 将字节数组转换为 int 的更快方法

用于大量项目的 C# 字典