简体   繁体   English

自我检查PE格式

[英]Self inspection of the PE format

Portable executable files remain valid even after data is appended to them. 即使数据被附加到便携式可执行文件,它们仍然有效。 As far as I can tell, this is due to the offset+size nature of executable code. 据我所知,这是由于可执行代码的偏移+大小性质。

I have an executable packaging application similar to Zip2Exe from Winzip. 我有一个类似于Winzip的Zip2Exe的可执行打包应用程序。 So far, I have been adding compressed payloads to the end of the executable stub followed by an 8 byte value representing the size in bytes of the payload. 到目前为止,我一直在可压缩有效负载添加到可执行存根的末尾,后跟一个8字节值,表示有效负载的字节大小。

What I'd like to do is to have the executable stub calculate its own size and assume the remaining bytes as the payload without having any size information. 我想要做的是让可执行存根计算自己的大小,并假设剩余的字节作为有效负载而没有任何大小信息。 This is purely out of curiosity and what I really want to know is can a PE calculate its own size and detect if anything has been added to it. 这纯粹是出于好奇,而我真正想知道的是PE可以计算出自己的大小并检测是否有任何添加。

Of course, I understand that it cannot verify it's own content if they have been changed by injection or otherwise. 当然,我知道如果通过注入或其他方式更改了它自己的内容,它就无法验证它。

To clarify the question, I'd like a function in .NET that inspects Assembly.GetExecutingAssembly().Location and figures out what the offset for an appended payload might be. 为了澄清这个问题,我想在.NET中使用一个函数来检查Assembly.GetExecutingAssembly().Location并找出附加有效负载的偏移量。 If this offset is the same as the file size, there would be no payload. 如果此偏移量与文件大小相同,则不会有有效负载。

Note that I'm not very comfortable with C# so this is a general answer. 请注意,我对C#不太满意,所以这是一个普遍的答案。

As Assembly.GetExecutingAssembly().Location seems to return the path of an image, you have a "flat" file path, that is an image on disk and not in memory. 作为Assembly.GetExecutingAssembly().Location似乎返回图像的路径,你有一个“平面”文件路径,即磁盘上的图像而不是内存中的图像。 The parsing is easier than in memory and you already know it's a valid PE file so you can skip all validity checks. 解析比在内存中更容易,并且您已经知道它是一个有效的PE文件,因此您可以跳过所有有效性检查。

As you'll be exploring the image file with C#, you might want to check " Exploring pe file headers using managed code " and the various structures on Pinvoke.net . 当您使用C#浏览图像文件时,您可能需要检查“ 使用托管代码探索pe文件头 ”以及Pinvoke.net上的各种结构。

To find if there is a payload at the end of your image file: 要查找图像文件末尾是否有有效负载:

  • Open the file :) 打开文件:)
  • Get the file size 获取文件大小
  • The file starts with an IMAGE_DOS_HEADER ( pinvoke ) 该文件以IMAGE_DOS_HEADER( pinvoke )开头
    • Follow e_lfanew member to find the IMAGE_NT_HEADERS 按照e_lfanew成员查找IMAGE_NT_HEADERS
  • There are two types of IMAGE_NT_HEADERS ( pinvoke ; msdn ) : IMAGE_NT_HEADERS32 (PE32: 32-bit PE) and IMAGE_NT_HEADERS64 (PE32+: 64-bit PE) 有两种类型的IMAGE_NT_HEADERS( pinvoke ; msdn ):IMAGE_NT_HEADERS32(PE32:32位PE)和IMAGE_NT_HEADERS64(PE32 +:64位PE)
    • In IMAGE_NT_HEADERS, Signature and FileHeader (IMAGE_FILE_HEADER structure) fields are the same for both, only OptionalHeader will change. 在IMAGE_NT_HEADERS中,两者的SignatureFileHeader (IMAGE_FILE_HEADER结构)字段相同,只有OptionalHeader会发生变化。
    • check the Machine from IMAGE_FILE_HEADER ( pinvoke ; msdn ) to see which type you have: 0x014c (Intel 386) = PE32 ; 从IMAGE_FILE_HEADER( pinvoke ; msdn )检查Machine以查看您的类型:0x014c(Intel 386)= PE32; 0x8664 = PE32+ 0x8664 = PE32 +
  • from IMAGE_FILE_HEADER, get the NumberOfSections field. 从IMAGE_FILE_HEADER获取NumberOfSections字段。
  • Skip entirely (jump over) the IMAGE_NT_HEADERS structure: its size is constant, whatever its type is. 完全跳过(跳过)IMAGE_NT_HEADERS结构:它的大小是不变的,无论它的类型是什么。
  • You'll fall on an array of IMAGE_SECTION_HEADER ( pinvoke ; msdn ). 你将落在一个IMAGE_SECTION_HEADERpinvoke ; msdn )数组上。 The number of entry in this array is the NumberOfSections field (from IMAGE_FILE_HEADER). 此数组中的条目数是NumberOfSections字段(来自IMAGE_FILE_HEADER)。
  • Find the biggest / highest value of all PointerToRawData fields in the IMAGE_SECTION_HEADER array (this is usually the last entry in the array, but you should check all entries in the array to be sure). 找到IMAGE_SECTION_HEADER数组中所有PointerToRawData字段的最大/最大值(这通常是数组中的最后一个条目,但您应该检查数组中的所有条目以确保)。
    • You now have the file offset of the beginning of the last section. 您现在拥有最后一节开头的文件偏移量。
  • From the IMAGE_SECTION_HEADER that has the highest PointerToRawData , get the SizeOfRawData field. 从具有最高PointerToRawDataIMAGE_SECTION_HEADER中,获取SizeOfRawData字段。
    • You have now the size of the last section 你现在有最后一节的大小
  • Add both the PointerToRawData and SizeOfRawData fields: if the result is less than the file size you'll then know that there's a payload at the end of your PE file. 添加PointerToRawDataSizeOfRawData字段:如果结果小于文件大小,那么您将知道PE文件末尾有一个有效负载。

Simple (visual) example: 简单(可视)示例:

第

The above picture represents all IMAGE_SECTION_HEADER from calc.exe. 上图代表calc.exe中的所有IMAGE_SECTION_HEADER As you can see the highest value for PointerToRawData (labeled "Raw address') is 0xE3A00, and the corresponding section size ( SizeOfRawData , labeled "Raw size") is 0x600. 如您所见, PointerToRawData (标记为“原始地址”)的最高值为0xE3A00,相应的部分大小( SizeOfRawData ,标记为“原始大小”)为0x600。

  • 0xE3A00 + 0x600 = 0xe4000 = 933888 0xE3A00 + 0x600 = 0xe4000 = 933888

The file size of calc.exe is the same (933888 bytes): calc.exe的文件大小相同(933888字节):

钙质属性

So, there is no payload at the end of the file. 因此,文件末尾没有有效负载。 If the file size has been bigger than 933888 (result from the above calculation), there would have been a payload at the end of the file. 如果文件大小大于933888(由上述计算得出),则文件末尾会有一个有效负载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM