Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IMAGE_SECTION_HEADER's VirtualAddress and PointerToRawData difference

In this article, the definitions are

DWORD VirtualAddress

In EXEs, this field holds the RVA to where the loader should map the section. To calculate the real starting address of a given section in memory, add the base address of the image to the section's VirtualAddress stored in this field.

DWORD PointerToRawData

This is the file-based offset of where the raw data emitted by the compiler or assembler can be found. If your program memory maps a PE or COFF file itself (rather than letting the operating system load it), this field is more important than the VirtualAddress field. You'll have a completely linear file mapping in this situation, so you'll find the data for the sections at this offset, rather than at the RVA specified in the VirtualAddress field

Also RVA is defined as

Many fields in PE files are specified in terms of RVAs. An RVA is simply the offset of some item, relative to where the file is memory-mapped

and

To convert an RVA into a usable pointer, simply add the RVA to the base address of the module. The base address is the starting address of a memory-mapped EXE or DLL

The problem in hand is to reach the import section of a PE file.

hFile = CreateFile(..);
hFileMapping = CreateFileMapping(..);
lpFileBase = MapViewOfFile(..);
ImageBase = (PIMAGE_DOS_HEADER)lpFileBase;
PEHeader = (ImageBase + ImageBase->e_lfanew);

Now to get hold of import table

PIMAGE_OPTIONAL_HEADER PEImageOptionalHeader = &(PEHeader->OptionalHeader);
IMAGE_DATA_DIRECTORY importTable = PEImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 

Since importTable.VirtualAddress is an RVA, to get a usable pointer, i can add the base of the image file.

So ImageBase + importTable.virtualAddress should get me to import section.But it does not.Why?

Then, if i reach at the correct section header(generally .idata) and do this.

ImageBase + pointerToSection->PointerToRawData;

The above correctly takes me to array of IMAGE_IMPORT_DESCRIPTORS.I understand that using pointerToSection->virtualAddress instead of PointerToRawData above, would not work as i am mapping the PE file myself.

Now to get the name of the item, the loaded module is dependent on,I can use pointer to IMAGE_IMPORT_DESCRIPTORS using the field name which is again anRVA.To convert an RVA, i just have to add the ImageBase..

 LPSTR libname = (PCHAR)((DWORD)ImageBase+ImageimportDescriptor->Name);

But it does not work.Why?To convert an RVA, we simply add base address of image.The below works

ImageBase+ImageimportDescriptor->Name + pointerToSection->PointerToRawData - pointerToSection->virtualAddress

And every time i need some info within a section, i need to make this adjustment

pointerToSection->PointerToRawData - pointerToSection->virtualAddress

Why is this adjustment required?

like image 222
Gaurav Sehgal Avatar asked Jul 20 '17 10:07

Gaurav Sehgal


2 Answers

First, this line:

PEHeader = (ImageBase + ImageBase->e_lfanew);

Is incorrect. ImageBase is of type PIMAGE_DOS_HEADERS so when you add to it ImageBase->e_lfanew, which is a DWORD you are doing pointer arithmetic, that is, you are adding to ImageBase as many bytes as (ImageBase->e_lfanew)*sizeof(IMAGE_DOS_HEADERS) which is not what you want. What you want is to advance ImageBase->e_lfanew bytes form the place ImageBase points to. You achieve this by doing the following:

PIMAGE_NT_HEADERS PEheader = (PIMAGE_NT_HEADERS) ((PBYTE)(ImageBase) + dosHeader->e_lfanew);

Notice the cast to PBYTE, this makes the operation advance byte by byte.

This is very common when dealing with PE file since many times you want to advance n bytes from a pointer and not n data structure the pointer points to. In the article you refered to it even says in a comment:

// Ignoring typecasts and pointer conversion issues for clarity...
pNTHeader = dosHeader + dosHeader->e_lfanew;

Now to your question about VirtualAddress and PointerToRawData:

The line ImageBase + importTable.virtualAddress is also incorrect for the following reason:

The PE Loader doesn't map all the executable file continuously in memory like you do in your file mapping, it maps each section at its corresponding VirtualAddress. In the latter situation, to get a VA from an RVA you just add the ImageBase to the RVA and it works, because the file on disk is meant to be a representation of what the PE loader maps in memory. However, since you are not mapping each sections where the PE loader would map them, adding the ImageBase to an RVA like you did doesn't work.

You need a function that given an RVA, gives you the file offset corresponding to that RVA in the file on disk. to get a VA you just need to add this file offset to the byte pointer that points to your mapped file.

Whenever you have an RVA (like the RVA to the import section, or to a name string or whatever), in order to access it you must do the following.

PBYTE actualAddress = (PBYTE) (lpFileBase + RVAtoFileOffset(pNTHeader, RVA))

Here is the function: I posted it on pastebin because I can't manage to format it correctly here.

Here is how it works: When you have an RVA, that RVA must lie within a section, so you traverse all section headers (which are right after the optional header) and whe you find the section where the RVA lies in, you calculate the offset of that RVA within that section RVA - VirtualAddress and add it to the PointerToRawData of that section, now you have the file offset of the RVA. If the RVA is invalid (it doesn't lie within any section), the function returns 0.

You need to do this in order to access the import directory or the name of each import descriptor, since what you have are RVAs.

I hope I have helped.

like image 153
Mihai Avatar answered Nov 02 '22 07:11

Mihai


Once we have valid PE/NT header address we can directly jump to first section:

PIMAGE_SECTION_HEADER sectionHeader;
sectionHeader = IMAGE_FIRST_SECTION(peHeader);

Also we can find name of section by masking

sectionHeader->Characteristics
like image 24
Nishikant Mokashi Avatar answered Nov 02 '22 08:11

Nishikant Mokashi