Я пытаюсь прочитать PE-файл.
Проблема в том, что данные используют указатели RVA, а мне нужно смещение внутри файла
, чтобы получить то, что мне нужно. Как преобразовать RVA в смещение в файле?
получение смещения в файле из RVA
Ответы (3)
Для определения смещения файла по RVA необходимо:
- определить, в каком разделе точки РВА.
- вычесть из вашего адреса относительный виртуальный адрес раздела
- добавить к результату смещение файла раздела
Вы получите смещение файла, которое вам нужно.
В приведенном ниже примере показано файловое смещение адреса точки входа из 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;
}
lpFileBase
в Raw Disk Offset? Похоже, мы добавляем необработанные смещения к виртуальному смещению, что, я думаю, неправильно. Я думал, что lpFileBase
- это виртуальный адрес, на который был сопоставлен файл. Чтобы получить виртуальный адрес точки входа этого файла, нам нужно добавить RVA точки входа к lpFileBase
, тогда мы получим VA точки входа этого сопоставленного файла.
- person Zeolite; 13.04.2020
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);
}