> 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-09.md).

# Часть 9

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

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

Мы будем практиковаться на очень простых примерах, в нашем случае это очень простые крэкми, которые скомпилированы в **VISUAL STUDIO 2015** для нашей практики. Очевидно, для того, чтобы крэкми заработал, у Вас должны быть установлены последние версия библиотек **VISUAL STUDIO 2015 C++**.

<https://www.microsoft.com/es-ar/download/details.aspx?id=48145>

Пакеты **Visual C++ Redistributable** устанавливают компоненты среды выполнения, которые необходимы для запуска приложений написанных на языке **C++** и скомпилированные в **Visual Studio 2015**.

Выберите нужный для своей операционной системы пакет, согласно вашему языку, загрузите и установите библиотеки.

Присоединенный файл - это исполняемый файл, который называется **HOLA\_REVERSER.EXE**([крэкми находится в архиве с оригиналом](http://ricardonarvaja.info/WEB/INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO/9-INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO%20PARTE%209.7z)) и который запускается под **WINDOWS 7**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgS2XsTX5UlG6nqU%2F09-01.png?generation=1563191097911149\&alt=media)

При вводе номера крэкми будет говорить, насколько я хороший или плохой реверсер.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgS4nmaURKdilB0x%2F09-02.png?generation=1563191098123188\&alt=media)

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

В моём случае (не в Вашем) функция **MAIN** появляется среди других функций, поэтому я могу найти её с помощью комбинации **CTRL+F** здесь на этой вкладке или там, где у меня открыта вкладка с функциями, но это происходит, потому что я скомпилировал программу с помощью **VISUAL STUDIO** и создал **PDB** файл с символами, который обнаруживает **IDA** и загружает оттуда имена функций и имена переменных, мы видим, что в моём листинге равно как и в моём исходном коде, появляется функция **MAIN**, а ниже функция **PRINTF**, мы будем смотреть, что будет происходить в Вашем случае.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4WowQMXaC7sS9Lg%2F03.png?generation=1563265914250220\&alt=media)

В Вашем случае, **IDA** не скажет, что это за функция, потому что у **IDA'**&#x44B; нет символов.

Вероятно, это потому, что никто не распространяет программу с символами.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4XZCiWqc60QjaZt%2F04.png?generation=1563265892821619\&alt=media)

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

Мы видим, что здесь у нас нет символов.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4YQDQk3ZMowEwaM%2F05.png?generation=1563265892877257\&alt=media)

Мы имеем очень мало информации, но хорошо то, что мы можем видеть строки.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4YkksADVNU531IB%2F06.png?generation=1563265891729693\&alt=media)

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

Мы можем сделать двойной щелчок на строке **"Pone un numerito\n"**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4Z4c3dLKcOi81de%2F07.png?generation=1563265894904208\&alt=media)

Здесь мы видим, что **0x402108** это адрес строки, а рядом с адресом мы видим **ТЭГ**, который помещен рядом и всегда начинается с буквы "**a**" если это строка **ASCII**, а оставшиеся символы принадлежат к той же строки, поэтому её очень легко распознать, в нашем случае тэг называется **aPoneUnNumerito**, а затем идут символы **DB**, потому что строка - это последовательность байт.

Строку можно рассыпать на байты с помощью клавиши **D**, теперь мы видим те же самые символы только по вертикали и по одному.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4Z_sAXsExtaK_8r%2F08.png?generation=1563265890817343\&alt=media)

Сейчас, когда мы убеждаемся, что это та же строка, мы вновь создаем строку с помощью клавиши **A** и собираем её по горизонтали.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSIAfKshU4E8yU4%2F09-09.png?generation=1563191260993194\&alt=media)

Поместив курсор мыши на ссылку в виде маленькой стрелки, мы видим откуда вызывается эта строка, но будет лучше, если мы нажмем клавишу **X**, чтобы увидеть список ссылок и перейдём туда.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4_0AY2rNQgZR-aP%2F10.png?generation=1563265899905010\&alt=media)

Хорошо, мы находимся в главной функции, здесь она не называется главной, хотя имя буфера, который является общим помечен как **BUF**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4_GWQTzNAlCG1yD%2F11.png?generation=1563265894124509\&alt=media)

Предполагается, что мы не знаем исходный код программы, но я Вам его покажу.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4baVHmqWjhYNN21%2F17.png?generation=1563265892299066\&alt=media)

Я понимаю, что переменные, которые Вы создаете, становятся оптимизированными, например такие как **COOKIE** и **MAX**, которые заменены константами и остаётся только мой буфер, который в моём коде составлял **120** байт в десятичной системе.

Буфер - это пространство памяти зарезервированное, чтобы хранить данные, в нашем случае резервируется **120** байтов.

Как мы можем узнать в **IDA** размер буфера в стеке, если у нас нет исходного кода?

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4aAiVJevdFwMvd4%2F13.png?generation=1563265892155497\&alt=media)

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

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSS8EfhERrisn59%2F09-14.png?generation=1563191266639519\&alt=media)

Здесь мы видим буфер **BUF**, но он определен как последовательность байт **DB** (**IDA** если нет символов не может обнаружить буфер). Чтобы собрать его в массив символов или пустой массив, щелкните правой кнопкой мыши на слове **BUF** и выберите параметр **ARRAY**.

-= Примечание от **Яши** — Можно также нажать символ **\*** на цифровой клавиатуре=-

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSUqlrEgrEeroUd%2F09-15.png?generation=1563191282520842\&alt=media)

Здесь мы видим, что до следующей переменной или того, что находится ниже в стеке, **IDA** обнаружила **120** десятичных **DB**, а элемент массива равен длине каждого поля, так как размер поля равен **1**байту, то это массив символов или байтов и его сумма рассчитывается так **120\*1** байт или просто **120** байт.

Если согласимся с этим, то получится так.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4bM-VcksAYeEZRh%2F16.png?generation=1563265892929855\&alt=media)

Я вижу, что буфер состоит из **120** байт, что соответствует моему исходному коду, хотя компилятор может сделать его больше, пока он минимум равен **120** байт, то всё хорошо, в этом случае они равны. **DUP** - означает дубликат (на самом деле он должен быть умножен) **120** раз на символ "**?"**, потому что значение ещё не определено и это соответствует пустому статическому буферу.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2Fsync%2F206aae45c914323235beb27551e691b764b7d098.png?generation=1617135494382272\&alt=media)

Я буду прояснять представление статического стека позже, но ниже **BUF** есть переменная **DWORD** (**DW**) называемая **VAR\_4**. **S** и **R** - это сохраненный **EBP** родительской функции, которая вызвала эту функцию и **АДРЕС ВОЗВРАТА**, как мы видели при входе в первую функцию - сначала кладутся аргументы с помощью **PUSH**, а затем делается **CALL**, чтобы войти в функцию, которая сохранит **АДРЕС ВОЗВРАТА** в стек, и локальные переменные будут выше **S**.

> **ПЕРЕМЕННЫЕ**
>
> …
>
> …
>
> **S** (Сохраненный **EBP** - как правило, происходит от **PUSH EBP**, которая является первой инструкцией функции)
>
> **R** (Адрес возврата)
>
> **АРГУМЕНТЫ**

Поскольку аргументы помещаются в стек перед **CALL**, который помещает адрес возврата в стек, они будут ниже него, затем будет идти адрес возврата, а выше него **СОХРАНЕННЙ EBP** порожденный инструкцией **PUSH EBP**, которая как правило первая инструкция в функции, а затем выше идет пространство локальных переменных, мы увидим их более подробно позже.

Если я нажму **X**, чтобы увидеть откуда вызывается эта функция, то увижу:

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4bsdw_xKsLwDcss%2F18.png?generation=1563265897664154\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4c5E_DjQ7_ygmTj%2F19.png?generation=1563265891719321\&alt=media)

И я иду туда и вижу, что у нас есть инструкции **PUSH**, которые передают аргументы функции, имя которой я видел, когда работал с **СИМВОЛАМИ**, а сейчас её здесь нет, 3 аргумента ниже пропущены, ниже есть изображение с символами.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSddEcn8OSrYzpu%2F09-20.png?generation=1563191266150516\&alt=media)

**IDA** обнаружила, что никогда не используются такие аргументы как **ARGC**, **ARGV** и **ENVP**, они присутствуют по умолчанию в функции **MAIN**, но так как там не было никаких ссылок на них или их использование в функции, **IDA** избавилась от них.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSfaAk8S75wqfVC%2F09-21.png?generation=1563191273230098\&alt=media)

Кроме того, в моём коде даже не передаются переменные как аргументы к функции **MAIN**, так что все хорошо - функция без аргументов.

Когда мы хотим увидеть из какого места получается доступ к переменной, мы отмечаем её и нажимаем **X**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSh4NuEkYxKdM9j%2F09-22.png?generation=1563191259502347\&alt=media)

Мы видим, что **VAR\_4** используется в двух местах, для тех кто не знает, это переменная **COOKIE**, которую я не программировал, это защита от переполнения стека, программа сохраняет их в начале при запуске функции, проверяет их на целостность при выходе из функции, теперь мы можем переименовать их в **COOKIE\_DE\_SEGURIDAD** или **CANARY**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSjUjDN9yaQ2h6a%2F09-23.png?generation=1563191276508692\&alt=media)

Мы видим, что когда функция хочет напечатать строки она вызывает **CALL** в которой в конечном итоге будет вызвана функция **PRINTF** для печати строк.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSlDTNwCA2Oh1tg%2F09-24.png?generation=1563191280569895\&alt=media)

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

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4eo0jcYodBdeDTC%2F25.png?generation=1563265893960980\&alt=media)

Но только если мы посмотрим внутрь **CALL** то узнаем, что аргументы, это строки, которые печатаются в консоли и мы делаем вывод, что это функция **PRINTF**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4fD6hNbKYR6d3bo%2F26.png?generation=1563265895020442\&alt=media)

Мы видим, что внутри эта функция заканчивается вызовом **VFPRINTF**, так что, это то, что нам нужно переименовать.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgSr6XXvZQsn1zkc%2F09-27.png?generation=1563191098035337\&alt=media)

У нас остаётся только буфер из **120** байт, давайте посмотрим, что будет с ним происходить.

Мы видим, что буфер идет как аргумент к функции **GETS\_S** - эта функция, которая получает то, что мы вводим в консоли.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4fhTgSfQm0ToXDu%2F28.png?generation=1563265900987288\&alt=media)

Мы видим, что есть два аргумента - указатель на буфер и его максимальный размер, в который позволено нам печатать, давайте посмотрим, что будет в нашем случае.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4gHzknAHDTLlDEV%2F29.png?generation=1563265894050277\&alt=media)

Ранее мы сказали, что **LEA** вычисляет адрес переменной, в этом случае **LEA** является указателем на буфер **BUF**, который передаётся с помощью инструкции **PUSH EAX**, а затем идёт **PUSH 0x14**,который указывает максимальное количество символов, которое можно ввести в консоли.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4gSLhQQofO-XVE3%2F30.png?generation=1563265900418407\&alt=media)

В моём исходном, мы видим тот же самый вызов **GET\_S** с двумя аргументами - **БУФЕР** и его максимальное значение, который я обозвал как переменную **MAX** из **20** элементов, но компилятор, чтобы сохранить пространство поместил именно **20** в десятичной или **0x14** в **HEX** в этот аргумент, так как не нужно использовать больше.

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

Позже, тот же указатель на буфер помещается как аргумент к функции **ATOI**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4gkxQSjDTc-uhPo%2F31.png?generation=1563265916704584\&alt=media)

Она делает то же самое.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu4h4L1c35G3VUS8P%2F32.png?generation=1563265891325886\&alt=media)

Эта функция конвертирует строку в целое число и если она не может это сделать, потому что происходит переполнение (выход за максимально возможное значение), нам будет показываться ошибка и вернётся ноль, тоже самое происходит и с отрицательным числом, но идея состоит в том, что всё что я буду вводить будет конвертироваться в число, если я введу значение **41424344** оно будет конвертироваться в десятичное значение **41424344**, а так как в ассемблере мы работаем с **HEX** значениями, оно будет возвращено в **HEX** через регистр **EAX**.

Каждая функция возвращает генерируемое значение **INT**, она интерпретирует входные символы как число. Функция возвращает значение **0** для **ATOI** и **\_WTOI**, если ввод не может быть преобразован в значение этого типа.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2Fsync%2F32277930452435b28fb47e9d535307f88fd5b2e8.png?generation=1617135494690811\&alt=media)

Мы видим, что значение возращенное из **EAX** переносится в **ESI** и после печати первоначальной строки, которая была введена, сравнивает **ESI** с числом **0x124578**.

Так что, то, что набрано интерпретируется как строка в десятичном формате, которая возвращается в **HEX** виде и это число сравнивается с этой константой, передавая десятичное значение этой константы.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgT2azI1UEa9DMPx%2F09-34.png?generation=1563191263428707\&alt=media)

Мы видим, что если сравнение не равно (**JNZ**) оно переносит меня к **BAD REVERSER**, а если равно, то переносит к **GOOD REVERSER**, давайте попробуем в консоли **PYTHON** увидеть десятичное значение числа **0x124578**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgT4hynRcdwv7Nnx%2F09-35.png?generation=1563191282296176\&alt=media)

Мы вводим это значение в наш **CRACKME**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgT65_n1Pg6D-Brv%2F09-36.png?generation=1563191281647672\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpRUnjpCK0-q7zigDZ%2F-LjpRgT8IONNhEjXmrPe%2F09-37.png?generation=1563191262471240\&alt=media)

Хорошо, это простой пример статического реверсинга, далее также продолжим работу с ЗАГРУЗЧИКОМ

До встрече в **10**-й главе.

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

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

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

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

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