- Главная
- Блог
- Информационная безопасность
- Обзор возможностей отладчика x64dbg. Часть 2. Плагины: NFDetector, Scylla, OllyDumpEx. Ручная распаковка UPX и ASPack
Обзор возможностей отладчика x64dbg. Часть 2. Плагины: NFDetector, Scylla, OllyDumpEx. Ручная распаковка UPX и ASPack
В первой части мы рассмотрели несколько простых плагинов отладчика x64dbg, а в этой немного усложним задачу, и проведём практический анализ упакованного в ASPack и UPX софта. Целью будет организовать это дело исключительно средствами самого отладчика, без привлечения таких инструментов как «LordPE, ImpRec» и прочих, которые на 64-битных системах потеряли свою актуальность. По сути ничего новаторского, но полезно знать.
Практический анализ упакованного в ASPack и UPX софта
Известно, что исполняемый файл состоит из секции-кода, данных, импорта, и т.д. В свою очередь, секция делится на более мелкие страницы «Page», размер которых обычно 512-байт. Аналогичную иерархию наблюдаем и в памяти ОЗУ, только страницы увеличиваются с 512 до 4096-байт. Такая разница позволяет хранить образ программы на диске в более компактном виде, чтобы он не занимал много места. Точные размеры страниц указываются в РЕ-заголовке файла: «FileAlignment» это размер на диске, а «SectionAlignment» уже в виртуальной памяти. При такой внутренней организации файла, его размер на диске будет всегда кратен 512-байтам.
С другой стороны, если размер данных превысит размер файловой страницы (например 550-байт), то компилятору придётся выделить ещё один 512-байтный пэйдж, что увеличит размер секции уже до 1024-байт. При этом разницу в 1024-550=474 байт он забивает пустыми нулями, которые известны как «Байты выравнивания секций». В такие безхозные поля малварь может поместить свой шелл, и подправив адрес входа в программу «EntryPoint» (см.скрин выше), передать на него управление.
Когда размер конечного продукта кодописателей выходит за рамки приличия, первое что приходит на ум – это упаковать/сжать его. Данный процесс в простейшей форме как-раз и подразумевает удаление из бинаря последовательности одинаковых байт, прописав на их место обычный счётчик. Например россыпь из 474-байт нулей выше, можно будет сжать до 3-байт по схеме 00,01da, где первый байт = само значение, а второе слово = счётчик его повторений. Попробуйте зипнуть экзе в архив, тогда процент сжатия получим формулой вида: 100-(717*100/3072)=76.66, а коэффициент 3072/717=4.28 :
Для дальнейших исследований понадобится компилятор ассемблера «fasm» для Windows: https://flatassembler.net/download.php ,
а так-же бесплатный упаковщик исполняемых файлов «UPX»: https://www.pazera-software.com/products/free-upx/
Теперь напишем тестовую программку на ассемблере, которая будет импортировать 4 функции Win32API из 3-х системных библиотек: msvcrt, kernel32 и user32.dll.
Поскольку программа у нас консольная, для вывода текста в кириллице нужно сменить кодировку на OEM-866, чем и занимается первая функция CharToOem(). Следом printf() печатает строку, и чтобы окно консоли сразу не закрылось, getch() ожидает нажатия любой клавиши, после чего ExitProcess() выгружает код из ОЗУ. Компилируем исходник в fasm’e по F9, и получаем готовую к употреблению программу.
Это будет оригинал, поэтому сделаем его копию и переименовав например в CodebyOrigin.exe, сохраним в укромном месте. Теперь запакуем исходную в UPX так, чтобы у нас получилось 2 файла – первый бэкап «xxOrigin.exe», а второй «xxUpx.exe». Это позволит наглядно увидеть разницу между обычным и упакованным кодом.
Если коротко, то upx полностью перекраивает структуру файла под себя. В независимости от кол-ва секций в исходном файле, он всегда создаёт три своих, назначая им порядковые имена UPX0, UPX1, и UPX2. Например если в оригинале было 8 секций, то из выхлопной трубы UPX выйдет всё-равно 3.
Сопоставив два родственных файла можно обнаружить, что пакер изменил оригинальную точку-входа в программу ОЕР на свою, которую в данном контексте называют уже фиктивной ЕР (при этом oep он запоминает где-то в своих закромах). Эта точка(G) очень важна, т.к. позволяет программе сделать первый вздох. Так upx получает управление первым, и приступает к распаковке сжатого файла в память. На заключительном этапе управление передаётся опять на ОЕР, чтобы софт отработал свой код в штатном режиме.
Вот скрин происходящего, где через плечо оригинала выглядывает РЕ-заголовок пакера. Как видим, ОЕР был 0x3000 и находился (где и положено ему быть) в секции-кода «.text», а стал 0x6220 сменив прописку в секцию «upx1». Обратите внимание, что исполняемую свою секцию упаковщик открывает на запись (о чём свидетельствует флаг RWX) – обычно для аверов типа Касперский это как красная тряпка, но только не в случае с легальными пакерами, к которым ав относятся более лояльно. Похоже они выпили за мировую, и как-то уладили этот вопрос.
Во всей этой кухне радует то, что запакованный код – это по сути мусор, а потому исполняя его ЦП рано или поздно обязательно нарвётся на исключение «Неверная команда», или доступ на чтение/запись запрещённой ячейки памяти «Access Violation». Это основная причина, по которой анпакер UPX должен сначала распаковать код программы в память, и только потом передать управление на её оригинальную точку ОЕР. Данному правилу следуют буквально все упаковщики в природе, что способствует ручной распаковке программ реверс-инженерами.
Здесь внимательный читатель может задать резонный вопрос: – «Зачем заниматься ручной распаковкой софта, когда можно озадачить этим сам упаковщик?». Всё верно, только большая часть из них платные, а во-вторых – на пакеры нацелен гадкий класс программ под названием «Скрамблеры». Они умышленно меняют служебные поля пакера так, что даже мать родная не сможет их опознать. Конечно можно прибраться за скрамблером (опять-же вручную), но это не всегда даёт ожидаемый результат. Вот здесь и приходится в рукопашную создавать дамп памяти процесса, и править его в офлайн при помощи перечисленных ниже инструментов. Наша цель – распаковать файл в исходный вид, чтобы открыть отладчику доступ к коду.
-
Плагин «Nauz-File-Detector»: https://github.com/horsicq/nfdx64dbg/releases
Из наиболее часто встречающихся упаковщиков исполняемых файлов, можно выделить безобидные UPX и ASPack, а остальные не только пакуют бинари, но и сразу шифруют их. К таким токсичным инструментам относятся протекторы: Armadillo, ASProtect, VMProtect, Themida, Enigma, ExeCrypt и множество других.
Весь этот софт уродует файлы так, что дизассемблерный их листинг превращается в набор безсмысленных инструкций. Если в наших планах реверс запакованной программы (например с целью найти флаг или пароль), то первым делом нужно будет привести её в человеческий вид, и только потом отправлять уже в отладчик. Всё это хорошо, только есть небольшая проблема.. Как узнать, каким именно инструментом был запакован наш клиент? На слепой перебор возможных вариантов можно потратить всю свою жизнь, поскольку пакеров этих – как звёзд на небе.
За всю историю было написано множество сканеров для этих целей, но с переходом на 64-битную архитектуру подавляющее большинство из них отправилась к праотцам. Одним из тех, кого обошла эта участь является «Detect-it-Easy» или просто DiE, который имеет в своей базе огромное число сигнатур, а наш плагин под названием «NFD» встраивает аналогичный функционал прямо в тушку отладчика. Помимо упаковщиков, он может вычислить линкер объектных файлов, непосредственно сам компилятор, и даже среду разработки. Отметим, что DiE и NFD тесно сотрудничают вместе, а потому можно доверять любому из них.
Упаковщики сдают себя с потрахами, поскольку всегда используют одинаковый алгоритм работы – код анпакера раздаётся ксерокопией буквально всему софту, а значит можно использовать первые его несколько байт в качестве сигнатуры. Правда если в сл.версии инструмента разраб вставит в шапку хоть одну инструкцию nop, то прежняя сигнатура уже слетит и сканеру придётся определять новую.
-
Плагин «Scylla»: идёт в комплекте с x64dbg, и активируется комбинацией Ctrl+I.
Значит открываем в x64dbg упакованный «CodebyUPX.exe», и сразу попадаем в точку-входа в распаковщик. Здесь он сохраняет значения всех регистров pushad, далее прописывает указатели на источник и приёмник данных в регистрах esi/edi, после чего прыгает чуть ниже jmp. Кому интересны детали распаковки, можете потрассировать весь код анпакера, но мы оставим это за кадром и попытаемся найти передачу управления на ОЕР уже после того, как upx отработает свою задачу.
Следуя логике можно предположить, что если на входе имеется pushad, значит на выходе должна быть обратная ей popad. Ищем эту инструкцию прокручивая экран вниз, и точно есть такая, ..а немного ниже видим и переход jmp 403000 на оригинальный ОЕР в уже распакованную программу – ставим на него брейк по F2. Теперь, если дать команду отладчику «Выполнить всё» по F9, то анпакер распакует весь код в память, а мы сможем поймать этот момент за хвост. Попробуем сейчас навести курсор мыши на jmp 403000, и увидим всплывающее окно с инструкциями по этому адресу, хотя перед нажатием F9, там было топкое болото нулей.
Основная проблема ручной распаковки заключается в восстановлении таблицы-импорта IAT (Import Address Table), которую упаковщики безжалостно кладут под свой асфальтный каток. Для себя они оставляют лишь пару функций LoadLibrary() (загрузить dll) и GetProcAddress() (найти в ней адрес функции), при помощи которых можно динамически подгружать остальные. Так вот плагин «Scylla» – это основное оружие ближнего боя в таких ситуациях. Он включает в себя дампер памяти процесса, и сразу реконструктор его таблицы IAT. То-есть получаем две мощные фишки в одном флаконе.
Поскольку наш CodebyUPX.exe лежит сейчас в распакованном виде, то сбрасываем его память на диск, иными словами дампим её.
Для этого зовём сциллу по Ctrl+I и в первую очередь переопределяем точку-входа ОЕР на свою. Теперь нужно: (1)найти IAT там, куда его в памяти спрятал UPX, (2)запросить библиотеки импорта и список их функций, и наконец (3)сбросить всё это хозяйство в качестве дампа на диск.
Так мы только создали дамп памяти нашего процесса, и если сейчас запустить «CodebyUPX_dump.exe», то приложение рухнет с ошибкой «Access-Violation». Это потому, что после внесённых нами изменений, в заголовке РЕ-файла полный бардак и анархия, ведь половина полей там осталось от UPX, а половина наши новые значения. Поэтому нужно пофиксить все эти баги, для чего не закрывая окно «Scylla», тут-же пимпой(4) «FixDump» открываем в ней наш свежеиспечённый дамп, и только теперь получаем полность рабочий (и уже распакованный) файл «CodebyUPX_dump_SCY.exe». Если вскормить его отладчику то обнаружим, что точка-входа ОЕР стала валидной, и мы сразу попадаем в знакомый нам код, а не куда-то в нёдра анпакера upx. С этого момента можем искать отладкой флаги, пароли, и всё остальное.
-
Плагин «OllyDumpEx»: https://low-priority.appspot.com/ollydumpex/
Ещё один неплохой дампер в виде плагина – это «OllyDump». Его название может сбить с толку, ведь разговор идёт об x64dbg. Однако суффикс «Ex» расставляет всё на свои места. В архиве идут плагины сразу для всех популярных отладчиков: Olly, Immunity, IDA, WinDbg и x64dbg. Пригодится, когда столкнёмся с дебагом накрытых протекторами программ. Если реверс поставлен на поток, можно потратиться на шекели и купить их для распаковки софта, но если это чисто хобби для повышения собственного скилла, то лучше учиться разворачивать фантики в ручную.
Заключение
Изучение анатомии файлов позволяет создавать менее уязвимые программы, ведь ничто не мешает нам заполнить «байты-выравнивания» мусором в любом Hex-редакторе, создав иллюзию забитой под макушку секции. Или можем легко ослепить сканеры DiE и NFD просто подменив в бинарнике сигнатуру. И таких мелочей очень и очень много.
Только нужно учитывать, что хакеры всегда идут на шаг впереди разработчиков, и это реально круто, т.к. только они и двигают прогресс в этой области вперёд, заставляя нас шевелить мозгами. В мире вредоностного кода встречаются такие зверьки, что просто поражаешься профессионализму их авторов. Живописно разбросанные по всему пространству стабы каким-то магическим образом взаимодействуют между собой, при чём эстафетную палочку они передают друг другу казалось-бы по недоступным юзеру адресам. Вот где кладезь примеров реального исскуства программирования.
Для серьезной прокачки скиллов реверс инжиниринга могу порекомендовать наш курс Реверсивный инжиниринг ПО под ОС Windows. Ведет мой коллега, автор книг по реверсингу и статей Хабра Статьи / Профиль Andrey_Biryukov / Хабр (habr.com)
Если вы еще только смотрите в сторону освоения реверсинга, то скорее вам стоит выбрать курс, дающий полную базу Введение в реверс инжиниринг