Chptr-3- FileHeader isnt' scary its our friend.
So here we are luke, use the force...the force!!... :)
Here we are, at the FileHeader, this is the actual start of our journey you
might say... as the rest of the code upto know is just DOS padding...checking
that we have a PE. I better refresh your minds:
- We had the DOS_MZ header called IMAGE_DOS_HEADER. Only two of its
members where important the e_magic which had the string "MZ" and the
e_lfanew, which was a offset from the start of the file to the PE header.
- Using the IMAGE_DOS_SIGNATURE value ("MZ" or 0x543D) as a check value to
confirm its a PE.
- Get the e_lfanew value from the file and use it to find the start of our
PE header.
- Check the first dword (4-bytes) of our PE header to see if it contained
the string "PE" (a.k.a 0x4550).
So now on with the story... The PE Header's offical name is
IMAGE_NT_HEADERS and can be found in the winnt.h file for visual c users.
But I'll show you it below:
struct
IMAGE_NT_HEADERS
{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}; |
Signature
- is the PE signature, "PE" followed by two zero's. You should already
know this!
FileHeader
- is a strucre that contains the information about the physical
layout/properties of the PE fie in general.
OptionalHeader is also a structure that contains the information about
the logical layout inside the PE (Note the word logical.)
So to start with I think we should have a look inside FileHeader, crack
this nut open and see what it contains :)
struct IMAGE_FILE_HEADER
{
WORD Machine;
WORD
NumberOfSections;
DWORD
TimeDateStamp;
DWORD
PointerToSymbolTable;
DWORD
NumberOfSymbols;
WORD
SizeOfOptionalHeader;
WORD
Characteristics;
}; |
Well there isnt' any thing in there thats special... nothing to make us
jump!
I think I should tell you what some of the values mean... so that you have
a greater understanding as they say...
Machine - The CPU platform the file is intended for. For intel
platform, the value is (0x014Ch) and is defined as IMAGE_FILE_MACHINE_I386 in
the winnt.h file. Note: if you go into a hex editor and change this
value windows will refuse to run your program.
NumberOfSections - Well it
should be obvious from the name, it tells us how many sections are in our
file... we could increase this value if we add a section to our file.
TimeDateStamp - The date
and time the file is created.
PointerToSymbolTable -
Used in debugging.
NumberOfSymbols - Used in
debugging.
SizeOfOptionalHeader - The
size of the OptionalHeader member that immediately follows this structure.
Must be a valid value.
Characteristics - List of
flags that tell us about the file, e.g. if its an .exe or .dll etc.
Well shall we wet our feet and do some coding to examine the .exe file some
more.
#include
<windows.h>
#include
<stdio.h>
// Output to a
text file.
void
output(char*
str)
{
FILE *fp =
fopen("output.txt", "a+");
fprintf(fp,
"%s\n", str);
fclose(fp);
}
char
buff[500];
// Entry point
(its a windows entry point).
int
_stdcall
WinMain(HINSTANCE, HINSTANCE, char*
k, int l)
{
// Open our file called simple.exe
FILE *pFile =
fopen("simple.exe", "rb");
short
unsigned
int DOS_SIG;
fread(&DOS_SIG,
2, 1, pFile);
sprintf(buff,
"DOS Signature at start of file: %x", DOS_SIG);
output(buff);
// Skip the next 58 bytes.
fseek(pFile,
58, SEEK_CUR);
unsigned
int e_lfanew;
fread(&e_lfanew,
4, 1, pFile);
sprintf(buff,
"e_lfanew value is: %x", e_lfanew);
output(buff);
// Use the e_lfanew value to seek to the
start of the PE Header
fseek(pFile,
e_lfanew, SEEK_SET);
// See if we have a PE Header signature
unsigned
int NT_SIG;
fread(&NT_SIG,
4, 1, pFile);
sprintf(buff,
"NT Signature at start of PE Header: %x", NT_SIG);
output(buff);
struct
stIMAGE_FILE_HEADER
{
WORD Machine;
WORD
NumberOfSections;
DWORD
TimeDateStamp;
DWORD
PointerToSymbolTable;
DWORD
NumberOfSymbols;
WORD
SizeOfOptionalHeader;
WORD
Characteristics;
};
stIMAGE_FILE_HEADER FileHeader;
// Well lets just read in the whole lot in
one go in to our defined structure
fread(&FileHeader,
sizeof(FileHeader),
1, pFile);
// Output what we have found.
sprintf(buff,
"FileHeader - Machine value: %x", FileHeader.Machine);
output(buff);
sprintf(buff,
"FileHeader - NumberOfSections: %x", FileHeader.NumberOfSections);
output(buff);
sprintf(buff,
"FileHeader - NumberOfSymbols: %x", FileHeader.NumberOfSymbols);
output(buff);
sprintf(buff,
"FileHeader - SizeOfOptionalHeader: %x", FileHeader.SizeOfOptionalHeader);
output(buff);
sprintf(buff,
"FileHeader - Characteristics: %x", FileHeader.Characteristics);
output(buff);
fclose(pFile);
}
|
And if you run the above code and read in the FileHeader information, the
output.txt contains:
DOS Signature at start of file: 5a4d
e_lfanew value is: e0
NT Signature at start of PE Header: 4550
FileHeader - Machine value: 14c
FileHeader - NumberOfSections: 3
FileHeader - NumberOfSymbols: 0
FileHeader - SizeOfOptionalHeader: e0
FileHeader - Characteristics: 10f
The value of FileHeader-Machine tells us that this code was compiled for an
intel machine (14c), we also now know that there are three sections (e.g.
NumberOfSections).
|