Go ahead and launch notepad under the debugger just like you did in the last post. Assuming you have already set the _NT_SYMBOL_PATH environment variable - go ahead and run .reload -f. This will load the symbols for all modules (We’ll discuss symbols later). Next, run lmvm notepad, it should give you an output similar to the one below. The address given under “start” is the address where this module was loaded - in my case 00007ff63f030000.
You can use the !dh <start address> command to dump the PE header. !dh is a command that is part of a built extension in windbg, it dumps the header of a file given its address. A lot of this will not make sense till we manually run through the structures, you can ignore this till then.
The output may seem long and strange, but its easy once you walk through the internal structures.
PE structures:
The PE file format is made up of IMAGE_DOS_HEADER - aka DOS header, IMAGE_NT_HEADERS - aka NT header (which consists of IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER), IMAGE_SECTION_HEADERS aka Section headers, and Sections. You can get the details on the structures of PE file format on Winnt.h which will be available once you install the SDK (usually at this location "C:\Program Files (x86)\Windows Kits\8.1\Include\um\winnt.h".
PE has been around since the DOS days, which is why the DOS header appears at the start of the file. Here’s a snippet from the winnt.h file showing the IMAGE_DOS_HEADER structure and its member. The comments beside each member tells you the fields.
On a debugger, you can use the dump type or dt command to dump a data type. dt <symbol> should just dump the data structure and all its fields of the type name or symbol. If you provide an address along with the symbol name, then it also dumps the contents of this address and arranges the values against each member of the type - An example for dt ntdll!_IMAGE_DOS_HEADER <start address> is listed below. You can also dump the raw bytes and character repersentation using dc <address> as shown below.
Now, lets take a moment to see what we have just done.
We first used lmvm command to get the module’s load address. This is where the module starts in memory.
Once we know the start address we used an internal command !dh to parse the header and dumps out useful information.
Since our aim is to learn about the actual data structure, we referred to winnt.h to understand the structure members.
We then dumped the start address again by typecasting it as ntdll!_IMAGE_DOS_HEADER in the ` dt ntdll!_IMAGE_DOS_HEADER ` command. This gave us the members of the structure along with their values.
Once we read about the members, we also calculated the size of the strucute using ??sizeof(<type>) and dumped the raw hexadecimal view of bytes from the start address using dc.
The size of the Header is 0x40 bytes, which means that the header extends from 0007ff63f030000 to 00007ff63f030040.
The first member of the structure is e_magic, this number will be hexadecimal representation of characters “MZ”. We could see that in the raw view (see dc command output above).
Immediately after the header is a tiny program that prints out “This program cannot be run in MS-DOS mode”, if this executable is run in DOS.
The most important member of the DOS header is e_lfanew, this member in the MS-DOS stub header is a relative offset (or RVA) to the actual NT header. To get a pointer to the NT header in memory, we just add that field’s value to the image base as follows:
The Pointer of NT Header = the Start Address of DOSHeader + DosHeader->e_lfanew;
0:000> ?00007ff63f030000+0n248
Evaluate expression: 140695595843832 = 00007ff63f0300f8 <– offset of the NT header
Note that when windbg prints number, it adds a prefix. If numbers are prefixed with 0x - those are hexadecimal representation, of a number is prefixed with 0n, that is the decimal representation and if a number is prefixed with 0y, that is the binary representation.
We now know how to calculate the offset of the NT header. We will dig into the NT header in the next post, you can also read about the format from Microsoft’s documentation here: http://msdn.microsoft.com/en-us/library/ms809762.aspx.