К.Н. Долгова, А.В. Чернов, Труды Института системного программирования РАН
Этот проект [14] был открыт в 1997 году компанией BackerStreet Software, но вскоре закрылся из-за ухода ведущего разработчика проекта. Позднее разработка декомпилятора продолжилась его автором в статусе собственного продукта. Сейчас декомпилятор распространяется свободно, а развивается достаточно вяло. Одной из особенностей рассматриваемого декомпилятора является то, что он восстанавливает исполняемые файлы в различных форматах, в частности ELF и PE. Также декомпилятор REC можно использовать на различных платформах. В ходе тестирования этого декомпилятора было отмечено, что наиболее успешно декомпилятор восстанавливает исполняемые файлы, полученные при компиляции с включением опций, которые отвечают за отключение оптимизаций и добавление отладочной информации.
Как уже говорилось, инструмент Hex-Rays [10] не является самостоятельным программным продуктом, а распространяется в виде плагина к дизассемблеру IdaPro [11]. Это самое новое из рассматриваемых средств декомпиляции: плагин появился на рынке в 2007 году. Особенностью данного инструмента является то, что он, как отмечалось, восстанавливает программы, полученные на выходе дизассемблера Ida Pro. Среди алгоритмов, используемых в Hex-Rays, заслуживают внимания алгоритм сигнатурного поиска FLIRT [1] и алгоритм поиска параметров в стеке PIT (Parameter Identification and Tracking).
В таблице 1 представлена сводная характеристика всех рассматриваемых декомпилятров.
| Boomerang | DCC | REC | Hex-Rays | |
| распознавание библиотечных функций | нет | заявлено | нет | да |
| активность разработки | да | нет | да | да |
| переносимость | нет | да | да | да |
| open source | да | да | нет | нет |
Таблица 1. Сравнительный анализ декомпиляторов
В этом разделе приведены результаты тестирования возможностей рассмотренных декомпиляторов. Для тестирования был разработан тестовый набор программ на языке Си, покрывающий основные языковые конструкции языка Си.
Тестирование проводилось по следующей методике. Исходный код программы на Си компилировался компилятором gcc 3.4.5 в среде Debian Linux и компилятором Borland C++ 3.1 в среде Windows XP. В первом случае результатом работы компилятора являлся файл формата ELF для архитектуры ia32, во втором – исполняемый файл DOS для 16-битного режима процессора. Исполняемый файл формата ELF подавался на вход декомпиляторам Boomerang, REC и Hex-Rays, работающим в среде Windows XP. Исполняемый файл формата DOS~EXE подавался на вход декомпилятору DCC. Результат декомпиляции сравнивался с исходным текстом.
Такая комбинация инструментальных и целевых сред была выбрана по следующим причинам. Во-первых, декомпилятор DCC поддерживает только 16-битные исполняемые модули DOS, поэтому для оценки качества работы декомпилятора был использован компилятор 16-битного режима. Декомпиляторы Boomerang и REC, наоборот, не поддерживают 16-битный режим DOS. Исполняемый модуль подавался на вход декомпиляторам в формате ELF, а не в естественном для Windows формате PE, поскольку, как оказалось, декомпиляторы Boomerang и REC некорректно обнаруживают точку начала программы на Си в файлах формата PE.
Качество работы каждого декомпилятора для каждого теста оценивалось по четырехбальной экспертной шкале, приведенной в таблице 2.
Так, оценка «3» выставлялась в случаях, когда в декомпилированной программе использовались адресная арифметика вместо массивов или приведение типов для получения указательных значений вместо корректного объявления типов переменных. Кроме того, оценка «3» выставлялась, если в результате декомпиляции цикл for оказывался преобразовыванным в цикл while.
| Количество баллов за тест | Комментарий |
| 0 | Декомпилятор закончил работу с ошибкой выполнения или пустым результатом. |
| 1 | Декомпилятор выдал ассемблерный код. Программа на Си не была получена. |
| 2 | Декомпилятор выдал программу на языке Си, которая либо не компилируется, либо работает неверно (неэквивалентна исходной), либо содержит ассемблерные вставки, то есть недекомпилированные фрагменты программы. |
| 3 | Декомпилятор выдал корректную программу, которая эквивалентна исходной, но в ней используются конструкции, отличные от конструкций исходной программы. |
| 4 | Декомпилятор выдал программу, которая эквивалентна исходной, и в которой используются те же конструкции, которые использовались в исходной программе. |
Таблица 2. Шкала оценки декомпиляторов
Тестовый набор содержал следующие основные группы.
Также рассматривались типы указателей на базовые типы. Проверялись факт обнаружения того, что переменная обладает указательным, а не целым типом, а также корректность восстановления целевого типа указателя.
Для массивов проверялся факт обнаружения того, что переменная является локальным или глобальным массивом, точность восстановления типа элементов массива, точность восстановления размера массива как для одномерных, так и для многомерных массивов.
Для структурных типов проверялся факт распознавания использования структурного типа и точность восстановления полей структур.
Кроме того, были рассмотрены разные комбинации указательных, массивовых и структурных типов и оценена корректность восстановления таких составных типов. В частности, рассматривались массивы структур, указатели на структуры, структуры, содержащие массивы, структуры, содержащие указатели на самих себя.
В другой группе тестов проверялась корректность восстановления логических операций && (логическое «и»), || (логическое «или») в условиях операторов if и циклов. Согласно семантике языка Си эти операторы транслируются в условные и безусловные переходы, то есть являются конструкциями, задающими поток управления, а не вычисления значений. Декомпиляторы должны по возможности восстанавливать сложные условия в операторах языка.
Отдельно проверялась корректность восстановления структурных операторов передачи управления, таких как break, continue и return.
Оператор switch рассматривался отдельно, так как в большинстве компиляторов он транслируется в косвенный безусловный переход, где адрес перехода выбирается из таблицы в соответствии с вычисленным в заголовке оператора значением. Декомпиляторы должны распознавать использование этого оператора в программе.
Кроме того, в тестах этой группы проверялось распознавание стандартных библиотечных функций языка Си (например, strlen и т. п.). Реализация сигнатурного поиска присутствует в декомпиляторе DCC, но наиболее развита эта технология в декомпиляторе Hex-Rays.
В таблице 3 приводятся результаты работы декомпиляторов на выбранном наборе тестов в соответствии с системой оценок, приведенной в таблице 2. Каждый столбец таблицы соответствует декомпилятору, а каждая строка – тесту. Общий результат для каждого декомпилятора получен суммированием оценок по всем тестам.
Из всех рассмотренных декомпиляторов только Boomerang поддерживает декомпиляцию оператора switch. Остальные декомпиляторы генерируют в этом случае некорректный код на языке ассемблера. Только декомпилятор REC сумел восстановить цикл for, в то время как остальные декомпиляторы в этом случае генерируют программу, использующую цикл while.
| Bom-merang | Rec | DCC | Hex-Rays | ||
| типы данных | struct | 3 | 2 | 3 | 3 |
| массивы | 4 | 3 | 3 | 4 | |
| unsigned int | 4 | 3 | 3 | 3 | |
| unsigned short | 3 | 3 | 3 | 3 | |
| структурные конструкции языка | логические операции | 4 | 4 | 4 | 4 |
| циклы for | 3 | 4 | 3 | 3 | |
| циклы while | 4 | 3 | 4 | 4 | |
| циклы do while | 4 | 4 | 4 | 4 | |
| оператор switch | 4 | 2 | 2 | 2 | |
| функции | рекурсия | 4 | 4 | 4 | 4 |
| оптимизация | inlining | 2 | 2 | – | 2 |
| tail recursion | 2 | 2 | – | 2 | |
| обнаружение функции main в PE файлах | 1 | 1 | – | 4 | |
| обнаружение функций стандартной библиотеки | 2 | 2 | 3 | 4 | |
| сумма баллов | 48 | 43 | 40 | 50 | |
Таблица 3. Результаты тестирования декомпиляторов
Наиболее развитым в настоящее время является декомпилятор Hex-Rays, который, в отличие от других декомпиляторов, поддерживает распознавание массивов и распознавание библиотечных функций, хотя даже и у Hex-Rays имеется много слабых сторон.
В данной работе рассмотрена задача декомпиляции как восстановления программы на языке высокого уровня по программе на языке ассемблера или в машинных кодах. Дано краткое описание основных шагов процесса декомпиляции программы. В работе представлено сравнительное тестирование существующих декомпиляторов и указаны их сильные и слабые стороны. Так, ни один существующий на данный момент декомпилятор не поддерживает в достаточной мере восстановление типов данных, как базовых, так и производных. Существующие декомпиляторы испытывают сложности с восстановлением цикла for и оператора switch. Наиболее развитым из всех декомпиляторов является Hex-Rays, однако он является коммерческим и с закрытыми исходными кодами, поэтому его доработка невозможна.
Поэтому представляются актуальными разработка и реализация алгоритмов, позволяющих восстанавливать базовые и производные типы данных в процессе декомпиляции. Алгоритмы должны быть апробированы в рамках экспериментальной инструментальной среды декомпиляции программ. Разработка таких алгоритмов и инструментальной среды декомпиляции программ является направлением дальнейших исследований авторов.