Question

I need to map RVA (Relative virtual address that's taken from pdb file) to PE file(EXE) offset when reading PE file from a disk location. For this I need to convert RVA to file offset so that I can read out GUIDS(CLSID,IID's) from that location.

Regards Usman

Was it helpful?

Solution

template <class T> LPVOID GetPtrFromRVA(
   DWORD rva,
   T* pNTHeader,
   PBYTE imageBase ) // 'T' = PIMAGE_NT_HEADERS
{
   PIMAGE_SECTION_HEADER pSectionHdr;
   INT delta;

   pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader);
   if ( !pSectionHdr )
      return 0;

   delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
   return (PVOID) ( imageBase + rva - delta );
}

template <class T> PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(
   DWORD rva,
   T* pNTHeader)   // 'T' == PIMAGE_NT_HEADERS
{
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
    unsigned i;

    for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
    {
      // This 3 line idiocy is because Watcom's linker actually sets the
      // Misc.VirtualSize field to 0.  (!!! - Retards....!!!)
      DWORD size = section->Misc.VirtualSize;
      if ( 0 == size )
         size = section->SizeOfRawData;

        // Is the RVA within this section?
        if ( (rva >= section->VirtualAddress) &&
             (rva < (section->VirtualAddress + size)))
            return section;
    }

    return 0;
}

should do the trick...

OTHER TIPS

You can use ImageRvaToVa function.

Below code snippet converts RVA of address of entry point to actual disk offset. Instead of address of AEP send any RVA to convert it into disk offset.

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);

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 
        //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
        //suppose any one wants to know actual disk offset of "address of entry point" (AEP)

        sectionHeader = IMAGE_FIRST_SECTION(peHeader);
        UINT nSectionCount = peHeader->FileHeader.NumberOfSections;
        UINT i=0;
        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);
        }

        DWORD retAddr = ptr - (sectionHeader->VirtualAddress) +
                (sectionHeader->PointerToRawData);
        printf("\n Disk Offset : %x \n",retAddr+(PBYTE)lpFileBase);
        // retAddr + lpFileBase  contains the actual disk address 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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top