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

# Часть 14

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

Это курс будет смешанным, и он будет включать в себя разные темы связанные с реверсингом (мы уже говорили о статическом реверсинге, а также будем говорить об отладке, распаковке, эксплоитинге).

В этой главе мы будем распаковывать файл **CRACKME.EXE** упакованный последним **UPX**. Это не означает, что мы собираемся посвятить много глав только распаковке, мы будем менять темы разговора, и перемешивать различные темы, для того, чтобы никто не скучал, так что у нас будут уроки по распаковке, смешанные с другими темами.

## Упакованные файлы

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

Существует тысяча видов упаковщиков и большинство из них являются протекторами, которые изменяют **IAT** или таблицу импорта, а также изменяют **ЗАГОЛОВОК**, они добавляют анти-отладочный код, чтобы предотвратить распаковку и восстановление исходного файла.

Самый простой случай упаковщика - это **UPX**, который не имеет анти-отладочных трюков, никаких грязных штучек, но поможет нам начать обучение, как всегда с самого простого, к туториалу будет приложен файл **PACKED\_CRACKME.EXE**.

![](/files/-LjpeqmoJRp0n9y6G5f8)

Мы отмечаем **MANUAL LOAD** и снимаем с пункта **CREATE IMPORTS SEGMENT** так как нам необходимо, чтобы у нас были загружены все секции программы, и если она может влиять на опцию **CREATE IMPORTS SEGMENTS**, то я про это не знаю, но **IDA** советует снять эту галочку при работе с упакованными файлами.

![](/files/-Ljtu6mCGV60BnNbPTBW)

Это начало или **EP** файла **PACKED\_CRACKME.EXE**, мы видим, что она находится по адресу **0x409BE0**, в то время как оригинальная **EP** находилась по адресу **0x401000**, как мы видим ниже.

![](/files/-Ljpeqms64Gki1WwV_nJ)

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

**OРИГИНАЛЬНЫЙ**

![](/files/-Ljtu6mi0HSISGQzMBT6)

**УПАКОВАННЫЙ**

![](/files/-Ljtu6msE0G3ZUr8w6Jg)

Мы видим, что секция **UPX0** упаковщика заканчивается по адресу **0x409000**, в то время как в исходном файле все секции расположены в памяти начиная с адреса **0x401000** и заканчиваются по адресу **0x408200**.

Здесь мы начинаем говорить о виртуальной памяти, т.е. когда программа запускается, она может иметь **1 килобайт** на жестком диске, а резервировать **20 килобайт** или сколько она пожелает в памяти.

Это возможно видеть в **IDA**, например, по адресу начала секции исходного файла **0x401000** мы видим.

![](/files/-Ljtu6n4GFRBVIVN-4TC)

Вышеупомянутая секция (**SECTION SIZE IN FILE**) занимает **0x600** байт в файле, в то время как в памяти (**VIRTUAL SIZE**) она занимает **0x1000** байт.

В то время, как у упакованного файла, если мы идём по адресу **0x401000**, который является началом секции **UPX0**, мы видим.

![](/files/-Ljpeqn3xuVlLgz4rx4Z)

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

![](/files/-Ljtu6nXRouQnBr6XMjs)

Также мы видим, что адрес **0x401000** имеет впереди префикс **DWORD\_**, который означает, что его содержимым является данные типа **DWORD**.

Знак (**?**) означает, что место только зарезервировано, т.е. оно не имеет содержимого и **DUP** или умножитель, означает, что этот **DWORD** умножается на **0xC00** и в итоге получится **0x3000**зарезервированных байт.

![](/files/-Ljpeqn8qXiF4pyqDg0N)

Затем по адресу **0x404000** есть **0x1400 DWORD** символов (**?**), это место тоже зарезервировано.

![](/files/-LjpeqnAH6spV74Jz4UF)

То есть, в памяти резервируется **0x8000** байт, чтобы загрузить туда программу.

![](/files/-MX3mKIxXQrvksZqjBgb)

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

![](/files/-Ljtu6oMG8oAi5DgK6tf)

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

Если мы видим ссылки по адресу начала секции **0x409000**.

Мы видим, что ниже (**DOWN**) есть ссылка в исполняемой части, если мы щелкнем на неё.

![](/files/-LjpeqnIqZS9igfbKSVc)

![](/files/-LjpeqnK1_5NmLgE4k13)

Мы видим, что в **СТАБЕ** после **EP** загружается адрес **0x409000** (запомните **СМЕЩЕНИЕ** впереди).

**Если мы нажмём на пробел, мы увидим там**

![](/files/-Ljtu6ouFF7p2wG35dfF)

Что код **СТАБА** находится в той же секции **UPX1** под упакованным кодом исходной программы, в секции **UPX1** у нас есть сохраненные байты исходной зашифрованной программы и код **СТАБА**находящийся по адресу **0x409BE0**.

Нам не нужно быть гением, чтобы знать, что он будет читать байты по адресу начиная с адреса **0x409000**, он применит некоторые операции над ними и сохранит их по адресу **0x401000**. **EDI = ESI - 0x8000**.

![](/files/-Ljtu6p3rHV6tHWEXQeI)

![](/files/-LjpeqnTHUocL3lzIGl5)

Другими словами, видно, что он будет использовать содержимое **ESI** как **ИСТОЧНИК** откуда он будет читать данные, он будет применять к ним некоторые операции и сохранять их в содержимое **EDI**, для создания программы.

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

![](/files/-LjpeqnVfboTAMJbcXNF)

Мы видим, что есть переход в **0x401000**.

![](/files/-LjpeqnXul1B2NwcJhUr)

**JMP NEAR** это прямой переход по адресу, который находится рядом с ним, т.е. он будет переходить по адресу **0x401000**, очевидно, здесь, позже, выполнится весь **СТАБ** и создастся исходный код, он будет переходить в **OEP** по адресу **0x401000**, что будет **OEP**, которая отличается от **EP СТАБА** тем, что находится по адресу **0x00409BE0**.

Мы будем вызывать **OEP** или **ORIGINAL ENTRY POINT** в **ENTRY POINT** исходной программы, очевидно, так как это упакованная программа, то мы не знаем где она находится и только поскольку мы у нас есть исходная программа, мы можем знать, что **OEP** была по адресу **0x401000**.

![](/files/-LjpeqnZ_mK3X3MnLPzN)

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

Мы могли бы установить **BP** в этот **JMP** на **OEP**, чтобы увидеть есть ли там оригинальная программа, которая уже создана, давайте попробуем.

![](/files/-Ljtu6pyEZ4hd0qGD8Iz)

Давайте выберем отладчик **LOCAL WIN32 DEBUGGER** и давайте нажмём **START DEBUGGER**.

![](/files/-Ljtu6qBye0blpWIjtW2)

Здесь я останавливаюсь на переходе в **OEP**, мы трассируем его с помощью **F8**.

![](/files/-Ljtu6qOaGTXRa2J2YrA)

Мы нажимаем **YES** для того, чтобы отладчик интерпретировал как **КОД** первую секцию **UPX0**, которая была определена как **ДАННЫЕ**.

![](/files/-LjpeqngiXkbhya6fXGq)

Мы видим, что отладчик уже распаковал код и теперь переходим туда, чтобы выполнить его. Код очень похож на код оригинальной программы по адресу **0x401000**, хотя, мы видим, что если мы захотим перейти в графический режим, у нас ничего не получится, потому что код не определен как функция (**loc\_401000**), но мы сделаем это автоматически.

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

![](/files/-Ljtu6qx2xqxjqT_ojLT)

Мы видим, что кликнув по адресу **loc\_401000** отладчик меняет на тэг на **sub\_401000**, который показывает, что сейчас это функция, так что теперь мы можем переключить его в графический режим с помощью пробела.

![](/files/-Ljtu6r8NO6zJmn67T5Y)

Сейчас это выглядит намного лучше.

![](/files/-LjpeqnmoMOcFFs-jL_O)

Различие, которое мы видим состоит в том, что оригинальный файл показывает по адресу **0x401002** вызов **CALL GetModuleHandleA**, в то время как запакованный показывает **CALL sub\_401056**, давайте посмотрим, что есть внутри этого **CALL**.

![](/files/-LjpeqnoiruWpqZ52rRa)

Давайте посмотрим различия с исходным файлом, если мы войдём в **CALL GetModuleHandleA** в исходном файле.

![](/files/-LjpeqnqaPqMvK3w8_AC)

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

![](/files/-LjpeqnsDOeqwownQroa)

Содержимым по адресу **0x403028** является смещение(**OFF\_)**, т. е. адрес **API** функции **GetModuleHandleA** и в исходной программе это тот же самый адрес в секции **IDATA** и он содержит также адрес той же самой **API**.

![](/files/-LjpeqnuLuwGeLiUdO9j)

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

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

Сначала в **СЕГМЕНТАХ**

![](/files/-Ljpeqnwtucwo1uLpwpd)

Я проверяю, что все секции упаковщика имеют букву **L**, что означает, что они будут загружены в **ЗАГРУЗЧИК**, как мы видим в образе, я могу даже добавить какую-либо **DLL** или сегмент, который я хочу, чтобы он был в в статическом анализе, для этого делаем **ПРАВЫЙ ЩЕЛЧОК → EDIT SEGMENT** на строке, которую мы хотим добавить в **ЗАГРУЗЧИК**.

![](/files/-LjpeqnywDF28_Qy7hGU)

На сегментах, которые мы хотим, чтобы они добавились, мы ставим галочку в **LOADER SEGMENT**, в этом случае мы оставим только сегменты **УПАКОВЩИКА**, но про это хорошо знать, что мы можем добавить и другие.

![](/files/-Ljtu6srmpvppxvZ4Okf)

![](/files/-Ljpeqo1yMjoM8C4fxmd)

Затем опция **TAKE MEMORY SNAPSHOT** будет сохранять сегменты, которые мы пометили как **ЗАГРУЖАЕМЫМИ** как код, который они имеют. (**НЕ ПУТАЙТЕ ЭТО С ДРУГОЙ ОПЦИЕЙ FILE → TAKE DATABASE SNAPSHOT**, которую мы изучали ранее)

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

Если я запущу снова отладчик и остановлюсь в той же **EP** до выполнения **СТАБА**, я увижу, что область по адресу **0x401000** снова пустая.

![](/files/-Ljpeqo47YR5k7YLusir)

![](/files/-Ljpeqo6TACSSWj9AMwU)

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

Поскольку, я очень надоедливый(Это **Рикардо** про себя ![:)](https://wasm.in/styles/smiles_s/smile3.gif) ), то я буду искать второй способ получит **OEP**, который ищет первую инструкцию, которая выполняется в первой секции, это другой метод, который иногда может работать.

Я запускаю снова **УПАКОВАННЫЙ ФАЙЛ** в **ОТЛАДЧИКЕ**, останавливаюсь в его **EP**.

![](/files/-Ljpeqo8JuQoElb5mfQj)

Я иду в первую секцию, где она начинается по адресу **0x401000**.

![](/files/-LjpeqoEsKGC8gm4qYI2)

Я установил **BP** с помощью **F2**. Я установил его для остановки по исполнению или **EXECUTE**. Отладчик будет останавливаться только при выполнении, а не при чтении или записи. Поскольку он будет останавливаться при копировании кода и его создании, я не хочу этого. Я просто хочу, чтобы он перешел, когда код уже создан, отладчик остановится на первой инструкции, которую он выполняет, и поскольку я не знаю, где это место, я устанавливаю **BP** на **ВЫПОЛНЕНИЕ**, который охватывает всю секцию (**0x8000** байт).

![](/files/-Ljtu6u9Z7zPajDXMYog)

Он пометил все инструкции в красный цвет.

![](/files/-Ljtu6uMmG33E0fNFQWj)

Я выключаю два других **BP** через **DEBUGGER → BREAKPOINT → BREAKPOINT LIST**.

![](/files/-LjpeqoKO-mYVFOgZAX6)

ДЕЛАЕМ ЩЕЛЧОК ПРАВОЙ КНОПКОЙ И ВЫБИРАЕМ **DISABLE**.

![](/files/-Ljtu6un1vqr2_oP5Afe)

И сейчас, если я нажму **RUN**.

И я вижу, что первая инструкция, на которой остановился отладчик, находится в секции созданной недавно, т.е. в этом случае по адресу **0x401000** находится моя найденная **OEP**.

![](/files/-Ljtu6v5mEWHshFyj5pl)

Таким образом, использую этот метод и мы находим **OEP**, адрес которой равен **0x401000**, теперь я удаляю **BP**.

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

![](/files/-LjpeqoQWN98rfmFw-cG)

Т.е. до сих пор мы получали **OEP** и останавливались на ней, используя два разных метода, мы могли бы сделать **СНИМОК** созданного-загруженного кода, единственное, что нам для этого не хватает, так это сделать **ДАМП** и **ВОССТАНОВИТЬ IAT**, чтобы получить распакованный исполняемый и функциональный файл.

До **15**-й главе, где мы закончим с этим.

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

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

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

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

14.09.2017

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