> For the complete documentation index, see [llms.txt](https://yutewiyof.gitbook.io/intro-rev-ida-pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yutewiyof.gitbook.io/intro-rev-ida-pro/chast-04.md).

# Часть 4

[\[Используемые материалы\]](https://github.com/yutewiyof/intro-rev-ida-pro/tree/e1367e11cc661f3d69c02ae5f733b7dd168bc5ab/.gitbook/assets/files/04.zip)

Мы продолжаем рассматривать инструкции обмена данными в **IDA**.

**XCHG A, B**

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

![](/files/-LjtttyaRmoneHecSqCG)

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

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

![](/files/-Ljp8xcTvKnuHapnd4Fu)

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

![](/files/-Ljp8xcVN-k8GLmS_uem)

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

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

![](/files/-Ljtttz0K-HnQM8HcM3W)

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

![](/files/-Ljtttz6517TZ3zjVUi0)

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

![](/files/-Ljp8xcaQG1NZBO8o-41)

И это меняет префикс **loc\_**, который означает "локальная метка" на префикс **sub\_**, который означает, "начало подпрограммы или функции".

![](/files/-LjtttzJ8tcDuX6XgASL)

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

![](/files/-Ljp8xce5IgX_6jKp55S)

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

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

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

![](/files/-Ljp8xcgdYKk2aZzntkB)

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

![](/files/-LjtttzagXsRjX2dnJVZ)

В этом случае, значение **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/>

![](/files/-Ljp8xckjDkm5Ka2OG-U)

![](/files/-Ljp8xcmpEvbBLX7brUz)

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

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

![](/files/-Ljp8xcoIwWo2u8fDaJh)

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

![](/files/-Ljp8xcqREkjRVwuVVkz)

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

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

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

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

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

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

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

![](/files/-Ljp8xcs4SPy0vjbKKA-)

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

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

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

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

![](/files/-Ljttu-9wFL1thQIj61T)

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

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

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

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

![](/files/-Ljttu-WHp9jd2o94UTR)

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

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

![](/files/-Ljp8xcyH5vMm8Dp3SsR)

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

![](/files/-MX3mIkKTGPEWOk2zgLc)

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

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

![](/files/-Ljp8xd1sLaQdoaBayv8)

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

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

![](/files/-Ljttu-rlKGxpHJZPuiG)

**push offset byte\_4020e7**

![](/files/-Ljp8xd5K8kG-Oxrx8YF)

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

![](/files/-Ljp8xd7GiwEIN6IJbdd)

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

![](/files/-Ljttu0JTGmOQ1FtIVHb)

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

![](/files/-Ljttu0Rzk6J2ZjTHM1T)

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

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

![](/files/-Ljp8xdDk-jyrsj3OfDN)

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

![](/files/-Ljttu0aB7VqPZIlYLGs)

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

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

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

![](/files/-Ljp8xdHUa61jcDobl-5)

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

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

**POP**

![](/files/-Ljttu0nNrgyCA0B1M8U)

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

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

![](/files/-Ljttu0ySD-gLUt0bnPK)

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

Пока пока.

Автор оригинального текста — Рикардо Нарваха.

Перевод и адаптация на английский язык — IvinsonCLS.

Перевод и адаптация на русский язык — Яша Яшечкин.

Перевод специально для форума системного и низкоуровневого программирования - WASM.IN

24.02.2017

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/4-INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO.docx)
