2012-03-31 106 views
5

我在嘗試讀取PE文件。
問題是,數據使用RVA指針,而我需要在文件
內偏移來獲得我所需要的。 如何將RVA轉換爲文件中的偏移量?從RVA獲得文件偏移

+0

假如你不能從文件中讀取它,如何做PE裝載器工作? – harold 2012-03-31 12:18:25

+0

我不知道...它顯示的是放鬆信息嗎?如果我可以從文件中讀取它,那麼地址偏移量是多少? – Idov 2012-03-31 12:21:52

+0

根據我的信息,他們是相對於ImageBase(在標題中) – harold 2012-03-31 12:28:54

回答

4

,以確定文件的RVA偏移,您需要:

  1. ,以確定其中部分點RVA。從部分
  2. 的地址相對虛擬地址
  3. 減增加導致文件部分

,您會收到一個文件偏移量,你需要的偏移。

0
file Offset = RVAOfData - Virtual Offset + Raw Offset 

例子:
我們的資源部分( 「.rsrc」)的詳細信息:
虛擬偏移:F000
原始偏移:C600

enter image description here

讓我們看看在資源上的一個我們有:
名稱:BIN
數據 RVA:F0B0
文件偏移量:?

enter image description here

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

文件偏移量:C6B0

enter image description here

參考:
Understanding RVAs and Import Tables - by Sunshine

在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); 
} 
0

下面的例子給出了來自RVA的入口點地址的文件偏移量。可以傳遞任何指針以從RVA獲取其磁盤偏移量。

基本上我們需要找到地址屬於哪個部分。一旦確定了正確的部分,使用下面的公式來獲得偏移量。

DWORD retAddr = PTR - (sectionHeader->其VirtualAddress)+
(sectionHeader->的PointerToRawData);

然後添加文件基地址來獲得物理地址

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

你可以給你的代碼添加一些評論嗎? – 2018-01-15 12:40:07

+1

添加了一些說明以及評論。 – 2018-01-15 13:28:40