- Сообщения
 - 8,143
 
- Решения
 - 27
 
- Реакции
 - 6,959
 
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 для этой папки
	Программная реализация
В дополнение к статье готовая программа для прикрепления к батнику ресурса из указанных файлов и/или каталогов.

