Similar presentations:
relocations_presentation_ru
1.
Релокации в PE-файлахПамять, ImageBase и manual
mapping на практике
2.
ImageBase и загрузка модуля• Каждый PE-файл (EXE/DLL) собирается под
предпочтительный базовый адрес
ImageBase.
• Пример: модуль скомпилирован под адрес
0x140000000.
• Абсолютные адреса внутри кода и данных
рассчитываются относительно этого
ImageBase.
• В заголовке PE это поле
IMAGE_OPTIONAL_HEADER::ImageBase.
3.
Почему вообще нужнырелокации?
• При загрузке по адресу ImageBase память
может быть уже занята.
• Система (или manual mapper) загружает
модуль по другому адресу, например
0x150000000.
• Все абсолютные указатели, 'зашитые' в
модуле, становятся неверными.
• Нужно прибавить дельту LocationDelta =
NewBase - ImageBase ко всем таким
указателям.
0x140000000 (ImageBase)
0x150000000 (NewBase)
4.
Что такое релокации• Релокации — это список мест в модуле, где
лежат абсолютные адреса/указатели.
• Если модуль загружен не по ImageBase, эти
адреса нужно поправить.
• Таблица релокаций хранится в
DataDirectory[IMAGE_DIRECTORY_ENTRY_BA
SERELOC].
• Обычный загрузчик Windows выполняет
релокации автоматически — manual
mapper должен делать это сам.
5.
Структура таблицы релокацийIMAGE_DATA_DIRECTORY dir = pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress; // Базовый RVA страницы
DWORD SizeOfBlock;
// Размер блока
} IMAGE_BASE_RELOCATION;
6.
Формат записи релокации(WORD)
Каждая запись — 16-битное значение (WORD):
15........12 | 11...............0
TYPE
|
OFFSET внутри страницы
TYPE = (*entry >> 12)
OFFSET = (*entry & 0x0FFF)
–
–
0x0C (12) — сдвиг вправо на 12 бит, чтобы получить тип.
0x0FFF — маска младших 12 бит, чтобы получить смещение внутри страницы.
7.
Тип IMAGE_REL_BASED_DIR64• На x64 наиболее важен тип
IMAGE_REL_BASED_DIR64.
• Он означает: по указанному адресу лежит
64-битный абсолютный указатель.
• Этот указатель нужно изменить: *ptr +=
LocationDelta.
• Другие типы релокаций используются реже
(HIGHLOW, HIGH, LOW и т.д.).
8.
Алгоритм обработки релокаций• 1. Посчитать LocationDelta = NewBase ImageBase.
• 2. Найти таблицу релокаций через
DataDirectory[BASE_RELOC].
• 3. Идти по блокам
IMAGE_BASE_RELOCATION до конца
таблицы.
• 4. Для каждого блока:
• вычислить количество WORD-записей,
• разобрать TYPE и OFFSET,
9.
Разбор кода обработкирелокаций
BYTE* LocationDelta = pBase - pOpt->ImageBase;
if (LocationDelta) {
auto* pRelocData = (IMAGE_BASE_RELOCATION*)(pBase + dir.VirtualAddress);
auto* pRelocEnd = (IMAGE_BASE_RELOCATION*)((BYTE*)pRelocData + dir.Size);
while (pRelocData < pRelocEnd && pRelocData->SizeOfBlock) {
UINT count = (pRelocData->SizeOfBlock - sizeof(*pRelocData)) / sizeof(WORD);
WORD* info = (WORD*)(pRelocData + 1);
for (UINT i = 0; i < count; ++i, ++info) {
if ((*info >> 12) == IMAGE_REL_BASED_DIR64) {
UINT_PTR* patch = (UINT_PTR*)(pBase + pRelocData->VirtualAddress
+ (*info & 0x0FFF));
*patch += (UINT_PTR)LocationDelta;
}
}
pRelocData = (IMAGE_BASE_RELOCATION*)((BYTE*)pRelocData +
pRelocData->SizeOfBlock);
}
}
10.
Пример изменения указателяПусть:
ImageBase = 0x140000000
NewBase
= 0x150000000
LocationDelta = 0x010000000
В коде/данных лежит абсолютный адрес:
*ptr = 0x140010000
После применения релокации:
*ptr = *ptr + LocationDelta
= 0x140010000 + 0x010000000
= 0x150010000
11.
Практические моменты• Если релокации вычищены (strip
relocations) — модуль нельзя безопасно
перемещать.
• Manual mapper обязан:
• корректно обработать релокации,
• учесть, что не все записи могут быть
DIR64.
• При отладке удобно дампить таблицу
релокаций и проверять несколько адресов
вручную.