cropped_parser: обрезанный через заголовок BMP

стеганография · задача 11   bmpзаголовокhex

Файл cropped_parser.bmp. В названии прямо сказано «обрезанный».

Платформа
CTF
Носитель
BMP, 32 бита на пиксель
Приём
высота в заголовке меньше реальной
Инструменты
exiftool, xxd, dd
Статус
метод найден, файл восстановлен

Аномалия в числах

Для форматов без сжатия (BMP, PPM, сырые пиксели) есть проверка, которую стоит делать всегда: ширина × высота × байт_на_пиксель должно совпасть с размером данных.

Image Width  : 1000
Image Height : 1000
Bit Depth    : 32           ← 4 байта на пиксель
Image Length : 4800000      ← столько байт пикселей на самом деле

ожидаемо: 1000 × 1000 × 4 = 4 000 000
лишнее:   800 000 / 4 байта = 200 000 пикселей = ровно 200 строк по 1000

Лишнее делится ровно на целое число строк, значит, это не мусор, а настоящие строки картинки. Реальный размер 1000 × 1200.

Почему в BMP это так просто

В BMP нет ни сжатия, ни контрольной суммы. Просмотрщик берёт высоту из заголовка и читает ровно столько строк. «Обрезать» картинку можно, поменяв 4 байта, и вернуть так же. В PNG пришлось бы подбирать высоту по CRC чанка IHDR, а здесь её можно просто посчитать.

СмещениеПолеБайтыЗначение
0x12ширинаe8 03 00 001000
0x16высотаe8 03 00 00 → b0 04 00 001000 → 1200

Числа в little-endian, младший байт первым: 1200 = 0x04B0 записывается как b0 04 00 00.

cp cropped_parser.bmp fixed.bmp
printf '\xb0\x04\x00\x00' | dd of=fixed.bmp bs=1 seek=$((0x16)) conv=notrunc
xxd -s 0x12 -l 8 fixed.bmp
00000012: e803 0000 b004 0000

Где появятся скрытые строки

BMP хранит строки снизу вверх. Просмотрщик прочитал первые 1000 строк данных, а это нижняя часть картинки. Лишние строки лежат в конце файла, то есть это верх изображения. Я воспроизвёл приём на своём файле:

Что показывает просмотрщикпо заголовку: 250 × 250
После исправления высотыпосле правки: 250 × 300
Мой демо-BMP: после исправления 4 байт сверху появляется спрятанная полоса
zsteg на этом файле падал не из-за задачи: он не понимает BMP версии 5 (заголовок 124 байта). Если понадобится LSB, достаточно сконвертировать: convert fixed.bmp fixed.png.

Другие способы

  • GIMP → Raw image data: смещение 138, 1000 × 1200, RGB Alpha. Потом отразить по вертикали и поменять местами R и B (BMP хранит BGR).
  • ImHex: поправить поле в шаблоне BMP прямо в редакторе.
  • Для PNG есть готовая «чинилка» PCRT: она сама подбирает ширину и высоту по CRC.