Пост обновлен, предыдущее название: «Как заинструментировать код на Си и понять что он делает? Реверсинг формата файла»
Вступление
Есть какой-то файл и я хочу понять его внутреннее устройство. В качестве примера, возмем файл формата PNG, так как он достаточно простой и хорошо документирован. Но далеко не все форматы хорошо документированы, поэтому полагаться только на документацию - нельзя.
Итак, у нас есть какой-то файл формата PNG - что с ним дальше можно сделать? Можно было бы взять готовую библиотеку для чтения данного формата (libpng), но она содержит более 100 000 строк кода, что крайне сложно для понимания.
Я предполагаю, что более наглядным для изучения будет разглядывать такие картинки:
- https://i.imgur.com/eLd44xQ.png - 010 hex editor + png.bt
- https://i.imgur.com/AwpmSxV.png - minimal png file
- https://i.stack.imgur.com/hcIIO.png - найдено в интернетах
- https://parsiya.net/images/2018/png1/03-ihdr.png - найдено в интернетах
- https://i.stack.imgur.com/aZUz1.png - найдено в интернетах
Здесь сразу видны байтики и их значение. По крайней мере, лично мне, такое изучение было бы наиболее близким и понятным. В этом месте можно назвать меня гуманитарием и посоветовать биореактор^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
Я себе это представляю как-то так:
- Читаем кусочек файла и помечаем, что это наш файл (перехватываем read/fread, «отравляем» эти участки памяти)
- Ставим брейтпоинт на чтение памяти, логгируем, смотрим по map-файлу где мы это читали, желательно размотать стек
- По коду уже можно представить, читаем мы
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, получить сегфолт, но непонятно как возвращать управление (сделал, но споткнулся на последнем пункте)