2012-03-31 3 views
5

Ich versuche, eine PE-Datei zu lesen.
Das Problem ist, dass die Daten RVA-Zeiger verwendet, während ich Offset innerhalb der Datei
brauche, um zu bekommen, was ich brauche. Wie kann ich die RVA in den Offset in der Datei konvertieren?bekomme Offset in Datei von RVA

+0

Angenommen, Sie es nicht aus der Datei lesen konnte, wie funktioniert der PE-Loader Arbeit? – harold

+0

Ich weiß es nicht ... Zeigt es die Abwicklungsinfo? und wenn ich es aus der Datei lesen kann, was ist der Adressversatz von? – Idov

+0

Nach meinen Informationen, sind sie relativ zu ImageBase (in der Kopfzeile) – harold

Antwort

4

die Datei von RVA Offset Um zu bestimmen, benötigen Sie:

  1. in dem Abschnitt Punkte RVA zu bestimmen.
  2. subtrahieren von Ihrer Adresse relativ virtuelle Adresse des Abschnitts
  3. fügen Sie die Datei von
  4. Abschnitt versetzt führen

Sie eine Datei erhalten Offset, die Sie benötigen.

0
file Offset = RVAOfData - Virtual Offset + Raw Offset 

Beispiel:
Unsere Ressource-Abschnitt (".rsrc") Details:
Virtuelle Offset: F000
Raw Offset: C600

enter image description here

Lässt auf einen der Ressource suchen wir haben:
Name: BIN
RVA von Daten: F0B0
Dateioffset:?

enter image description here

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

Datei-Offset: C6B0

enter image description here

Referenz:
Understanding RVAs and Import Tables - by Sunshine

Funktion 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

Das folgende Beispiel gibt den Dateioffset der Adresse des Eingangspunkts von RVA an. Man kann jeden Zeiger übergeben, um seinen Plattenoffset von RVA zu erhalten.

Grundsätzlich müssen wir herausfinden, in welchen Abschnitt die Adresse gehört. Sobald der richtige Abschnitt identifiziert wurde, verwenden Sie die Formel unten, um den Offset zu erhalten.

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

dann Datei Basisadresse hinzufügen physikalische bekommen Adresse

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

Können Sie Ihrem Code Kommentare hinzufügen? –

+1

hinzugefügt eine Beschreibung sowie Kommentare. –