我正在编写一个小型PE阅读器,因此我在我的测试应用程序旁边运行dumpbin以确认正确读取了值。到目前为止它所做的一切,除了出口表。
我正在测试的文件是DLL。我的应用程序以字节数组的形式读取文件,并将其传递给我的PE读取器类。这些值与dumpbin输出的值一致,包括RVA和导出数据目录的大小。
E000 [ 362] RVA [size] of Export Directory
问题是,字节数组的大小只有42,496。你可以想象,当我的PE读者试图在E000(57,344)阅读时,我得到一个IndexOutOfRangeException
。但是,dumpbin没有这样的问题,并且读取导出目录就好了。是的,整个文件确实被读入字节数组。
这怎么可能?
答案 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”(相对虚拟地址)时,使用此方法将其解析为文件偏移量(或字节数组的索引):
您可以使用的另一种方法是使用 dwDesiredAccess 参数中设置的标记MapViewOfFileEx()
来调用FILE_MAP_EXECUTE
。此API将解析PE文件中的节头,并将这些节的内容读入相对于“模块库”的位置。
模块库是加载PE头的基地址。使用LoadLibrary()
函数加载DLL时,可以通过GetModuleInformation()
函数的MODULEINFO
成员 lpBaseOfDll 获取。
使用MapViewOfFileEx()
时,模块库只是MapViewOfFileEx()
的返回值。
在以这些方式加载模块的设置中,将RVA解析为正常指针值是一个问题:
char *
char *
char *
转换为实际数据类型并取消引用。让OS按照这些方法映射文件的一个缺点是,如果您使用此工具调查某些可疑文件,并且不确定开发人员是否对部分标题采取了奇怪的自由,那么您可能会错过让操作系统处理这部分解析的一些有价值的信息。