R0 CREW

Реверс-инжиниринг баз данных. Часть 1. Введение

reverse
ru
writeup
#1

Прелюдия

Индустрия RE в настоящее время сконцентрирована на исследовании кода и ставит вопрос “как работает код и как он обрабатывает данные?” Мы рассмотрим обратную разработку с не самого популярного угла и поставим вопрос “как организованы данные, обрабатывающиеся кодом?” Мы увидим, насколько слабее развита область реверс-инжиниринга данных по сравнению с областью реверса кода.

Что будет: анализ проприетарных форматов файлов и баз данных; межфайловые форматы; подходы к реверсу структур данных; методы исследования без применения дизассемблера и отладчика; работа с зашифрованными данными.

Чего не будет: исходников целиком (только части кода, к сожалению), реляционных SQL-баз (возможно, лишь немного).

Реверс-инжиниринг форматов файлов

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

На первом уровне абстракции мы исследуем одиночные файлы, никак не связанные друг с другом, либо связанные лишь семантически, например, набор .jpg-файлов в папке. Для начала определим, что такое файл, формат файла и бинарный файл.

Файл - данные, структурированные по определённым правилам.

Формат файла - правила, описывающие то, как именно организованы данные в файле.

Простейшим примером может служить текстовый файл, состоящий из нескольких строк (листинг 1). Формат такого файла можно описать как текст в кодировке UTF-8, разделённый символами конца строки.

Пред нашим представленьем
Мы просим со смиреньем
Нас выслушать с терпеньем.
Листинг 1. Пример текстового файла

Бинарный файл - файл, который может содержать как человекочитаемую информацию, так и сырые байты.

Приведём пример гипотетического бинарного файла, в котором хранятся сообщения и дата их добавления. В листинге 2 показано содержимое этого файла, открытого в хекс-редакторе. Его формат уже более строг: первые четыре байта - длина сообщения (0xC), дальше - сообщение указанной длины без завершающего NULL-байта (“Some message”), после которого один байт - день добавления (0x6), ещё один - месяц (0xB), и два последних - год (0x7E1 = 2017).

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 располагаются фотографии участников групп и обложки альбомов.

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).

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).

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 байт - картинка (воображаемая, естественно).
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), хотя кроме самой концепции с реверсом БД он имеет мало общего.

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

Промежуточные итоги

Мы дали довольно формальное определение БД как совокупности файлов, но в действительности границы могут быть размытыми, и порой единственное, почему мы называем этот файл или файлы базой данных, это наше субъективное представление о ней как о наборе взаимосвязанных данных. Не имеет значения, лежат они в одном большом файле или разбросаны по множеству файлов, важно лишь понять, как эти данные связаны между собой.

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

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

Уроки реверс-инжиниринга баз данных