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;
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);