我正在实施一个用于执行某些 PE 分类的软件。在这些功能中的值,我从每个PE聚集是,该部分的ammount的,该部分的名称,图像章节标题。
我一直在阅读有关ImageHlp 结构的信息。但是没有关于如何从您传递的文件/path_to_a_file 初始化这些结构的示例。我对IMAGE_SECTION_HEADER结构特别感兴趣。
如何以编程方式从可执行文件中获取IMAGE_SECTION_HEADER?
我正在实施一个用于执行某些 PE 分类的软件。在这些功能中的值,我从每个PE聚集是,该部分的ammount的,该部分的名称,图像章节标题。
我一直在阅读有关ImageHlp 结构的信息。但是没有关于如何从您传递的文件/path_to_a_file 初始化这些结构的示例。我对IMAGE_SECTION_HEADER结构特别感兴趣。
如何以编程方式从可执行文件中获取IMAGE_SECTION_HEADER?
我在Windows上解析PE有丰富的经验,主要用于函数拦截。以下是实现目标应遵循的步骤。
第一步是找到加载到内存中的图像的基地址。这一步会根据可执行文件是否已映射到内存而有所不同,但基本思想是相同的。假设您有兴趣为磁盘上的文件执行此操作,那么您可以使用文件映射 API执行此操作,如果您希望在作为运行进程加载到内存中的可执行文件上执行此操作,则可以通过使用来实现等效该工具帮助快照 API。基地址将与从快照检索hModule
的MODULEENTRY32
数据中的字段相同。有关什么是模块句柄的更多信息,请参见此处。
完成第一步后,基地址的结构是IMAGE_DOS_HEADER
,虽然 MSDN 上没有记录,但它有两个非常重要但神秘的字段。您需要知道的两个字段是e_magic
字段和e_lfanew
字段。该e_magic
字段包含一个用于 32 位的双字或用于 64 位的四重字,允许您测试正在读取的文件或您的实现是否正确格式化,正确的值定义为IMAGE_DOS_SIGNATURE
,这是“MZ”的 ASCII-Z 字符串\0”。该e_lfanew
字段包含一个相对虚拟地址,其需要添加到在步骤之一中找到,以计算图像碱虚拟地址的的IMAGE_NT_HEADERS
结构。
第三步是检查 的第一个成员,IMAGE_NT_HEADERS
看它是否是一个实际的PE文件,这将由Signature
结构体的字段定义,并且要测试的定义常量是IMAGE_NT_SIGNATURE
. 这通常不是必需的,因为大多数 Windows 版本将使用可执行文件的 PE 格式,但这是一种很好的做法,以确保您的代码更加健壮。
一旦一切检查完毕并且您已经执行了第 1-3 步,您就可以在第 4 步最终计算IMAGE_SECTION_HEADER
结构的地址。IMAGE_SECTION_HEADER 结构体作为数组存储在文件中,因此要获得数组的大小,您需要使用嵌套在上述结构体中的结构体中的NumberOfSections
成员。一旦获得该值,您可能会发现虚拟地址首先加上结构成员的大小,结构中成员的大小,最后是结构中的值。您不能简单地对上面列出的公式中的最后一个值执行 a 的原因是因为磁盘上的文件不会IMAGE_FILE_HEADER
IMAGE_NT_HEADERS
IMAGE_SECTION_HEADER
Signature
IMAGE_NT_HEADERS
FileHeader
IMAGE_NT_HEADERS
SizeOfOptionalHeader
IMAGE_FILE_HEADER
sizeof(
IMAGE_OPTIONAL_HEADER
)
有IMAGE_OPTIONAL_HEADER
,所以要动态获得合适的大小,你应该通过我前面提到的结构成员来做到这一点。
现在,您可以随意IMAGE_SECTION_HEADER
从内存中复制结构数组。请记住,这些结构在内存中是连续的,因此您需要做的就是将每个结构的大小乘以节数,以找到整个数组在内存中的总大小。计算出该值后,收集数据就很简单了。
有关 PE 可执行格式的更多资源,请参阅 Matt Pietrek 撰写的这篇精彩文章Peering Inside the PE。您也可以在此处查看官方规范。