2012-03-31 14 views
5

Sto provando a leggere un file PE.
Il problema è che i dati utilizzano puntatori RVA mentre ho bisogno di offset all'interno del file
per ottenere ciò di cui ho bisogno. Come posso convertire l'RVA in offset nel file?ottenere offset in file da RVA

+0

Supponiamo non si poteva leggere dal file, come fa il caricatore PE lavoro? – harold

+0

Non so ... Mostra le informazioni per lo svolgimento? e se posso leggerlo dal file, qual è l'offset dell'indirizzo? – Idov

+0

Secondo le mie informazioni, sono relativi a ImageBase (nell'intestazione) – harold

risposta

4

per determinare il file compensato da RVA, è necessario:

  1. per determinare in cui i punti di sezione RVA.
  2. sottrarre dal tuo indirizzo virtuale relativo di sezione
  3. aggiungere al risultato il file di offset della sezione

Riceverai compensato un file di cui avete bisogno.

0
file Offset = RVAOfData - Virtual Offset + Raw Offset 

Esempio:
nostra sezione delle risorse (".rsrc") particolari:
virtuale Offset: F000 compensato
Raw: C600

enter image description here

lascia lo sguardo su una delle risorse abbiamo:
Nome: BIN
RVA di dati: F0B0
Offset file:?

enter image description here

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

compensare File: C6B0

enter image description here

Riferimento:
Understanding RVAs and Import Tables - by Sunshine

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

Nell'esempio seguente viene fornito l'offset del file dell'indirizzo del punto di ingresso da RVA. Si può passare qualsiasi puntatore per ottenere il suo offset del disco da RVA.

Fondamentalmente abbiamo bisogno di trovare in quale sezione appartiene l'indirizzo. Una volta identificata la sezione corretta, utilizzare sotto la formula per ottenere l'offset.

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

quindi aggiungere l'indirizzo di base di file per ottenere l'indirizzo fisico

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

Puoi aggiungere alcuni commenti al tuo codice? –

+1

aggiunto qualche descrizione e commenti. –