25.08.2013

В помощь пентестеру: простые и полезные трюки для анализа бинарных файлов. Часть третья

image

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

Автор: Йори Квичко (Yori Kvitchko) (Counter Hack)

Примечание редактора: в третьей статье Йори Квичко рассматривает техники декомпилирования исполняемых файлов и дает конкретные советы по их применению для Python и Java. В таких файлах часто скрыто множество вещей, представляющих интерес для пентестера, и Йори рассказывает о методах по выявлению этих секретов!

В первой статье мы рассматривали анализ бинарных файлов в разрезе поиска коммуникационных потоков. Во второй статье мы изучали методы анализа файлов данных, которые часто создают автономные приложения. В третьей и последней статье из этого цикла, посвященного анализу бинарных файлов, я расскажу о простых методах декомпиляции бинарных файлов, которые не скомпилированы в набор чистых ассемблерных инструкций. Все дело в том, что анализ чистых ассемблерных инструкций – сложная область, рассмотрение которой выходит за рамки данной статьи. Я буду рассказывать об анализе исполняемых файлов, состоящих не из чистых ассемблерных инструкций, а «скомпилированных» версиях программ, написанных на интерпретируемых языках (таких как Python) или скомпилированных в байт-код для запуска на виртуальной машине (например, Java Virtual Machine).

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

В предыдущих статьях объекты для поиска были намного проще, чем в исходном тексте приложения. Пароли, URL’ы или настройки, представленные в формате XML или обычном тексте, могут быть найдены при поиске по релевантным ключевым словам внутри соответствующих переменных (например, «pass» или «xml»). Что же касается исходного кода, то его анализ, к примеру, может помочь нам в анализе файлов, создаваемых приложением. Часто кодирование и шифрование осуществляется при помощи библиотек, исходных код которых находится в общем доступе, что может помочь нам в расшифровке соответствующих файлов. Более того, исследование исходного кода – наиболее простой способ поиска метода по расшифровке сетевого протокола. Поиск имен функций таких как "getInt" или "getString" поможет найти участки кода, отвечающие за декодирование пользовательского протокола.

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

C# .NET

C# используется повсеместно, начиная от автономных приложений и заканчивая модулями и веб-приложениями. Платформа .NET от компании Microsoft и технологии, связанные с .NET, - гибки и относительно просты в изучении, что и стало причиной их популярности. Широкая популярность платформы, а также потребность со стороны разработчиков привели к появлению инструментов по декомпиляции бинарных файлов и библиотек, написанных на C#.

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

Существует и бесплатная альтернатива, утилита ILSpy, которая также позволяет декомпилировать и анализировать программы, написанные на C#. Кроме того, что шанс декомпиляции программы при помощи этой утилиты весьма высок. У ILSpy также есть множество полезных функций. Во-первых, ILSpy позволяет осуществлять навигацию по коду так же, как и в современных IDE. Переходить к объявлению функции или переменной очень просто, также как и искать зависимости. Кроме того, ILSpy позволяет сохранять значимые участки исходного кода как серию файлов и соответствующий файл проекта, чтобы затем открыть их в редакторе или IDE на ваш выбор и при помощи утилит наподобие grep осуществлять быстрый поиск.

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

Java

Несмотря на снижение популярности за последние несколько лет, Java используют многие разработчики, и появление телефонов на платформе Android только усилили на рынке позиции этого языка. Также как и в C# Java-программы компилируются в байт-код, который можно преобразовать обратно в почти первоначальный исходный текст. Приложения обычно упакованы в JAR (Java-архив), которые по объему немного больше, чем zip-архивы.

Java Decompiler, где есть большинство функций как и в ILSpy, - свободно распространяемый инструмент, которые прекрасно декомпилирует Java-классы и Java-пакеты. Вы можете просматривать исходный код, находить места объявления функций и сохранять исходный текст для просмотра в IDE (например, в Eclipse).

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

Python

Python используется разработчиками при создании небольших скриптов или веб-приложений на базе фреймворка Django. Как у интерпретируемого языка у Python еще слабее выражен процесс компиляции, однако также присутствует так называемый слой компиляции, состоящий из байт-кода, который хранится в файлах с расширением «.pyc». Обычно файлы с расширением «.pyc» декомпилируются еще проще, чем программы, написанные на Java and C#. Таким образом, за исключением случаев, когда код обфусцирован, вы практически всегда сможете получить исходный текст исполняемого файла.

Существует несколько утилит, позволяющих выполнять декомпиляцию исполняемых файлов, написанных на Python, но лично мне нравится сервис depython.com. Сервис рабочий и простой в использовании, однако поддерживает декомпиляцию скриптов, написанных на Python до версии 2.6. Для более поздних версий попробуйте утилиты unpyc и unpyc3.

Помимо декомпиляции скриптов существует еще один, более красивый, метод для извлечения внутренностей Python-скриптов. Поскольку Python – интерпретируемый язык, взаимодействие со скриптом можно осуществить в более динамичном режиме. К примеру, интерпретатор Python можно запустить с ключом «-i», когда сначала запускается скрипт, а затем управление тут же передается интерпретатору с сохранением текущего состояние всех объектов внутри скрипта. После этого вы можете выполнять любую Python-команду, оставаясь внутри среды выполнения скрипта. Это означает, что вы можете получить доступ к любой переменной или вызвать любую функцию. Вывести список функций и переменных можно при помощи функции dir(). У этого метода не слишком много возможностей, которые ограничены лишь использованием встроенных функций в интерпретатор Python. Ниже показан пример считывания значения переменной внутри среды выполнения скрипта:

$ python -i someprogram.py
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'secret_variable']
>>> print secret_variable
secret value

На этом я заканчиваю свою трилогию, посвященную анализу бинарных файлов. Если вы работаете с языками, не упомянутыми мной, но в которых создаются исполняемые файлы с байт-кодом (как в C# или Java) или которые являются интерпретируемыми (как Python), вы легко можете нагуглить соответствующие инструменты для декомпиляции таких файлов.
Если вы новичок, надеюсь, теперь вы поняли, что владение некоторыми методами из области реверс-инжиниринга вовсе не требует от вас знание ассемблера. Если же вы эксперт, надеюсь, что вы также подчерпнули для себя нечто новое. Спасибо за внимание и, как всегда, успешного хакинга. 
или введите имя

CAPTCHA