Search code examples
creverse-engineeringportable-executable

Empty data after OptionalHeader


I'm working on PE parser, just for learning purposes. As the doc said, the first section header should be immediately after OptionalHeader, but in my case I have a lot of empty data before first header. Here is my code to calculate where should be firtst section:

IMAGE_NT_HEADERS* inth = get_nt_headers(buffer);

DWORD optional_headers_size = inth->FileHeader.SizeOfOptionalHeader;
DWORD calculated_ptr = (DWORD)inth + optional_headers_size;

printf("Pointer to IMAGE_NT_HEADERS: %p\n", inth);

printf("Size of optional headers: %x\n", optional_headers_size);

printf("Pointer to first section header: %p\n", calculated_ptr);

BYTE* pointer = (BYTE*)calculated_ptr;

When I iterate over the 'pointer' I see a lot of nullable data, so it is not section I need. PEView or Hexplorer shows empty data too. Why is that? This 'nullable' part of data takes about 24 bytes.

App which I analze is a simple HelloWorld.exe.

I'm confused with one more thing.

In FileHeader I has set 13 number of sections, but if I take a look on PEView in IMAGE_OPTIONAL_HEADER I see 16 sections but the last 3 sections have any assigned values, which means that the RVA and Size are set to 0. This sections are: DELAY_IMPORT_DESCRIPTORS, CLI_HEADER, but the last doesn't has any name.

I calculated that these three last section's size is 24 bytes. This the excatly the same as I mentioned before.

So how I can calculate where excatly is the firts IMAGE_SECTION_HEADER?

Problem solved, but I'm not sure about my solution.

DWORD padding = (IMAGE_NUMBEROF_DIRECTORY_ENTRIES - inth->FileHeader.NumberOfSections) * sizeof(IMAGE_DATA_DIRECTORY);
DWORD calculated_ptr = (DWORD)inth + padding + optional_headers_size;

Solution

  • first of all - never use DWORD in place pointer. this is error. DWORD is always 4 byte size, when pointer 4 or 8. code like

    DWORD calculated_ptr = (DWORD)inth + optional_headers_size;

    always wrong. you can use DWORD_PTR(which is exactly pointer size) instead DWORD.

    then SizeOfOptionalHeader how easy understand is size of IMAGE_OPTIONAL_HEADER which is part of IMAGE_NT_HEADERS. but code like this

    DWORD_PTR calculated_ptr = (DWORD_PTR)inth + inth->FileHeader.SizeOfOptionalHeader; use SizeOfOptionalHeader as size of IMAGE_NT_HEADERS. you simply confuse size of IMAGE_NT_HEADERS with size of IMAGE_OPTIONAL_HEADER

    so correct solution will be

        PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)(
            (ULONG_PTR)&inth->OptionalHeader + inth->FileHeader.SizeOfOptionalHeader);
    

    need add SizeOfOptionalHeader not to inth (address of PIMAGE_NT_HEADERS) but to &inth->OptionalHeader

    or better use PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(inth);

    the IMAGE_FIRST_SECTION - this is ready macro defined in winnt.h which have the same effect (produce same code) as (PIMAGE_SECTION_HEADER)((ULONG_PTR)&inth->OptionalHeader + inth->FileHeader.SizeOfOptionalHeader);