Когда наш журнал был бумажным, мы считали не очень хорошей идеей делать серии зависимых друг от друга статей, ведь, чтобы освежить воспоминания месячной и двухмесячной давности, читателю пришлось бы поднимать подшивку. А теперь все просто :). Мы делаем цикл по реверсу малвари, две статьи уже вышло — вот нулевая (если кто не заметил, там офигенные ссылки, почитай, не пожалеешь. — Прим. ред.), вот первая. Если ты что-то забыл — вспоминай, а если нет — готовься узнать о том, как работают упаковщики и протекторы, для чего их используют и как с ними можно бороться.

WARNING

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

 

Сага о протекторах и упаковщиках

Один из излюбленных приемов зловредописателей — использование упаковщиков (packers) и протекторов (protectors) исполняемых файлов (хотя это также относится и к DLL). Изначально эти инструменты считались весьма банальными и были призваны, по сути, уменьшать размер скомпилированного файла, а в случае протекторов — позволять модифицировать авторам свои программы, превращая их, к примеру, в demo- или trial-версию, и не заморачиваться с защитой в основном коде. Но позднее вирусописатели приспособили эти инструменты в корыстных целях.

Создатели вредоносов успешно стали применять их, чтобы усложнить антивирусный и эвристический анализ, защитить свои детища от запуска в виртуальной среде, отладки, дизассемблирования и последующего анализа. Поэтому с тех пор навыки и умения распаковывать исполняемые файлы вошли в обязательные требования как для начинающего, так и для опытного реверс-инженера. Наиболее популярные сегодня упаковщики — UPX, ASPack, FSG, PeShield, VMProtect. Это, так сказать, джентльменский набор, с которым аналитику приходится сталкиваться каждый день.

Протекторы, в отличие от упаковщиков, призваны защитить исходный файл от обратной разработки, соответственно, при этом они используют более изощренные методы, чем просто упаковщики: обфускацию, шифрование с использованием самописного либо популярного криптоалгоритма, такого, например, как RSA-1024, встраивание антиотладочных функций.

Как мы понимаем, чтобы добраться до нужного нам кода, который мы будем анализировать, сначала требуется распаковать файл, то есть снять все навесные защиты, восстановить оригинальную OEP и таблицу импорта, это как минимум. Частенько распаковка — это задача, укладывающаяся в стандартный набор действий, но иногда она становится творческой и выливается в целое хакерское исследование — с ящиками пива, блоками сигарет и сантиметрами сожженных нервных волокон :).

 

Ликбез по теории

Итак, как мы понимаем, использование упаковщиков/протекторов/крипторов значительно усложняет реверсинг. Помимо этого, писатели зловредов могут использовать многократную упаковку (так называемый послойный пак), применять малоизвестные или вовсе самописные тулзы (для тех, кто хочет накодить что-то свое, небольшой ликбез), сигнатуры которых будут отсутствовать, к примеру, в том же PEiD. Интересно, что любой пакер, не созданный специально для шифрования малвари, оставляет свою уникальную сигнатуру в бинарнике, а соответственно, умея пользоваться Hex-редакторами, можно определить его сигнатуру и без PE-анализатора.

Общий принцип рассматриваемых инструментов упаковки/защиты таков: после клика на EXE-файле и его запуска выполнение основного кода программы начинается с так называемой точки входа (Entry Point) — адреса, по которому передается управление после загрузки программы в оперативную память. Когда программа запакована, алгоритм работы несколько изменится. Упаковщик запоминает точку входа EP, потом, используя алгоритмы архивирования, сжимает содержимое файла (как правило, это секция кода и данных), после чего дописывает свою сигнатуру после либо до сжатого кода программы и перенаправляет ее не в основной код программы, а в код упаковщика (точнее сказать — распаковщика). Сам же код распаковщика, находящийся теперь внутри файла, получает управление первым и распаковывает упакованные секции кода/данных в памяти! На диске исходный файл остается нетронутым, то есть упакованным, неизменным. После того как код и данные программы распакованы, код распаковщика восстанавливает таблицу импорта и передает управление основному коду программы, на бывшую точку входа, которая в упакованных программах называется оригинальной точкой входа (Original Entry Point). Если кратко, то это все основные моменты.

Схема упаковки исполняемого файла
Схема упаковки исполняемого файла

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

Протекторы, как и некоторые упаковщики, используют ряд приемов борьбы с динамической распаковкой, например расшифровывают код не полностью, а лишь по мере исполнения или создают образ и распаковывают его в память только на момент запуска. Протекторы, используя API-функции, могут определять, что их код запущен под отладчиком, после чего прекращают свою работу. Причиной тому — результат вызова функции API IsDebuggerPresent(), которая определяет, отлаживается программа или нет. Помимо этого, протекторы внедряют процедуры проверки целостности исходного файла, шифруют таблицу импорта, запрещают снятие дампа с определенных адресов виртуальной памяти и иногда используют малодокументированные и недокументированные API-функции, защищающие от трассировки и установки аппаратных точек останова.

 

Ручная и автоматическая распаковка

С большой долей вероятности все рабочие экземпляры малвари будут запакованы тем или иным упаковщиком/протектором. Но чтобы все-таки убедиться, что файл запакован, запускаем PEiD или любой другой PE-анализатор. В 90% случаев этого будет достаточно, PEiD имеет большую базу данных сигнатур и плагинов, что позволяет обойтись без лишних хлопот.

Дальнейшим шагом станет распаковка файла (восстановление) в его исходный (wild source) вид. И тут есть несколько сценариев действий. Первый — это использовать автораспаковщики, тулзы, специально заточенные под автоматическую распаковку файла, основываясь на уже известном алгоритме упаковщика/протектора. Например, UN-PACK — это анпакер для UPX, ACKiller — для программ, защищенных протектором ACProtect, Stripper — для файлов, запакованных ASProtect, ASPack unp — для накрытых упаковщиком ASPack.

Второй вариант — использовать универсальные распаковщики, например QuickUnpack, RL!dePacker или Dr.Web FLY-CODE Unpacker, основанный на движке FLY-CODE антивируса Dr.Web. Фича программ в том, что они сами автоматически анализируют файл и ищут в нем ОЕР, а после дампят программу (в том числе и импорт восстанавливают). Однако часты случаи, когда сдампленный файл оказывается неработоспособным из-за некорректности его обработки универсальным распаковщиком или из-за изменения алгоритма пакера, который несовместим с тем, что использует универсальный распаковщик. Но есть и плюс: иногда, если файл не удается распаковать до рабочего состояния, секция кода в любом случае получается распакованной, а этого вполне достаточно для анализа.

И третий сценарий, более длительный, но в перспективе более успешный, — ручная пошаговая распаковка с помощью OllyDbg. Если файл запакован чем-то неизвестным, это легко определить по наличию в таблице импорта защищаемого приложения WinAPI-функций из библиотеки kernel, таких как GetProcAddressA, LoadLibraryA или GetModuleHandle.

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

А вот аналогичная страница, но только на этот раз про распаковщики (на всякий случай зеркало тут).

INFO

Авторы вредоносного ПО широко используют упаковщики и протекторы для усложнения его детектирования и для противодействия анализу. Большинство из них анализируются стандартным арсеналом инструментов реверс-аналитика, но некоторые требуют нестандартного подхода и глубокого знания PE-архитектуры.

 

Учимся скрывать присутствие отладчика и обходить методы противодействия

В одной из статей нашего журнала были описаны наиболее интересные плагины для OllyDbg. Нам обязательно понадобятся:

  • OllyExt — содержит опции Anti-AntiDebug;
  • OllyDumpEx — отличный дампер процессов;
  • swordfish — быстрая установка точек останова;
  • uberstealth — фича Anti-AntiDebug, основанная на коде IDA Stealth.

Все самые нужные плагины OllyDbg 2.xx Plugins можно забрать с файлового архива Tuts4you тут и тут. Набор плагинов для IDA Pro с подробным описанием доступен на GitHub или на Tuts4you. Тем же, кто готов написать свой плагин, могу рекомендовать интересную статью.

 

Шифрование кода

При анализе различных защит нередко приходится определять, какой алгоритм был использован для шифрования данных. Часто зловредописатели не изобретают велосипедов, а используют уже готовые алгоритмы шифрования. К примеру, если алгоритмы стандартные, то их можно идентифицировать по некоторым характерным константам-полиномам, таблицам преобразований или по последовательности выполняемых операций. Для поиска криптоалгоритмов в исполняемых файлах созданы специальные программы, которые можно посмотреть и скачать тут.

Наиболее популярен плагин Krypto ANALyzer для PEiD. Найденные значения можно просто посмотреть или экспортировать в скрипт для дизассемблера IDA Pro.

 

Краткое руководство по анализу

Типовой набор действий банален: определение сигнатуры упаковщика, поиск OEP, дамп программы на диск, восстановление таблицы импорта, восстановление релоков, пересборка. А если же файл не просто был запакован, а еще и обработан протектором, то могут потребоваться дополнительные действия, такие, например, как удаление мусорных инструкций, обход антиотладочных приемов, изоляции функций проверки целостности кода CRC.

Несколько слов о динамических библиотеках. Распаковка DLL практически не отличается от распаковки EXE-файла. У DLL, как и у EXE, есть точка входа в код программы — Entry Point, созданная пакером, и оригинальная OEP. Таким образом, нужно остановиться на DLL в Entry Point, распарсить и оттуда идти к единственно верной OEP нашей DLL. Дальше можно стандартно дампить. И еще пара коротких абзацев из матчасти, которая сегодня нам пригодится.

 

Несколько слов о breakpoints (точках останова)

Точки останова — часто используемый и незаменимый прием любого реверс-аналитика. Основные режимы — это:

  • останов при чтении;
  • останов при записи;
  • выполнение памяти по заданному адресу.

Команда CALL $+5 POP REG характерна для защитных механизмов, к примеру копирующих себя на стек. А часто возникающая инструкция PUSHFD присутствует в самотрассирующихся программах и антиотладочных защитных механизмах.

OllyDbg поддерживает несколько видов брейк-пойнтов:

  • обычный брейк-пойнт, первый байт команды, на которой мы хотим остановиться, заменяется специальной командой INT3, вызывается по клавише F2 или из контекстного меню;
  • условный брейк-пойнт (Shift + F2) — обычный INT3 брейк-пойнт со связанным условием;
  • условный брейк-пойнт с записью (Shift + F4) — условный брейк-пойнт с возможностью регистрации значения некоторого выражения или параметров известной функции.

 

Шпаргалка: способы адресации

Немного о том, как передать управление в другую часть кода.

1-й способ:

jmp metka
metka:
mov eax,metka
jmp eax

2-й способ:

push metka
retn
metka:

3-й способ:

call metka
metka:

4-й способ:

stc
jc metka
metka:

5-й способ:

mov cl,1
loop metka
metka:

Все эти примеры могут нам пригодиться при нахождении OEP.

 

Немного о структуре PE-файла

Обзор структуры PE-файла выходит за рамки данной статьи, поэтому не будем лезть в дебри, однако полностью обойти эту тему нельзя, и знание матчасти в дальнейшем нам хорошо поможет. Могу посоветовать следующие статьи по анатомии PE-файлов на Хабре, хороший гайд по полному пониманию Win32- и Win64-файлов и небольшой ликбез на ExeL@b.

Как видишь, вопросу внутреннего устройства PE-файла посвящено большое количество теоретического материала, и это неслучайно: его структура довольно богата, а умение хорошо ориентироваться в ней позволяет проводить более сложный и глубокий анализ. Но, повторюсь, эта тема выходит за рамки нашей статьи, поэтому скажем о ней весьма кратко. Если упрощенно, то PE-файл — исполняемый EXE-файл, который содержит непосредственно исполняемый код и данные, необходимые для корректного выполнения программы в системе. Обычно содержимое PE-файла разбито на несколько секций, которые описываются в заголовке. Это что-то типа оглавления к книге. Попробую объяснить пару важных нюансов.

Значения RVA/VA

RVA (Relative Virtual Address) переводится как относительный виртуальный адрес. Его относительность заключается в том, что он отсчитывается от адреса загрузки, который может быть, а может и не быть равен ImageBase.

RVA вычисляется так:

RVA = VA – адрес загрузки

где VA (Virtual Address) — виртуальный адрес элемента в памяти, а адрес загрузки берется из поля OptionalHeader.ImageBase в том случае, если он равен ImageBase, либо вычисляется лоадером.

Общий алгоритм распаковки большинства файлов таков:

  1. Находим RVA OEP.
  2. Дампим программу.
  3. Восстанавливаем таблицу импорта.
  4. Меняем точку входа на оригинальную.

Значение OEP

OEP (Original Entry Point) — это адрес, с которого бы начала выполняться программа, если бы не была упакована. Virtual Address (VA) — виртуальный адрес элемента в памяти. Relative Virtual Address (RVA) — относительный виртуальный адрес. Адрес относительно ImageBase. К примеру, мы нашли OEP, равный 00301000, а ImageBase равно 00300000, тогда RVA OEP будет 1000. Значение ImageBase можно узнать, посмотрев в любом редакторе PE-заголовков.

 

Лаборатория для исследований

Как и в прошлый раз, все эксперименты по анализу малвари мы будем выполнять в нашей импровизированной лаборатории — виртуальной машине с предустановленной Windows XP. Набор инструментов, в принципе, всегда один и тот же, разница лишь в том, как часто мы будем применять тот или иной.

Образцы исследуемой малвари прилагаются к статье. Помни, при распаковке архива с лабами антивирус будет распознавать файлы соответствующим образом. Не забывай, что бэкап — лучший друг админа! До и после всех экспериментов не забывай делать резервные копии, тем более это так легко с виртуальными машинами: раз, два — и снапшот готов! А это потом сохранит тебе кучу времени, поверь, проверено на практике!

WARNING

Будь осторожней при скачивании и распаковке архивов с образцами malware на свой компьютер. Все исследования выполняй только в изолированной виртуальной среде! Не выполняй действий, в которых не уверен на 100%! И делай регулярные snapshot системы для быстрого отката.

 

Анализ семпла malware01

На примере этого семпла мы разберем базовый алгоритм первичного анализа файла, поиска OEP, оригинального (незапакованного) кода, после чего файл можно будет легко сдампить на жесткий диск и, к примеру, открыть в IDA Pro для просмотра таблицы импорта всех функций.

Используемые инструменты:

  • PEiD (DiE);
  • OllyDbg v2;
  • IDA Pro.

Первым делом запускаем анализатор PEiD или DiE.

Результат сигнатурного анализа PE-анализатора
Результат сигнатурного анализа PE-анализатора

Итак, видим, что перед нами Win32-приложение, любезно запакованное PECompact, а сам бинарник скомпилирован Visual C++.

Идем дальше, грузим OllyDbg и закидываем в него наш семпл. Если дебаггер будет ругаться, потому что файл не опознан из-за упаковщика, — не обращаем внимания, щелкаем ОK и загружаем файл.

Окно OllyDbg после первичной загрузки семпла
Окно OllyDbg после первичной загрузки семпла

Наш курсор встает на адресе 00405139 PUSHAD. Справа в окне можем просмотреть текущее значение регистров. Дальше ставим точку останова hardware on access на регистре ESP, после чего строка окрашивается в красный цвет. Жмем несколько раз F9, чтобы запустить программу, после чего она наткнется на наш брейк-пойнт и остановится. Что мы видим? Курсор остановился на адресе 0045013А CALL malware01.00405141, соответственно, это наш главный CALL.

Окно OllyDbg после установки точки останова
Окно OllyDbg после установки точки останова

В правом окне регистров на значении ESP 0012FfA0 щелкаем правой клавишей и выбираем Follow Dump. После этого переключаемся в нижнее окно, где содержится Hex dump, и, выделив несколько элементов, также щелкаем правой клавишей на Breakpoint → memory on access. Запускаем выполнение программы F9. Ставим еще один брейк-пойнт: Breakpoint → Hardware on access → Dword. Далее выполнение кода останавливается на точке POPAD.

Окно OllyDbg в точке останова POPAD
Окно OllyDbg в точке останова POPAD

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

Окно OllyDbg с нечитаемым кодом
Окно OllyDbg с нечитаемым кодом

Чтобы это исправить, жмем Ctrl + A и видим, как на глазах строки преобразуются в понятный набор инструкций.

Преобразованный код после нажатия Ctrl + A
Преобразованный код после нажатия Ctrl + A

После этого мы дампим процесс, открываем Plugins → OllyDmp → Dump → Debugged process, в открывшемся окне обязательно щелкаем Get EIP as OEP и потом кнопку Dump.

Окно OllyDbg с опциями дампа
Окно OllyDbg с опциями дампа

В итоге получаем распакованный файл, который теперь легко можно закинуть в IDA Pro.

Распакованный файл загружен в IDA Pro
Распакованный файл загружен в IDA Pro
 

Анализ семпла malware02

А теперь — более сложный вариант предыдущего семпла, затруднять жизнь нам будет испорченный PE-заголовок. Однако и на него есть решение.

Используемые инструменты:

  • PEiD;
  • OllyDbg;
  • Import REConstructor;
  • IDA Pro.

PEiD нам говорит, что семпл зашифрован UnPack.

Сигнатурный анализ с помощью PE-анализаторов
Сигнатурный анализ с помощью PE-анализаторов

Если попытаться открыть его в IDA Pro, PEview или в ранних версиях OllyDbg без плагинов, получим сообщение о некорректности файла. А в IDA Pro у открытого файла напрочь будет отсутствовать таблица импорта, все, что мы сможем увидеть, — это функции LoadLibraryA и GetProcAddress, через которые пакер будет грузить оригинальный код.

Семпл malware02, загруженный в IDA Pro
Семпл malware02, загруженный в IDA Pro

Неплохой трюк, правда? Открываем OllyDbg и грузим туда наш файл. По клавишам Ctrl-G открываем окно поиска, в котором вводим LoadLibraryA, переходим на соответствующую строку кода и ставим брейк-пойнт по F2.

Окно OllyDbg с искомой строкой кода
Окно OllyDbg с искомой строкой кода

После этого запускаем выполнение и видим, что после загрузки библиотеки kernel32.dll сразу подгружается advapi32.dll, а также commctrl.dll. Выскакиваем на строчку PUSH EBP, в правой колонке наблюдаем вызов функций kernel32.GetVersion и kernel32.GetCommandLineA — вуаля, попадаем на распакованный оригинальный код.

Окно OllyDbg после перехода на PUSH EBP
Окно OllyDbg после перехода на PUSH EBP

По аналогии с прошлым вариантом мы можем сдампить файл, однако, если это сделать, сохранение произойдет с ошибками. Помнишь, я говорил про битый PE header? Именно в нем причина. В нашем случае нужно восстановить таблицу импорта (IAT) с помощью программы Import REConstructor. Запускаем тулзу, выбираем нужный нам процесс из памяти, жмем последовательно IAT autosearch, Get Imports и Fix Dump.

Окно программы Import REConstructor с восстановлением таблицы импорта
Окно программы Import REConstructor с восстановлением таблицы импорта

Вот наконец мы и получили распакованный файл, с которым дальше можно делать все, что угодно.

 

Анализ семпла malware03

А что же делать, если нам попалась малварь, которая запакована еще неизвестным пакером? Конечно, общий алгоритм действий сохраняется, но мыслить придется нестандартно, искать новые подходы и экспериментировать. Ниже мы разберем несложный пример того, как нужно проводить анализ, когда файл запакован тем, что в андеграунде называется hacker-packer.

Используемые инструменты:

  • PEiD;
  • OllyDbg.

Первым делом запускаем анализаторы PEiD/DiE/Pe-Scan, и что мы видим? Файл чем-то запакован :). Несмотря на то что PEiD все-таки распознал его сигнатуру, это нестандартный упаковщик, а в сигнатуры он попал потому, что уже устарел.

Результаты анализа PEiD
Результаты анализа PEiD
Анализ в DiE и попытка вычислить пакер в Pe-Scan
Анализ в DiE и попытка вычислить пакер в Pe-Scan
Анализ в DiE и попытка вычислить пакер в Pe-Scan
Анализ в DiE и попытка вычислить пакер в Pe-Scan
Анализ в DiE и попытка вычислить пакер в Pe-Scan

Грузим файл в OllyDbg, открываем диалог поиска по Ctrl-G, пишем VirtualAlloc, жмем OK и попадаем на нужную нам строку кода, на которой устанавливаем брейк-пойнт по F2.

Окно OllyDbg после поиска VirtualAlloc
Окно OllyDbg после поиска VirtualAlloc

Теперь смело по F9 запускаем программу, пока она не остановится на брейк-пойнте. В правом окне со значением регистров на значении EAX правый щелчок мышью и выбираем Follow in Dump.

Окно OllyDbg с регистрами при выполнении дампа
Окно OllyDbg с регистрами при выполнении дампа

Теперь в нижнее окно, выделяем несколько байтов и снова щелкаем правой кнопкой Breakpoint → Hardware, write → Byte, после чего снова запускаем программу клавишей F9.

Выделяем байты в памяти и ставим новый брейк-пойнт
Выделяем байты в памяти и ставим новый брейк-пойнт

Повторяем это до тех пор, пока снова не упремся в точку останова. Что мы видим? Неужели это нужная нам PE-секция?

Окно OllyDbg после поиска OEP
Окно OllyDbg после поиска OEP

Все же нет, потому что семпл многократно запакован, соответственно, у него несколько точек загрузки пакера. Повторяем запуск по F9 еще несколько раз. Для того чтобы добраться до оригинальной OEP, нужно каждый раз ставить новые брейк-пойнты, выбирать в секции регистров Follow in Dump. Наконец мы попадем на строчку POPAD и увидим оригинальный код.

Строка POPAD после многократного поиска
Строка POPAD после многократного поиска

Теперь все, что нам осталось, — это сдампить образ из памяти в файл на жесткий диск, выбрав в нижнем окне несколько байтов и щелкнув правой кнопкой BackUp → Save data to file.

 

Заключение

Сегодня мы проделали хорошую работу, вспомнили матчасть по PE-архитектуре файлов и на практике познакомились с методикой анализа и распаковки различных пакеров. Не забывай тренироваться, читать дополнительную информацию по предложенным ссылкам, самостоятельно анализируй семплы, и, безусловно, тебя будет ждать успех!

Буду рад ответить на все вопросы, связывайтесь со мной по почте или пишите в комментарии. Всем удачи в исследованиях и до новых встреч!

 

Благодарности

Автор и редакция благодарят Сергея Харламова, антивирусного эксперта «Лаборатории Касперского», за ценные коррективы и комментарии к готовому тексту.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    8 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии