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

# Часть 36

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

Хорошо. Давайте начнем работать с версией программы, которая имеет защиту **DEP**. Мы знаем, что программа похожа на предыдущую, но что произойдёт, если мы запустим скрипт для версии где защита **DEP** отсутствует.

Изменим путь в скрипте, для того, чтобы он указывал на файл **DEP.EXE**.

![](/files/-Ljtu1_lvWCs6hjnDjB1)

Я запускаю скрипт и присоединяюсь к процессу помощью **IDA**, которая уже имеет анализ файла **DEP.EXE**.

![](/files/-LjrE0qqASwaHkGclBve)

Я установлю **BP** сразу после функции **GETS**, чтобы увидеть, что происходит в функции **SALUDA**, так как процесс ожидает здесь внутри **API** функции, когда мы присоединяемся к нему.

![](/files/-Ljtu1a_QTex1X52so5B)

Программа остановилась здесь. Я буду трассировать её до инструкции **RET** c помощью клавиши **F8**.

![](/files/-LjrE0r-Dw38mPBkbV2y)

Здесь мы видим перезапись стека. Программа будет переходить на гаджет **PUSH ESP** - **RET**, который находится по адресу **0x7800F7C1**. Здесь не должно быть никаких проблем, потому что это инструкция кодовой секции модуля и эти секции всегда имеют разрешение на выполнение. Мы нажимаем клавишу **F7**.

![](/files/-Ljtu1b3yaIrYZaedyj6)

Трассируем программу далее с помощью клавиши **F7**.

![](/files/-Ljtu1bLpQ3GPGsUBHmA)

Программа помещает в стек значение регистра **ESP**, а затем переходит к исполнению инструкции **RET**. Здесь программа будет переходить на адрес **0x78FBC8**, чтобы выполнить его, как если бы это был обратный адрес для выполнения и здесь это мой шеллкод в стек. В файле **NO DEP** программа переходила и выполняла этот шеллкод, который я засылал. Но что происходит здесь? Я нажимаю клавишу **F7**.

> 0078FBC4 0078FBC8 STACK\[00005608]:0078FBC8

![](/files/-Ljtu1bamKLQQcJQ3CVI)

Код в стеке, который программа выполняла без проблем для файла **NO DEP**, не может быть здесь выполнен, потому что защита **DEP** удаляет разрешение на выполнение в стеке (в куче и т.д.) и оставляет только права на чтение и запись.

Что мы можем сделать здесь ?

Мы видим, что когда программа переходит в код библиотеки как мы это делали с помощью гаджета **PUSH ESP - RET** и это является основном смыслов **ROP**. Поместите гаджеты вместе, которые представляют собой небольшие кусочки кода, которые заканчиваются на **RET**, чтобы наконец получить разрешение на выполнение в стеке, куче или того, что нам нужно.

Например, если я хочу поместить значение в регистр **EAX**, то вместо перехода на гаджет **PUSH ESP - RET** я буду переходить на гаджет **POP EAX - RET**. Я буду искать гаджет **POP EAX - RET** среди гаджетов **IDASPLOITER** в моей библиотеке **MYPEPE**, которая не имеет защиту **ASLR**.

![](/files/-LjrE0rU2mQrEYfhJqeJ)

![](/files/-LjrE0rlAY6kdQF7jrI-)

Здесь такой гаджет расположен по адресу **0x78003D08**.

![](/files/-LjrE0rt0E2fPuiaz_gm)

Здесь, мы заменили переход на гаджет **PUSH ESP** - **RET** нашим **ROP**, который начинается с инструкции **POP EAX**, которая помещает значение **0x41424344**. Это значение находится ниже в регистре **EAX** и затем когда программа переходит к инструкции **RET** (помните, что все или почти все гаджеты заканчиваются на инструкции **RET**) она переходит к следующему гаджету по адресу **0xCCCCCCCC**. Позже я посмотрю, что это такое, но сейчас давайте выполним этот код, чтобы посмотреть, что произойдёт. Давайте снова присоединимся к процессу и потрассируем его немного, как и раньше.

![](/files/-Ljtu1cQC2uCLKYx7a8W)

Когда я дохожу до инструкции **RET**, я вижу как гаджет **POP EAX - RET** переходит в мой **ROP**. Значение **0x41424344**, которое в конечном итоге поместится в регистр **EAX** и значение **0xCCCCCCCC** где вы должны добавить указатель на следующий гаджет. Давайте потрассируем этот гаджет с помощью клавиши **F7**.

![](/files/-Ljtu1ccdcPfvvV26H8x)

Мы переходим к моему первому гаджету. Это гаджет **POP EAX - RET**. Мы знаем, что инструкция **POP** берет значение с вершины стека и помещает его, в нашем случае, в регистр **EAX**. Если я выполю код с помощью клавиши **F7**.

![](/files/-LjrE0sC6fjnrx73lVQP)

Здесь это значение было помещено в регистр **EAX**, и поскольку программа достигла инструкции **RET**, теперь она будет переходить на следующий гаджет, в этом случае на адрес **0xCCCCCCCC**. У Вас его ещё нет, но мы должны добавить его сюда.

И всё это называется **ROP**. Объединяя разные гаджеты вместе, программа будет делать то, что пожелаю. Гаджет будет выполняться один за другим. Вот почему всё это называется **ROP** (**RETURNORIENTED PROGRAMMING**). Потому что мы исполняем код без сборки наших собственных инструкций. Мы только помещает список адресов, которые указывают на кусочки кода. Они служат нам для достижения цели и приводят к захвату системы.

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

Общий метод состоит в том, чтобы разместить определенные значения в регистрах и затем перейти к гаджету **PUSHAD** - **RET**. Мы увидим, что программа будет перестраивать всё. Хотя есть тысячи способов собрать **ROP**. Это самый распространенный метод.

Прежде всего нужно решить, какой **API** мы будем использовать для снятия защиты со стека. В этом случае, это могут быть функции **VIRTUALALLOC** или **VIRTUALPROTECT**, которые наиболее часто используются, хотя, на самом деле, этих способов больше.

Мы знаем, что сейчас есть две вкладки с модулями. Это **IDASPLOLITER** и сама **IDA**. Последняя находится в меню **DEBUGGER → DEBUGGER WINDOWS → MODULE LIST**. Здесь мы сделаем щелчок правой кнопкой по библиотеке **MYPEPE** и будем анализировать его. Затем заставьте **IDA** загрузить его символы, если они конечно, есть.

![](/files/-LjrE0sIC6guymJZKwY5)

Поскольку у нас нет символов для библиотеки **MYPEPE**, это выглядит хорош&#x43E;**(???)**, но **IDA** не добавляет никакой информации про импортированные функции, которые видно в списке функцией. Там есть только для библиотеки **MYPEPE(???)**.

Но хорошо, давайте будем искать строку **OFF\_**.

![](/files/-LjrE0s_OIdiApD2-U_I)

Мне не нужны все вхождения. Только одно.

![](/files/-Ljtu1dbexRgkApXWq5E)

Инструкция **CALL** является типичным переходом к импортированной функции **IAT**, так как префикс **OFF\_** (не путать с **OFFSET**, который указывает адресом) в этом случае означает, что это содержимое адреса, куда программа будет переходить. Он также является указателем, как в случае **IAT**. Давайте перейдём по этому адресу.

![](/files/-MX3mKJdAAh65N2CLabI)

Хорошо. Смотря между функциями **IAT** мы видим функцию **VIRTUALALLOC**. Поэтому мы будем подготавливать для неё **ROP** (мы уже знаем, что **0x7802E0B0** это начало **IAT VA**. С этого момента я будет называть **VIRTUALALLOC → VA**)

Основной смысл состоит в том, чтобы разместить эти значения в каждом регистре и затем с помощью некоторых гаджетов **PUSHAD** - **RET** вставить их в стек, чтобы они были упорядочены как аргументы для функции **VIRTUALALLOC**. Да, да - это не волшебство.

![](/files/-LjrE0sg4USrFo-PXdTu)

Мы видим, что нам нужно поместить значение **0x90909090** в регистр **EAX**. Для это есть гаджет **PUSH EAX - RET** мы уже добавили его. Теперь нам нужно изменить регистр **POPEA** на регистр **EAX** в **0x90909090**, но регистр **EAX** всегда соглашается установить его последним, потому что он может быть необходим для установки других значений. Рекомендуется добавлять сначала самые сложные. В регистре **ESI** должен быть адрес функции **VIRTUALALLOC**, но у нас есть только расположение **IAT** и адрес **API** будет меняться, записи **IAT** не будет. Поэтому основываясь на местоположении, мы будем искать адрес и **ROP** будет работать всегда.

Для этого, мы должны искать самые простые гаджеты. Если есть такой гаджет **MOV ESI**, \[**РЕГИСТР**] **- RET**. Давайте искать эту последовательность среди гаджетов.

Такого гаджета нет, но зато есть такой.

![](/files/-Ljtu1eb-CcOIjLw6YQP)

Всё хорошо. Мы помещаем в регистр **EAX** адрес **IAT + 4** и с помощью этой инструкции мы помещаем адрес **API** в регистр **EAX**. Нам придется переместить значение из регистра **EAX** в регистр **ESI** с помощью другого гаджета. Но давайте упорядочим всё это и попробуем всё это в деле.

Расположение записи **IAT** было по адресу **0x7802E0B0**. Мы добавим к ней значение **4** и поместим значение в регистр **EAX** с помощью гаджета **POP EAX - RET**, который у нас уже есть.

![](/files/-LjrE0skbbqIZzYFkiDy)

При этом у нас будет местоположение **IAT + 4** в регистре **EAX**. Следующий гаджет будет тем, который мы уже нашли.

> 780022DE MOV EAX, \[EAX - 4] # RETN

![](/files/-Ljtu1f4XH8eTDr6f-Vk)

Здесь мы объединяем оба гаджета. Давайте протестируем их, чтобы убедиться, что они делают то, что мы задумали и адрес **VIRTUALALLOC** остаётся в **EAX**.

Одно из неудобств, которое мы увидим, заключается в том, что **IDASPLOITER** работает только в режиме отладки. Поэтому если нам нужно отлаживать, он будет закрываться при перезагрузке, но мы можем открыть другой экземпляр **IDA** с процессом c остановленным процессом отладки, для того чтобы найти его в **IDA SPLOITER** и отлаживать его в другом окне.

![](/files/-Ljtu1fDIv8rC18KAu4o)

Мы будем трассировать **ROP**, который мы сделали, до этого места с помощью клавиши **F7**.

![](/files/-LjrE0srLSL-dvwlo1J9)

Теперь программа будет помещать адрес записи **IAT** из **VA + 4** в регистр **EAX**.

![](/files/-Ljtu1fYhgvxLQLWMmY1)

Сейчас, программа будет переходить на второй гаджет. Я продолжаю с помощью клавиши **F7**.

![](/files/-Ljtu1ff8Kw_rirzBZbs)

Я исполняю гаджет с помощью клавиши **F7**.

![](/files/-Ljtu1foqeUuGk3gfSgS)

Мы видим, что мы достигли нашей цели. Адрес **API** находится в регистр **EAX** и мы вытащили его из **IAT**. Поэтому он будет работать на любой машине. Следующий гаджет должен поместить **VA** адрес из регистра **EAX** в регистр **ESI**, чтобы он оставался в регистр **ESI**, где это соответствует следующему.

![](/files/-Ljtu1iKl8MMN0d-5Yfl)

Здесь нет инструкции **MOV ESI, EAX** или что-то в этом роде. Поэтому мы должны использовать наше воображение. Несмотря на то, что гаджеты обычно заканчивает на инструкции **RET**, любой код, даже если он не заканчивается на **RET**, позволяет мне продолжать и удерживать контроль. Он также будет считаться гаджетом, хотя он и менее традиционный, но он всё равно будет работать.

![](/files/-Ljtu1gAldrBJD4KqjwI)

Если я помещу значение регистра **EAX** в стек используя гаджет **PUSH EAX - CALL ESI** и подготовлю регистр **ESI** для гаджета **POP ESI** - **RET**, я мог бы поместить содержимое регистра **EAX** в **ESI** используя стек. Давайте посмотрим на этот случай.

![](/files/-LjrE0tBV2A5YxFVbIv5)

Поэтому я буду добавлять гаджет **POP ESI – RET** в **ESI** раньше.

![](/files/-LjrE0tFp5EDMkQc3c4m)

![](/files/-LjrE0tIINMlWgyUrgv-)

Мы видим, что инструкция **POP ESI**, помещает в регистр **ESI** тот же самый указатель на гаджет **POP ESI – RET**, чтобы после следующего гаджета восстановить управление.

![](/files/-Ljtu1h474pBmpwoSjXT)

Этот гаджет будет помещать в стек адрес **VA** и снова переходит с помощью инструкции **CALL ESI** обратно к гаджету **POP ESI** - **RET** так как мы сохранили адрес гаджета **POP ESI** - **RET** в регистр **ESI**.

![](/files/-LjrE0tQ9e0WHlH0FJpH)

Мы видим, что гаджет не сработал, потому что он помещает адрес возврата, который он сохранил в регистр **ESI** и чуть ниже это адрес **VA**. Поэтому вместо гаджета **POP ESI** - **RET** последним должен быть гаджет **POP XXX**, **POP ESI** - **RET** что перенести первое значение из стека в другое место и затем вытолкнуть в регистр **ESI** адрес **VA**.

![](/files/-LjrE0tU6bmSLd0lKaQ-)

Вот нужный нам гаджет. Поэтому я меняю именно его, который я помещаю в регистр **ESI**. Другой гаджет должен оставаться таким же.

![](/files/-Ljtu1hr0bWOCgSWV61F)

Давайте попробуем сейчас.

![](/files/-LjrE0teqEYIAZwEj6CL)

Я вхожу в гаджет с помощью клавиши **F7**.

![](/files/-Ljtu1iAzB-fWlSD271N)

Готово. Первая цель уже достигнута. В регистре **ESI** находится адрес **VA** и программа будет переходить по адресу **0xCCCCCCCC**, который является адресом следующего гаджета. Поэтому я снова взял контроль над выполнением.

![](/files/-MX3mKLcikdMKC5qOxqA)

Следующий гаджет будет легче. В регистр **EBP** мы должны поместить адрес гаджета **JMP ESP, CALL ESP** или **PUSH ESP - RET**. У нас уже был гаджет **PUSH ESP - RET**. Мы только должны найти гаджет **POP EBP - RET** чтобы поместить его в регистр **EBP**.

![](/files/-Ljtu1iUscVwZyZz7dhF)

![](/files/-LjrE0tvzHj7X1dUguJ1)

![](/files/-LjrE0tzwMTh1Wpsn0ui)

Это настройка для регистра **EBP**. При этом, он будет установлен с указателем на гаджет **PUSH ESP - RET**. Давайте продолжим.

![](/files/-Ljtu1jzKunufsmu-C1c)

**EDI** = **ROP NOP** означает, что регистр должен указывать на **RET**, который является **NOP** в программировании **ROP**. Поэтому давайте найдем гаджет **POP EDI - RET** для установки регистра **EDI**.

![](/files/-Ljtu1jYzrCZCau1LU0N)

![](/files/-LjrE0uCB2ezjNRub_4O)

Мы устанавливаем любой указатель библиотеки **MYPEPE** на **RET**. Он переместит его в регистр **EDI**. Давайте продолжим.

![](/files/-MX3mKMIpYMN5w8yAS9e)

Нам нужно установить **4** константы: значение **90909090** в регистр **EAX**, значение **40** в регистр **ECX**, значение **1000** в регистр **EDX** и значение **1** в **EBX**. Мы будем искать соответствующие **POP** и добавлять константы.

![](/files/-Ljtu1k9qdXzLHBOV4sq)

![](/files/-Ljtu1kIRJs7wde00FfA)

![](/files/-Ljtu1kSDs1EdzMEz0fv)

![](/files/-LjrE0uYOoV5Hxwpo-mq)

Давайте добавим их в нашу цепочку **ROP**.

![](/files/-Ljtu1knC2k1N9shda4L)

Готово. Теперь нам нужен только последний гаджет, который завершит всю цепочку. Им будет **PUSHAD** - **RET**.

![](/files/-LjrE0ugGCcLmaqCrBuY)

Вот он. Инструкция **ADD AL**, **XX** ничего не делает, потому что до этого была инструкция **PUSHAD**. Поэтому он будет сохранять **90909090** в стеке. Давайте добавим его.

![](/files/-Ljtu1lSXU0l9EaVajqg)

Цепочка уже должна заработать с этими гаджетами. Давайте трассировать её полностью до тех пор пока не доберемся до функции **VIRTUALALLOC**.

Мы пришли к инструкции **PUSHAD**.

![](/files/-LjrE0upFjqf0EACxYQB)

Всё выглядит хорошо. Мы нажимаем клавишу **F7**.

![](/files/-LjrE0uto0mLTTra4f6Z)

Мы добрались до функции **VIRTUALALLOC**. Мы видим аргументы в стеке. Первым будет место, где программа вернётся после возвращения из **API**. Если я посмотрю, это будет гаджет **PUSH ESP** - **RET**. Затем приходят аргументы для **API**. Давайте проверим.

![](/files/-LjrE0uxVTzldjItzV_-)

Адрес для снятия защиты **LPADDRESS** принадлежит стеку и показывает, где находится мой шеллкод.

![](/files/-Ljtu1mk5FaCLd31pUFG)

Затем идёт параметр **SIZE 1**, который будет снимать защиту блока длиной равной **0x1000**, потому что это минимальный блок для снятия защиты. Независимо от того, что вы введете. Затем идёт значение **0x1000**, которое является константой для указания типа распределения и значение **0x40**, которое является другой константой **FLPROTECT**. Если я выполню код **API** до инструкции **RET**, то нажимая **CTRL + F7**, я увижу, что программа возвращается к гаджету **PUSH ESP - RET**.

![](/files/-LjrE0v5Edgm6H9kJsoq)

Если в регистре **EAX** программа вернет адрес, то гаджет правильный и стек теперь не защищен. Сейчас я могу выполнить мой код в стеке. Я продолжаю трассировать с помощью клавиши **F7**.

![](/files/-LjrE0v9g9DEt24VO6Vj)

Мы видим, что программа прибывает в мой шеллкод без проблем и он исполняется.(**Аллилуйя**)

![](/files/-LjrE0vE_ZREw3hKUMGJ)

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

МЫ ПОБЕДИЛИ.

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

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

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

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

24.03.2018

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