Определить физический адрес файла каталога RVA в PE-файле
Как определить адрес изображения (смещение байта в файле) определенного каталога данных в PE-файле?
Например, даны каталоги данных следующим образом:
directory 1 RVA: 0x0 Size: 0
directory 2 RVA: 0xaf974 Size: 300
directory 3 RVA: 0xb8000 Size: 22328
directory 4 RVA: 0x0 Size: 0
directory 5 RVA: 0xc0800 Size: 6440
directory 6 RVA: 0xbe000 Size: 27776
directory 7 RVA: 0x91760 Size: 28
directory 8 RVA: 0x0 Size: 0
directory 9 RVA: 0x0 Size: 0
directory 10 RVA: 0x0 Size: 0
directory 11 RVA: 0xa46b8 Size: 64
directory 12 RVA: 0x0 Size: 0
directory 13 RVA: 0x91000 Size: 1736
directory 14 RVA: 0x0 Size: 0
directory 15 RVA: 0x0 Size: 0
directory 16 RVA: 0x0 Size: 0
Каталог импорта (#2 выше) показан как находящийся в RVA 0xAF974. Однако каталог импорта НЕ находится в байте 0xAF974 файла EXE. Как вычислить смещение байтов каталога импорта в файле, как оно написано на диске?
1 ответ
Это весело! Вы должны пройтись по разделам, чтобы найти правильное местоположение на основе его виртуального адреса. Вот код, который я написал после многих
Я могу попытаться объяснить это, но потребовалось много времени, чтобы понять это самому, и я не смотрел на это в течение нескольких недель, и я уже забыл много технических вещей. Я писал класс C++, чтобы справиться с этим тоже
В моем коде буфера есть указатель на MapViewOfFile, но это может быть любой указатель на символ.
/* Example usage...I know not perfect but should help a bit. */
unsigned char * lpFile = (unsigned char *)(void *)MapViewOfFile(fileMap, FILE_MAP_ALL_ACCESS, 0,0, 0);
if(lpFile==NULL) {
printf("Failed to MapViewOfFile\r\n");
exit(0);
}
header_dos = (PIMAGE_DOS_HEADER)lpFile;
header_nt = (PIMAGE_NT_HEADERS32)&lpFile [header_dos->e_lfanew];
IMAGE_DATA_DIRECTORY import = header_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR im = (PIMAGE_IMPORT_DESCRIPTOR)&lpFile[RVA2Offset(lpFile, import.VirtualAddress)];
/* RVA is relative to the section it resides in. */
int RVA2Offset(unsigned char * buffer, DWORD rva)
{
PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew ];
PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew + sizeof(IMAGE_NT_HEADERS) ];
for(int sectionIndex = 0; sectionIndex < header->FileHeader.NumberOfSections; sectionIndex++) {
/*
Check if the RVA is within the virtual addressing space of the section
Make sure the RVA is less than the VirtualAddress plus its raw data size
IMAGE_HEADER_SECTION.VirtualAddress = The address of the first byte of the section when loaded into memory, relative to the image base. For object files, this is the address of the first byte before relocation is applied.
Our ImageBase is 0, since we aren't loaded into actual memory
*/
section = (PIMAGE_SECTION_HEADER) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (sectionIndex*sizeof(IMAGE_SECTION_HEADER))];
if (rva >= section->VirtualAddress && (rva <= section->VirtualAddress + section->SizeOfRawData)) {
/**
PointerToRawData gives us the section's location within the file.
RVA - VirtualAddress = Offset WITHIN the address space
**/
return section->PointerToRawData + (rva - section->VirtualAddress);
}
}
return 0;
}