简体   繁体   中英

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. 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.

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.

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. 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.

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. The parsing is easier than in memory and you already know it's a valid PE file so you can skip all validity checks.

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 .

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 )
    • Follow e_lfanew member to find the 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)
    • In IMAGE_NT_HEADERS, Signature and FileHeader (IMAGE_FILE_HEADER structure) fields are the same for both, only OptionalHeader will change.
    • check the Machine from IMAGE_FILE_HEADER ( pinvoke ; msdn ) to see which type you have: 0x014c (Intel 386) = PE32 ; 0x8664 = PE32+
  • from IMAGE_FILE_HEADER, get the NumberOfSections field.
  • Skip entirely (jump over) the IMAGE_NT_HEADERS structure: its size is constant, whatever its type is.
  • You'll fall on an array of IMAGE_SECTION_HEADER ( pinvoke ; msdn ). The number of entry in this array is the NumberOfSections field (from 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).
    • 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.
    • 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.

Simple (visual) example:

第

The above picture represents all IMAGE_SECTION_HEADER from calc.exe. 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.

  • 0xE3A00 + 0x600 = 0xe4000 = 933888

The file size of calc.exe is the same (933888 bytes):

钙质属性

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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