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

# Часть 42

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

В 41 части, для практики было оставлено два упражнения. К сожалению, никто не прислал мне решения. Это заставляет меня задаться вопросом, стоит ли оно того, что я делаю. По крайней мере для меня это сейчас вопрос. Ни обратной связи, ни вопросов ко мне. Ничего нет.

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

Нам необходимо обновить до новой версии плагин **KEYPATCH**, поскольку мы будем использовать его в конце.

![](/files/-Ljtu4kB7wVNawMXPED7) <https://github.com/keystone-engine/keypatch>

Я заменяю файл **.PY** новым скриптом.

[http://ricardo.crver.net/WEB/INTRODUCCION AL REVERSING CON IDA PRO DESDE CERO/EJERCICIOS/](http://ricardo.crver.net/WEB/INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO/EJERCICIOS/)

Давайте откроем пример **41** в **IDA**.

Я буду стараться не использовать символы, так как у вас их то же нет. Поэтому мы будем это делать похожим способом.

![](/files/-LjrT5Op34p7qg5s5fqB)

Если мы посмотрим **STRINGS WINDOWS**, мы увидим строку **MYPEPE.DLL**. Поэтому, возможно, что необходимо поместить библиотеку в ту же папку. Это та же самая **DLL** из предыдущих упражнений.

![](/files/-LjrT5OvD8Sk-KzS3kmk)

Я помещаю библиотеку в нужную папку.

![](/files/-Ljtu4kxk_utYFRgCyZe)

Я делаю двойной щелчок по этой строке.

![](/files/-Ljtu4l6fK2JiqIV9f4e)

Мы видим ссылку. Мы идем в неё с помощью нажатия **X** или **CTRL + X**.

![](/files/-Ljtu4lF2zNF28e-_41P)

Мы видим, что программа загружает библиотеку здесь. Поэтому всё хорошо. Это похоже на функцию **MAIN**. Поскольку это консольная программа, если это так, то она должна иметь функцию в качестве ссылки, которой передаётся такие аргументы как **ARGC**, **ARGV** и т.д.

![](/files/-Ljtu4lQ_TY4mrAmsnuv)

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

![](/files/-LjrT5PK1vvpKIHhF0X6)

Поэтому, по адресу **401090** находится функция **MAIN**. Мы переименовываем её.

![](/files/-Ljtu4lv0kz6yZvCa0fd)

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

Давайте начнем реверсить.

![](/files/-LjrT5PddAxBs4yUK67V)

Здесь, мы видим, что программа читает запись **IAT SYSTEM**, которая находится в секции **IDATA**. Адрес указанной **API** помещается в регистр **EAX**.

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

![](/files/-LjrT5PjYJIQHeOt22Za)

Здесь, Вы можете увидеть запись **IAT. IDA** логически говорит нам о типе **EXTRN**, потому что это внешняя **API** импортированного модуля.

![](/files/-LjrT5PsbewX1J6reK8s)

Конечно, в **IMPORTS** есть импортированные функции для модуля и адрес записи **IAT**, который показывает значение **4020A8**, поэтому у нас всё совпадает.

![](/files/-LjrT5Pzc4Ji1VKYYeW7)

Затем программа запишет в глобальную переменную **DWORD**\_**403088**, (которая является **DWORD)** значение регистра **EAX**.

![](/files/-LjrT5Q6kGeOJDjeohbM)

Мы помним, что в **IDA** если существует префикс типа данных перед адресом, это означает, что содержимое этого адреса имеет тот же тип. В этом случае это **DWORD**. По крайней мере это **4** байта. Также программа записывает адрес **API** здесь.

Поэтому мы переименовываем глобальную переменную в **P**\_**SYSTEM**.

Мы знаем, что это переменная длиной **4** байта и так как она сохраняет адрес, то она должна быть типа указатель. Я изменяю её тип.

![](/files/-LjrT5QCLUtmi3sjq7St)

Поскольку я знаю, что это указатель на **API**, то могу легко сделать его указателем на что-то неизвестное.

```
VOID * P_SYSTEM
```

В любом случае, нет необходимости иметь слишком точные определения, потому что они лишние. Важно просто то, что это указатель на что-то.

![](/files/-LjrT5QIIDozFzgJ7grv)

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

![](/files/-Ljtu4nRwfSIHCIokLhm)

Существует другая переменная того же типа, которая хранит адрес **API SETPROCESSDEPPOLICY**. Я делаю то же самое.

Я изменяю тип также в декомпиляторе **HEXRAYS** с помощью **F5**. Изменение типа ни на что не влияет.

![](/files/-LjrT5QQ-6nCh8ZxkZoa)

![](/files/-Ljtu4nnfSychHdHuNvq)

Это не имеет большого значение. Это просто нужно, чтобы показать Вам больше вариантов.

![](/files/-Ljtu4nwsgiGzOa-ODaV)

Мы видим, что глобальная переменная **P\_SYSTEM** используется повторно и сохраняет указатель (используется инструкция **LEA** для поиска адреса) на переменную **SIZE**, которая является **DWORD**. Очевидно, it will cast it to do it **C++**(**??? Опять куча itов. Не понял как тут правильно будет**), но здесь это не имеет значения. Они обе являются указателями.

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

Что-то вроде этого:

> **P\_SYSTEM\_\_\_\_\_P\_SIZE**

В сложных функциях они много раз повторяется и мы должны следовать этому.

![](/files/-LjrT5Qmmt9n5EZm5XII)

Затем программа сравнивает переменную **ARGC**, которая представляет собой число аргументов с числом **2**. Таким образом это имя исполняемого файла + аргумент, т.е. всего два аргумента. Если нет двух аргументов, программа пропускает всё и выходит из функции напрямую.

![](/files/-Ljtu4oGStm6dUHi-AVl)

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

![](/files/-LjrT5QxojhImhhO08w5)

Затем программа передает эту строку в функцию **ATOI**, чтобы попытаться преобразовать строку в целое число. Если у функции это не получается, программа выдаёт ошибку.

![](/files/-LjrT5R1Z2IrvUEcD_OO)

![](/files/-Ljtu4oo44vltug5lWrz)

После возврата из функции **ATOI** это значение сохраняется в переменную **SIZE**, которая находится в стеке.

![](/files/-LjrT5RIRz3KsLI2gFyl)

Не путайте её с глобальной переменной **P\_SYSTEM\_\_\_\_\_P\_SIZE**, которая имеет сохраненный **АДРЕС** этой же переменной **SIZE**.

Программа сравнивает это значение размера, которое пришло из **ARGV** со значением **0x300** и если оно больше, программа переходит и возвращается в функцию **MAIN**. Конечно, этот **SIZE** является знаковым, потому что сравнение с использованием инструкции **JLE** говорит нам об этом.

![](/files/-Ljtu4pFP9x0YI_PpC50)

Поскольку переменная является знаковой, когда мы передаем ей отрицательное значение, она будет меньше **0x300**. Например, если я передам ей значение **-1**, это значение будет меньше **0x300**, потому что рассматривается знак и переменная пройдет сравнение.

Очевидно, если эта переменная **SIZE** используется как размер в **API** функции, которая принимает переменную как беззнаковую, то в программе может случиться переполнение, потому что для этой **API** функции значение не будет отрицательным, но без знака. Например, если значение равно **-1**, для **API**, которая принимает это значение как положительное, максимальным положительным будет значение **0xFFFFFFFF**. Т.е. **-1** равно **0xFFFFFFFF**.

![](/files/-LjrT5RUZ7KWbtSRokAa)

Мы видим функцию, ей аргументом является переменная **SIZE**. Мы ещё не переименовывали её. Давайте посмотрим что она делать. Пойдем туда и посмотрим.

![](/files/-Ljtu4pcXNyd_YmhgB4k)

Мы видим, что есть здесь есть функция **GETS\_S** для ввода данных. Поэтому я даю функции имя **INGRESO**.

Эта функция **GETS\_S** имеет переменную **SIZE**, которая принимается как беззнаковая и может вызвать переполнение буфера.

![](/files/-Ljtu4prSbq3IQO40qo9)

Здесь мы видим, что тип переменной **SIZEINCHARACTERS** является типом **SIZE\_T**.

![](/files/-MX3mHaCP9bcwHdmZm2p)

И этот **SIZE\_T** является беззнаковым. Поэтому я уверен, что мы можем переполнить буфер. Давайте посмотрим насколько он большой. Хотя мы уже видели, что я сделал его плохим, но программы пытается фильтровать **SIZE** больше чем **0x300** байт. Поэтому очень вероятно, что размер буфера таков.

![](/files/-LjrT5RmI7DeWGcvs6ku)

Мы видим, что буфер находится в секции **DATA** и **IDA** говорит мне, что его размер равен **0x64** байт. Чуть ниже буфера мы видим глобальные переменные **P**\_**SETDEP** и **P\_SYSTEM**\_\_\_\_**P**\_**SIZE**. Поэтому здесь нет ошибки. Максимальная проверка позволяет нам переполнить даже этот **0x64** байтный буфер (**100** десятичных байт), без требования быть отрицательным. Только с размером больше чем **0x64** байта.

![](/files/-Ljtu4qPMJsQcJlGp4he)

Как только я запишу больше чем **0x64** байта, я буду продолжать двигаться вниз и смогу перезаписать сохраненные указатели в секции **DATA**.

Сейчас, после того как Вы перезапишите указатели, будет ли программа использовать эти указатели?

![](/files/-Ljtu4q_nGmYDWWNqAcz)

Я вижу в ссылках на **P**\_**SETDEP**, что есть вызов с использованием этого указателя на функцию и что, если я перезаписываю его с помощью переполнения, он может отклонить выполнение программы.

![](/files/-Ljtu4qqbruHru0314u-)

Это происходит сразу после функции **GETS**\_**S**. Это прекрасно. Давайте сделаем скрипт.

![](/files/-LjrT5S6FoMSBGuKYuNm)

Я изменяю скрипт, который был достаточно похожий и устанавливаю размер равным **-1**. Он будет проходить проверку. Я помещаю **0x64** байта символов **A** чтобы заполнить буфер, и затем я помещаю значение **0x99989796**, которое предположительно должно перезаписать указатель, который находится чуть ниже.

Поскольку **ROP** для библиотеки **MYPEPE.DLL** уже создан, я оставляю его. Я увижу, как я расположу **ROP**. Сейчас я запускаю скрипт и присоединяю **IDA** к процессу, помещаю **BP** сразу после функции **GETS**\_**S**, для того, чтобы остановится там.

![](/files/-LjrT5SBrVcY-AhwRRBg)

![](/files/-Ljtu4rPtWWJA7ti5Rpc)

![](/files/-Ljtu4rcA-uxA5NszXJk)

Мы видим, что буфер выглядит почти полным. Давайте пойдем туда, чтобы увидеть его.

Если я нажму **U** для **UNDEFINE**, мы увидим много символов **A**. Давайте посмотрим перезаписался ли указатель.

![](/files/-LjrT5SYq7X_SvECkTaF)

Мы должны увидеть, перезаписали ли мы указатель.

![](/files/-LjrT5Sd3Hkgk8u_QaZI)

Я нажимаю **D** до тех пор пока не получу **DWORD** и вижу что это всё хорошо перезаписалось. Установлено значение, которое я хотел.

![](/files/-LjrT5SoFJtOfLblSqbW)

Я вижу, что у процесса нет **DEP**, потому что мы перезаписали правильный **API SETPROCESSDEPPOLICY**, которая собиралась включить его. Поэтому здесь нам не понадобится **ROP**.

![](/files/-LjrT5Svwd6UAibmNv0m)

Регистр **EAX** указывает на буфер, который заполнен **A**. Поэтому если я смогу перейти туда и разместить шеллкод в начале буфера и выполнить его.

Я мог бы искать вызов **CALL EAX** в библиотеке **MYPEPE**, который не содержит защиту **ASLR**. Я использую новый **KEYPATCH** с опцией **SEARCH** и ввожу инструкцию **CALL EAX**.

![](/files/-LjrT5T-zXCtcgjqaGZN)

![](/files/-LjrT5T48Z3rjeTN1Fq_)

Мы видим в результатах, что есть несколько, которые принадлежат библиотеке **MYPEPE**. Я выбираю некоторые для примера.

![](/files/-LjrT5T984L5x-GgGfKt)

Когда я иду туда, я нажимаю **C** для преобразования его в код, потому что я его не дизассемблировал.

По адресу **0x7802C16E** будет инструкция **CALL EAX**, которую я выбрал. Я добавляю этот адрес в скрипт.

![](/files/-LjrT5TEVmMNkrzY89pI)

Я помещаю шеллкод вперед, потому что он переходит в начало буфера и не меняет длину перед указателем. Оставшаяся часть шеллкода вычитается из общего количества букв **A**. Мне больше не понадобится **ROP**. Поэтому я удаляю его.

![](/files/-LjrT5TM45-9lg87QNUY)

Наша курочка готова. Шеллкод запускает калькулятор. Я надеюсь, что кто-то сделает меня счастливым, решив задачку **41B** или, по крайней мере, просто попробует её на вкус.

`\#8eqw0uExIPQMo0hlG2SMbg.kWxA60qd204.wQ0f6qnVEDF3sTM4kUnjA82Jgnlue8Wsgi0LIXEGPRLM89DcLVaUVNH29WUFmLizrcwP9OtNDlc4wPiQ6DtpTgbIFIhKqOATEW8MBxHDk2Uvz/8H8BgX5L2XHkS/zfDWlnPEVsMXsg`

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

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

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

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

22.04.2018

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/42-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-42.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.
