СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H Навыки написания шаблонов и работы в hex-редакторе 010 Editor — Часть I в черновиках Из песочницы Tutorial

010 Editor — пожалуй, один из самых многофункциональных hex-редакторов. Основной его полезной возможностью является написание шаблонов (templates), с помощью которых можно легко описывать структуры любых файлов. Это значительно облегчает процесс обратной инженерии и технического анализа, многочасового копания в hex.


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

Для того, чтобы разобраться с тем, что есть шаблоны 010 Editor-а и «с чем их едят», рассмотрим небольшой, но наглядный пример. Допустим, у нас есть файл, который может быть дампом памяти или сборником ресурсов (например, какой-нибудь видеоигры), необходимо понять, зачем он нужен, и описать структуру. В качестве учебного примера рассмотрим небольшой файл, представляющий собой бинарную версию каталога некой директории.

Часть 1 — предварительный анализ


Для начала откроем файл в hex-редакторе 010 Editor, видим непонятные названия (ASCII) и много-много цифр/символов:


Попробуем немного проанализировать ситуацию.

  1. По смещению 0x0 мы видим 4 байта с целочисленным значением 2 — возможно, это некая величина типа данных int (DWORD), можем предположить, что это версия файла, оставим для себя такую заметку (обычно в заголовках файлов она указывается).
  2. По смещению 0x4 находится довольно большое целочисленное число 6043. Учитывая, что дальше видим огромный перечень симметрично повторяющихся записей с названиями, есть вариант, что это их количество. Также сделаем для себя такую заметку.

Для того, чтобы узнать, какое значение перед вами (перевести из шестнадцатиричного кода в «читабельный вид»), достаточно кликнуть по нужному смещению и посмотреть слева панель inspector — там представлены варианты просмотра шестнадцатиричного кода в различных режимах — int/float/string и прочие. Грубо говоря, в панели Inspector показывается то, как шестнадцатиричный код может быть представлен в различных вариантах «читабельности».



Исходя из предварительного анализа, отбросим первые 8 байт файла, обозначив его «заголовок». Следом (начиная со смещения 0x8) видим характерные симметрично повторяющиеся данные, в которых:
  1. Смещение 0x0 от начала блока данных (первая группа в 4 байта) — возрастающие значения: 0x0 (0), 0x5 (5), 0xA (10), 0xF (15) ...Integer/DWORD 4 байта?
  2. Смещение 0x4 от начала блока данных (вторая группа в 4 байта) — всегда 0x5 (5). Integer/DWORD 4 байта?
  3. Смещение 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.

Обновление: добавлена часть II.

комментарии (17)

+3
felicast ,  

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

0
Ivanhoe ,  

Когда-то давно анализировал формат QHF хранения истории Qip, эта штука мне бы пригодилась :)

+1
esl ,  

очень удобный инструмент, это точно
до него пользовался StructLoook (STL) от автора hiew, но этот гораздо удобнее.

+2
+3 –1
d_olex ,  

> 010 Editor — пожалуй, один из самых многофункциональных hex-редакторов

Мне больше нравится radare: OpenSource, кросплатформенный, намного более функциональный.

+2
Self_Perfection ,  

KDEшная Okteta тоже умеет анализировать по шаблонам (structures в её терминологии). Свободная утилита.

0
nwalker ,  

Я бы для подобного разбора написал скрипт на Erlang-е, наверное. Хотя, конечно, с GUI все нагляднее.

+1
EvilsInterrupt ,  

Я часть из этого функционала реализовал в своем плагине к Hiew, очень выручает. Вообще хотелось бы найти уже реализованную фичу хоть в одном из существующих Hex-редакторов, фича эта должна уметь двигать вперед\назад представление по написанным шаблонам. К примеру анализируешь поток байт и понимаешь что если отступить 5 байт вперед то все точно также и хочется нажать просто пять раз стрелку вправо, чтобы отображение шаблона было обновлено новыми байтами. Но к сожалению такой фичи еще не видел (

0
SFx ,  

то что нужно! как раз прошивку редактировать надо будет… попробую!

+1
Hoshi ,   * (был изменён)

Даже не догадывался о существовании подобного рода инструментов. Спасибо, буду пользовать.
Раньше всё глазами выискивал.

+1
+2 –1
GRascm ,  

А я сразу узнал файл. Описание архива ресурсов для игр серии GTA. Притом это GTA3\VC, потому что в SA этот файл был уже вместе с самим архивом.

+4
PsyHaSTe ,  

Спасибо за статью. Однако

в данной статье, да и вообще в программистской практике, я стараюсь придерживаться венгерской нотации, в которой первые символы наименования определяют тип поля или переменной).

Есть мнение, что венгерская нотация уже себя изжила, по крайней мере если мы не говорим о разработке в каких-то древних или еще не развитых IDE. Как тот же мартин говорил, венгерская нотация была нужна, когда IDE не было в принципе, или они выполняли лишь простейший анализ кода, а когда у нас есть всякие IntelliSense и прочие инструменты, которые разве что кофе в постель не приносят — пора бы уже отказаться, как от анахронизма. Это нормальный процесс, который происходит с любым инструментом в процессе эволюции, но не надо за него держаться полсотни лет и считать, что это правильно.
+1
EvilsInterrupt ,  

>>что венгерская нотация уже себя изжила
Это верно при обычном программировании. Но когда дело касается Reverse Engineering-а, то появляются нюансы и которые нужно учесть.

0
PsyHaSTe ,   * (был изменён)

Возможно, в этом узком ракурсе она и существует нормально (хотя это попадает под определение неразвитой IDE, в данном случае — декомпилятора, хотя декомпиляторы байт-кода вполне себе ок) ), но фраза вообще в программистской практике как бы намекает… :)

+1
EvilsInterrupt ,  

>> вообще в программистской практике
Пост не про это! Пост про инструмент для необычного программиста, а для программиста занимающегося Reverse-Engineering. Вот когда он поймет как что-то работает, сядет писать нормальный продукт на основе полученных знаний, вот тогда-то и вступают в силу все общепринятые практики. Но здесь идет речь о другом программировании! Идет об очень узко-специализированном инструменте помогающему программисту справиться! Вы видимо не представляете себе что же такое на самом деле Reversing!

Попробую пояснить:
Есть поток байт, выдвигаются множество гипотез что означает очередной кусок данных. Идет перепроверка гипотез.Идет сопоставление полученных данных и устанавливаются предварительные факты. Этих гипотез, перепроверок, сопоставлений во время reversing ооочень много! И человек легко забывает какой тип он поставил для поля и уверяю Вас ему меньше всего хочется в этот момент обращаться к его декларации, он лучше переместится на другой кусок данных чтобы перепроверить очередную догадку, чем уточнять то что уже исследовано!

Венгерская нотация очень экономит время reversing-engeer-а!

0
PsyHaSTe ,  

Я представляю. Что касается основной статьи, она мне понравилась, о чем я написал сразу.

А вы считаете, что ТС все свое время проводит за RE?

0
Dageron ,  

В C/C++/Delphi, увы, не знаю хорошей альтернативы, поэтому и использую венгерскую нотацию, старая привычка. В C# руководствуюсь советами ReSharper-а, тоже неплохо выстраивает логику наименований.

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

0
PsyHaSTe ,  
Учту замечания, в статье скорее всего было лучше упомянуть не о венгерской нотации конкретно, а о том, что в программировании всегда следует соблюдать единообразие наименований и их подчинение логике

В программировании в целом приветствуется наличие логики :)