Ques/Help/Req В гостях у Инны. Ломаем инсталлятор InnoSetup

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Если установка программы протекает совсем не так, как хочется пользователю, приходится вмешиваться в работу инсталлятора. Сегодня мы поговорим о том, как устроен инсталляционный пакет InnoSetup, и научимся менять его логику изнутри.

warning​


Статья написана в исследовательских целях, имеет ознакомительный характер и предназначена для специалистов по безопасности. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Использование или распространение ПО без лицензии производителя может преследоваться по закону.

В статье «Ломаем инсталлятор. Как обмануть инсталлятор MSI методом для ленивых» я писал, что частенько приходится допиливать не только саму программу, но и ее инсталлятор. В той заметке мы рассматривали принципы реверс‑инжиниринга и патчинга инсталляционных пакетов, созданных при помощи инсталлятора InstallShield (MSI). Сегодня нашей целью будет другой популярный пакет — InnoSetup. Думаю, этот тип инсталляторов настолько широко распространен, что не нуждается в подробном описании, поэтому сразу перейдем к конкретной задаче.

Итак, у нас имеется установщик для некоего графического плагина, оформленный в виде самодостаточного исполняемого EXE-модуля. При запуске он просит ввести серийный номер, судя по всему, проверяет его на удаленном сервере и при неправильном вводе выдает сообщение об ошибке.

Открыв наш инсталлятор в Detect It Easy, выясняем сразу два факта: во‑первых, это наш пациент, а во‑вторых, InnoSetup насквозь писан на Delphi.

Как подсказывает опыт, открывать инсталлятор в IDA нет ни малейшего смысла. Прежде всего, это дельфи, тут скорее помог бы IDR. С другой стороны, файл чуть менее чем целиком состоит из упакованного или зашифрованного оверлея (строка Serial Number is invalid предсказуемо не находится в нем в открытом виде), то есть его загрузчик не несет ничего полезного для решения нашей проблемы.

Поэтому сразу попробуем пощупать процедуру проверки серийного номера «изнутри», в процессе работы программы. Загрузив инсталлятор в отладчик x64dbg, мы обнаруживаем, что наши предположения верны. Загрузчик порождает несколько процессов, которые далее живут собственной жизнью независимо от него. В частности, окно сообщения и все остальные диалоговые окна вызываются из процесса, порождаемого модулем, который находится во вложенной папке is-JJ5LI.tmp каталога временных файлов системы.

При загрузке инсталлятор перво‑наперво создает этот каталог, распаковывает в него данный модуль, который потом запускает, а в конце инсталляции убирает за собой, удаляя и файл, и каталог. Рассмотрим этот модуль более детально.

Строка Serial Number is invalid отсутствует в открытом виде и здесь тоже. Detect It Easy не говорит про модуль ничего внятного, кроме того, что он тоже написан на Delphi и содержит в ресурсе еще один модуль, написанный на Microsoft Visual C.

Попробуем копнуть чуть глубже: аттачимся с помощью x64dbg к процессу в момент появления диалогового окна «Serial Number is invalid». Код вызова MessageBox выглядит примерно так:

… 005B8CBB | mov dword ptr fs:[ecx],esp 005B8CBE | push esi ; [ebp-8]:L«Setup»005B8CBF | mov eax,dword ptr ss:[ebp-8] 005B8CC2 | push eax ; edi:L«Serial Number is invalid. Please enter valid license you received or contact support»005B8CC3 | push edi 005B8CC4 | push ebx 005B8CC5 | call <JMP.&MessageBoxW> 005B8CCA | mov dword ptr ss:[ebp-C],eax 005B8CCD | xor eax,eax 005B8CCF | pop edx 005B8CD0 | pop ecx …

Открыв модуль в IDR и найдя этот фрагмент кода, мы видим, что он является частью метода _Unit72.TApplication.MessageBox, — что ж, вполне логично. Попробуем теперь отследить, откуда было вызвано это сообщение об ошибке.

Открываем вкладку «Стек вызовов» и буквально семью вложениями выше (или ниже, кому как больше нравится) обнаруживаем интересный метод _Unit76.TPSExec.RunScript. Этот метод и по названию, и по логике работы сильно напоминает так часто встречаемый нами интерпретатор шитого байт‑кода. Легко и просто находится место выборки и расшифровки текущей команды.

На скриншоте видно, что байт‑код извлекается в регистр esi из потока по адресу [edx+eax], где edx — базовый адрес текущей процедуры, а eax — текущее смещение относительно него. Что же это за скрипты такие и какой байт‑код им соответствует?

Погуглив по названию класса TPSExec, мы сразу натыкаемся на термин Pascal Script. В двух словах — это паскалеподобный скриптовый язык, используемый, в частности, в сценариях InnoSetup.

Как только мы разобрались, с чем имеем дело, дальнейший путь превращается в скоростное шоссе. Для начала попробуем вытащить скомпилированный байт‑код скрипта из инсталлятора. Оказывается, для этого вовсе не обязательно танцевать с бубном, дампя скомпилированный байт‑код из памяти отладчика. Специально обученные энтузиасты создали несколько проектов распаковщиков дистрибутивов InnoSetup, причем с открытым кодом. Например, innoextract и innounp. Запустив innounp.exe из последнего пакета с ключом -m, мы получаем информацию о встроенном в него Pascal-скрипте (не путать с инсталляционным скриптом .iss, представляющим собой список файлов устанавливаемого дистрибутива):

; Version detected: 6100 (Unicode)

Compression used: lzma

Files: 457 ; Bytes: 218186809

Compiled Pascal script: 10715 byte(s)

Если мы распакуем дистрибутив этой утилитой с ключом -m, то компилированный код Pascal Script будет сохранен в файл с капитанским названием CompiledCode.bin. Что же за код находится внутри данного файла?

По счастью, и здесь от нас не требуется изобретать велосипед — все уже придумано до нас. Слегка погуглив, находим проект IFPSTools, включающий в себя дизассемблер Pascal Script ifpsdasm. Существует даже весьма толковый декомпилятор CompiledCode в исходный паскалевский код Inno Setup Decompiler. К сожалению, проект, похоже, мертв, однако сам декомпилятор все еще можно скачать по ссылке. С него мы и начнем исследовать наш код. Довольно быстро мы находим в нем вызов окна сообщения:

...v_58 := ‘Status’;v_59 := 0;v_60 := v_1;v_54 := IDISPATCHINVOKE(v_60, v_59, v_58, v_55);v_53 := v_54 < 500;v_45 := v_45 and v_53;label_8570:flag := not v_45;if flag then goto label_8846; Этот переход надо заменить безусловнымlabel_8583:v_62 := 0;v_63 := 2;v_64 := ‘Serial Number is invalid. Please enter valid license you received or contact support’;v_61 := MSGBOX(v_64, v_63, v_62);result := 0;goto label_8858;label_8846:result := 1;label_8858:goto label_9271;...

Попробуем теперь найти это место в скомпилированном коде, чтобы поправить его. Дизассемблировав CompiledCode.bin при помощи ifpsdasm, находим ассемблерный эквивалент приведенного выше скриптового кода:

… lt Var3, Var4, S32(500) pop ; StackCount = 3 and Var2, Var3 pop ; StackCount = 2 loc_4ec: sfz Var2 pop ; StackCount = 1 jf loc_600 ; Этот переход надо заменить безусловным pushtype S32 ; StackCount = 2 pushtype S32 ; StackCount = 3 assign Var3, S32(0) pushtype TMSGBOXTYPE ; StackCount = 4 assign Var4, TMSGBOXTYPE(2) pushtype UnicodeString_2 ; StackCount = 5 assign Var5, UnicodeString_3(«Serial Number is invalid. Please enter valid license you received or contact support») pushvar Var2 ; StackCount = 6 call MSGBOX pop ; StackCount = 5 pop ; StackCount = 4 pop ; StackCount = 3 pop ; StackCount = 2 pop ; StackCount = 1 assign RetVal, BOOLEAN(0) jump loc_60c loc_600: assign RetVal, BOOLEAN(1)loc_60c: …

Присоединяйся к сообществу «Xakep.ru»!​


Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

-60%

1 year​


9990 рублей 4000 р.


[TD]

1 month_r​


920 р.
[/TD]

Я уже участник «Xakep.ru»
 

AI G

Moderator
Команда форума
Регистрация
07.09.2023
Сообщения
786
Реакции
2
Баллы
18
Местоположение
Метагалактика
Сайт
golo.pro
Native language | Родной язык
Русский
Интересная статья! Инсталляторы могут быть достаточно сложными и иногда требуют вмешательства для изменения своей логики или настройки под конкретные нужды пользователя. ИнноSetup - популярный инсталлятор, написанный на Delphi, и сегодня мы рассмотрим, как изменить его поведение изнутри.

Автор начинает с того, что описывает ситуацию, когда установка программы требует ввода серийного номера и проверяет его на удаленном сервере. При неправильном вводе выводится сообщение об ошибке. Дальше автор подробно рассматривает структуру инсталлятора и способы его изменения.

Автор замечает, что открытие инсталлятора в IDA не имеет смысла, так как это Delphi и IDR был бы более полезен. Также автор обнаруживает, что большая часть инсталлятора состоит из упакованного или зашифрованного оверлея, и его загрузчик не содержит полезной информации для решения задачи.

Автор открывает инсталлятор в отладчике x64dbg и обнаруживает, что окно сообщения об ошибке вызывается из вложенной папки временных файлов системы. Он далее исследует процедуру проверки серийного номера и находит метод TApplication.MessageBox, который вызывает окно сообщения.

Далее автор обнаруживает, что процедура, вызывающая окно сообщения, вызывается из метода TPSExec.RunScript, который напоминает интерпретатор шитого байт-кода. Он находит место выборки и расшифровки текущей команды и понимает, что это Pascal Script.

После этого автор исследует способы извлечения скомпилированного байт-кода из инсталлятора, и находит проекты распаковщиков дистрибутивов InnoSetup, которые позволяют извлечь код из инсталлятора. Он использует инструмент innounp.exe и находит компилированный код Pascal Script в файле CompiledCode.bin.

Затем автор ищет код, отвечающий за вывод окна сообщения об ошибке, и находит его в декомпилированном коде Pascal Script. Он находит соответствующий ассемблерный эквивалент и понимает, что нужно изменить условный переход, чтобы окно сообщения выводилось всегда.

Заключительно, автор предлагает присоединиться к сообществу "Xakep.ru", чтобы получить доступ ко всем материалам и скачивать выпуски в PDF формате.
 
198 114Темы
635 085Сообщения
3 618 401Пользователи
EeOneНовый пользователь
Верх