Idov
Idov

Reputation: 5124

getting offset in file from RVA

I'm trying to read a PE file.
The problems is that the data uses RVA pointers while I need offset within the file
to get what I need. How can I convert the RVA to offset in the file?

Upvotes: 9

Views: 14011

Answers (3)

Nishikant Mokashi
Nishikant Mokashi

Reputation: 161

Below example gives file offset of address of entry point from RVA. One can pass any pointer to get its disk offset from RVA.

Basically we need to find in which section the address belongs. Once the correct section is identified use below formula to get offset.

DWORD retAddr = ptr - (sectionHeader->VirtualAddress) +
(sectionHeader->PointerToRawData);

then add file base address to get physical address

retAddr+(PBYTE)lpFileBase

    LPCSTR fileName="exe_file_to_parse";
    HANDLE hFile; 
    HANDLE hFileMapping;
    LPVOID lpFileBase;
    PIMAGE_DOS_HEADER dosHeader;
    PIMAGE_NT_HEADERS peHeader;
    PIMAGE_SECTION_HEADER sectionHeader;

    hFile = CreateFileA(fileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

    if(hFile==INVALID_HANDLE_VALUE)
    {
        printf("\n CreateFile failed in read mode \n");
        return 1;
    }

    hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);

    if(hFileMapping==0)
    {
        printf("\n CreateFileMapping failed \n");
        CloseHandle(hFile);
        return 1;
    }

    lpFileBase = MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0); // Base pointer to file

    if(lpFileBase==0)
    {
        printf("\n MapViewOfFile failed \n");
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return 1;
    }

    dosHeader = (PIMAGE_DOS_HEADER) lpFileBase;  //pointer to dos headers

    if(dosHeader->e_magic==IMAGE_DOS_SIGNATURE)
    {
        //if it is executable file print different fileds of structure
        //dosHeader->e_lfanew : RVA for PE Header
        printf("\n DOS Signature (MZ) Matched");

        //pointer to PE/NT header
        peHeader = (PIMAGE_NT_HEADERS) ((u_char*)dosHeader+dosHeader->e_lfanew);

        if(peHeader->Signature==IMAGE_NT_SIGNATURE)
        {
            printf("\n PE Signature (PE) Matched \n");
            // valid executable so we can proceed

            //address of entry point
            DWORD ptr = peHeader->OptionalHeader.AddressOfEntryPoint;

            //instead of AEP send any pointer to get actual disk offset of it
            printf("\n RVA : %x \n",ptr); // this is in memory address i.e. RVA
            //suppose any one wants to know actual disk offset of "address of entry point" (AEP)

            sectionHeader = IMAGE_FIRST_SECTION(peHeader); //first section address
            UINT nSectionCount = peHeader->FileHeader.NumberOfSections;
            UINT i=0;
            //check in which section the address belongs
            for( i=0; i<=nSectionCount; ++i, ++sectionHeader )
            {
                if((sectionHeader->VirtualAddress) > ptr)
                {
                    sectionHeader--;
                    break;
                }
            }

            if(i>nSectionCount)
            {
                sectionHeader = IMAGE_FIRST_SECTION(peHeader);
                UINT nSectionCount = peHeader->FileHeader.NumberOfSections;
                for(i=0; i<nSectionCount-1; ++i,++sectionHeader);
            }

            //once the correct section is found below formula gives the actual disk offset 
            DWORD retAddr = ptr - (sectionHeader->VirtualAddress) +
                    (sectionHeader->PointerToRawData);
            printf("\n Disk Offset : %x \n",retAddr+(PBYTE)lpFileBase);
            // retAddr+(PBYTE)lpFileBase contains the actual disk offset of address of entry point

        }
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        //getchar();
        return 0;
    }
    else
    {
        printf("\n DOS Signature (MZ) Not Matched \n");
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return 1;
    }

Upvotes: 3

E235
E235

Reputation: 13400

file Offset = RVAOfData - Virtual Offset + Raw Offset  

Example:
Our resource section (".rsrc") details:
Virtual offset: F000
Raw offset: C600

enter image description here

Lets look on one of the resource we have:
Name: BIN
RVA of Data: F0B0
File offset: ?

enter image description here

fileOffset = RVAOfData - Virtual Offset + Raw Offset   
=>  C6B0   = F0B0      - F000           + C600 

File offset: C6B0

enter image description here

Reference:
Understanding RVAs and Import Tables - by Sunshine

Function in C#:

// Example:
//   RVA: F0B0
//   Virtual offset: F000 ("RVA" in PEview)
//   Raw offset: C600 ("Pointer to Raw Data" in PEview)
//   fileOffset = F0B0 - F000 + C600 = C6B0
private static uint rvaToFileOffset(uint i_Rva, uint i_VirtualOffset, uint i_RawOffset)
{
    return (i_Rva - i_VirtualOffset + i_RawOffset);
}

Upvotes: 3

Evgeny
Evgeny

Reputation: 156

To determine the file offset by RVA, you need:

  1. to determine in which section points RVA.
  2. subtract from your address relative virtual address of section
  3. add to result the file offset of section

You will receive a file offset that you need.

Upvotes: 13

Related Questions