LINUX.ORG.RU

Как разобраться в формате файла? (было: Как заинструментировать код на Си)

 , , , ,


3

2

Пост обновлен, предыдущее название: «Как заинструментировать код на Си и понять что он делает? Реверсинг формата файла»


Вступление

Есть какой-то файл и я хочу понять его внутреннее устройство. В качестве примера, возмем файл формата PNG, так как он достаточно простой и хорошо документирован. Но далеко не все форматы хорошо документированы, поэтому полагаться только на документацию - нельзя.

Итак, у нас есть какой-то файл формата PNG - что с ним дальше можно сделать? Можно было бы взять готовую библиотеку для чтения данного формата (libpng), но она содержит более 100 000 строк кода, что крайне сложно для понимания.

Я предполагаю, что более наглядным для изучения будет разглядывать такие картинки:

Здесь сразу видны байтики и их значение. По крайней мере, лично мне, такое изучение было бы наиболее близким и понятным. В этом месте можно назвать меня гуманитарием и посоветовать биореактор^Wчтение исходников, но это не так наглядно.

К сожалению, не все форматы файлов так хорошо описаны, как описан формат PNG. Далеко не для всех форматов файлов есть такие картинки и тем более шаблоны для hex-редакторов. И я бы хотел делать такие картинки самостоятельно.


Идея

Я предполагаю, что если для этого формата есть открытая библиотека (libpng), то для него можно написать свою читалку (my_png_reader). В свою очередь, у нашей библиотеки (libpng) могут быть свои зависимости (zlib) и я предполагаю, что нужно будет разобраться и с устройством этой библиотеки тоже.

Само собой, для тестирования, нужно будет собрать некий тестовый датасет (набор png-файлов с разными разрешениями, режимами компрессии, битые файлы). Для этого было бы неплохо использовать утилиты из набора AFL для уменьшения датасета и уменьшения самих исходных данных: https://youtu.be/0dqL6vfPCek (фаззинг файла вместе с ffmpeg)

Вопрос: как бы заинструментировать имеющийся софт (программу, библиотеки), чтобы понять, что такое оно делает с файлом, что внутри и как его вообще читать? Да и вообще, что можно вытащить из подобной затеи?

Например, очень бы хотелось узнать:

  • Сигнатуру файла (\x89PNG в начале файла)
  • Структуру «чанков», что она представляет собой 4 поля: длинна, тип, данные, CRC32
  • Алгоритм расчета CRC32: какая часть данных считается, с заголовком или без, какой полином
  • Какая часть файла пожата zlib, какие части файла просто являются несжатыми массивами
  • Нарисовать какую-то диаграмму, где какой байт чему соответстует, вроде https://i.imgur.com/eLd44xQ.png или https://i.imgur.com/AwpmSxV.png

Я себе это представляю как-то так:

  1. Читаем кусочек файла и помечаем, что это наш файл (перехватываем read/fread, «отравляем» эти участки памяти)
  2. Ставим брейтпоинт на чтение памяти, логгируем, смотрим по map-файлу где мы это читали, желательно размотать стек
  3. По коду уже можно представить, читаем мы float или int16, находимся ли в структурке или еще где. Если мы внутри функции check_file_signature(), то это вообще очевидно. Можно пометить как ручками, так и чем-то вроде IDA.

Зачем? Это поможет в написании файлов-шаблонов для таких программ как https://ide.kaitai.io/ или 010 Editor. Конечно, в идеале запустить на входе PNG-файл, а на выходе получить KSY (формат описания файлов kaitai) или BT (формат для 010 Editor), но понятно, что идеальной документации не будет. Но я стремлюсь именно к этому.

Однако я понятия не имею как это реализовать, да и наверняка я не первый до этого додумался. Может кто-то встречал нечто подобное?

Буду благодарен на статьи просто по инструментации сишного кода. Или не только сишного.


Референсы и идеи

  • https://github.com/AFLplusplus/AFLplusplus - отличное средство для фаззинга (пример фаззинга libpng: https://youtu.be/LsdDRat4S0U), но я не очень понимаю как это применить именно к описанию файла. А вот тулзы вроде afl-cmin - чистое золото
  • https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-dynamic-binary-instrumentation-tool.html - Intel PIN
  • Address Sanitizer or ASAN - можно попробовать поиграться с ним и залоггировать доступ к памяти
  • valgrind + lackey - очень многообещающе, но боюсь не осилить
  • Попробовать сделать доступ к страничке PROT_NONE, получить сегфолт, но непонятно как возвращать управление (сделал, но споткнулся на последнем пункте)


Последнее исправление: ruzisufaka (всего исправлений: 2)
Ответ на: комментарий от ruzisufaka

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

такая компонента находится, и глазками изучается.

alysnix ★★★
()
Ответ на: комментарий от alysnix
libpng1.6-1.6.37# cat *c | wc -l
cat: powerpc: Is a directory
35764
libpng1.6-1.6.37#

Да, всего-то надо прочитать 35к строк и понять их. Плевое дело!

Поправка:

libpng1.6-1.6.37# find -iname "*.c" | xargs -n1 cat | wc -l
106351
libpng1.6-1.6.37#

Если считать со всеми платформами и ассемблерными оптимизациями, то всего-то 106к строк!

ruzisufaka
() автор топика
Последнее исправление: ruzisufaka (всего исправлений: 1)
Ответ на: комментарий от ruzisufaka

Нет, выкидывай оттуда лишнее блок за блоком, строчка за строчкой, собирай и постоянной проверяй сохранение-открытие твоего файла. В итоге останется только код сохранения/открытия, который тебе и нужен: он всяко понятнее дизасма или реверс-инжениринга файла. Ну приведи в порядок, добавь комментов

pihter ★★★★★
()
Ответ на: комментарий от Forum0888

В 90-х была програмка для реверсинга игр, которая работала так. Меняем значение опции в игре, а программа в памяти производит поиск изменённых байт.

Artmoney?

pihter ★★★★★
()
Ответ на: комментарий от ruzisufaka

Всего 8203 блоков! До обеда разберусь!

Можно выкидывать более крупными блоками :)

До обеда не разберёшься, но за несколько дней я так программу на 50 тыс строк припорировал. Потому что если просто тащить из неё нужный мне кусок кода - он не работал и, чтобы выяснить что же там скрыто влияет - пришлось вот так разобрать. Не быстро да, но зато результат гарантирован

pihter ★★★★★
()
Ответ на: комментарий от ruzisufaka

Я не хочу находить небольшую часть, я хочу ПОНИМАТЬ устройство файла в целом

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

bugfixer ★★★★★
()
Ответ на: комментарий от ruzisufaka

Можно и без перекомпиляции отключать ASLR через setarch -R. Без:

$ cat /proc/self/maps  | sha1sum
061811ab4aaf61afefb150e10cd39aa7911806f3  -
$ cat /proc/self/maps  | sha1sum
307ac5769750e791a28003f45af31d34651c8d29  -
$ cat /proc/self/maps  | sha1sum
29caaacbff80daf22627ebd3dca3e5463822505a  -

С:

$ setarch -R cat /proc/self/maps  | sha1sum
7806dcdf8de1e5ed91dca6f508b985c8ccabc4e4  -
$ setarch -R cat /proc/self/maps  | sha1sum
7806dcdf8de1e5ed91dca6f508b985c8ccabc4e4  -
$ setarch -R cat /proc/self/maps  | sha1sum
7806dcdf8de1e5ed91dca6f508b985c8ccabc4e4  -
anonymous
()

C, asm - хороши если есть толпа бездельников разработчиков. А в одну харю - ну наверное действительно Ruby (если подзубрить нативные библиотеки, вместо Си-алгоритмов) стоит подучить. У ‘‘‘Добби’’’ ловко получилось!

anonymous
()

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

frob ★★★★★
()

Я бы покопал в сторону WireShark: https://www.wireshark.org/

Это анализатор сетевого трафика, но он имеет похожее HEX представление и интерпритацию. Возможно есть способ приспособить его для парсинга обычных файлов, а не перехваченных данных из сети.

asashnov
()

С реверсом такое дело. Это в png хорошо что всё просто и очевидно, а в реверсе тебе сначала надо базу файлов набрать большую, чтоб фичи стандарта которым с тобой не поделились узнать. Ну и для обработки этого добра рекомендую не сразу на сях код писать, а на том же питоне быстро чтоб все фичи найти, а потом на си свои или расты переписывай.

peregrine ★★★★★
()
Ответ на: комментарий от Stanson

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

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от ruzisufaka

35к строк

Код в дипломе студента (если он реально код писал для решения какой-то простой задачи, скажем уровня определения авторства текста) будет где-то 10к строк на питоне. Так что я не вижу сложности в прочтении 35к строк на сишке, которая куда более многословная

peregrine ★★★★★
()