PE格式自检

Posted

技术标签:

【中文标题】PE格式自检【英文标题】:Self inspection of the PE format 【发布时间】:2015-04-12 08:40:55 【问题描述】:

可移植的可执行文件即使在附加数据后仍然有效。据我所知,这是由于可执行代码的偏移+大小性质造成的。

我有一个类似于 Winzip 的 Zip2Exe 的可执行打包应用程序。到目前为止,我一直在将压缩的有效载荷添加到可执行存根的末尾,然后是一个 8 字节的值,表示有效载荷的大小(以字节为单位)。

我想做的是让可执行存根计算自己的大小,并将剩余的字节假定为有效负载,而没有任何大小信息。这纯粹是出于好奇,我真正想知道的是 PE 是否可以计算自己的大小并检测是否添加了任何东西。

当然,我知道如果它们被注入或其他方式更改,它无法验证它自己的内容。

为了澄清这个问题,我想要 .NET 中的一个函数来检查 Assembly.GetExecutingAssembly().Location 并确定附加有效负载的偏移量可能是多少。如果此偏移量与文件大小相同,则不会有有效负载。

【问题讨论】:

【参考方案1】:

请注意,我对 C# 不太熟悉,所以这是一个一般性的答案。

由于Assembly.GetExecutingAssembly().Location 似乎返回图像的路径,您有一个“平面”文件路径,即磁盘上的图像而不是内存中的图像。解析比在内存中更容易,并且您已经知道它是一个有效的 PE 文件,因此您可以跳过所有有效性检查。

由于您将使用 C# 浏览图像文件,因此您可能需要检查“Exploring pe file headers using managed code”以及Pinvoke.net 上的各种结构。

要查找图像文件末尾是否有有效负载:

打开文件:) 获取文件大小 文件以 IMAGE_DOS_HEADER (pinvoke) 开头 关注e_lfanew会员,查找IMAGE_NT_HEADERS IMAGE_NT_HEADERS 有两种类型(pinvoke;msdn):IMAGE_NT_HEADERS32(PE32:32 位 PE)和 IMAGE_NT_HEADERS64(PE32+:64 位 PE) 在 IMAGE_NT_HEADERS 中,SignatureFileHeader(IMAGE_FILE_HEADER 结构)字段相同,只有 OptionalHeader 会改变。 检查来自 IMAGE_FILE_HEADER (pinvoke ; msdn) 的 Machine 以查看您拥有的类型:0x014c (Intel 386) = PE32 ; 0x8664 = PE32+ 从 IMAGE_FILE_HEADER 获取NumberOfSections字段。 完全跳过(跳过)IMAGE_NT_HEADERS 结构:无论其类型是什么,它的大小都是恒定的。 您会遇到IMAGE_SECTION_HEADER (pinvoke ; msdn) 的数组。此数组中的条目数是NumberOfSections字段(来自IMAGE_FILE_HEADER)。 在IMAGE_SECTION_HEADER 数组中找到所有PointerToRawData 字段中的最大值/最高值(这通常是数组中的最后一个条目,但您应该检查数组中的所有条目以确定)。 您现在有了最后一节开头的文件偏移量。 从PointerToRawData 最高的IMAGE_SECTION_HEADER,得到SizeOfRawData 字段。 你现在有最后一节的大小 同时添加PointerToRawDataSizeOfRawData 字段:如果结果小于文件大小,您就会知道PE 文件末尾有一个有效负载。

简单(可视)示例:

上图代表所有来自calc.exe的IMAGE_SECTION_HEADER。如您所见,PointerToRawData(标记为“原始地址”)的最大值为 0xE3A00,相应的节大小(SizeOfRawData,标记为“原始大小”)为 0x600。

0xE3A00 + 0x600 = 0xe4000 = 933888

calc.exe的文件大小相同(933888字节):

因此,文件末尾没有有效负载。如果文件大小已大于 933888(由上述计算得出),则文件末尾会有一个有效负载。

【讨论】:

这太棒了,包括指向PE Headers in Managed Code 的链接。谢谢!

以上是关于PE格式自检的主要内容,如果未能解决你的问题,请参考以下文章

PE文件格式详解,第一讲,DOS头文件格式

PE文件格式偏移参考

PE文件格式偏移参考

PE文件格式学习之PE头移位

PE文件格式

PE文件格式分析