Разрешение RVA для таблиц импорта и экспорта в PE-файле - PullRequest
10 голосов
/ 04 июня 2010

Я сейчас пишу парсер / загрузчик 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 кажется скудной. заранее спасибо.

Ответы [ 3 ]

13 голосов
/ 05 июня 2010

Я открыл один свой старый проект того времени, поскольку мне нравится, что вы изучали структуру каталогов импорта и экспорта (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 s, где

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

0 голосов
/ 16 сентября 2013

Для получения первого раздела определен макрос

PIMAGE_SECTION_HEADER FisrtSection = IMAGE_FIRST_SECTION(NtHeaders)

0 голосов
/ 04 июня 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...