none
PE format for win32 exe RRS feed

  • Question

  • Hello,

    I built a win32 console application and then tried to inspect the exe file according to:

    PE Format

    Offset 0x3C has a 16 bits offset to where the file header starts. 

    This file header is 20 bytes long.

    f_magic =  0x4550 (PE)

    f_nscns = 0

    f_opthdr = 0;

    This does not make sense.

    How can f_nscns  be 0 ?

    24 bytes after the file header I have 0x10B which is the magic in the optional file header. 

    How can f_opthdr be 0 if there is an optional file header ?

    Thank you,

    Zvika 

    Friday, May 29, 2020 11:20 PM

Answers

  • Umm, the PE Format documentation clearly states:

    "After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte signature that identifies the file as a PE format image file. This signature is "PE\0\0" (the letters "P" and "E" followed by two null bytes).

    At the beginning of an object file, or immediately after the signature of an image file, is a standard COFF file header in the following format."

    Also, according to the Windows headers the PE signature is a DWORD and not part of the image header or the optional header.

    typedef struct _IMAGE_NT_HEADERS64 {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER64 OptionalHeader;
    } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
    
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


    Also, just looking at the naming makes me think that you are using the xcoff, osdev wiki or some other source along those lines to parse this header. The osdev wiki does mention:

    "In brief, a PE/COFF Image contains a pointer at offset 0x3C which points to the PE header. The COFF File Header immediately follows this PE signature."

    f_magic doesn't refer to the PE signature, it refers to the machine identifier 4 bytes after the PE identifier. Maybe the use of magic confuses you because the PE documentation on that site does refer to the PE signature as mMagic on another page.

    Anyway, let's parse the following:

    50 45 00 00 4c 01 08 00 c5 25 63 5e 00 00 00 00

    00 00 00 00 e0 00 02 01

    This includes the PE signature. So if we parse this using the layout that the Windows IMAGE_NT_HEADERS structure states.

    Signature = 50 45 00 00 (32 bit)

    IMAGE_FILE_HEADER

    Machine (f_magic) = 4c 01

    NumberOfSections (f_nscns) = 08 00

    TimeDateStamp (f_timdat) = c5 25 63 5e

    PointerToSymbolTable (f_symptr) = 00 00 00 00

    NumberOfSymbols (f_nsyms) = 00 00 00 00

    SizeOfOptionalHeader (f_opthdr) = e0 00

    Characteristics (f_flags) = 02 02

    So, the magic/machine identifier in the PE Format documentation is 4c 01 or 0x014c.

    "IMAGE_FILE_MACHINE_I386   0x14c   Intel 386 or later processors and compatible processors"

    So that is a good start considering the executable I am looking at was built targeting 32 bit.

    The optional header size is e0 00 or 0x00e0. As we know the 32 bit optional header structure is 96 bytes, and the data directories after this make it up to 224 bytes. Since 0xe0 is 224 then again this is a good sign.

    So while you are starting at the correct starting point, you are missing the PE signature.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Saturday, May 30, 2020 1:11 AM
    • Marked as answer by Z. V Sunday, May 31, 2020 7:25 PM
    Saturday, May 30, 2020 1:06 AM

All replies

  • Umm, the PE Format documentation clearly states:

    "After the MS-DOS stub, at the file offset specified at offset 0x3c, is a 4-byte signature that identifies the file as a PE format image file. This signature is "PE\0\0" (the letters "P" and "E" followed by two null bytes).

    At the beginning of an object file, or immediately after the signature of an image file, is a standard COFF file header in the following format."

    Also, according to the Windows headers the PE signature is a DWORD and not part of the image header or the optional header.

    typedef struct _IMAGE_NT_HEADERS64 {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER64 OptionalHeader;
    } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
    
    typedef struct _IMAGE_NT_HEADERS {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;
    } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


    Also, just looking at the naming makes me think that you are using the xcoff, osdev wiki or some other source along those lines to parse this header. The osdev wiki does mention:

    "In brief, a PE/COFF Image contains a pointer at offset 0x3C which points to the PE header. The COFF File Header immediately follows this PE signature."

    f_magic doesn't refer to the PE signature, it refers to the machine identifier 4 bytes after the PE identifier. Maybe the use of magic confuses you because the PE documentation on that site does refer to the PE signature as mMagic on another page.

    Anyway, let's parse the following:

    50 45 00 00 4c 01 08 00 c5 25 63 5e 00 00 00 00

    00 00 00 00 e0 00 02 01

    This includes the PE signature. So if we parse this using the layout that the Windows IMAGE_NT_HEADERS structure states.

    Signature = 50 45 00 00 (32 bit)

    IMAGE_FILE_HEADER

    Machine (f_magic) = 4c 01

    NumberOfSections (f_nscns) = 08 00

    TimeDateStamp (f_timdat) = c5 25 63 5e

    PointerToSymbolTable (f_symptr) = 00 00 00 00

    NumberOfSymbols (f_nsyms) = 00 00 00 00

    SizeOfOptionalHeader (f_opthdr) = e0 00

    Characteristics (f_flags) = 02 02

    So, the magic/machine identifier in the PE Format documentation is 4c 01 or 0x014c.

    "IMAGE_FILE_MACHINE_I386   0x14c   Intel 386 or later processors and compatible processors"

    So that is a good start considering the executable I am looking at was built targeting 32 bit.

    The optional header size is e0 00 or 0x00e0. As we know the 32 bit optional header structure is 96 bytes, and the data directories after this make it up to 224 bytes. Since 0xe0 is 224 then again this is a good sign.

    So while you are starting at the correct starting point, you are missing the PE signature.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    • Edited by Darran Rowe Saturday, May 30, 2020 1:11 AM
    • Marked as answer by Z. V Sunday, May 31, 2020 7:25 PM
    Saturday, May 30, 2020 1:06 AM
  • Hello,

    I think my mistake is that I had to start reading 4 bytes later.

    The first 4 bytes are PE signature: 0x00004550 (IMAGE_NT_SIGNATURE)

    Thank you,

    Zvika 

    Saturday, May 30, 2020 4:35 AM