Урок 6. Как восстановить файл из фрагмента данных

Находим PNG с помощью `binwalk`, извлекаем его в копию и проверяем результат.

Иногда изображение или документ находится внутри большого файла без собственного имени. Например, содержимое памяти может выглядеть как один memory.raw, хотя внутри сохранилась целая картинка. Поиск и извлечение таких объектов называют восстановлением по содержимому или file carving.

В этом уроке рассматривается простой и важный для ВСОШ случай:

  • встроенный файл не разбит на части;
  • его формат распознаётся автоматически;
  • объект продолжается до конца учебного фрагмента;
  • исходный файл остаётся неизменным.

На олимпиадной Kali установлен binwalk, который ищет известные форматы внутри других данных и показывает их смещения.

Из чего состоит задача

Пусть внутри fragment.raw находится PNG. Нужно выполнить четыре действия:

  1. найти начало изображения;
  2. скопировать данные с этого места в новый файл;
  3. проверить получившийся файл;
  4. извлечь требуемое значение или посчитать его SHA-256.

Позиция внутри исходного файла называется смещением. Смещение 0 — первый байт, 1 — второй и так далее.

Если PNG начинается после 768 посторонних байт, его смещение равно 768. В шестнадцатеричной записи то же число выглядит как 0x300. Сдавайте ту форму, которую требует условие.

Шаг 1. Найти встроенный файл

Запуск:

binwalk fragment.raw

Пример вывода:

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
768           0x300           PNG image, 16 x 12, 8-bit/color RGB

Первая колонка содержит десятичное смещение, вторая — то же значение в шестнадцатеричном виде. Описание показывает, что binwalk распознал PNG.

Не ищите число 768 в самостоятельном задании: оно относится только к демонстрации. Для l6_fragment.raw смещение нужно получить самостоятельно.

Шаг 2. Извлечь объект командой dd

dd копирует выбранную часть данных:

mkdir -p work/l6
dd if=fragment.raw of=work/l6/recovered.png bs=1 skip=768 status=none

Параметры означают:

  • if — входной файл;
  • of — новый выходной файл;
  • bs=1 — работать блоками по одному байту;
  • skip=768 — пропустить 768 байт входа;
  • status=none — не печатать служебную статистику.

Исходный fragment.raw не изменяется. Все результаты появляются в work/l6/.

В демонстрационном фрагменте после PNG есть ещё данные, поэтому для него известна точная длина 545:

dd if=l6_demo_fragment.raw of=work/l6/demo.png \
  bs=1 skip=768 count=545 status=none

count=545 ограничивает число скопированных байт. В самостоятельном l6_fragment.raw изображение специально расположено до самого конца файла, поэтому достаточно skip без count.

Демонстрационный фрагмент данных для повторения примера
binwalk нашёл PNG внутри большого файла. Как извлечь его, не меняя исходник? · 4 б.

Шаг 3. Проверить результат

После извлечения не следует сразу сдавать ответ. Сначала проверьте новый файл:

file work/l6/recovered.png
exiftool work/l6/recovered.png

file должен сообщить PNG и его размеры. exiftool должен без ошибки прочитать служебные поля. Картинку также можно открыть в просмотрщике, но одна только фраза «она открылась» слабее вывода двух независимых утилит.

Если file по-прежнему показывает просто data, проверьте:

  • не переписали ли вы число из демонстрации;
  • взяли ли десятичную колонку binwalk;
  • указали ли bs=1;
  • не перепутали ли входной и выходной файлы.

Шаг 4. Получить ответ

Задача может попросить поле из восстановленного изображения:

exiftool -G -s work/l6/recovered.png

Или SHA-256 именно восстановленного файла:

sha256sum work/l6/recovered.png

Не считайте сумму всего fragment.raw: в нём есть посторонняя часть до PNG, поэтому значение будет другим.

Зачем нужны начало и длина

Когда после встроенного объекта остаются другие данные, нужно знать не только начало, но и длину:

начало = 768
длина = 545
первый байт после объекта = 768 + 545 = 1313

Команда с skip=768 count=545 копирует байты с позиции 768 до позиции 1312 включительно. Число 1313 уже не входит в результат.

В более сложной задаче конец определяют по внутреннему устройству формата или специализированной утилитой. Такие случаи будут разбираться позже. В текущей самостоятельной практике объект идёт до конца фрагмента, поэтому внимание сосредоточено на правильном применении binwalk и dd.

Как убедиться, что после извлечения получился именно PNG? · 4 б.

Типичные ошибки

Перепутано десятичное и шестнадцатеричное число

binwalk показывает обе записи:

65536    0x10000

Если условие просит десятичное смещение, ответ — 65536. Значение 0x10000 равно ему, но записано в другом формате.

Изменён исходный файл

Не записывайте результат поверх fragment.raw. Всегда задавайте другое имя в of=.

Посчитан хеш не того объекта

sha256sum fragment.raw              # исходный большой файл
sha256sum work/l6/recovered.png     # восстановленное изображение

Обе команды работают правильно, но отвечают на разные вопросы.

Слепо использовано автоматическое извлечение

У binwalk есть режим автоматического извлечения, но в этом уроке полезнее явная команда dd: видно, какое смещение использовано и куда записан результат. Это делает решение понятным и воспроизводимым.

Практический набор урока

Сначала повторите пример на l6_demo_fragment.raw, доступном в блоке файла этого урока:

binwalk l6_demo_fragment.raw
dd if=l6_demo_fragment.raw of=work/l6/demo.png \
  bs=1 skip=768 count=545 status=none
file work/l6/demo.png
exiftool -G -s work/l6/demo.png

Затем работайте с самостоятельным l6_fragment.raw:

binwalk l6_fragment.raw
dd if=l6_fragment.raw of=work/l6/recovered.png \
  bs=1 skip=<НАЙДЕННОЕ-СМЕЩЕНИЕ> status=none
file work/l6/recovered.png
exiftool -G -s work/l6/recovered.png
sha256sum work/l6/recovered.png

Задания проверяют разные части решения:

  • C16 — десятичное смещение PNG;
  • C17 — значение поля Case-ID восстановленного изображения;
  • C18 — SHA-256 восстановленного PNG.

Реальная задача ВСОШ: «Порча модуля памяти Коллектора»

Открыть исходный PDF с условием и решением. Это задача заключительного этапа 2024–2025 для 10 класса.

Подробный разбор и важная неточность исходного решения

Участнику выдавался collector_memory.img размером около 32 МБ. Команда:

strings collector_memory.img | less

показывала строку IHDR. Так называется первый служебный блок PNG. Это был признак, что в образе может находиться изображение с повреждённым началом.

В авторском решении предлагалось скопировать начало образа, а затем восстановить первые восемь байт PNG только в рабочей копии:

dd if=collector_memory.img of=work/candidate.bin bs=1 count=<ДЛИНА>
printf '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a' | \
  dd of=work/candidate.bin bs=1 count=8 conv=notrunc status=none

После исправления сигнатуры картинку можно было открыть и прочитать флаг.

В опубликованном PDF есть неточность: текст говорит о первых 10 мегабайтах, а пример bs=1 count=10000 копирует 10 000 байт, то есть примерно 10 килобайт. Поэтому команды из разбора нельзя копировать без понимания параметров.

Эта реальная задача сложнее учебного файла: сигнатура была повреждена, а границу изображения требовалось определить внимательнее. Но общий порядок совпадает:

найти признак файла -> работать с копией -> восстановить объект -> проверить -> получить ответ

Главный защитный принцип — никогда не исправлять выданный образ на месте. Ошибка в рабочей копии обратима, изменение исходника уничтожает исходное состояние.

Результат восстановления

Корректное решение оставляет после себя не только recovered.png, но и воспроизводимую команду извлечения. По ней видно исходный файл, смещение и выбранную длину. file и exiftool подтверждают, что копия читается как PNG, а SHA-256 фиксирует её точное содержимое.

Если изменить skip хотя бы на один байт, проверка типа перестанет проходить. Если посчитать сумму исходного фрагмента, получится корректный SHA-256 другого объекта. Эти две ошибки разделены между C16 и C18 намеренно.

Скачать практический набор: l6_fragment.raw
C16

C16. Где начинается изображение

12 б.

С помощью binwalk найдите, с какого смещения начинается PNG внутри l6_fragment.raw. Сдайте смещение десятичным числом.

C17

C17. Метка восстановленного PNG

12 б.

Извлеките PNG из l6_fragment.raw и назовите значение поля Case-ID в его метаданных. Регистр и дефис важны.

C18

C18. Hash восстановленного PNG

16 б.

Извлеките валидный PNG в новый файл и сдайте его lowercase SHA-256.