PE-файл содержит «разделы», а разделы имеют независимые базовые адреса. PE не является непрерывным изображением памяти. Каждый раздел представляет собой непрерывный образ памяти.
Сначала вам нужно будет прочитать информацию раздела и составить карту памяти их макета. Затем вы сможете выровнять смещения раздела с смещениями на основе файлов.
В качестве альтернативы рассмотрим OllyDbg, который является бесплатным отладчиком и дизассемблером с открытым исходным кодом для Windows. Это, возможно, поможет вам протестировать ваше собственное программное обеспечение и, возможно, сервер будет самой целью, которую вы пытаетесь заполнить, «сворачивая свою собственную».
Пример из dumpbin /all
выхода:
SECTION HEADER #1
.text name
BC14 virtual size
1000 virtual address (00401000 to 0040CC13)
BE00 size of raw data
400 file pointer to raw data (00000400 to 0000C1FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
В этом случае мой .text раздел начинается на RVA 1000 и продолжается до RVA CE00. Указатель файла для этого раздела - 400. Я могу преобразовать в файл-указатель любые RVAs в диапазоне 1000-CDFF работой вычитания 600. (Все числовые значения шестнадцатеричные.)
Всякий раз, когда вы сталкиваетесь с «RVA »(Относительный виртуальный адрес), вы разрешаете его на смещение файла (или индекс в массив байтов), используя этот метод:
- Определите, к какому разделу принадлежит RVA. Каждый раздел содержит RVAs от своего виртуального адреса по его размеру. Разделы не перекрываются.
- Вычтите виртуальный адрес раздела из RVA - это дает смещение относительно раздела.
- Добавьте указатель PointerToRawData этого раздела в смещение, которое вы получите на шаге (2). Это смещение файла, соответствующее RVA.
Другой подход, который можно использовать, чтобы позвонить MapViewOfFileEx()
с флагом FILE_MAP_EXECUTE
набора в dwDesiredAccess аргумента. Этот API будет анализировать заголовки разделов из файла PE и читать содержимое разделов в их местоположениях относительно «базы модулей».
Основание модуля - это базовый адрес, на который будет загружен PE-заголовок. При загрузке DLL с использованием функций LoadLibrary()
это можно получить через GetModuleInformation()
function MODULEINFO
member lpBaseOfDll.
При использовании MapViewOfFileEx()
основание модуля представляет собой просто возвращаемое значение от MapViewOfFileEx()
.
В настройках загрузки модуля в этих способах, решении RVA к нормальному значению указателя является вопросом:
- Храните модуль базового адреса в
char *
- Добавьте RVA к
char *
- Передайте
char *
фактическому типу данных и разыгрывайте их.
Недостаток позволяя ОСА отобразить файл, как в этих подходах является то, что если вы используете этот инструмент, чтобы исследовать некоторые подозрительные файлы и не уверены, если разработчик взял странные вольности заголовка раздела, то возможно, вы пропустите некоторую ценную информацию, позволяя ОС обрабатывать эту часть синтаксического анализа.
Извинения, поскольку я учусь, когда я иду ... До сих пор я добавил логический параметр, который сообщает читателю PE, если данные переданы в память (которые я установил в false при чтении из файла) , Если он не сопоставлен с памятью, я читаю каталог экспорта по адресу, указанному PointerToRawData в разделе .edata. Однако на этот раз AddressOfFunctions указывает на E000. Какую информацию мне нужно перевести на смещение файла? Или я что-то пропустил? –
Вы используете карту памяти MapViewOfFileEx() и передаете FILE_MAP_EXECUTE? Или вы загрузили его с помощью LoadLibraryEx() и LOAD_LIBRARY_AS_IMAGE_RESOURCE? –
Ничего. Я просто читаю байты из файла на диске. Я хотел бы поддерживать оба PE-изображения на диске и загружаться в память, поэтому я добавил параметр boolean, чтобы указать, какой тип изображения он есть. Если 'MemoryMapped' является ложным, я знаю, что изображение было прочитано с диска, и я могу соответствующим образом перевести адреса экспорта. Я просто не знаю, какую информацию мне нужно сделать для перевода. –