我们如何将位置的RVA(相对虚拟地址)映射到PE文件偏移量?

时间:2010-12-24 07:16:27

标签: c++ debugging process portable-executable cffile

当从磁盘位置读取PE文件时,我需要将RVA(从pdb文件获取的相对虚拟地址)映射到PE文件(EXE)偏移量。为此,我需要将RVA转换为文件偏移量,以便我可以从该位置读出GUIDS(CLSID,IID)。

此致 乌斯曼

3 个答案:

答案 0 :(得分:4)

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

应该做的伎俩...

答案 1 :(得分:4)

您可以使用ImageRvaToVa功能。

答案 2 :(得分:0)

下面的代码段将入口点地址的RVA转换为实际磁盘偏移量。而不是AEP的地址发送任何RVA将其转换为磁盘偏移量。

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