Введение в реверсинг с нуля используя IDA PRO. Часть 4

Дата публикации 20 фев 2017 | Редактировалось 15 апр 2017
Мы продолжаем рассматривать инструкции обмена данными в IDA.

XCHG A, B

Эта инструкция обменивает значение A со значением B, давайте рассмотрим пример.

1.png

В файле VEVIEWER нет такой инструкции, поэтому я загружаю СRACKME.EXE Cruehead, и меняю инструкцию по адресу 0x4013D8.

Я помещаю курсор на строку адреса и перехожу в меню EDIT->PATCH PROGRAM->ASSEMBLE.

2.png

Мы видим, что функция была повреждена, так как я работаю сейчас с ней.

3.png

Мы уже видели, что, если инструкция не существует, эта область показывается, как область данных. В этом случае тут один байт, поскольку нет никаких ссылок ни в какую часть программы, то и нет никакой информации на правой стороне окна. Затем тип данных, становится DB, здесь только один байт и его значением является 0xC0.

Таким образом, если мы запишем инструкцию NOP, что означает NO OPERATION или инструкция заполнения, которая ничего не делает, то так заменим байт 0xC0.

4.png

Поставим по этому адресу NOP.

5.png

Вполне очень симпатично, но функция повреждена. Если есть не распознанные части, подобно коду ниже, и IDA не распознаёт его, но когда с кодом всё ОК, мы щелкаем правой кнопкой мыши, где было начало функции 0x4013D8, и выбираем там пункт CREATE FUNCTION.

6.png

И это меняет префикс loc_, который означает “локальная метка” на префикс sub_, который означает, “начало подпрограммы или функции”.

7.png

Теперь, это функция, и если мы не находимся в графическом режиме, то нажимаем пробел, чтобы переключиться в него.

8.png

Теперь намного лучше и сейчас здесь есть наш XCHG.

Мы видели, что если EAX равняется 12345678 и ESI равняется 55, то когда выполняется XCHG, регистр EAX будет равняться 55 и ESI будет равняться 12345678.

Мы видим, что в меню PATCH есть элемент под названием PATCHED BYTES, который показывает изменения, и он может вернуть к исходному неизменному коду.

9.png

XCHG также может обменивать значения между регистром и содержимом регистра, который указывает на ячейку памяти.

10.png

В этом случае, значение ESI будет искать содержимое по этому адресу памяти и оно будет обмениваться со значением EAX, которое будет сохранено в той же ячейке памяти, если есть разрешение на запись.

Например, если значение EAX равно 55 и значение ESI равно 0x10000.

Инструкция будет проверять, что находится здесь, в этой ячейке памяти и если она доступна на запись, она сохранит туда значение 55 и прочитает значение по адресу памяти 0x10000 и сохранит его в EAX.

Что произойдет, если мы сделаем то же самое, но вместо того, чтобы использовать регистр мы используем адрес в памяти, как мы сделали в MOV ?

Поскольку команда ASSEMBLE не работает полноценно для всех инструкций, мы должны изменить байты в меню где написано PATCH BYTES, но лучше загрузить плагин, такой как Keystone, который позволяет нам записать все инструкции намного проще.

https://github.com/keystone-engine/keypatch
https://drive.google.com/file/d/0B13TW0I0f8O2eU1VdUJzVjdYTWs/view?usp=sharing


Во второй ссылке находится файл keypatch.py, который мы должны скопировать в каталог плагинов IDA и затем можно установить keystone-0.9.1-python-win32.msi.

Кроме того, необходимо установить Microsoft VC ++, библиотеку времени исполнения.

http://www.keystone-engine.org/keypatch/

11.png
12.png

В Keypatch выберите PATCHER.

Когда мы выбираем PATCHER, мы видим что, если запишем инструкцию в простой форме и со скобками, он запишет её и преобразует в синтаксис IDA.

13.png

И я получаю такой результат.

14.png

Как и в MOV, когда показывается префикс dword_ без СМЕЩЕНИЯ в начале, это будет означать, что обменивается содержимое 0x4020DC со значением EAX.

СПЕЦИАЛЬНЫЕ ИНСТРУКЦИИ ПЕРЕСЫЛКИ ОСНОВАННЫЕ НА РАБОТЕ СО СТЕКОМ

ЧТО ТАКОЕ СТЭК?

Стэк, это область в памяти, которая работает по принципу LIFO.

Для обработки данных предоставляется две основные операции: положить или PUSH, которая помещает объект в стек и обратная операция, чтобы забрать последнее значение или POP.

В каждый момент времени, есть доступ только к верхушке стека, то есть к последнему сохраненному объекту. Операция POP получает обратно этот элемент, который вытолкнут со стека, разрешая доступа к тому, который находится ниже (положен ранее) и он становится последним доступным объектом.

В CRACKME.EXE мы видим примеры обеих инструкций.

15.png

Обычно, в 32-битных приложениях, PUSH используется, чтобы передать аргументы функции в стек, прежде, чем вызвать функцию с помощью CALL, на картинке выше мы видим это по адресу 0x40104F.

PUSH 64 кладет dword 64 в верхнюю часть стека, затем PUSH EAX кладет значение EAX, на предыдущее значение в стеке, оставляя внизу это предыдущее значение, и поэтому оно будет последним на верхушке стэка.

ESP ->значение EAX
->
0x64

Ниже мы видим другой вид PUSH, мы можем также сохранять константы, но и также мы можем сохранить адрес памяти, как в этом случае.

16.png

Мы видим слово СМЕЩЕНИЕ перед символьным ТЭГОМ, соответствующее строке символов, здесь будет положен в стэк адрес начала строки или строковый массив.

Если мы дважды щёлкнем на этот тэг, который представляет название строки WindowName.

В исходнике на C увидим массив символов, который может быть определен таким образом:

char mystring[] = "Hello WASM.IN";

17.png

Мы видим, что в этом случае используются строчки для описания переменной.

Здесь записано char WindowName[], потому что IDA обнаружила функцию API CreateWindow.

18.png

В любом случае, это массив символов или байтов, только IDA добавляет немного полезной информации, которая получена от API функции, мы видим, что после адреса 0x4020E7 следующий адрес в списке 0x4020F4, здесь есть некоторая последовательность байт, которые принадлежат символам строки “Crackme v1.0” и ноль, который говорит о конце строки.

19.png

Если мы нажмём кнопку D, чтобы изменить тип данных на WindowName.

Мы видим, что мы можем заставить IDA прекратить обнаруживать эту строку как символьный массив, и оставить её как DB или то же самое, что и байт.

20.png

Это те же самые байты, которые соответствуют последовательности crackme v1.0.

Мы видим, что оригинальная инструкция изменилась, очевидно слово offset впереди говорит о том, что будет заталкиваться значение 0x4020E7, но сейчас, содержимое прекратило быть символьным массивом и теперь стало байтом и инструкция изменилась на

21.png

push offset byte_4020e7

22.png

Нажмём кнопку A и строка из ASCII последовательности станет снова как и раньше.

23.png

Также, когда мы работаем, мы можем видеть некоторую последовательность, такую как нулевые байты.

24.png

Передвигаемся в начало последовательности байт и нажимаем A, теперь смотрится намного лучше.

25.png

В этом случае, мы видим, что эта строка не определена в двух строчках, как предыдущая, IDA даже не говорит, что она CHAR[], но она определена с помощью тэга, который начинается с буквы a, для того, чтобы быть ASCII строкой, в предыдущем случае IDA показывает дополнительную информацию, потому что IDA обнаружила, что это был аргумент API или функция системы и IDA предупредила, что аргумент должен быть CHAR[] и вот почему она добавил это там, но нормальная строка будет похожа на эту последнюю строку.

Здесь мы видим другую строку.

26.png

По адресу 0x402110 начинается первый байт строки, она может быть расщеплёна на байты, чтобы их видеть отдельно, просто нажатием клавиши D на строке aMenu.

27.png
Если мы нажмём A, мы отменим сделанные изменения.

Если я нажму X, чтобы искать ссылки, то я буду видеть где используются эти строки.

Мы видим, что тут сохраняется адрес 0x402110, потому что стоит слово СМЕЩЕНИЕ.

28.png

Обычно, когда аргументы передаются к функциям, мы всегда будем видеть PUSH offset xxxxx, потому что ищется адрес строки, чтобы передать его функции, если инструкция не имеет слово OFFSET, мы бы заталкивали содержимое адреса 0x402110, байты 55 4E 45 4D которого являются той же строкой и API не будет работает, API всегда передаётся указатель на начало или адрес где начинается строка.

В этом случае, в этой инструкции, которую мы видим выше, префикс DS:TAG указывает, что она собирается сохранить его в адрес памяти секции данных (DS=DATA), когда мы будем рассматривать структуры, мы изучим этот случай, сейчас важно запомнить, что инструкция сохраняет адрес начала строки в секции DATA.

POP

29.png

Эта операция, которая читает вершину стэка и перемещает значение с этой вершины в регистр назначения, в этом случае мы видим, что POP EDI будет читать первое значение или ВЕРШИНУ СТЭКА и скопирует его в EDI, а затем ESP будет указывать на значение, которое было ниже и теперь оно станет ВЕРШИНОЙ стэка.

Если мы ищем текст, а именно слово POP, мы видим, что вариантов используется не так много, несмотря на то, что там есть возможность вытолкунуть POPEAR(wtf amigos???) в адрес памяти вместо регистра, эта опция не является очень используемой.

30.png

Мы продолжим с другими инструкциями в пятой главе, чтобы быть готовыми изучать функционирование ЗАГРУЗЧИКА.

Пока пока.
Рикардо Нарваха

Источник:
http://ricardonarvaja.info/WEB/INTRODUCCION AL REVERSING CON IDA PRO DESDE CERO/EN INGLES/
Перевод на английский - @IvinsonCLS
Перевод на русский — Яша_Добрый_Хакер
Перевод специально для форума системного и низкоуровневого программирования - WASM.IN
24.02.2017

3 1.462
yashechka

yashechka
Ростовский фанат Нарвахи
Команда форума

Регистрация:
2 янв 2012
Публикаций:
25

Комментарии


      1. yashechka 12 мар 2017
        Вроде всё. Кто увидит ошибку - пишите. Кто-то может спросить, почему так долго. Ответ -> потому что, у меня всего 2 выходных и время после 18 основной работы, и главное, я стараюсь переводить и испанского и когда уже не получается переходить к анг. варианту.
      2. yashechka 21 фев 2017
        Тут я не закончил ещё. Как отпишу, что всё готово, значит всё ок. Вчера свет выключили.
      3. TermoSINteZ 20 фев 2017
        расскажите в двух словах, что в этой статье вы хотели раскрыть?