2

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

Usman
  • 77
  • 2
  • 9

3 Answers3

6

You can use ImageRvaToVa function.

Abyx
  • 12,345
  • 5
  • 44
  • 76
5
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...

Len Holgate
  • 21,282
  • 4
  • 45
  • 92
  • What would be PBYTE "imageBase" address be in this case? Is this what u can get by loading dll as LoadLibrary("xyz.dll")? If thsi is so, how would then be in case of EXE? (which can't be loaded in this way properly). – Usman Dec 24 '10 at 13:55
  • Simply load the contents of the exe as a binary file into a memory buffer so that you can walk the PE file structure easily. The image base is the pointer to the start of that buffer. – Len Holgate Dec 24 '10 at 14:16
  • actually this one not giving me the correct (Offset where the GUID is located) which I need. It gives me some other arbitrary offset. can u please give me your e-mail id so that I can give you complete description and sample pdb of whole RVA I have known? – Usman Dec 28 '10 at 05:14
  • Might be I have to subtract image base address from this code's returned offset. – Usman Dec 28 '10 at 07:54
  • I assume you're templatising on the correct header type, i.e. the x86 or x64 structure? – Len Holgate Dec 28 '10 at 08:07
  • I checked closely everything and I found(the RVA that I am just getting from pdb giving DIA SDK) of the guid is say (hex : 654A0 and dec:414,880) while CFF explorer (which converts the RVA to Offset ) giving me the Offset (hex: 648A0 and dec:411808) this is where actuall guids located and I actually need to pick the guids data from this address in the binary file. I observed that the difference is just (hex : 00C00 and dec:3072)..? Why this is the difference? Is there any need at all to subtract this difference from RVA? If yes then why? do every time I need to subtract..? – Usman Dec 28 '10 at 11:53
  • I've got how to calculate Offset : rva - ((sections's VirtualAddress) - (sections's PointerToRawData)) – Usman Dec 28 '10 at 13:10
  • SO you want to map the opposite way to what the function I supplied is doing? – Len Holgate Dec 28 '10 at 13:20
  • I mapped successfully the RVA read from pdb to File offset by above formula. Actually the rva that's your function was returning needs to be sbutract some section's VirtualAddress and section's PointerToRawData Thanks Len Holgate. – Usman Dec 28 '10 at 13:46
0

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