Chptr-4- Optional Header
Shall we jump right in.. .the Optional Header structure follows imediately
after the FileHeader Structure as contains an enourmas amount of information.
I'll show you what it looks like:
struct IMAGE_OPTIONAL_HEADER
{
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD
AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD
ImageBase;
DWORD
SectionAlignment;
DWORD
FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD
MajorSubsystemVersion;
WORD
MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD
SizeOfImage;
DWORD
SizeOfHeaders;
DWORD CheckSum;
WORD
Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};
|
So that you don't loose hope, and who wouldn't ... after seeing this for
the first time people usually think of turning back... but the only important
members of the structure to us are the ones I've made black, and I've sort of
greyed out the others.
I know.. I know... whats so important about these few member variables...
well I'll tell you in a sec. But first I must clarify a few simple
things. "RVA"s??? Well a big thing in PE's is
RVA, which stands for
Relative Virtual Address... say it with me... "Relative Virtual
Address".. its important you know what it means as well. As you know in
a physical file you can refer to things relative to the start of file, the
DOS_MZ signature :) Well when the file is loaded into memory instead of
refairing to the start of the file we use the start address of where its
located in memory instead of the start of file.
Let me give you an example, if the file was loaded into memory starting at
virtual address (VA) space 400000h and the program needed to start execution
at the virtual address 401000h, then we can say that the program starts
execution at RVA 1000h. An RVA is relative to the starting VA of the
module (a.k.a the file without the dos stuff).
Member Field of Optional Header Structure |
Description |
AddressOfEntryPoint |
Its the RVA of the first instruction that will
be exectued when the PE loader is ready to run the PE file. |
ImageBase |
The preferred load address of the PE, for
example if the value in this field is 400000h, the PE loader will "try" to
load it into the virtual address space starting at 400000h. Remember
I said try, so if the PE loader can't load it there it may put it at some
other starting address. |
SectionAlignment |
As like disks memory is split up into
sections... chunks... pieces.. etc... and they have a pre-defined size...
this field says how big the sections are with our code and data in.
For example, if this field is 4096 (or 1000h), each section must start at
a multiple of 4096 bytes... so if the section in memory starts at 401000h
and is 10 bytes big,.. well the next section must be at 420000h even if
the address space between 41000h and 402000h will be mostly unused. |
FileAlignment |
The alignment of the sections in the
"file"!.... remember SectionAlignment is for memory, this is for the
alignment in the file. For example.. if the value in this field is
512 (200h), each section must start at multiples of 512 bytes. If
the first section is at file offset 200h and the size is 10 bytes, the
next section must be at location at file offset 400h: the space between
the file offsets 522 and 1024 is unused/undefined. |
MajorSubsystemVersion
MinorSubsystemVersion |
The Windows subsytem version - e.g. versions
over 4.0 contain a 3D look for dialog boxes etc. |
SizeOfImage |
The total size of the PE in memory. Its
teh sum of all headers and sections aligned to SectionAlignment. |
SizeOfHeaders |
The size of all headers+ the section table
(not the sections). In short this value is equal to the file size
minus the combined size of all sections in the file. You could use
this value as an offset to the start of the first section. |
Subsystem |
Windows GUI (2) or Windows CUI (1)(console). |
DataDirectory |
Array of IMAGE_DATA_DIRECTOR structures.
Contains the information for import functions (e.g. if we import fro many
external dlls etc the info is in here). |
Well here is the section of code which expands of previous coding and tells
us so much more information :)))
#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);
struct
stIMAGE_OPTIONAL_HEADER
{
BYTE
skip1[16];
DWORD
AddressOfEntryPoint;
BYTE
skip2[8];
DWORD
ImageBase;
DWORD
SectionAlignment;
DWORD
FileAlignment;
BYTE
skip3[8];
WORD
MajorSubsystemVersion;
WORD
MinorSubsystemVersion;
DWORD skip4;
DWORD
SizeOfImage;
DWORD
SizeOfHeaders;
DWORD skip5;
WORD
Subsystem;
BYTE
skip6[26];
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};
stIMAGE_OPTIONAL_HEADER OptionalHeader;
fread(&OptionalHeader,
sizeof(OptionalHeader),
1, pFile);
// Output what we have found.
sprintf(buff,
"OptionalHeader - AddressOfEntryPoint value: %x",
OptionalHeader.AddressOfEntryPoint);
output(buff);
sprintf(buff,
"OptionalHeader - ImageBase value: %x", OptionalHeader.ImageBase);
output(buff);
sprintf(buff,
"OptionalHeader - SectionAlignment value: %x",
OptionalHeader.SectionAlignment);
output(buff);
sprintf(buff,
"OptionalHeader - FileAlignment value: %x", OptionalHeader.FileAlignment);
output(buff);
sprintf(buff,
"OptionalHeader - MajorSubsystemVersion value: %x",
OptionalHeader.MajorSubsystemVersion);
output(buff);
sprintf(buff,
"OptionalHeader - MinorSubsystemVersion value: %x",
OptionalHeader.MinorSubsystemVersion);
output(buff);
sprintf(buff,
"OptionalHeader - SizeOfImage value: %x", OptionalHeader.SizeOfImage);
output(buff);
sprintf(buff,
"OptionalHeader - SizeOfHeaders value: %x", OptionalHeader.SizeOfHeaders);
output(buff);
sprintf(buff,
"OptionalHeader - Subsystem value: %x", OptionalHeader.Subsystem);
output(buff);
fclose(pFile);
} |
And the output for our little program (output.txt) is:
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
OptionalHeader - AddressOfEntryPoint value: 1030
OptionalHeader - ImageBase value: 400000
OptionalHeader - SectionAlignment value: 1000
OptionalHeader - FileAlignment value: 1000
OptionalHeader - MajorSubsystemVersion value: 4
OptionalHeader - MinorSubsystemVersion value: 0
OptionalHeader - SizeOfImage value: 9000
OptionalHeader - SizeOfHeaders value: 1000
OptionalHeader - Subsystem value: 2
|