- Сообщения
- 8,064
- Решения
- 15
- Реакции
- 6,838
Cabinet's Batch inline. "CBI method" by Dragokas
Метод предоставляет возможность встраивать бинарную информацию (любые файлы)
в качестве ресурсов BAT-файла, получая на выходе 1 комбинированный файл
с расширением BAT или CMD.
Батник затем сможет распаковать свой ресурс при необходимости его использования.
В статье представлены описание метода и программная реализация.
Описание метода
Оригинальная идея принадлежит человеку с ником: Somebody.
Она звучала так:
Можно сделать cab архив с расширением bat, а в конце - пустую строку и extrac32 /e %0.
extrac32 в винде вроде всегда есть. Побочный эффект - попытка запуска "MSCF"
(заголовок .cab).
Данный способ не подходит для случаев упаковки бинарных ресурсов различного содержания,
т.к. некоторые комбинации символов для формата CMD являются недоспустимым и
приводят к его "падению" прежде, чем BAT-файл начнет исполнение своей части кода
из конца Cabinet архива.
К счастью структура формат CAB предоставляет возможность резервирования произвольного
количества байт (начиная со смещения 0x28) для хранения цифровой подписи.
Эту область мы задействуем под свой нужны, расположив в ней основной код
и команду распаковки.
Техническая часть
Код батника будет содержать команду для распаковки себя же:
Код:
@extrac32.exe /E /Y /L "папка, куда распаковуем" "%~f0"
/y - без подтверждения при замене
Структура формата Cabinet архива описана в статье базы знаний: MSKB417343
Она разделена на 4 блока:
- CFHEADER
- CFFOLDER
- CFFILE
- CFDATA
Описание первого блока:
C++:
// Размер | имя параметра | смещене | описание параметра
struct CFHEADER
{
u1 signature[4] // 0x00 - сигнатура архива "MSCF"
u4 reserved1 // 0x04 - зарезервировано
u4 cbCabinet // 0x08 - размер архива в байтах
u4 reserved2 // 0x0С - зарезервировано
u4 coffFiles // 0x10 - смещение первого вхождения блока CFFILE
u4 reserved3 // 0x14 - зарезервировано
u1 versionMinor // 0x18 - версия формата архива (minor)
u1 versionMajor // 0x19 - версия формата архива (major)
u2 cFolders // 0x1A - количество блоков CFFOLDER
u2 cFiles // 0x1C - количество блоков CFFILE
u2 flags /* 0x1E - флаги наличия или отсутствия зарезервированной областей
abReserve[], szCabinetPrev[], szDiskPrev[], szCabinetNext[], szDiskNext[] */
u2 setID // 0x20 - должен быть одинаковый для всех частей составного архива
u2 iCabinet; // 0x22 - порядковий номер этого файла в составном архиве
u2 cbCFHeader; // 0x24 - (опционально) размер зарезервированной под ЭЦП области архива
u1 cbCFFolder; // 0x26 - (опционально) размер зарезервированной области каждой папки
u1 cbCFData; // 0x27 - (опционально) размер зарезервированной области каждого блока данных
u1 abReserve[]; // 0x28 - (опционально) область, зарезервированная под ЭЦП (сюда будем записывать батник)
u1 szCabinetPrev[]; // (опционально) имя предыдущего файла CAB
u1 szDiskPrev[]; // (опционально) имя предыдущего диска
u1 szCabinetNext[]; // (опционально) имя следующего файла CAB
u1 szDiskNext[]; // (опционально) имя следующего диска
};
Чтобы создать скомбинированный файл, сперва нужен сам архив.
Наиболее родной способ - воспользоваться встроенной в систему утилитой makecab.
Синтаксис у нее непростой, поэтому лучше воспользоваться готовой реализацией:
CMD/BATCH:
@echo off
SetLocal
:: Имя для CAB-архива
set "CabinetName=test.cab"
:: Путь к папке, которую упаковуем
set src=C:\Users\Alex\Desktop\gardening\gardening
chcp 1251 >NUL
For /F "delims=" %%a in ('dir /B /a-d "%src%\*.*"') do echo "%src%\%%a">>"%Temp%\list.txt"
chcp 866 >NUL
set .=
set .=%.% /D FolderSizeThreshold=50000000
set .=%.% /D DestinationDir=.
set .=%.% /D MaxDiskSize=0
set .=%.% /D cabinet=on
set .=%.% /D compression=on
set .=%.% /D CabinetDir=\.
set .=%.% /D CabinetNameTemplate="%CabinetName%"
set .=%.% /D CabinetName="%CabinetName%"
set .=%.% /D InfFileName=NUL
set .=%.% /D RptFileName=NUL
set .=%.% /D CompressionMemory=21
set .=%.% /D DiskDirectoryTemplate=.
set .=%.% /D UniqueFiles=Off
set .=%.% /D CompressionType=LZX
makecab %.% /V1 /F "%Temp%\list.txt"
del /F "%Temp%\list.txt"
pause
Тем не менее, у Microsoft есть и другая утилита из состава Resource Kit
под названием CabArc.
Ввел в YANDEX слово Cabarc и получил "Сфинкс". Круто! M$ отдыхает
Создать архив CAB можно такой простой командой:
Код:
cabarc N test.cab *.*
Упакует все файлы в текущей папке в архив test.cab
Чтобы вставить код Batch в такой архив, нам нужно зарезервировать область
соответствующего размера, и здесь Cabarc будет как нельзя кстати.
Синтаксис:
Основных каманды всего три:
L - просмотр
X - разархивировать
N - архивировать
Код:
CABARC [опции] команда cabfile [@список] [файлы] [папка назначения\]
Основных каманды всего три:
L - просмотр
X - разархивировать
N - архивировать
Код:
Опции:
-c подтверждать операции с файлами
-o во время распаковки не запрашивать подтверждения при замене
-m алгоритм сжатия [LZX:<15..21>|MSZIP|NONE], (по-умолчанию - MSZIP)
-p сохранять пути файлов (абсолютные пути не поддерживаются)
-P урезать указанный префикс из файлов при добавлении в архив
-r рекурсивно с подкаталогами при добавлени в архив (см. также -p)
-s зарезервировать место под цифровую подпись (например, -s 6144 резервирует 6 КБ.)
-i Устанавливает ID архива при создании (по-умолчанию - 0)
-d установить размер частей (по-умолчанию, размер не определен, т.е. создается единый архив)
Ключ -s позволяет установить произвольный размер зарезервированного под ЭЦП блока
(от 1 до 65535 байт (0xFFFF)).
Теперь смотрим, какой размер у батника, к которому мы хотим добавить ресурс.
Пусть будет 250 байт (0xFA).
Прибавляем 6 байт (ниже узнаете зачем).
250 + 6 = 256 (0x100).
Создаем архив с резервной областью в 256 байт:
Код:
cabarc -s 256 N test.cab *.*
Принцип слияния кода батника с архивом такой:
Берем смещение архива 0x28 (блок abReserve[]).
Добавляем туда 2 переноса строки (0x0D, 0x0A, 0x0D, 0x0A) - 4 байта.
Далее вставляем сам код и еще + перенос строки (0x0D, 0x0A) - 2 байта.
4 + 2 = 6 байт, о которых мы говорили выше.
В коде батника должна быть предусмотрена команда распаковки архива из себя
и очистка сообщения о неверной команде (когда батник попытается исполнить хидер CAB-архива):
Код:
@cls & @extrac32.exe /E /Y /L .\ "%~f0"
Комбинированный CBI-файл готов.
Нужно переименовать его расширение в CMD.
Правка упакованного батника напрямую
Также можно выделить резервную область путем правки определенных байт CAB-архива:
1. В структуре CFHEADER:
C++:
u4 cbCabinet // 0x08 - размер архива в байтах
u4 coffFiles // 0x10 - смещение первого вхождения блока CFFILE
u2 flags // 0x1E - флаги наличия или отсутствия зарезервированной областей
u2 cbCFHeader; // 0x24 - (опционально) размер зарезервированной под ЭЦП области архива
flags должен содержать константу:
C++:
#define cfhdrRESERVE_PRESENT 0x0004
cbCFHeader - для архива с флагом = 0 (нет резервных областей) имеет смещение 0x2C.
2. В каждой из структур CFFOLDER:
C++:
u4 coffCabStart; // смещение первого вхождения блока CFDATA для этой папки
Программная реализация
В дополнение к статье готовая программа для прикрепления к батнику ресурса из указанных файлов и/или каталогов.