Упакованный SWF. Как распаковать?

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

Итак, что же такое упакованный SWF?

Если Вы никогда ранее его не видели, не поленитесь скачать простой классический пример упакованного SWF:
http://codestage.ru/files/flood/security/packed.swf
Запустив SWF, вы увидите немного текста в левом верхнем углу. Однако, если вы попробуете декомпилировать этот файл, то вы не увидите кода, который этот текст показывает.
Стоит отметить, что если бы в упакованном SWF были ещё какие-нибудь ресурсы (изображения, звуки, шрифты и т.д.), то их вы бы тоже не увидели. Это из-за того, что оригинальный SWF находится внутри того SWF что вы скачали и декомпилировали, и часто в зашифрованном виде.
Обычно все, что вы можете получить из таких SWF с помощью декомпиляторов – это код распаковщика\расшифратора и, возможно, сам зашифрованный SWF в виде набора байт (зависит от того, умеет ли используемый вами декомпилятор отображать тэг DefineBinaryData).
Такая “упаковка” на самом деле достигается с помощью простого Flex тэга [Embed].

Динамическая распаковка (dumping)

Динамическая – значит для распаковки потребуется исполнение SWF во Flash Player’е (далее – FP).
Т.к. FP не умеет проигрывать зашифрованную неведомо как SWF, то логично что перед проигрыванием, SWF должна расшифровываться и загружаться уже в чистом виде (например, с помощью Loader.loadBytes()).
Что более важно, распакованный и расшифрованный SWF будет в памяти все время, пока он исполняется FP’ром.

И это наш шанс достать его!
Существует два основных способа сделать это.

1) Динамическая распаковка с помощью утилит
Используя сторонние или даже самописные утилиты для поиска SWF в памяти процесса FP. Это самый быстрый, самый простой и обычно самый эффективный способ. Но он не вызывает ощущения что вы – тру крякер ;)
Существуют различные платные и бесплатные утилиты для этих целей.
Одна из наиболее продвинутых – это SWF Revealer, бесплатная утилита для владельцев лицензий на ASV. В некоторых случаях, она может обходить проверки на домен (которые не дают распаковаться и расшифроваться SWFке) и заставлять SWF запускаться в вашей среде.
Также достаточно легко гуглятся разные бесплатные дамперы.

2) Ручная динамическая распаковка
Поиск SWFки вручную, с помощью нахождения CWS (сжатый SWF) или FWS (несжатый SWF) заголовков, которые являются началом любого SWF. Если вы никогда не пробовали такой способ, я очень рекомендую попробовать! Он не только позволит немного подтянуть ваши скиллы в hex, но и подарит вам ощущение, что вы тру-крякер!)
Для поиска заголовков можно использовать любой HEX редактор, который умеет читать память процессов и имеет функцию поиска.
Если вы хотите искать упакованный SWF в памяти FP в котором проигрывается файл-пример по ссылке выше, то стоит начать с поиска FWS подписи (несжатый SWF) – просто ищите строку ‘FWS’, т.к. перед исполнением FP разжимает SWF, если он был сжат.
Если вы будете запускать и искать SWF в браузере, то закройте все лишние вкладки, чтобы снизить количество лишних SWF в памяти.

Обычно при таком поиске вы найдете несколько заголовков в памяти, т.к. сам FP держит там разные служебные SWF, например ту, что показывается после входа в полноэкранный режим.
Так что если вы сомневаетесь, то лучше проверить все найденные заголовки.
Итак, что же делать с найденным заголовками, спросите вы? Как их проверить, как узнать, где заканчивается SWF?
Пожалуйста, взгляните на этот скриншот:

Это заголовок одной из SWF в памяти FP при проигрывании файла-примера, найденный поиском по строке ‘FWS’ (совершенно случайно это оказался заголовок искомого упакованного файла, который мы и хотим найти ;))
Что же дальше? А дальше необходимо посмотреть какой длины получается найденный SWF. Длина расположена в 4 байтах начиная с 4го:

Как я узнал? Я просто прочитал спецификацию формата SWF: “SWF File Format Specification” http://www.adobe.com/content/dam/Adobe/en/devnet/swf/pdf/swf_file_format_spec_v10.pdf (раздел “The SWF header”)
Т.к. это шестнадцатеричное число, записанное в память, вам стоит знать, что порядок записи его байт – справа налево. Поэтому в результате число такое:
00 00 04 DB в hex и 1243 десятичном представлении.
Теперь отмеряем эти 1243 байт начиная с FWS подписи.
Т.к. подпись начинается на 053DD020, окончание SWF файла должно находиться по адресу 053DD4FB (053DD020 + 4DB):

Пожалуйста, имейте ввиду, что адрес расположения SWF в памяти будет отличаться на разных ОС и на разном железе.

Итак, мы видим, что найденный SWF действительно заканчивается на 053DD4FB, так что мы можем смело выделить все байты начиная с 053DD020, заканчивая 053DD4FB и скопировать их в новый SWF файл.
После проделывания этой операции со всеми вхождениями FWS, которые вам покажутся подходящими, среди сохраненных SWF файлов будет один искомый, распакованный SWF!
Теперь у вас не должно возникнуть проблем с его декомпиляцией.

Некоторые виды пакеров усложняют поиск искомого SWF с помощью размещения множества фальшивых FWS заголовков в памяти. Так что вам следует более тщательно подбирать FWS – проверять его длину, и то как он в целом выглядит. Опытные в реверсинге люди (вроде меня :p) могут на глаз отличить фальшивый заголовок от настоящего, глянув на сам заголовок и на несколько десятков байт после него.

Иногда, упакованный SWF может не распаковываться в память до проверки каких-нибудь условий. Например, загрузчик может проверять текущий домен или наличие какого-нибудь файла с лицензией. В таком случае вам придётся пропатчить эти проверки (например, с помощью дизассемблеров байткода, таких как Yogda или RABCDasm) или предоставить необходимые файлы (в которых может находиться ключ для расшифровки), чтобы заставить SWF запуститься и распаковаться.

Статическая распаковка

Статическая – значит без запуска SWF во FP.
В целом, к этому типу распаковки прибегают когда не вышло распаковать SWF динамически (кто его знает, почему у вас не получилось запустить SWF?)
Статическая распаковка может быть очень сложной задачей, т.к. есть не один способ её усложнить и сделать мучительно долгой.

Итак, с чего начать при статической распаковке? Для начала, вам следует получить доступ как минимум к двум вещам в SWF:
1 – DefineBinaryData тэг(и).
2 – Декомпилированный AS или abc байткод распаковщика\загрузчика.
Также, в некоторых случаях понадобится
3 – SymbolClass тэг
Для этого используйте доступные утилиты (ASV, Adobe SWF Investigator, SWiX, и т.д.).

Как найти тэг DefineBinaryData в SWF?
Сначала отмечу, что некоторые утилиты, например, ASV, могут вам явно указать на наличие этого тэга, сразу после открытия SWF. В них же можно этот тэг сохранить в виде двоичного файла.
Также можно найти его вручную, с помощью различных инспекторов тэгов, вроде упомянутого выше Adobe SWF Investigator.
Для получения содержимого тэга DefineBinaryData из файла-примера с помощью Adobe SWF Investigator, просто откройте файл, перейдите на вкладку Tag Viewer, выберите тэг DefineBinaryData и нажмите на кнопку Dump To File.

Иногда в этом списке тэгов может быть множество фальшивых, чтобы сбить с толку незадачливого крякера. Для поиска необходимого тэга придётся немного изучить код загрузчика\распаковщика и отследить там обращение к упакованным данным.
Обычно оно выглядит так:

var someVar:ByteArray = new SomeClass();

Где SomeClass имеет тип Class и наследуется от класса ByteArrayAsset.

Давайте посмотрим в код загрузчика и поищем что-то похожее.
Ага, вот и оно!

private var content:Class;
//...
var _local3:ByteArray = new this.content();

Теперь нам следует поискать класс с именем оканчивающимся на “_content” и наследующийся от ByteArrayAsset.
А вот и он:

public class MainTimeline_focus_loader_content extends ByteArrayAsset

Чтобы выяснить, какой тэг DefineBinaryData связан с этим классом, нам следует заглянуть в тэг SymbolClass и поискать там запись с названием найденного класса “MainTimeline_focus_loader_content”.
В нашем случае эта запись выглядит так (в Adobe SWF Investigator):

<Symbol idref='1' className='MainTimeline_focus_loader_content' />

Запомните значение поля idref. Это id нужного тэга DefineBinaryData!
Теперь ищите тэг с таким id среди всех тэгов DefineBinaryData.
После того, как вы его найдёте, его можно сохранить в файл и продолжать распаковку.
Почему я попросил запомнить idref, а не название класса? Потому что в том случае, если AS распаковщика обфусцирован, работать с именами классов может быть очень затруднительно.

Теперь успех вашего мероприятия зависит от количества времени, которое вы готовы потратить, сложности упаковщика и удачи)
Если повезёт, то полученные из DefineBinaryData данные окажутся чистым SWF без какого-либо шифрования и распаковку можно считать оконченной.
Но чаще всего, на этом этапе все самое интересное только начинается и впереди реверсинг загрузчика – разбор алгоритмов шифрования и написания собственного дешифровщика.

В нашем случае, код загрузчика намеренно сделан максимально простым и не обфусцированным, так что на этот раз нам повезло – мы легко находим функцию расшифровки:

private function decryptFile(_arg1:ByteArray):void
{
    _arg1.position = 0;
    var _local2:int = -1;
    var _local3:uint = _arg1.length;
    var _local4:uint = uint("55");
    while (_local2++ < _local3)
    {
        _arg1[_local2] = (_arg1[_local2] ^ _local4);
    };
}

И узнаем, что для получения оригинального SWF достаточно каждый его байт поксорить на 55.
Теперь вы можете написать свой декриптор, или скрипт, который сделает все операции для расшифровки SWF. Вот и все, распаковка закончена. После расшифровки вы получите оригинальный SWF, код и ресурсы которого видны в декомпиляторе.
Остаётся надеяться, что это так и распакованный SWF не окажется точно так же расшифровщиком SWF, который вы только что ковыряли, хахаха!)
Иногда при упаковке используют принцип матрёшки – запихивают один расшифровщик в другой – и так десятки раз, да ещё и алгоритмы расшифровки везде разные.
В любом случае, динамическая распаковка все это обходит.
Запомните – в мире Flash, ничего, кроме названий, нельзя скрыть от глаз профессионала высокого класса с достаточным уровнем мотивации ;)

Есть вопросы, идеи, комментарии? Оставляйте всё в виде комментариев к посту, пишите!

Нашли опечатку? Выделите её и нажмите Shift + Enter или кликните здесь, спасибо!

Share Button

Комментарии

Упакованный SWF. Как распаковать? — Комментарии (11)

  1. Привет
    Извиняюсь за прошлые комментарии запись не появилась в них
    вот это idref=’1′ не могу найти его SWF Investigator

    • Ага, не страшно. Эту запись надо искать в тэге SymbolClass, как и написано в статье.

  2. Спасибо хорошая статья

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

    • Боюсь что других дельных статей я подсказать не смогу кроме уже упомянутой выше (http://habrahabr.ru/post/110686/), т.к. сам не читал ничего такого.

      Наверняка я смогу вам помочь с вашей флэшкой, если хотите продолжить обсуждение – пишите лучше лично, буду рад (http://blog.codestage.ru/ru/contacts/), ибо через комменты весьма неудобно.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">