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. Я могу преобразовать в указатель файла любые RVA в диапазоне 1000-CDFF, вычитая 600. (Все числовые значения шестнадцатеричные.)
Всякий раз, когда вы сталкиваетесь с «RVA» (относительным виртуальным адресом), вы разрешаете его в смещение файла (или индекс в вашем массиве байтов), используя этот метод:
- Определите, к какому разделу относится RVA. Каждый раздел содержит RVA от виртуального адреса до размера. Разделы не пересекаются.
- Вычтите виртуальный адрес раздела из RVA — это даст вам смещение относительно раздела.
- Добавьте PointerToRawData раздела к смещению, полученному на шаге (2). Это смещение файла, соответствующее RVA.
Другой подход, который вы можете использовать, заключается в вызове MapViewOfFileEx()
с флагом FILE_MAP_EXECUTE
, установленным в аргументе dwDesiredAccess. Этот API будет анализировать заголовки разделов из PE-файла и считывать содержимое разделов в их расположение относительно «базы модуля».
База модуля — это базовый адрес, по которому будет загружаться PE-заголовок. При загрузке DLL с помощью LoadLibrary()
функций это можно получить с помощью MODULEINFO
члена lpBaseOfDll GetModuleInformation()
функции.
При использовании MapViewOfFileEx()
базой модуля является просто возвращаемое значение из MapViewOfFileEx()
.
В настройках загрузки модуля этими способами преобразование RVA в нормальное значение указателя зависит от:
- Сохраните базовый адрес модуля в
char *
- Добавьте RVA в
char *
- Приведите
char *
к фактическому типу данных и разыменуйте его.
Недостатком того, что ОС позволяет отображать файл, как в этих подходах, является то, что если вы используете этот инструмент для исследования какого-то подозрительного файла и не уверены, что разработчик позволил себе странные вольности с заголовками разделов, возможно, вы упустите некоторую ценную информацию. позволяя ОС обрабатывать эту часть синтаксического анализа.
person
Heath Hunnicutt
schedule
15.10.2009