Запись в архивы ACE, HA и LIM без помощи архиватора

Начну с формата ACE. Это сравнительно свеженький продукт, по крайней мере есть версия под Windows, а сайт датирован 2000-м годом. Разработчики утверждают, что по степени сжатия чуть ли не превосходят архиватор RAR. Однако, в дикой природе я пока что не встречал чего-либо, упакованного этим архиватором, поэтому он и попал в категорию экзотических. Но внутренний формат архивных файлов .ARC очень простой. Не используются никакие "хвосты" в конце архива, есть только главный заголовок архива, после которого идут подряд упакованные файлы с заголовками. Формат заголовка следующий:
;---------------------------------------------
; ACE Header
;---------------------------------------------
ahcrc   dw      ?                       ; CRC32x of the header
ahsize  dw      ?                       ; Size of the header
ahtype  db      ?                       ; Header type (01 = files)
aflags  dw      ?                       ; Header flags (8001h)
acsize  dd      ?                       ; Compressed file size
aosize  dd      ?                       ; Original file size
adtm    dd      ?                       ; Date/Time
aattr   dd      ?                       ; File attributes
afcrc   dd      ?                       ; CRC32x of the file
ainfo   dd      ?                       ; Type and quality of compression
ares    dw      ?                       ; Unknown
aflen   dw      ?                       ; Filename size
afname  rb      (?)                     ; Filename (ASCII)

Архиватор ARC поддерживает длинные имена файлов Windows, поэтому поле для хранения имени файла afname обозначено уже знакомым вам мнемокодом (?), то есть текстовая строка неопределенной длины. В нашем случае хватит MAX_PATH или другой фиксированной длины.

Записываемый файл предварительно надо загрузить в память, после этого заполняем поля заголовка архива:
ahcrc = контрольная сумму CRC32x заголовка от поля ahsize до afname включительно;
ahsize = длина заголовка от поля ahcrc до afname включительно;
ahtype = 1 - тип заголовка - файл;
aflags = 8001h - флаг заголовка;
aosize = размер оригинального файла;
acsize = размер сжатого файла (равен оригинальному);
adtm = дата и время создания файла;
afcrc = CRC32x оригинального файла;
ainfo = 0 - тип компрессии Store;
aflen - длина имени файла;
afname - имя файла;
Первым делом заполняется имя файла и поле aflen, куда записывается длина имени файла. Строка имени не должна заканчиваться нулевым символом. Затем заполняется длина заголовка ahsize с учетом имени файла. Для подсчета контрольной суммы заголовка и файла используется стандартная функция вычисления CRC32, но с одной небольшой особенностью. Особенность заключается в том, что значение CRC32 не финализируется (по указанной ссылке за финализацию в функции расчета отвечает флаг dFlag), то есть не выполняется заключительная команда XOR EAX,-1. Зачем так было сделано - я не знаю. Может быть ошибка при выпуске первой версии, а может быть по каким-то соображениям так сделано специально. После заполнения всех полей заголовка устанавливаем указатель на конец архивного файла, записываем заголовок, после него записываем наш файл. Все, с внедрением в файлы .ARC разобрались.

HA - еще один из архиваторов-долгожителей под MS-DOS, который ведет свою историю аж с 1993 года (по другим данным с 1994). Хотя времени прошло немало, но архивы, упакованные HA иногда встречаются на дисках с различной документацией. Это связано с тем, что наилучшие результаты по сжатию архиватор показывает именно на текстовых файлах, давая реальный выигрыш до 20% по сравнению с другими архиваторами. Интересующая нас информация для внедрения в файлы .HA состоит из двух частей - главного заголовка архива и заголовка отдельного файла в архиве.
;---------------------------------------------
; Главный заголовок архива
;---------------------------------------------
hid     dw      ?                       ; ID='HA'
hfnum   dw      ?                       ; Number of files in archive

Первые 4 байта файла - это и есть главный заголовок архива. Он состоит из идентификатора "HA" и WORD'а с количеством файлов в архиве. Как вы, наверное, догадались, количество файлов в архиве .HA не может превышать 65535 штук. Вряд ли на практике вы столкнетесь с такими архивами, но знать это будет нелишним.
;---------------------------------------------
; HA Header
;---------------------------------------------
hver    db      ?                       ; Version & compression type
hcsize  dd      ?                       ; Compressed file size
hosize  dd      ?                       ; Original file size
hfcrc   dd      ?                       ; CRC-32 of file
hdtm    dd      ?                       ; Date/Time
hpath   rb      (?)                     ; ASCIIZ pathname
hfname  rb      (?)                     ; Filename (ASCIIZ)
hmlen   db      ?                       ; Length of machine specific info
hmach   dw      ?                       ; Machine specific information

Перед внедрением нашего файла в архив, поля в заголовке надо установить равным следующим значениям:
hver = 20h - версия заголовка и тип компрессии Store;
hosize = размер оригинального файла;
hcsize = размер сжатого файла (равен оригинальному);
hdtm = дата и время создания файла;
hfcrc = CRC32 оригинального файла;
hpath - путь файла в формате ASCIIZ;
hfname - имя файла в формате ASCIIZ;
hmlen = 2 - размер дополнительной информации;
hmach = 2001h - дополнительная информация;
Обратите внимание, что поле даты/времени создания файла hdtm заполняется значением в формате TIMESTAMP, то есть количеством секунд, прошедшим с 00:00:00 UTC 1 января 1970 года. Конечно, можно отконвертировать дату создания файла в TIMESTAMP как это советуют сделать в Misrosoft, или использовать какое-нибудь фиксированное значение, но я сделал хитрее. При внедрении в файл я читаю дату создания первого файла в архиве и использую это значение для внедряемого файла. Кстати, я видел исходники некоторых вирусов и всякие вирусные мануалы, где используется или описывается заражение архивов формата .HA, и везде была одна и та же ошибка - поле hdtm заполнялось как дата/время в формате файловой системы, а не как TIMESTAMP. В моем варианте это поле заполняется абсолютно корректно. Уже при написании этой статьи я подумал, что будет правильно приравнивать дату и время создания внедряемого файла с первым файлом архива не только при работе с форматом .HA, а и вообще со всеми типами архивов. В этом случае не будет такого явного палева с внезапным появлением в архиве новых файлов. Контрольная сумма CRC32 файла считается как обычно, с финализацией, тут никаких сюрпризов нет. Путь файла hpath должен быть пустой строкой, то есть один нулевой байт. Имя файла hfname не должно превышать 255 символов. Назначение полей с дополнительной информацией hmlen и hmach я не знаю, но они обязательно должны присутствовать в файловом заголовке архива и именно с указанными значениями.

При внедрении в архив загружаем файл в память, заполняем поля заголовка. Устанавливаем указатель на конец файла архива и записываем сперва сформированный заголовок, а затем и сам внедряемый файл. Специфических признаков окончания архива нет. Последним действием надо установить указатель на самое начало файла, прочитать главный заголовок архива, увеличить счетчик файлов на единицу и записать его обратно. На этом с архивами формата .HA и закончим.

LIM - формат файлов, создаваемых DOS'овским архиватором Limit от некоего J Y LIM. Судя по дате исполняемого файла и документации, архиватор был создан в 1993 году. Больше про Limit ничего неизвестно, упоминаний в сети мало, архивов и вовсе нет. Никаких описаний формата я также не нашел, с внутренней структурой архивов пришлось разбираться на готовых архивных файлах. К счастью, структура оказалась несложной, удалось идентифицировать все поля, нужные для внедрения. Я сильно сомневаюсь, что вам где-то попадутся архивы .LIM, так что это все не более, чем "proof of concept".
;---------------------------------------------
; LIM Header
;---------------------------------------------
lsign   dw      ?                       ; Sign
lsize   db      ?                       ; Size of Header
        db      ?                       ; unknown
        db      ?                       ; unknown
        db      ?                       ; unknown
ldtm    dd      ?                       ; Date/Time
lattr   db      ?                       ; File attribute
        db      ?                       ; unknown
lmeth   db      ?                       ; Compression method (0 = store)
losize  dd      ?                       ; Original file size
lcsize  dd      ?                       ; Compressed file size
lfcrc   dd      ?                       ; 32-bit CRC
lfname  rb      (?)                     ; Filename (ASCIIZ)

Как я уже говорил, некоторые поля мне не удалось правильно идентифицировать, в заголовке они отмечены комментарием "unknown".
; Признак окончание архива
tail    db      013h,0F8h,005h,00h,00h

Признаком окончания архива является "хвост" длиной 5 байт, который записывается после последнего файла. Его значение неизменно.
lsign = 0F123h - сигнатура заголовка;
lsize - размер заголовка от поля lsign до lfname включительно;
losize = размер оригинального файла;
lcsize = размер сжатого файла (равен оригинальному);
ldtm = дата и время создания файла;
lfcrc = CRC32 оригинального файла;
lattr = 20h - атрибуты файла;
lmeth = 0 - метод компрессии Store;
lfname - имя файла в формате 8.3, завершается нулевым символом;
При внедрении сперва загружаем наш файл в память, заполняем известные поля заголовка. После этого надо установить указатель файла на 5 байт от конца архива, записать сформированный заголовок, затем наш файл и после этого записать пятибайтовый "хвост" архива. С внедрением в архивы формата .LIM тоже разобрались.

В приложении примеры программ с исходными текстами, демонстрирующие все три описанных способа записи в архивы. При каждом запуске программа дописывает себя к архиву "example" соответствующего формата, выбирая случайное имя исполняемого файла.
Добавлено: 13 Сентября 2013 02:29:01 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...