我一直在阅读有关ImageHlp结构的信息。但是,没有关于如何从传递的文件/ path_to_a_file中初始化那些结构的示例。我对IMAGE_SECTION_HEADER结构特别感兴趣。
如何以编程方式从可执行文件中获取IMAGE_SECTION_HEADER?
#1 楼
我在Windows上解析PE方面具有丰富的经验,主要用于函数拦截。以下是实现目标所应遵循的步骤。第一步是找到加载到内存中的图像的基地址。根据可执行文件是否已映射到内存,此步骤将有所不同,但是基本思路是相同的。假设您有兴趣对磁盘上的文件执行此操作,则可以使用文件映射API进行此操作,如果您希望在作为运行进程加载到内存的可执行文件上实现此功能,则可以通过使用工具帮助快照API。基址将与从快照检索到的
hModule
数据中的字段MODULEENTRY32
相同。有关模块句柄是什么的更多信息,请参见此处。完成第一步后,基地址的结构为
IMAGE_DOS_HEADER
,尽管MSDN上未对此进行记录,但它具有两个非常重要但神秘的领域。您将需要知道的两个字段是e_magic
字段和e_lfanew
字段。 e_magic
字段包含一个用于32位的双字或一个用于64位的四字,可让您测试是否正在读取文件或实现是否被正确格式化,且正确的值定义为IMAGE_DOS_SIGNATURE
,即ASCII-Z字符串“ MZ \ 0”。 e_lfanew
字段包含一个相对虚拟地址,您需要将该相对虚拟地址添加到在第一步中找到的映像库中,以计算IMAGE_NT_HEADERS
结构的虚拟地址。第三步将检查第一个成员
IMAGE_NT_HEADERS
的值以查看它是否是实际的PE文件,这将由结构的Signature
字段定义,并且要测试的已定义常数将为IMAGE_NT_SIGNATURE
。通常这不是必需的,因为大多数Windows版本将使用可执行文件的PE格式,但这是一种很好的做法,可以确保您的代码更加健壮。一切检查完毕并执行了步骤1-3后,第四步即是您终于可以计算出
IMAGE_SECTION_HEADER
结构的地址了。 IMAGE_SECTION_HEADER结构以数组形式存储在文件中,因此要获取数组的大小,您将需要使用嵌套在上述NumberOfSections
结构中的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
,因此要动态获取适当的大小,您应该通过结构成员I前面已经提到过。现在,您可以随意从内存中复制
IMAGE_SECTION_HEADER
结构数组。请记住,这些结构在内存中是连续的,因此您要做的就是将每个结构的大小乘以段数,以找到内存中整个数组的总大小。计算完该值之后,收集数据将变得很简单。有关PE可执行格式的更多资源,请参见PE深入PE中的Matt Pietrek撰写的精彩文章。您也可以在这里查看官方规格。
评论
努力,但有许多小问题。 1)DOS标头的e_magic始终是一个WORD(16位),不能是32或64位; 2)IMAGE_DOS_SIGNATURE与两个字符的“ MZ”序列匹配-不需要零终止符; 3)严格来说,e_lfanew是文件偏移量而不是RVA(尽管在这种情况下它们恰好匹配); 4)IMAGE_OPTIONAL_HEADER确实存在于磁盘上的文件中,它并不是仅仅因为您使用文件映射而神奇地出现; 5)之所以需要使用SizeOfOptionalHeader,是因为某些恶意软件/打包程序使用的值与sizeof(IMAGE_OPTIONAL_HEADER)不同。
–伊戈尔·斯科钦斯基♦
2014年8月15日23:05
@Igor糟糕,我在想一个目标文件。我的错。
–船长很明显
2014年8月15日23:12
提到的“文件映射API”仅适用于Windows。各种来源都对PE格式进行了详细描述,实际上并不需要使用Windows API-例如,我在Mac上从头开始编写了最新的PE反汇编程序。
–杂件
2014年8月15日在23:13
@Jongware好吧,如果他愿意的话,他总是可以使用一些第三方库以更可移植的方式解析PE。 Windows是我使用的唯一操作系统,因此如果有人想为其他系统提供答案,请随意。他发布的参考资料适用于Windows实现,因此我这样回答了这个问题。
–船长很明显
2014年8月15日在23:18
是的,您是正确的,OP确实似乎正在使用Windows。我的load_exec源代码是(..检查)接近300行代码,它使用了结构和#define的另外250行左右。总而言之,仅加载可执行文件就需要大约2,000行C代码(注意,它还显示了大量的调试数据)。对于RE回答,我可能会冒太多的危险。
–杂件
2014年8月15日在23:28
评论
PE格式有据可查。手动解析文件。尽管示例在python中,但该页面可以作为参考。除此之外,您可以使用预构建的解析器库,例如pe-parse