Blog. Just Blog

Запись в архивы ARC, ZOO и LHZ без помощи архиватора

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
В первой части статьи о записи в архивы без помощи архиваторов я разобрал внутренний формат наиболее популярных современных архиваторов. Как я понял, особого интереса статья не вызвала, но материал на новую статью уже был практически подготовлен. Не пропадать же добру. В этой части я расскажу о том, как внедряться в более редкие форматы архивов: ARC, ZOO и LHZ без использования сторонних приложений. Поскольку такие раритеты найти уже проблематично, к каждому примеру я приложил сам архиватор и описание внутреннего формата его архивов. Ну а совсем экзотические архиваторы рассмотрены в третьей части статьи.

ARC - формат архивов одноименного архиватора от компании System Enhancement Associates, который был достаточно широко распространен в 80-90-х годах прошлого века. Примечательно, что параметры его командной строки в последующем стали эталоном практически для всех других архиваторов с их появления и до нашего времени. Этот же формат архивов (но с расширением .PAK) также имеет архиватор PAK. Сейчас для операционных систем Windows появился архиватор FreeArc, который создает архивы с таким же расширением .ARC, но они имеют другой формат. Здесь я рассмотрю именно старый, DOS'овский формат архивов ARC.
  1. ;---------------------------------------------
  2. ; ARC/PAK Header
  3. ;---------------------------------------------
  4. csig    db      ?                       ; Sign
  5. cmeth   db      ?                       ; Compression method (2 = store)
  6. cfname  rb      13                      ; 12 char File name ASCIIZ
  7. ccsize  dd      ?                       ; Compressed file size
  8. cdtm    dd      ?                       ; Date/Time
  9. cfcrc   dw      ?                       ; 16-bit CRC
  10. cosize  dd      ?                       ; Original file size
Обратите внимание, что поле для хранения имени файла имеет фиксированный размер 13 символов (формат имени 8.3 + нулевой символ). Когда создавался этот архиватор, про длинные имена файлов никто даже не мечтал.
  1. ; Признак окончание архива
  2. tail    db      1Ah,00
  3. tail_length   = $-tail
Признаком окончания архива является двухбайтовый "хвост", который записан после последнего файла. Больше никаких особенностей нет, формат очень простой, многотомные архивы, блокировки от изменений и прочие новомодные штучки не поддерживаются, поэтому процесс внедрения также очень простой.

Записываемый файл предварительно надо загрузить в память, после этого заполняем поля заголовка архива:
  • csig = 1Ah - байт сигнатуры начала блока данных;
  • cmeth = 2 - метод сжатия, в нашем случае Store;
  • cfname = имя файла в формате 8.3, завершается нулевым символом;
  • cosize = размер оригинального файла;
  • ccsize = размер сжатого файла (равен оригинальному);
  • cdtm = дата и время создания файла;
  • cfcrc = CRC-16 оригинального файла;
Пример расчета CRC-16 для файла можете посмотреть здесь. После заполнения заголовка надо переместить указатель на позицию 2 байта от конца файла, чтобы удалить существующий "хвост" архива. После этого записываем сформированный заголовок, за ним внедряемый файл и 2-байтовый "хвост" архива. Все, с форматом ARC/PAK разобрались.

Формат ZOO появился также в начале 80-х годов и использовался в основном на компьютерах Commodore. Также были версии для UNIX и MS-DOS, но там он использовался очень редко, по крайней мере за всю мою многолетнюю практику работы под MS-DOS я встречал такие архивы всего несколько раз. Из-за малой распространенности архиватора и закрытого кода долгое время я не мог найти нормальной документации по его формату, поэтому все мои попытки внедрения в эти архивы заканчивались неудачей. И лишь совсем недавно мне в руки попали исходники архиватора WinZOO, где я за пару дней экспериментов наконец-то смог выяснить назначение, формат и правильное количество всех полей заголовка архива, а также узнал все остальные интересующие меня технические подробности. Так что перед вами, пожалуй, единственное в Интернете корректное описание внутреннего формата архива ZOO.
  1. ;---------------------------------------------
  2. ; ZOO Header
  3. ;---------------------------------------------
  4. zsign   dd      ?               ; Signature (0FDC4A7DCh)
  5. zentry  db      ?               ; Type of directory entry (=2)
  6. zmeth   db      ?               ; Compression method (0 = store)
  7. zdir    dd      ?               ; Offset of next directory entry
  8. zfile   dd      ?               ; Offset of next header
  9. zdtm    dd      ?               ; Time/Date
  10. zfcrc   dw      ?               ; File CRC 16
  11. zosize  dd      ?               ; Original file size
  12. zcsize  dd      ?               ; Compressed file size
  13. zver1   db      ?               ; Version this file was compressed by
  14. zver2   db      ?               ; Minimum version needed to extract
  15. zextr   db      ?               ; Deleted flag
  16. zstruc  db      ?               ; File structure if any
  17. zcmnto  dd      ?               ; Offset of comment field, 0 if none
  18. zcmntl  dw      ?               ; Length of comment field
  19. zfname  rb      13              ; Filename (ASCIIZ)
  20. zvlen   dw      ?               ; Length of variable part of dir entry
  21. ztzone  db      ?               ; Timezone where file was archived
  22. zhcrc   dw      ?               ; CRC 16 of directory entry
  23. zlead   dd      ?               ; Allowing location of file data
  24. zres    db      ?               ; Reserved
Как и в предыдущем архиваторе, здесь длина имени файла тоже фиксированная - 13 байт - и подразумевает имя в формате 8.3 с завершающим нулевым символом.
  1. ; Признак окончание архива
  2. tail:
  3. tsign   dd      ?                       ; Signature (0FDC4A7DCh)
  4. tentry  db      ?                       ; Type of directory entry (=2)
  5.         rb      49                      ; Empty data
  6. tend    dw      ?                       ; End of archive
  7. tail_length   = $-tail
"Хвост" архива по сути представляет собой 56-байтный заголовок архивного блока, но только с минимальными данными. Поскольку его тоже придется заполнять, я с него и начну.
  • tsign = 0FDC4A7DCh - сигнатура заголовка;
  • tentry = 2 - тип заголовка;
  • tend = 83FCh - признак окончания архива;
В принципе, "хвост" архива можно хранить в теле вашей программы уже в заполненном виде, так как он все равно никогда не меняется. Но заполнять его непосредственно перед использованием, на мой взгляд, более корректно. Переходим к заполнению остальных полей файлового заголовка. Подразумевается, что записываемый файл предварительно уже загружен в память.
  • zsign = 0FDC4A7DCh - сигнатура заголовка;
  • zentry = 2 - тип заголовка;
  • zmeth = 0 - тип компрессии Store;
  • zvlen = 0 - размер блока с дополнительными данными;
  • ztzone = 07Fh - временная зона, в которой был создан архив;
  • zlead = '@)#(' - маркер начала упакованных данных;
  • zdtm = дата и время создания файла;
  • zfcrc = CRC-16 оригинального файла;
  • zosize = размер оригинального файла;
  • zcsize = размер сжатого файла (равен оригинальному);
  • zfname = имя файла в формате 8.3, завершается нулевым символом;
  • zhcrc = CRC-16 заголовка от поля zsign до поля zhcrc включительно;
  • zdir = адрес следующего архивного блока в архиве от начала файла;
  • zfile = адрес начала упакованных данных от начала файла;
Временная зона ztzone используется для того, чтобы при распаковке корректировать дату и время создания файлов. В принципе, этот параметр может и должен меняться, но кому это на практике надо? Все спецэффекты с полями zdir, zfile и маркером zlead сделаны для того, чтобы максимально обеспечить сохранность внутренней структуры архива и возможность его восстановления в случае повреждения носителя. Если кто забыл, то дискеты, которые во времена этого архиватора были основным инструментом для переноски данных, частенько царапались и портились. Меня сперва сильно удивило, что контрольная сумма заголовка zhcrc входит в состав блока данных, от которой она сама же и считается. После штудирования исходников выяснилось, что она считается следующим образом: сперва заполняются все поля заголовка, затем поле zhcrc обнуляется, считается CRC-16 от полученного блока, и только потом zhcrc заполняется нужным значением. Соответственно, при проверке целостности архива, значение zhcrc сохраняется в отдельной переменной, затем в заголовке это значение обнуляется, считается CRC-16 и только потом результат сравнивается с сохраненным. Суровые программисты не ищут легких путей.

При внедрении в архивы ZOO надо установить указатель на 56 байт от конца файла, чтобы перекрыть существующий "хвост" архива. После этого записать сформированный заголовок, затем наш файл, и после этого дописать заполненный "хвост" архива. С форматом ZOO тоже разобрались.

LHZ - также один из первых появившихся форматов архивов. Разработанный японцами еще в 80-х годах, он был неоднократно "клонирован" другими разработчиками, портирован на различные операционные системы, поэтому этот формат архива встречается и в других архиваторах, например, LHA и ICE. Несмотря на столь почтенный возраст, этот архиватор до сих пор успешно используется на своей родине - Японии, а также применяется для хранения сжатых данных в некоторых программах и играх. Я встретил как минимум две разных структуры файлов формата LHZ. Как я понял, в новых версиях используются расширенные заголовки с дополнительными полями. Но так как в новых версиях осталась поддержка старого формата, то и внедряться в архивы мы будем, используя заголовки старого формата. Как показали опыты, гибрид из архива нового формата с дописанным к нему файлом со старым заголовком остается вполне корректным, проходит все проверки и прекрасно распаковывается.
  1. ;---------------------------------------------
  2. ; LHA/LZH/ICE Header
  3. ;---------------------------------------------
  4. lsig    db      ?                       ; Header size
  5. lhcrc   db      ?                       ; --> Header CRC
  6. lmeth   rb      5                       ; Packing method '-lh0-' = store
  7. lcsize  dd      ?                       ; --> Compressed file size
  8. losize  dd      ?                       ; --> Original file size
  9. ldtm    dd      ?                       ; Time/Date
  10. lflag   dw      ?                       ; File attribute
  11. lnlen   db      ?                       ; Filename length
  12. lfname  rb      (?)                     ; Filename (ASCII)
  13. lfcrc   dw      ?                       ; --> File CRC 16
  14. lres1   db      ?                       ; Reserved 1
  15. lres2   dw      ?                       ; Reserved 2
На всякий случай напомню, что мнемокода "(?)" в FASM нет, просто таким образом я обозначил текстовую строку для записи имени файла неопределенной длины. В реальном проекте будет достаточно MAX_PATH.
  1. ; Признак окончания архива - нулевой байт
  2. tail    db      0
  3. tail_length   = $-tail
Записываемый файл также предварительно надо загрузить в память, после этого заполняем поля заголовка.
  • lsig = размер заголовка от lsig до lres1 включительно;
  • lmeth = '-lh0-' - метод компрессии Store;
  • losize = размер оригинального файла;
  • lcsize = размер сжатого файла (равен оригинальному);
  • ldtm = дата и время создания файла;
  • lflag = 120h - атрибуты файла;
  • lnlen = длина имени файла с расширением;
  • lfname = имя файла;
  • lfcrc = CRC-16 оригинального файа;
  • lres1 = 'M' - какое-то служебное поле;
После заполнения заголовка надо посчитать его CRC. Тут используется свой простенький алгоритм - считается сумма символов от lmeth до lres2 включительно и берется от нее младший байт. Полученное значение записывается в поле lhcrc. Имя файла может иметь длину до 255 символов и не заканчивается нулевым символом.

После заполнения заголовка надо переместить указатель на 1 байт от конца файла, чтобы удалить существующий "хвост" архива. После этого записываем сформированный заголовок, за ним внедряемый файл и "хвост" архива, состоящий из нулевого символа. Точно так же выполняется запись в архивы форматов ICE, LHA и других, имеющих аналогичную структуру.

В приложении примеры программ с исходными текстами, демонстрирующие все три описанных способа записи в архивы. При каждом запуске программа дописывает себя к архиву "example" соответствующего формата, выбирая случайное имя исполняемого файла.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Store.to.ARC.without.Archiver.Demo.zip (96,131 bytes)

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Store.to.ZOO.without.Archiver.Demo.zip (59,524 bytes)

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Store.to.LZH.without.Archiver.Demo.zip (115,933 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 5647 | Комментариев: 4

Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (22.02.2013 в 18:59):
Окей, перефразирую свою мысль :) Есть программа, которая создает архивы с расширением .ICE, которые, в свою очередь, по внутреннему формату полностью соответствуют архивам LZH/LHA. А уж кто там у кого чего притырил - это уже пусть другие разбираются.
lammer (22.02.2013 в 18:51):
<ICE> - нет такого архиватора, это была (красиво хакнутая) версия LHArc 1.13, отличавшаяся (в лучшую сторону) только оформлением. Появление ICE 1.14, в свое время, вызвало большой шум, файл был немедленно дизассемблирован и установлена его бинарная идентичность с LHArc 1.13, исключая замену нескольких текстовых элементов (название итд.)
ManHunter (22.02.2013 в 18:46):
Их я видел, я больше провозился с вычислением контрольных сумм заголовка. А этот кусок был нормально описан только в исходниках WinZoo.
lammer (22.02.2013 в 18:40):
исходники ZOO 2.10 давно валяются по всему инету. Или речь не об этой версии? http://en.wikipedia.org/wiki/Z...le_format%29

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2018
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.09 сек. / MySQL: 2 (0.0055 сек.) / Память: 4.75 Mb
Наверх