010 Editor — пожалуй, один из самых многофункциональных hex-редакторов. Основной его полезной возможностью является написание шаблонов (templates), с помощью которых можно легко описывать структуры любых файлов. Это значительно облегчает процесс обратной инженерии и технического анализа, многочасового копания в hex.
Примечание: статья аналитическая, предназначена для тех, кто не имеет большого опыта hex-исследований (надеюсь, картинки покажут процесс максимально наглядно).
Для того, чтобы разобраться с тем, что есть шаблоны 010 Editor-а и «с чем их едят», рассмотрим небольшой, но наглядный пример. Допустим, у нас есть файл, который может быть дампом памяти или сборником ресурсов (например, какой-нибудь видеоигры), необходимо понять, зачем он нужен, и описать структуру. В качестве учебного примера рассмотрим небольшой файл, представляющий собой бинарную версию каталога некой директории.
Часть 1 — предварительный анализ
Для начала откроем файл в hex-редакторе 010 Editor, видим непонятные названия (ASCII) и много-много цифр/символов:
Попробуем немного проанализировать ситуацию.
- По смещению 0x0 мы видим 4 байта с целочисленным значением 2 — возможно, это некая величина типа данных int (DWORD), можем предположить, что это версия файла, оставим для себя такую заметку (обычно в заголовках файлов она указывается).
- По смещению 0x4 находится довольно большое целочисленное число 6043. Учитывая, что дальше видим огромный перечень симметрично повторяющихся записей с названиями, есть вариант, что это их количество. Также сделаем для себя такую заметку.
Для того, чтобы узнать, какое значение перед вами (перевести из шестнадцатиричного кода в «читабельный вид»), достаточно кликнуть по нужному смещению и посмотреть слева панель inspector — там представлены варианты просмотра шестнадцатиричного кода в различных режимах — int/float/string и прочие. Грубо говоря, в панели Inspector показывается то, как шестнадцатиричный код может быть представлен в различных вариантах «читабельности».
Исходя из предварительного анализа, отбросим первые 8 байт файла, обозначив его «заголовок». Следом (начиная со смещения 0x8) видим характерные симметрично повторяющиеся данные, в которых:
- Смещение 0x0 от начала блока данных (первая группа в 4 байта) — возрастающие значения: 0x0 (0), 0x5 (5), 0xA (10), 0xF (15) ...Integer/DWORD 4 байта?
- Смещение 0x4 от начала блока данных (вторая группа в 4 байта) — всегда 0x5 (5). Integer/DWORD 4 байта?
- Смещение 0x8 — 0x25 (остальные байты до конца структура) — ASCII-строка, в конце которой нулевые байты.
Пока результаты нашего исследования неизвестны, насколько мы близки от истины. Поэтому переходим ко второй части.
Часть 2 — написание шаблона
Выбираем: Templates -> New template. Откроется окно, похожее на небольшой «блокнот» — текстовое поле для написания шаблона 010 Editor-а. Синтаксис шаблонов — Си-подобный (однако с рядом неплохих расширений, но это пока что опустим, равно как и ограничения).
Вспомним, какие у нас были предположения по поводу заголовка файла: первая группа 4 байта (смещение 0x0) — версия, вторая группа (смещение 0x4) — число записей. Оформим это в виде кода, описав структуру:
typedef struct header{
DWORD dwVersion; // версия
DWORD dwItemCount; // число записей
};
Наименования полей говорят сами за себя (кстати, давайте сразу учиться называть переменные правильно! в данной статье, да и вообще в программистской практике, я стараюсь придерживаться венгерской нотации, в которой первые символы наименования определяют тип поля или переменной).
Далее опишем структуру самой единичной записи:
typedef struct item{
DWORD unk1; // ?
DWORD unk2; // ?
char strFileName[24]; // название (ASCII)
};
И перейдем к описанию всего файла (заголовок + массив записей):
header m_header;
item m_item[m_header.dwItemCount];
Общий вид окна шаблона — что в итоге должно получиться:
После этого можно запустить полученный код: Template -> Run Template.
Теперь можно посмотреть результаты в TemplateResults — вся структура файла отображается в удобном виде с легкой навигацией. Проверим, были ли мы правы на счет того, что поле 0x4 — количество записей. Действительно, шаблон «покрыл» исследуемый файл до самого конца — байт-в-байт!
Неизвестными остались поля unk1 и unk2. Просмотрев таблицу, сгенерированную при выполнении шаблона, мы можем увидеть некую зависимость, исходя из которой значения unk1 всегда возрастают, а unk2 — никогда не равно нулю. Очень похоже на то, что unk1 есть ни что иное, как смещение файла в некоем другом сборнике, при чем указано оно в блоках данных (забегая вперед, уточню: в данном случае 2048 байт), такой метод хранения используется довольно часто. А unk2 — размер самого файла, указанный также в блоках. Так что эти поля можно назвать dwOffset и dwFileSize.
Вывод
На рассмотренном «игровом» примере, быть может, не слишком характерно показана необходимость в 010 шаблонах — по сути это лишь учебный пример для наглядной демонстрации базовых возможностей. Но представьте, если приходится описывать крупные файлы со сложными (вложенными, многоуровневыми) структурами, сколько усилий и времени на это тратится.
Шаблоны позволяют существенно сократить временные траты, и лучше «уложить все в голове». Используя потенциал Си-подобного синтаксиса, можно без труда использовать циклы, условия, функции, фактически писать Си-код для обработки файла (который будет в разы проще, чем если делать отдельную программу с тем же самым назначениям).
Буду рад услышать дополнения и комментарии! Это лишь только своеобразная «вводная» статья, дальше планирую продолжать уроки, как по базовым навыкам hex, так и по методологии написания шаблонов в 010 Editor. С уважением, Dageron.
Автор: Dageron