Chptr-5- Sections Table
Well its taken us long enough to get here! But finally we've nearly
found our code that we compiled... so much checking and other things...
So stay with me just a little bit longer and you'll not be disappointed... as
I must admit we haven't really discovered anything exciting yet!.. But we will
by golly.. we will !! :)
The sections table is just an array of structures... for example if we have
3 sections, we'll have 3 structures on after the other located here, which
will tell us the size and offset to our section and what sort of information
is in there.
struct
IMAGE_SECTION_HEADER {
char Name[8];
union Misc
{
DWORD PhysicalAddress;
DWORD VirtualSize;
};
DWORD
VirtualAddress;
DWORD
SizeOfRawData;
DWORD
PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD
Characteristics;
}; |
So what are the structure members fore? There meanings? Well
the only ones we need to understand are as follows:
Name - an 8 byte variable that represents the section name, e.g. its not a
null terminated string. And can have any name, even just a null.
VirtualAdress - The RVA of the section. The PE loader examines and
uses the value in this field when its mapping the sections into memory.
Thus if the value in this section is 1000h, and the PE file is loaded into
memory at 400000h the section will be loaded at 401000h.
SizeOfRawData - The size of the sections data rounded up to the next
multiple of "file" alignment.
PointerToRawData - The file offset of the beginning of the section.
The PE loader uses the value in this field to find where the data in the
sections is in the file.
Characteristics - Contains flags which tell us whether the section contains
exectuable code, initilisation data, if it can be written to or from etc.
One thing you should remember from previous tutorials is the member
variable of IMAGE_FILE_HEADER, NumberOfSections. This member variable
tells us how many sections we have to read in.
So in we go...
#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; // Tells us how
many sections are in the file.
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);
// NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW NEW NEW NEW
struct
stIMAGE_SECTION_HEADER
{
char Name[8];
DWORD skip1;
DWORD
VirtualAddress;
DWORD
SizeOfRawData;
DWORD
PointerToRawData;
DWORD
PointerToRelocations;
DWORD
PointerToLinenumbers;
WORD
NumberOfRelocations;
WORD
NumberOfLinenumbers;
DWORD
Characteristics;
};
stIMAGE_SECTION_HEADER Section;
// We get the nubmer of sections which we
read in earlier.
unsigned
int iNumSections =
FileHeader.NumberOfSections;
for(unsigned
int i=0; i<iNumSections;
i++)
{
sprintf(buff,
"\n----------Details for Section *%d* -------------", i+1);
output(buff);
fread(&Section,
sizeof(Section),
1, pFile);
sprintf(buff,
"Section - Name %.8s", Section.Name);
output(buff);
sprintf(buff,
"Section - VirtualAddress %x", Section.VirtualAddress);
output(buff);
sprintf(buff,
"Section - SizeOfRawData %x", Section.SizeOfRawData);
output(buff);
sprintf(buff,
"Section - PointerToRawData %x", Section.PointerToRawData);
output(buff);
sprintf(buff,
"Section - Characteristics %x", Section.Characteristics);
output(buff);
}
fclose(pFile);
}
|
Well we have got a lot of code there now... man has that baby grown since
chapter one! Shall we see what the output looks like (output.txt):
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
----------Details for Section *1* -------------
Section - Name .text
Section - VirtualAddress 1000
Section - SizeOfRawData 4000
Section - PointerToRawData 1000
Section - Characteristics 60000020
----------Details for Section *2* -------------
Section - Name .rdata
Section - VirtualAddress 5000
Section - SizeOfRawData 1000
Section - PointerToRawData 5000
Section - Characteristics 40000040
----------Details for Section *3* -------------
Section - Name .data
Section - VirtualAddress 6000
Section - SizeOfRawData 3000
Section - PointerToRawData 6000
Section - Characteristics c0000040
As you can see we read in the details for our 3 sections, and displayed the
data for them... as you can see some of the data is pretty useless to us at
the moment.. But I'll explain it in a sec to you.
Our offset to the sections table - OptionalHeader.SizeOfHeaders. ---- we
set this to our VA (virtual address) so that we can use our RVA with respect
to this value.
Lets take Section-1-'s details and examine them.
----------Details for Section *1* -------------
Section - Name .text - this tells us that the name of our section is .text,
which is where our application starts
Section - VirtualAddress 1000 - this tells u the RVA of our section... used by
the PE loader to load the section into memory.
Section - SizeOfRawData 4000 - size of the raw data in bytes, rounded up to
the file alignment value (e.g. declared in OptinalHeaders as 1000h)
Section - PointerToRawData 1000 - the "file" offset to the beginning of the
section
Section - Characteristics 60000020
|