Я в настоящее время пишу синтаксический анализатор/загрузчик PE. Я успешно загрузил файл PE в память с помощью стандарта c файл io, получил допустимый DOS и заголовки PE (дополнительный заголовок), а также получив доступ к разделам PE. Моя следующая цель состоит в том, чтобы получить доступ к Таблице экспорта для получения экспортируемых символов. Чтобы сделать это, я использовал RVA, сохраненный в дополнительном массиве словаря данных заголовков в индексе 0 (который я верю точкам к таблице экспорта), и добавил этот адрес к адресу файла PE, загруженного в память программ, затем литую это в действительный заголовок таблицы экспорта. Я поднимаю ПУСТЫЕ адреса и данные, когда я делаю это. вот маленький фрагмент кода;
// 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 кажется редкой.заранее спасибо.
Не все образы PE будут иметь таблицу каталогов экспорта. Вам необходимо проверить поле NumberOfRvaAndSizes необязательного заголовка для Windows. Если он меньше или равен IMAGE_DIRECTORY_ENTRY_EXPORT
(0), то таблица каталога экспорта отсутствует (т.е. нет ничего действительного, расположенного в ioh-> DataDirectory [IMAGE_DIRECTORY_ENTRY_EXPORT]
).
См. Ответ на этот вопрос в качестве примера.
Я открыл один свой старый проект с того времени, как я, как и вы, исследовал структуру каталогов импорта и экспорта (IMAGE_DIRECTORY_ENTRY_EXPORT
, IMAGE_DIRECTORY_ENTRY_IMPORT
, IMAGE_DIRECTORY_ENTRY_IAT
и IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
). Я могу вкратце объяснить ту часть, где у вас возникла проблема. Я имею в виду часть, как узнать указатель на, например, IMAGE_EXPORT_DIRECTORY
внутри PE.
Прежде всего, конечно, можно использовать файловые операции Read/Write для анализа 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
- это виртуальный адрес директории export. После этого, чтобы преобразовать виртуальный адрес в указатель памяти, мы должны найти секцию 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