Прелюдия
Индустрия RE в настоящее время сконцентрирована на исследовании кода и ставит вопрос "как работает код и как он обрабатывает данные?" Мы рассмотрим обратную разработку с не самого популярного угла и поставим вопрос "как организованы данные, обрабатывающиеся кодом?" Мы увидим, насколько слабее развита область реверс-инжиниринга данных по сравнению с областью реверса кода.
Что будет: анализ проприетарных форматов файлов и баз данных; межфайловые форматы; подходы к реверсу структур данных; методы исследования без применения дизассемблера и отладчика; работа с зашифрованными данными.
Чего не будет: исходников целиком (только части кода, к сожалению), реляционных SQL-баз (возможно, лишь немного).
Реверс-инжиниринг форматов файлов
Реверс-инжиниринг БД есть процесс, базирующийся на реверс-инжиниринге форматов файлов, т.е. он находится на один уровень абстракции выше.
На первом уровне абстракции мы исследуем одиночные файлы, никак не связанные друг с другом, либо связанные лишь семантически, например, набор .jpg-файлов в папке. Для начала определим, что такое файл, формат файла и бинарный файл.
Файл - данные, структурированные по определённым правилам.
Формат файла - правила, описывающие то, как именно организованы данные в файле.
Простейшим примером может служить текстовый файл, состоящий из нескольких строк (листинг 1). Формат такого файла можно описать как текст в кодировке UTF-8, разделённый символами конца строки.
Code:Пред нашим представленьем Мы просим со смиреньем Нас выслушать с терпеньем.Листинг 1. Пример текстового файла
Бинарный файл - файл, который может содержать как человекочитаемую информацию, так и сырые байты.
Приведём пример гипотетического бинарного файла, в котором хранятся сообщения и дата их добавления. В листинге 2 показано содержимое этого файла, открытого в хекс-редакторе. Его формат уже более строг: первые четыре байта - длина сообщения (0xC), дальше - сообщение указанной длины без завершающего NULL-байта ("Some message"), после которого один байт - день добавления (0x6), ещё один - месяц (0xB), и два последних - год (0x7E1 = 2017).
Code:00000000: 0C 00 00 00-53 6F 6D 65-20 6D 65 73-73 61 67 65 ♀ Some message 00000010: 06 0B E1 07- - - ♠◙с•Листинг 2. Пример бинарного файла
В интернете есть статьи, посвящённые исследованию форматов бинарных файлов, но не сказать, что много. Также есть программы, позволяющие описывать структуру файла; как правило, это хекс-редакторы со встроенным императивным языком скриптования. Одна из последних разработок, однозначно продвинувшая данную область - Kaitai Struct, позволяющая описывать бинарный формат в декларативном стиле.
Реверс-инжиниринг БД
Второй уровень абстракции появляется тогда, когда мы исследуем несколько бинарных файлов, внутренне жёстко связанных друг с другом. Такие совокупности файлов мы будем называть базой данных.
База данных - набор бинарных файлов, содержащих упорядоченные данные и имеющих перекрёстные ссылки друг на друга.
Сразу замечу, что это очень низкоуровневое определение БД. Обратная разработка в наше время всё ещё является процессом, где не избежать детализации, и реверс БД не является исключением: редко когда можно абстрагироваться от внутреннего устройства базы и сразу начать работать с данными. В таком случае реверс-инжиниринг баз не выполняется как таковой.
Рассмотрим пример. Имеется база данных музыкальных групп, состоящая из трёх бинарных файлов (листинг 3). В файле Band.dat1 хранится список групп, в Album.dat2 лежат альбомы каждой группы, в Image.dat3 располагаются фотографии участников групп и обложки альбомов.
Code:Band.dat1 Album.dat2 Image.dat3Листинг 3. Список файлов БД
Опишем формат Band.dat1 (листинг 4). Он состоит из массива, в котором лишь один элемент, описывающийся следующей структурой:
1. Ворд - ID группы.
2. 0x20 байт - название группы, неиспользованные байты заполнены нулями.
3. Список вордов до терминирующего 0xFFFF - список ID альбомов.
4. Терминирующий 0xFFFF.
5. Список двордов до терминирующего 0xFFFFFFFF - список ID фотографий.
6. Терминирующий 0xFFFFFFFF.
В этом файле две зависимости: ID альбомов (перекрёстная ссылка на файл Album.dat2) и ID фотографий (перекрёстная ссылка на файл Image.dat3).
Code:00000000: 00 00 54 6F-6F 6C 00 00-00 00 00 00-00 00 00 00 Tool 00000010: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00 00000020: 00 00 00 00-01 00 02 00-03 00 FF FF-00 00 00 80 ☺ ☻ ♥ А 00000030: 01 00 00 80-FF FF FF FF- - ☺ АЛистинг 4. Содержимое Band.dat1
Теперь взглянем на формат Album.dat2 (листинг 5). Он состоит из массива, в котором 4 элемента. Каждый элемент описывается так:
1. Ворд - ID альбома.
2. Ворд - год выхода.
3. Байт - длина названия.
4. N байт - название.
5. Дворд - ID обложки.
В этом файле уже лишь одна зависимость: ID обложки (перекрёстная ссылка на файл Image.dat3).
Code:00000000: 00 00 C9 07-08 55 6E 64-65 72 74 6F-77 02 00 00 ╔•◘Undertow☻ 00000010: 80 01 00 CC-07 06 41 65-6E 69 6D 61-03 00 00 80 А☺ ╠•♠Aenima♥ А 00000020: 02 00 D1 07-09 4C 61 74-65 72 61 6C-75 73 04 00 ☻ ╤•○Lateralus♦ 00000030: 00 80 03 00-D6 07 0A 31-30 30 30 30-20 44 61 79 А♥ ╓•◙10000 Day 00000040: 73 05 00 00-80 - - s♣ АЛистинг 5. Содержимое Album.dat2
Наконец, изучим файл Image.dat3 (листинг 6). Снова массив, теперь из 6 элементов размером 0x10 байт. Здесь зависимостей от других файлов нет.
1. Дворд - ID изображения.
2. 0xC байт - картинка (воображаемая, естественно).
Code:00000000: 00 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 АPIC 00000010: 01 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 ☺ АPIC 00000020: 02 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 ☻ АPIC 00000030: 03 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 ♥ АPIC 00000040: 04 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 ♦ АPIC 00000050: 05 00 00 80-50 49 43 00-00 00 00 00-00 00 00 00 ♣ АPICЛистинг 6. Содержимое Image.dat3
Ниже изображены три перечисленных формата и зависимости между ними, что в итоге и составляет архитектуру вымышленной БД.
Итак, мы описали два уровня: форматов файлов и баз данных. Теперь мы можем сформулировать основную проблему, возникающую при работе на втором уровне.
Проблема обратной разработки БД заключается в восстановлении неизвестных структур данных и нахождению зависимостей между ними.
Во многих реальных задачах исследование БД является не самоцелью, а этапом, после которого начинается работа с содержимым (извлечение, модификация, преобразование в иной вид) с последующим сохранением его в новую, возможно, реляционную, БД. Этот процесс даже имеет название - ETL (Extract, Transform, Load), хотя кроме самой концепции с реверсом БД он имеет мало общего.
Статей по данной тематике мной найдено не было. Возможно, дело в том, что специалисты не делали различия между реверсом форматов файлов и баз данных. К тому же, программы с большими массивами данных будут исследоваться скорее под заказ, чем для себя, и это накладывает ограничения на информативность статей.
Промежуточные итоги
Мы дали довольно формальное определение БД как совокупности файлов, но в действительности границы могут быть размытыми, и порой единственное, почему мы называем этот файл или файлы базой данных, это наше субъективное представление о ней как о наборе взаимосвязанных данных. Не имеет значения, лежат они в одном большом файле или разбросаны по множеству файлов, важно лишь понять, как эти данные связаны между собой.
Но в этом "лишь понять" и заключается вся сложность. Приступая к очередной задаче, перед нами есть набор файлов, названия и расширения которых редко говорят что-либо, и программа, эти файлы использующая. Мы начинаем просматривать в хекс-редакторе файлы один за другим, сразу же примечая, насколько они отличаются друг от друга, какова их приблизительная структура, есть ли текстовые файлы и т.д. Когда файлы просмотрены, мы осматриваем саму программу, оценивая, с чем придётся иметь дело.
После такого обзора мы оказываемся наедине с несколькими десятками блобов, создатели которых явно не горели желанием, чтобы их изучали. Что делать дальше, увидим в следующих статьях.





Reply With Quote
Thanks