Образ мышления – дизассемблер IDA Pro. Том I [Крис Касперски] (pdf) читать постранично, страница - 2

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

SDK (Software Development Kit) – программного пакета, позволяющего
пользователю самостоятельно разрабатывать процессорные модули, файловые
загрузчики и плагины (внешние самостоятельные модули). Это неограниченно расширяет
возможности IDA Pro, позволяя анализировать любой код, для какого бы микропроцессора
и операционной системы он ни предназначался. SDK различных версий не совместимы
друг с другом и созданные пользователем модули могут не работать в другой версии
IDA Pro, поэтому, прежде чем переходить на очередную версию IDA Pro, настоятельно
рекомендуется убедиться в сохранении работоспособности всех скриптов, модулей и
плагинов и т.д.
Рисунок 1 ”ida.console.view” Так выглядит консольная ипостась IDA Pro 4.01
Рисунок 2 “ida.gui.view” Так выглядит графическая ипостась IDA Pro 4.01
Рисунок 3 “ida.gui.view.4.14.bmp” Так выглядит графическая ипостась IDA Pro 4.14
Demo
2

Кратное введение в дизассемблирование
Одним из способов изучения программ в отсутствии исходных текстов является
дизассемблирование, – перевод двоичных кодов процессора в удобочитаемые
мнемонические инструкции. С перового взгляда кажется: ничего сложного в такой операции
нет, и один дизассемблер не будет сильно хуже любого другого. На самом же деле,
ассемблирование – однонаправленный процесс с потерями, поэтому автоматическое
восстановление исходного текста невозможно.
Одна из фундаментальных проблем дизассемблирования заключается в
синтаксической неотличимости констант от адресов памяти (сегментов и смещений).
Потребность распознавания смещений объясняется необходимостью замены конкретных
адресов на метки, действительное смещение которых определяется на этапе
ассемблирования программы.
Сказанное можно проиллюстрировать следующим примером: рассмотрим
исходную программу (a). При ассемблировании смещение строки s0, загружаемое в
регистр s0 заменяется его конкретным значением, в данном случае равным 108h, отчего,
команда “MOV DX, offset s0” приобретает вид “MOV DX, 108h”. Это влечет за собой потерю
информации – теперь уже нельзя однозначно утверждать как выглядел исходный текст, т.к.
ассемблирование “…offset s0” и “…108h” дает одинаковый результат, т.е. функция
ассемблирования не инъективна 1.
Если все машинные инструкции исходного файла, перевести в соответствующие им
символьные мнемоники (назовем такую операцию простым синтаксическим
дизассемблированием), в результате получится (b). Легко видеть – программа сохраняет
работоспособность лишь до тех пор, пока выводимая строка располагается по адресу
108h. Если модификация кода программы (c) нарушает такое равновесие, на экране
вместо ожидаемого приветствия появляется мусор – теперь выводимая строка находится
по адресу 0x10C, но в регистр DX по прежнему загружается прежнее значение ее
смещения – 0x108 (d).
mov
mov
int
ret
s0

ah,9
dx, offset s0
21h

Æ

DB 'Hello,World!',0Dh,0Ah,'$'

(а) Исходная программа

mov
ah,9
mov
dx,0108h
int
21h
ret
s0 DB 'Hello,World!',0Dh,0Ah,'$'

Æ

(b) Дизассемблированная программа
:0100 start
:0100
:0102
:0105
:0107
:0109
:010B
:010B aHelloWorld
:010C end

mov
ah,09
mov
dx,0108h
int
21h
xor
ax,ax
int
16h
ret
s0 DB 'Hello,World!',0Dh,0Ah,'$'
(с) Модифицированная программа

proc
near
mov
ah, 9
mov
dx, 108h ─┐
int
21h

xor
ax, ax

int
16h ◄────┘
retn
db 'Hello,World!',0Dh,0Ah,'$'
start

(d) Неработоспособный результат

Аналогичная проблема возникает и переводе с одного языка на другой – фраза
«это ключ» в зависимости от ситуации может быть переведена и как “this is key”, и “this is
clue”, и “this is switch”… Для правильного перевода мало простого словаря подстрочечника, необходимо еще понимать о чем идет речь, т.е. осмысливать
переводимый текст.
Человек легко может определить, что содержимое регистра DX в данном случае
1

Функция f(x) = y называется инъективной, если уравнение f(y) = x, имеет только один
корень и, соответственно, наоборот.
3

является именно смещением, а не чем ни будь иным, поскольку, его ожидает функция 0x9
прерывания 0x21. Но дизассемблеру для успешной работы мало знать одних прототипов
системных и библиотечных функций, – он должен еще уметь отслеживать содержимое
регистров, а, следовательно, «понимать» команды микропроцессора. Создание такого
дизассемблера (часто называемого контекстным) очень сложная инженерная задача,
тесно граничащая с искусственным интеллектом, которая на сегодняшний день еще никем
не решена. Существует более или менее удачные разработки, но ни одна из них не
способна генерировать 100%-работоспособные листинги.
Например, путь в исходной программе имелся фрагмент (а), загружающий в
регистр AX смещение начала таблицы, а в регистр BX индекс требуемого элемента.
Ассемблер, заменяя оба значения константами (b), создает неразрешимую задачу, – легко
видеть, что один из регистров содержит смещение, а другой индекс, но как узнать какой
именно?
MOV
AX,offset Table
MOV
BX,200h ; Index
ADD
AX,BX
Æ
MOV
AX,[BX]
(а) Исходная программа

BB 00 02
01