Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
MSI — самый популярный формат инсталляторов. Для редактирования таких установочных пакетов придумано много удобных инструментов, но они могут не сработать, если инсталлятор содержит набор CAB-архивов. Сегодня я расскажу, как править данные внутри инсталляционных пакетов MSI в ручном режиме, если другими способами сделать это не получается.
В своих статьях я периодически поднимаю тему разборки и патча инсталляционных пакетов. На этот раз я хочу продолжить тему, начатую в статье «Ломаем инсталлятор. Как обмануть инсталлятор MSI методом для ленивых», — ручной патчинг нестандартных MSI-пакетов, редактировать которые традиционными средствами невозможно. В той статье мы разбирали правку и замену установочного скрипта, а сейчас попробуем поменять данные в инсталлируемых файлах.
Итак, нам нужно внести изменения в инсталлятор MSI, например заменить в нем один содержащийся в CAB-архиве файл другим. В связи с востребованностью задачи умные люди придумали множество редакторов MSI-пакетов разной степени продвинутости: Advanced Installer, Master Packager, Orka, MSI Editor и другие. Из них лично я особо выделил бы Master Packager: этот редактор, на мой взгляд, наиболее корректно выполняет разборку, редактирование и пересохранение MSI-пакетов различной сложности.
Перечисленные утилиты обладают удобным и дружественным интерфейсом, позволяющим даже неопытному пользователю сесть и без подготовки просто редактировать файлы, таблицы и прочую логику инсталляционного процесса. Собственно, на этом моменте и можно было бы закончить статью, но, к сожалению, в мире нет совершенства. Иногда попадаются MSI-пакеты, которые нельзя просто так взять и открыть, отредактировать и пересохранить с использованием подобного редактора, не нарушив их работоспособность.
Причем разобрать пакет на составляющие его файлы и таблицы — как раз задача несложная, проблемы начинаются именно в процессе перекомпиляции патченного файла. В принципе, вытащить файлы из инсталлятора (как я уже писал в статье «Ломаем инсталлятор. Как обмануть инсталлятор MSI методом для ленивых») можно и без спецсредств — практически любой нормальный архиватор (7-Zip, WinRAR и другие) открывает MSI, как архив.
С помощью архиватора можно извлечь оттуда составляющие установочный пакет CAB-файлы, а они, в свою очередь, также открываются многими архиваторами (собирать CAB из составляющих умеют такие программы, как PowerArchiver, ACDzip или специализированный Cabarc). О том, как засунуть исправленный CAB обратно в MSI, я расскажу позже.
В конце концов, можно разложить MSI на составляющие файлы, минуя промежуточные CAB, просто запустив msiexec
с ключом /a
(при этом создается папка со всем содержимым пакета MSI). Есть еще более продвинутый способ — натравить на инсталляционный пакет утилиту с открытым исходным кодом msi2xml. Она запускается следующей командой:
msi2xml -c files installation.msi
При этом в каталог files
распакуются все файлы проекта из составляющих его CAB, а также создастся файл полного описания проекта installation.msi
со всеми таблицами и логикой процесса установки. С использованием этого файла становится возможным собрать инсталлятор командой
xml2msi -m installation.xml
Такая низкоуровневая операция помогает, если не работают описанные выше методы. Но, к сожалению, пересобранный подобным способом инсталлятор тоже не всегда оказывается работоспособным. Действительно, бывают случаи, когда автоматизированные способы не срабатывают. Например, если у нас имеется многотомный непрерывный архив, в середине которого нужно поменять один файл, не трогая остальную структуру. По традиции я расскажу, как руками пропатчить файл в CAB-архиве без его полной перепаковки.
Первым делом, как обычно, изучим спецификацию. Попробуем разобрать написанное там на примере готового многотомного архива. Начнем с заголовка файла.
Распишем эту структуру поподробнее:
struct CFHEADER{ // 1 красный — сигнатура файла MSCF u1 signature[4] u4 reserved1 // 2 желтый — размер файла в байтах u4 cbCabinet u4 reserved2 // 3 зеленый — смещение до первой записи CFFILE u4 coffFiles u4 reserved3 // 4 голубой — minor-байт версии файла u1 versionMinor // 5 фиолетовый — major-байт версии файла u1 versionMajor // 6 белый — количество записей CFFOLDER в файле u2 cFolders // 7 черный — количество записей CFFILE в файле u2 cFiles // 8 оранжевый — флаги формата: 3 = 1 (cfhdrPREV_CABINET у файла есть предыдущий том) | 2 (cfhdrNEXT_CABINET у файла есть следующий том) u2 flags // 9 желтый — ID кабинета, один и тот же у всех томов архива u2 setID // 10 красный — порядковый номер данного тома u2 iCabinet; // Эти поля не обязательны и в архиве не присутствуют, поскольку бит 2 поля flags не установлен u2 cbCFHeader; u1 cbCFFolder; u1 cbCFData; u1 abReserve[]; // 11 зеленый — необязательное имя предыдущего тома, строка, заканчивающаяся 0, в нашем случае Data1.cab u1 szCabinetPrev[]; // 12 белый — необязательное имя предыдущего диска, в нашем случае пустое u1 szDiskPrev[]; // 13 фиолетовый — необязательное имя следующего тома, в нашем случае Data12.cab u1 szCabinetNext[]; // 14 белый — необязательное имя следующего диска, в нашем случае пустое u1 szDiskNext[];};
Чтобы поменять файл в архиве, надо для начала его найти. В этом плане нам интересен массив записей CFFILE
. Каждая из записей в этом массиве содержит данные о файле, хранящемся в архиве. На начало массива указывает поле coffFiles
. Посмотрим, как оно выглядит в реальном файле.
Распишем подробно и эту структуру:
struct CFFILE{ // 1 красный — размер распакованного файла в байтах u4 cbFile; // 2 желтый — смещение до начала файла в распакованном блоке folder u4 uoffFolderStart; // 3 зеленый — номер структуры CFFOLDER, содержащей данные файла в общей таблице folder’ов // В этом примере равно ifoldCONTINUED_FROM_PREV (0xFFFD) u2 iFolder; // 4 желтый — дата создания файла u2 date; // 5 фиолетовый — время создания файла u2 time; // 6 голубой — атрибуты файла u2 attribs; // 7 оранжевый — имя файла, заканчивающееся нулем u1 szName[];};
Настало время пояснить несколько моментов. Ты, видимо, уже обратил внимание, что не все содержащиеся внутри CAB-архива файлы имеют свои оригинальные имена. Скажем так, практически все файлы, содержащиеся внутри архива CAB, используют некие промежуточные «технические» имена, чтоб нам жизнь медом не казалась. В этом можно убедиться, открыв CAB-файл в любом поддерживающем данный формат архиваторе. По сути, «технические» имена — это сокращенный GUID, который инсталлятор присваивает каждому файлу в пакете.
Источник: xakep.ru