получение смещения в файле из RVA

Я пытаюсь прочитать PE-файл.
Проблема в том, что данные используют указатели RVA, а мне нужно смещение внутри файла
, чтобы получить то, что мне нужно. Как преобразовать RVA в смещение в файле?


person Idov    schedule 31.03.2012    source источник
comment
Предположим, вы не смогли прочитать его из файла, как работает PE-загрузчик?   -  person harold    schedule 31.03.2012
comment
Я не знаю... Он показывает информацию о размотке? и если я могу прочитать это из файла, от чего смещение адреса?   -  person Idov    schedule 31.03.2012
comment
По моей информации, они относятся к ImageBase (в шапке)   -  person harold    schedule 31.03.2012
comment
проблема в том, что значение ImageBase в заголовке намного больше, чем размер исполняемого файла.   -  person Idov    schedule 31.03.2012
comment
Ну да, позиция, которую вы получите из этого, - это позиция, которую она будет иметь в памяти, а не в файле.   -  person harold    schedule 31.03.2012
comment
так что мне нужно загрузить модуль?   -  person Idov    schedule 31.03.2012
comment
ОК, подождите ... это актуальный вопрос: как мне преобразовать RVA в смещение в файле?   -  person harold    schedule 31.03.2012
comment
хм... ну, я думаю, это то, что я пытаюсь сделать :)   -  person Idov    schedule 31.03.2012
comment
Я думаю, что это будет. Если вы опубликуете это как ответ, я приму это. Я также обновлю свой вопрос :)   -  person Idov    schedule 31.03.2012
comment
Вы ознакомились с примером PeDump Мэтта Петрека? Он показывает, как это работает.   -  person mox    schedule 01.04.2012


Ответы (3)


Для определения смещения файла по RVA необходимо:

  1. определить, в каком разделе точки РВА.
  2. вычесть из вашего адреса относительный виртуальный адрес раздела
  3. добавить к результату смещение файла раздела

Вы получите смещение файла, которое вам нужно.

person Evgeny    schedule 13.04.2012
comment
‹Плачет от радости› Часы! Часы! Я боролся с этим ... Спасибо, что ясно сказали! ‹Больше плача› - person TinyRacoon; 31.10.2019

В приведенном ниже примере показано файловое смещение адреса точки входа из 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;
    }
person Nishikant Mokashi    schedule 15.01.2018
comment
добавлено некоторое описание, а также комментарии. - person Nishikant Mokashi; 15.01.2018
comment
Не могли бы вы объяснить, почему мы добавляем указатель базы файлов lpFileBase в Raw Disk Offset? Похоже, мы добавляем необработанные смещения к виртуальному смещению, что, я думаю, неправильно. Я думал, что lpFileBase - это виртуальный адрес, на который был сопоставлен файл. Чтобы получить виртуальный адрес точки входа этого файла, нам нужно добавить RVA точки входа к lpFileBase, тогда мы получим VA точки входа этого сопоставленного файла. - person Zeolite; 13.04.2020
comment
Я думаю, что пропустил, что файлы отображаются в памяти как 1 к 1 из их образа жесткого диска. Поправьте меня если я ошибаюсь. Таким образом, чтобы получить Entry Point файла с отображением памяти, нам нужно использовать Raw Offsets из file base pointer в памяти. Поэтому, во-первых, из его RVA получаем Entry Point Raw Offset, во-вторых, прибавляем к этому Raw Offset file base pointer (ВА в памяти), чтобы получить VA of EntryPoint of memory mapped file. - person Zeolite; 13.04.2020

file Offset = RVAOfData - Virtual Offset + Raw Offset  

Пример:
Сведения о нашем разделе ресурсов (.rsrc):
Виртуальное смещение: F000
Необработанное смещение: C600

введите здесь описание изображения

Давайте посмотрим на один из имеющихся у нас ресурсов:
Имя: BIN
RVA данных: F0B0
Смещение файла: ?

введите здесь описание изображения

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

Смещение файла: C6B0

введите здесь описание изображения

Ссылка:
Знакомство с RVA и таблицами импорта — Sunshine

Функция на С#:

// 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);
}
person E235    schedule 19.01.2017