Разрешение RVA для импорта и экспорта таблиц в PE файле

В настоящее время я пишу парсер/загрузчик PE. Я успешно загрузил PE файл в память с помощью стандартного c файла io, извлечил действительные заголовки DOS и PE (дополнительный заголовок), а также получил доступ к разделам PE. Моя следующая цель - получить доступ к таблице Экспорт для получения экспортированных символов. Для этого я использовал RVA, хранящийся в дополнительном массиве данных-словаря заголовков с индексом 0 (который, я полагаю, указывает на таблицу экспорта), и добавил этот адрес к адресу PE файла, загруженного в память программы, затем перебросил его в допустимый заголовок таблицы экспорта. Когда я делаю это, я запускаю NULL-адреса и данные. вот небольшой фрагмент кода;

// RVA from optional headers data dictionaries array cast to Export directory type 
  IMAGE_EXPORT_DIRECTORY* ied(
  (IMAGE_EXPORT_DIRECTORY*)((void*)
  ((unsigned char*)buffer + ioh->DataDirectory[0].VirtualAddress)));

Нужно ли мне использовать IO с отображением карты памяти, чтобы сделать это правильно? Я неправильно вычисляю адрес? Информация о PE RVA кажется редкой. спасибо заранее.

Ответ 1

Я открыл один мой старый проект того времени, так как мне нравится, что вы изучали структуру каталогов импорта и экспорта (IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_DIRECTORY_ENTRY_IMPORT, IMAGE_DIRECTORY_ENTRY_IAT и IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). Я могу вкратце объяснить ту часть, где у вас есть проблема. Я имею в виду часть, как найти указатель, например, на IMAGE_EXPORT_DIRECTORY внутри PE.

Прежде всего, для анализа PE файла можно использовать операции чтения/записи файла, но гораздо проще использовать сопоставление файлов, например:

hSrcFile = CreateFile (pszSrcFilename, GENERIC_READ, FILE_SHARE_READ,
                       NULL, OPEN_EXISTING, 0, NULL);
hMapSrcFile = CreateFileMapping (hSrcFile, NULL, PAGE_READONLY, 0, 0, NULL);
pSrcFile = (PBYTE) MapViewOfFile (hMapSrcFile, FILE_MAP_READ, 0, 0, 0);

после того, как у нас есть указатель pSrcFile, который указывает на PE файл, мы можем найти другие важные места внутри PE:

pDosHeader = (IMAGE_DOS_HEADER *)pSrcFile;
IMAGE_NT_HEADERS32 *pNtHdr = (IMAGE_NT_HEADERS32 *)
    ((PBYTE)pDosHeader + pDosHeader->e_lfanew);
IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *)
    ((PBYTE)&pNtHdr->OptionalHeader +
     pNtHdr->FileHeader.SizeOfOptionalHeader);

Теперь у нас есть все необходимые виртуальные адреса любого каталога. Например,

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

- это виртуальный адрес каталога экспорта. После этого, чтобы преобразовать виртуальный адрес в указатель памяти, мы должны найти раздел PE, в котором этот виртуальный адрес находится внутри. Для этого мы можем перечислить разделы PE и найти i больше или равно 0 и меньше, чем pNtHdr->FileHeader.NumberOfSection где

pFirstSectionHeader[i].VirtualAddress <= 
pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress

и в то же время

pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
< pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize

тогда вам нужно искать данные экспорта в разделе pFirstSectionHeader[i]:

IMAGE_SECTION_HEADER *pSectionHeader = &pFirstSectionHeader[i];
IMAGE_EXPORT_DIRECTORY *pExportDirectory =
   (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
    pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress -
    pSectionHeader->VirtualAddress);

Эту же процедуру вы должны повторить, чтобы найти (IMAGE_IMPORT_DESCRIPTOR *), который соответствует IMAGE_DIRECTORY_ENTRY_IMPORT и (IMAGE_BOUND_IMPORT_DESCRIPTOR *), который соответствует IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, чтобы выгрузить информацию об импорте, включая информацию о связывании (если существует).

Чтобы получить информацию из IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT (соответствует (ImgDelayDescr *), определенному в delayimp.h), вам также следует использовать информацию из IMAGE_DIRECTORY_ENTRY_IAT (соответствует (IMAGE_THUNK_DATA32 *)).

Для получения дополнительной информации о PE я рекомендую вам http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

Ответ 2

Не все изображения PE будут иметь таблицу каталогов экспорта. Вам нужно проверить необязательный заголовок Windows-specific "NumberOfRvaAndSizes". Если оно меньше или равно IMAGE_DIRECTORY_ENTRY_EXPORT (0), то нет таблицы экспорта (т.е. Нет ничего действительного, расположенного в ioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).

См. ответ на этот вопрос для примера.

Ответ 3

Существует макрос, определенный для получения первой секции

PIMAGE_SECTION_HEADER FisrtSection = IMAGE_FIRST_SECTION(NtHeaders)