> 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)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://yutewiyof.gitbook.io/intro-rev-ida-pro/chast-36.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
