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

# Часть 23

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

Осталось решить незаконченное упражнение **IDA1.EXE**.

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

Функция основана на **EBP** как предыдущие упражнения. Разница заключается в том, что этот пример скомпилирован с помощью **DEVC**++, который имеет особый способ компиляции вызовов **API**, отличный от обычного способа и это может вызвать головокружение, у тех, кто никогда такого не видел.

Хорошо, "**VAMOS POR PARTES**", как сказал **Джек**. Первое, что мы видим - это функция **MAIN**. Если она не появляется, Вы также можете перейти к важной функции, просто посмотрев на строки.

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

Сделаем двойной щелчок по строке "**You are a winner man je**" и мы попадём на этот адрес:

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

Я помещаю курсор мышки над стрелкой перекрёстной ссылки. Мы можем видеть куда ведёт эта перекрёстная ссылка.

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

Но лучше, конечно, нажать **CTRL** + **X**. Так мы попадём туда, где находится данный код.

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

Переходим в этот код, щелкая по этой ссылке.

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

Я меняю в зеленый цвет блок кода, который является **ХОРОШИМ СООБЩЕНИЕМ**. Нам нужно попасть в него.

Мы видим, что перед ним идёт сравнение переменной **VAR**\_**C** с константой **0x51525354**.

Если мы сделаем правый щелчок на этом значение **0x51525354**, появятся альтернативные значения, как можно представить это значение.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjqtEP2kV1qNtJHVrED%2F-LjqtGZ4iHdqCR8E-KCR%2F23-07.png?generation=1563215342163662\&alt=media)

Я могу изменить это представление на буквы **QRST**, которые являются символами **ASCII** этого **HEX** значения.

Мы также можем видеть, что компилятор не использует **CANARY** защиту, потому что в начале функции программа должна считать переменную из секции **DATA** и **XOR**'ить эту переменную с помощью регистра **EBP** и сохранить её чуть выше **STORED EBP** в стек, а также, считать её снова, непосредственно перед выходом из функции, чтобы вызвать **CALL**, который проверит это значение переменной. Ничего из этого не происходит здесь. Если мы посмотрим статический анализ стека, сделав двойной щелчок на любой переменной.

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

Мы видим, что единственное, что есть в стеке, чуть выше **STORED EBP**, это переменная **VAR**\_**C**, которая сравнивается со строкой **QRST**, чтобы идти к хорошему сообщению, что исключает, что это переменная **CANARY**, так как в этом случае это проверка, которая принадлежит исходному коду программы. **CANARY** не подмешивается к решениям исходного кода программы. Это что-то добавленное самим компилятором, внешнее по отношению к исходному коду и это не защита.

Мы можем переименовать эту переменную, чтобы не путать её с **CANARY**. Назовём её как **VAR\_DECISION**.

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

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

Те, кто смотрит на этот код впервые, обратят внимание, что существуют переменные и аргументы связанные с **EBP**, но есть и другие, которые отсчитываются от **ESP**.

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

Весь этот начальный код, добавлен компилятором, чтобы установить **ESP** чуть выше переменных и локальных буферов. После исполнения **SUB ESP**, **0B8** программа подготовлена к этому. Хотя программа никогда не изменяет намного больше памяти чем выравнять и округлить, мы могли бы делать математические расчёты. Но если мы не хотим осложнять себе жизнь, мы можем отладить программу, чтобы увидеть какое значение осталось в **ESP**, чтобы закончить всё это и начать с оригинального кода функции.

Тот, кто захочет отладить это место, может сделать это, но у нас есть другая помощь от **IDA**, которая очень полезна. Это расчёт отклонения **ESP** в стеке начиная с самого начала стека функции, что принимается за нуль.

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

Если посмотрим на код сейчас, после установки этой опции.

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

Мы видим влияние каждой инструкции на стек начиная с нуля, что является началом стека. После выполнения инструкции **PUSH EBP**, стек уменьшается на **4**, поэтому у второй строки справа написано **004**.

Вторая инструкция - это **MOV EBP**, **ESP**, которая не изменяет стек, потому что это только одинокая инструкция **MOV** и поэтому регистр **ESP** не меняется, а изменяется только регистр **EBP**.

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

Вот почему третья строка имеет то же самое значение **004**, потому что инструкция не изменила значение **ESP**.

Давайте запомним, что **ESP** и **EBP** остаются одинаковыми и **EBP**, начиная отсюда, будет ссылкой отстающей на **4** байта от начала **ESP**.

Следующая строка вычитает значение **0xB8** из **ESP**, поэтому **ESP** будет равен **0xBC** от начала отсчёта в стеке и поскольку **EBP** был равен **4**, разница между **EBP** и **ESP** будет только **0xB8** байт.

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

Мы видим, что потом расстояние не меняется, даже при вызове функций \_\_**ALLOCA** и \_\_\_**MAIN**, которые добавлены компилятором. Поэтому, мы можем заключить, что всё это не влияёт ни на что. Расстояние между **EBP** и **ESP** всё также равно **0xB8** и это пространство для локальных переменных и буферов.

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

Здесь уже начинается код самой функции и расстояние от **ESP** до начала стека осталось равным **0xBC** и **0xB8** - это область, зарезервированная для локальных переменных и буферов.

Поскольку переменная **VAR\_9C** является временной переменной, созданной компилятором и не используется больше, то мы переименуем её в **TEMP**.

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

Ниже переменной **TEMP** у нас есть буфер. Я делаю правый щелчок и выбираю – **ARRAY**. Мы видим, что размер буфера равен **140** байт в десятичной системе, так как каждый элемента равен **1** байт, поэтому и размер буфера равен **140** байт в десятичной системе.

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

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

Если бы нам удалось переполнить буфер, скопировав в него больше **140** байт, он бы имел уязвимость типа **BUFFER OVERFLOW**, эксплуатируя которую, можно было бы перезаписать переменную **VAR**\_**DECISION** и если бы могли писать дальше вниз, нам удалось бы дойти до **STORED EBP** и **RETURN** и перезаписать их, в зависимости от того, сколько байт мы скопировали.

Давайте продолжим реверсить. Самая высокая точка компиляции - это способ, как Вы передаёте аргументы в функции. Вместо того, чтобы использовать **PUSH** для сохранения аргументов в стек, сохраняйте их непосредственно с помощью инструкции **MOV**. Мы увидим скоро это пример.

Здесь всё становится ясно. В этом случае, **PRINTF** имеет единственный аргумент, который является адресом строки "**You are a winner je**" и больше не имеет никаких других аргументов.

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

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

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

Если мы изменим представление на этот пункт.

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

Мы видим, что то, что действительно происходит, состоит в том, что адрес строки помещается в содержимое **ESP** (самое верхнее положение стека), чтобы использовать его как аргумент. Другими словами, это программа вместо того, чтобы исполнить **PUSH** на вершине стека, помещает аргументы в положение стека с помощью инструкции **MOV** и логически **PUSH** изменяет значение **ESP**, в то время как инструкция **MOV** – нет. Это можно увидеть по значению **BC**, которое расположено непосредственно перед функцией.

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

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

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

Мы видим, что первый **PRINTF** имеет **3** аргумента, потому что он заменяет форматную строку в строке `buf : %08x cookie : %08x\n`. Для двух верхних аргументов, будет так.

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

Первый аргумент - это адрес переменной **VAR**\_**DECISION**, который получен с помощью инструкции **LEA**. Инструкция помещает адрес в **EAX** и сохраняет его в содержимое **ESP + 8**.

Второй аргумент - это адрес переменного буфера, который получен также с помощью **LEA**. Инструкция помещает его в **EAX** и сохраняет адрес в содержимое **ESP+4** как следующий аргумент. Третий аргумент сохраняет адрес в содержимое **ESP** и это будет адресом строки. В нашем случае, это строка с форматом.

Если Вы запустите программу вне **IDA**, мы увидим, что программа печатает в консоли адреса обоих переменных, так как программа заменяет исходную строку на форматную, на **HEX** значения обоих адресов, потому что используется последовательность **%x**, которая является преобразованием вывода строки в **HEX** представление.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjqtEP2kV1qNtJHVrED%2F-LjqtGZecWsN-nQ5wPaR%2F23-25.png?generation=1563215341447377\&alt=media)

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

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

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjqtEP2kV1qNtJHVrED%2F-LjqtGZiYHRhR4-BeZ87%2F23-27.png?generation=1563215341762095\&alt=media)

Здесь также программа передаёт адрес буфера, в который будут поступать символы с клавиатуры как аргумент, в содержимое **ESP**

Так что мы знаем, что если я напишу например **140** символов **A** и затем символы **TSQR**, так как они должны идти наоборот из-за режима **LITTLE ENDIAN**, программа должна показать мне хорошее сообщение, так как мы будем перезаписывать переменную **VAR**\_**DECISION** значением **QRST**, которая находится чуть ниже буфера. Давайте сначала сделаем всё это вручную, перед тем как сделать скрипт.

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

Я печатаю строку в **IDA**, и копирую её в буфер обмена, и вставляю её здесь.

`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATSRQ`

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

Когда программа ожидаем ввода я вставляю подготовленную строку и ...

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

Скрипт очень простой. Он также совпадает с предыдущим. В нашем случае он не имеет двух потоков ввода для **STDIN**, а имеет только один.

> **from** subprocess **import** \*
>
> p = Popen(\[**r'C:\Users\ricna\Desktop\New folder (6)\IDA1.exe'**, **'f'**], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
>
> **print "ATACHEA EL DEBUGGER Y APRETA ENTER\n"**
>
> raw\_input()
>
> primera=**"A"** \*140 + **"TSRQ\n"**
>
> p.stdin.write(primera)
>
> testresult = p.communicate()\[0]
>
> **print** primera
>
> **print**(testresult)

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

Здесь Вы видите результат. Многие не смогли бы это сделать из-за способа передачи аргументов. Но сейчас будет проще сделать упражнение №**2**, так как оно очень похожее и скомпилировано таким же образом, и Вы уже знаете про этот трюк.

Следующее упражнение называется **IDA2.EXE**.

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

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

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

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

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

27.11.2017

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