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

Безусловно, термин нестандарно упакованные файлы не удачен, но другого лучшего выражения не придумал, да и в общем то это не суть так важно. А суть в следующем — встречаются файлы, про которые точно знаешь, что они упакованы определенным архиватором, а распаковать их стандартным способом не можешь, или, например, распаковал, а в распакованном файле обнаруживаешь другие упакованные файлы, распаковать которые тоже обычным способом не получается.
Вот о распаковке таких файлов и хочу поделиться опытом с пользователями, которые с этим не знакомы. А чтобы бы понять саму идею распаковки таких файлов, сначала немного поэкспериментируем, а для проведения экспериментов упакуем/заархивируем произвольный простой файл, но сначала создадим его
$ echo 'Т Е С Т' > ~/test
Убедимся, что файл создан
$ cat ~/test
Т Е С Т
упакуем этот файл, например, архиватором gzip
$ gzip ~/test
и посмотрим на упакованный файл утилитой hexdump, точнее посмотрим 1-ые 16 байт
$ hexdump -C -n 16 ~/test.gz
00000000 1f 8b 08 08 9e 52 18 59 00 03 74 65 73 74 00 bb |.....R.Y..test..|
Первые 3 байта — это так называемая сигнатура (HEX код) архиватора gzip - 1F 8B 08, которая является составной частью упакованного файла (его началом) и присуща только архиватору gzip, что позволяет отличить этот файл от других и, главное, видно, что архиватор, точнее сигнатура начинается с самого начала (с нулевого байта, смещение равно 0).
UPD - если быть точным, то сама сигнатура два байта (0x1f, 0x8b), а 3-ий байт определяет compression method (08 - deflate)
При распаковке этого файла, утилита gzip сначала проверит наличие сигнатуры, присущей gzip, и только после этого примет решение о распаковке.
Проверим это, а для чего изменим сигнатуру файла, точнее, изменим 1-ый байт — вместо 1F запишем 1E (я проделал это в hex редакторе)
$ hexdump -C -n 16 ~/test.gz
00000000 1e 8b 08 08 9e 52 18 59 00 03 74 65 73 74 00 bb |.....R.Y..test..|
Ну и попытаемся рапаковать
$ gzip -d ~/test.gz
gzip: ~/test.gz: not in gzip format
И то же самое будет, если сигнатура будет правильная, но начинаться будет не с начала файла (смещение не равно 0) — вернем все на место, но перед сигнатурой запишем 1 байт — 00 (я сохранил этот файл, как test1.gz).
$ hexdump -C -n 16 ~/test1.gz
00000000 00 1f 8b 08 08 9e 52 18 59 00 03 74 65 73 74 00 |......R.Y..test.|
$ gzip -d ~/test1.gz
gzip: ~/test1.gz: not in gzip format
И значит распаковывать такие файлы нужно по-другому, а именно, нужно указать при распаковке смещение, откуда начинать, т.е. где начинается сигнатура.
Самый простой вариант — удалить байты до сигнатуры, но это не этично, да и иногда это выливается в мегабайты и десятки мегабайт.
Лучше поступить грамотно — указать утилите смещение, с которго начинать распаковку (делаем пропуск с помощью dd в 1 байт прежде чем начать распаковку)
$ dd if=~/test1.gz skip=1 bs=1 | gzip -d > test1
Проверим, что мы получили
$ cat ~/test1
Т Е С Т
То есть распаковали успешно и получили исходный файл.
И так на простом файле показал суть и сам принцип распаковки таких нестандартно упакованных файлов.
Но в жизни все сложнее, но когда понимаешь суть, то можно распаковать и более сложные файлы.
Попробуем сейчас опробовать наши знания на ядре Archlinux - пример неудачный, но полезный для обучения.
Справка - ядро, как правило, находится в сжатом виде, но, главное, сжатое ядро представляет собой загрузчик и распаковщик, за которым следует собственно сжатый алгоритмом zlib vmlinux, а потому сначала необходимо отделить сжатое ядро от загрузчика.
Сначала используя утилиты hexdump и file попробуем выяснить, что же это такое, наше ядро
# hexdump -C -n 16 /boot/vmlinuz-linux
00000000 4d 5a ea 07 00 c0 07 8c c8 8e d8 8e c0 8e d0 31 |MZ.............1|
Судя по сигнатуре 4d 5a (MZ) перед нами стандартный исполняемый формат (исполняемый DOS файл), сигнатура которого 4D 5A (MZ) составлена из инициалов одного из создателей MS-DOS Марка Збиковски.
$ file /boot/vmlinuz-linux
/boot/vmlinuz-linux: Linux kernel x86 boot executable bzImage, version 4.7.6-1-ARCH (builduser@tobias) #1 SMP PREEMPT Fri Sep 30 19:46, RO-rootFS, swap_dev 0x4, Normal VGA
И в итоге подтверждается сказанное выше, что сжатое ядро представляет собой загрузчик + распаковщик + само ядро сжатое алгоритмом zlib архиватора gzip с распаковкой в процессе загрузки.
Но нам, главное, понятно (по 1-ой части), чтобы распаковать ядро, нам нужно отделить сжатое ядро от загрузчика.
Как нам уже известно, gzip имеет сигнатуру 1f 8b 08 — вот и найдем его начало.
Перечислю способы, которыми можно это сделать.
1. Используя hex-редактор, например, bless - определяем, что 1f 8b 08 начинается с адреса 0х4501 или в 10 системе — 17665
UPD — делал и писал давно (обучал молодежь), так что число 17665 уже будет другое.
2. Используя утилиту od
od -A d -t x1 vmlinuz-linux | grep "1f 8b 08"
0017664 e0 1f 8b 08 00 00 00 00 00 02 03 ec 5a 7b 74 53
и получаем опять 17665
3. Очень хорошую утилиту binwalk
binwalk vmlinuz-linux
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Microsoft executable, portable (PE)
17665         0x4501          gzip compressed data, maximum compression, from Unix, NULL date (1970-01-01 00:00:00)
................................................................................
Как видим совпадает во всех случаях - 17665
Остается только извлечь из vmlinuz сжатое ядро и распаковать его:
dd if=vmlinuz-linux skip=17665 bs=1 | gzip -d > vmlinux
gzip: stdin: decompression OK, trailing garbage ignored
Желающие могут снова применить binwalk - binwalk vmlinux
и увидят уже названия файлов, правда вытащить их просто так уже не получится.
Вот и все.
binwalk также удобно использовать для определения архиватора, в случае если есть сомнения. Утилита включает большую базу сигнатур известных архиваторов. Но, разумеется, база базой, но лучше всегда перепроверить ручками, использую hex-редактор.
Ну и бонус на посошок любителям паролей - можно не вешать никакие пароли на сжимаемый файл, а просто ручками добавить в начало несколько байтов, но ЛУЧШЕ изменить сигнатуру и никто этот файл не распакует.
Конечно, эти изменения должны быть постоянны и легко запоминаемы.
Ошибки не исчезают с опытом - они просто умнеют