Урок 6. Как восстановить файл из фрагмента данных
Находим PNG с помощью `binwalk`, извлекаем его в копию и проверяем результат.
Иногда изображение или документ находится внутри большого файла без собственного имени. Например, содержимое памяти может выглядеть как один memory.raw, хотя внутри сохранилась целая картинка. Поиск и извлечение таких объектов называют восстановлением по содержимому или file carving.
В этом уроке рассматривается простой и важный для ВСОШ случай:
- встроенный файл не разбит на части;
- его формат распознаётся автоматически;
- объект продолжается до конца учебного фрагмента;
- исходный файл остаётся неизменным.
На олимпиадной Kali установлен binwalk, который ищет известные форматы внутри других данных и показывает их смещения.
Из чего состоит задача
Пусть внутри fragment.raw находится PNG. Нужно выполнить четыре действия:
- найти начало изображения;
- скопировать данные с этого места в новый файл;
- проверить получившийся файл;
- извлечь требуемое значение или посчитать его 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.
Шаг 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.
Типичные ошибки
Перепутано десятичное и шестнадцатеричное число
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 намеренно.
C16. Где начинается изображение
С помощью binwalk найдите, с какого смещения начинается PNG внутри l6_fragment.raw. Сдайте смещение десятичным числом.
C17. Метка восстановленного PNG
Извлеките PNG из l6_fragment.raw и назовите значение поля Case-ID в его метаданных. Регистр и дефис важны.
C18. Hash восстановленного PNG
Извлеките валидный PNG в новый файл и сдайте его lowercase SHA-256.