Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #66, МАЙ 2006 г.

термоядерный инлайн

GETORIX | INT3

Спецвыпуск: Хакер, номер #066, стр. 066-068-5


Итак, ядро написано, осталось привязать патч к основной программе, а именно найти для него место вызова. В соответствии с идеей, первый встретившийся в программе вызов функции должен быть подменен и переадресован на наш патч, а сама функция должна быть вызвана внутри патча. Первый переход в программе расположен по адресу 1D60C, там происходит обращение к некоторой функции _cinit. Реализовать такую переадресацию можно только вручную, путем замены в инструкции относительного смещения до этой функции на смещение до нашего inline-патча. Точно таким же образом необходимо рассчитать смещение из тела патча до функции _cinit. О том, как это сделать, можно узнать из врезки.

Вычисление относительного адреса

ПРИ ПРОГРАММИРОВАНИЕ НА ARM-АССЕМБЛЕРЕ С ИСПОЛЬЗОВАНИЕМ ОПКОДОВ ОЧЕНЬ ВАЖНО ПОНИМАТЬ, КАК РАССЧИТЫВАЕТСЯ ОТНОСИТЕЛЬНЫЙ АДРЕС В ИНСТРУКЦИЯХ ВЕТВЛЕНИЯ ТИПА B,BL. В ОФИЦИАЛЬНОМ ОПИСАНИИ АРХИТЕКТУРЫ ARM О ЕГО ВЫЧИСЛЕНИИ ГОВОРИТСЯ СЛЕДУЮЩЕЕ:

THE BRANCH TARGET ADDRESS IS CALCULATED BY:

1 SIGN-EXTENDING THE 24-BIT SIGNED (TWO'S COMPLIMENT) IMMEDIATE TO 32 BITS.

2 SHIFTING THE RESULT LEFT TWO BITS.

3 ADDING THIS TO THE CONTENTS OF THE PC, WHICH CONTAINS THE ADDRESS OF THE BRANCH INSTRICTION PLUS 8.

ПЕРЕВЕСТИ МОЖНО ВОТ ТАК: ДЛЯ ПОЛУЧЕНИЯ АБСОЛЮТНОГО АДРЕСА ПЕРЕХОДА 24-БИТОВОЕ СМЕЩЕНИЕ, СОДЕРЖАЩЕЕСЯ В КОМАНДЕ, СДВИГАЕТСЯ ВЛЕВО НА ДВА БИТА, ПОСЛЕ ЧЕГО К НЕМУ ПРИБАВЛЯЕТСЯ ЗНАЧЕНИЕ РЕГИСТРА PC, КОТОРОЕ СОДЕРЖИТ АДРЕС ТЕКУЩЕЙ ИНСТРУКЦИИ ВЕТВЛЕНИЯ, УВЕЛИЧЕННЫЙ НА 8 БИТ.

ЭТО УТВЕРЖДЕНИЕ ТАКЖЕ МОЖНО ЗАПИСАТЬ ДВУМЯ ФОРМУЛАМИ:

1. ((da-ba)-8)>>2 [для перехода вперед по коду (на больший адрес)]

2. 0-(((ba-da)+8)>>2) [для перехода назад по коду (на меньший адрес)]

ba — адрес команды ветвления (branch address)

da — адрес команды назначения (distination address)

ДЛЯ ПРОСТОТЫ И ЯСНОСТИ РАЗБЕРЕМ ПРИНЦИП РАБОТЫ ЭТОГО НА ПРИМЕРЕ.

ИТАК, НАМ ДАНО:

1D60C: адрес вызова _cinit

1D6EC: адрес функции _cinit

1D840: адрес inline-пачта

1D860: адрес вызова _cinit из тела inline-пачта

СНАЧАЛА НЕОБХОДИМО РАССЧИТАТЬ СМЕЩЕНИЕ ОТ БЫВШЕГО ВЫЗОВА ФУНКЦИИ _CINIT ДО НАЧАЛА INLINE-ПАТЧА. ПОСКОЛЬКУ ПАТЧ НАХОДИТСЯ НИЖЕ ПО КОДУ, ИСПОЛЬЗУЕМ ФОРМУЛУ (1):

offset = ((1D840-1D60C)-8)>>2 = 8B

ТЕПЕРЬ ПО ФОРМУЛЕ (2) РАССЧИТЫВАЕМ СМЕЩЕНИЕ ИЗ ТЕЛА ПАТЧА ДО ФУНКЦИИ _cinit, КОТОРАЯ НАХОДИТСЯ ВЫШЕ ПО КОДУ.

offset = 0-(((1D860-1D6EC)+8)>>2) = FFFFA1

После расчета заменяем соответствующие смещения в вызовах и получаем:

по адресу 1D60C: 8B 00 00 EB [вызов inline-пачта вместо _cinit]

по адресу 1D860: A1 FF FF EB [вызов _cinit из тела патча]

Таким образом, конечная версия inline-патча в шестнадцатеричном виде будет выглядеть так, как показано в листинге 5:

Листинг 5. HEX-код инлайн-патча

.text:0001D840 00 40 2D E9 0F 00 2D E9 EA 00 A0 E3 14 10 9F E5 .@-щ¤.-щъ.ау¶ Ях

.text:0001D850 00 00 C1 E5 10 10 9F E5 00 00 C1 E5 0F 00 BD E8 ..+х Ях..+х¤.-ш

Назад на стр. 066-068-4  Содержание  Вперед на стр. 066-068-6