Исследование защиты программы ScriptCryptor Compiler


Скриншот программы ScriptCryptor Compiler

Программа ScriptCryptor Compiler от Abyssmedia предназначена для компиляции скриптов VBScript и JavaScript в самостоятельные EXE-файлы, при этом их исходные тексты шифруются. Откомпилированные скрипты могут работать без вспомогательных системных файлов cscript.exe и wscript.exe, при выполнении не создается никаких временных файлов, все данные берутся из памяти. Об остальных функциях, если интересно, можете почитать на сайте. Ну а поскольку программа ScriptCryptor Compiler появилась в этом разделе блога, значит что-то с ней не так.

Качаем дистрибутив, устанавливаем, запускаем. Незарегистрированная версия компилятора создает EXE-файлы с напоминалкой, что они сделаны триальной версией. Не смертельно, конечно, но напрягает. Открываем окно регистрации, вводим левые данные. Здесь разработчики не наступили на традиционные грабли, программа молча принимает любое имя и серийник без всяких сообщений, даже куда-то их добросовестно сохраняет. Теперь посмотрим исполняемый файл. Он упакован UPX без всяких модификаций, распаковывается обычным "upx -d". Переходим к внутренностям файла. Единственная видимая зацепка для исследования - триальная надпись "UNREGISTERED COPY" в строке статуса программы, но она находится не в коде, а в ресурсах, причем не просто в ресурсах, а в формах Delphi. Можно потратить некоторое время, гоняя программу в DeDe, а можно наудачу предположить, что где-то есть строка типа "REGISTERED COPY" или типа того. И действительно, по паттерну "registered" находится что-то похожее:


Строка о зарегистрированности программы

На нее ссылается следующий код:
.text:00504963                 mov     edx, off_534538
.text:00504969                 mov     edx, [edx+4]
.text:0050496C                 mov     eax, off_534538
.text:00504971                 mov     eax, [eax]
; Вызвать какую-то функцию проверки
.text:00504973                 call    sub_528688
; Если она вернула в AL не ноль, то программа считается зарегистрированной
.text:00504978                 test    al, al
.text:0050497A                 jz      short loc_5049D3
.text:0050497C                 mov     edx, off_534538
.text:00504982                 mov     edx, [edx]
.text:00504984                 mov     eax, [ebx+380h]
.text:0050498A                 call    sub_45F530
.text:0050498F                 mov     edx, offset aRegisteredVe_1
; Строка "Registered Version"
.text:00504994                 mov     eax, [ebx+388h]
.text:0050499A                 call    sub_45F530
.text:0050499F                 xor     edx, edx
.text:005049A1                 mov     eax, [ebx+370h]
.text:005049A7                 call    sub_45F420
.text:005049AC                 xor     edx, edx
.text:005049AE                 mov     eax, [ebx+360h]
.text:005049B4                 mov     ecx, [eax]

Теперь посмотрим процедуру проверки в дизассемблере и параллельно пройдем ее под отладчиком. Обратите внимание, что эта процедура вызывается только из одного места, и причем даже не при старте программы, а при открытии окна регистрации. Значит это не единственная проверка, и просто пропатчить ее нельзя. Я прокомментировал в коде все важные участки.
.text:00528688                 push    ebp
.text:00528689                 mov     ebp, esp
.text:0052868B                 xor     ecx, ecx
.text:0052868D                 push    ecx
.text:0052868E                 push    ecx
.text:0052868F                 push    ecx
.text:00528690                 push    ecx
.text:00528691                 push    ebx
.text:00528692                 push    esi
.text:00528693                 push    edi
.text:00528694                 mov     [ebp+var_4], edx
.text:00528697                 mov     eax, [ebp+var_4]
.text:0052869A                 call    sub_40541C
.text:0052869F                 xor     eax, eax
.text:005286A1                 push    ebp
.text:005286A2                 push    offset loc_528714
.text:005286A7                 push    dword ptr fs:[eax]
.text:005286AA                 mov     fs:[eax], esp
.text:005286AD                 xor     ebx, ebx
; Вот здесь ссылка на интересный блок данных. Он представляет собой большое
; количество шестнадцатеричных цифр.
.text:005286AF                 mov     esi, offset aE9210182c802b9
; "e9210182c802b90244f6d8b9c2f56036ca39a17"...
.text:005286B4                 lea     eax, [ebp+var_8]
.text:005286B7                 call    sub_404F9C
.text:005286BC                 lea     ecx, [ebp+var_C]
.text:005286BF                 mov     edx, [ebp+var_4]
.text:005286C2                 mov     eax, 103h
; Если дошагать сюда под отладчиком, то видно, что берется введенный
; серийный номер, и из него вычисляется 64-битное число. Его видно в
; стеке. Анализаторы криптоалгоритмов показывают наличие в коде функции
; расчета MD5, и этот расчет выполняется в следующей функции.
.text:005286C7                 call    sub_481870
; Проверим нашу догадку, рассчитав MD5 от введенного "левого" серийника
; при помощи любой сторонней программы, строка будет в точности равна
; вычисленной в предыдущей функции. Значит для проверки берется хэш MD5
; от введенного серийного номера.
.text:005286CC                 xor     edi, edi
.text:005286CE loc_5286CE:
.text:005286CE                 lea     eax, [ebp+var_10]
.text:005286D1                 mov     edx, edi
.text:005286D3                 add     edx, edx
.text:005286D5                 add     edx, edx
.text:005286D7                 lea     edx, [esi+edx*8]
.text:005286DA                 mov     ecx, 20h
; Взять от блока данных 32 символа
.text:005286DF                 call    sub_40520C
.text:005286E4                 mov     eax, [ebp+var_10]
.text:005286E7                 mov     edx, [ebp+var_C]
; Сравнить блок с рассчитанным хэшем от серийного номера
.text:005286EA                 call    sub_4053C4
; Если не совпадает, то взять сделующие 32 символа и т.д. до окончания
; блока данных
.text:005286EF                 jnz     short loc_5286F3
; Найдено совпадение
.text:005286F1                 mov     bl, 1
.text:005286F3 loc_5286F3:
.text:005286F3                 inc     edi
.text:005286F4                 cmp     edi, 65h
; Проверено 65h блоков по 32 байта?
.text:005286F7                 jnz     short loc_5286CE
; Совпадений не найдено, EAX=0 и на выход
.text:005286F9                 xor     eax, eax
.text:005286FB                 pop     edx
.text:005286FC                 pop     ecx
.text:005286FD                 pop     ecx
.text:005286FE                 mov     fs:[eax], edx
.text:00528701                 push    offset loc_52871B
.text:00528706 loc_528706:
.text:00528706                 lea     eax, [ebp+var_10]
.text:00528709                 mov     edx, 4
.text:0052870E                 call    sub_404FC0
.text:00528713                 retn
.text:00528714 ; --------------------------------------------------
.text:00528714 loc_528714:
.text:00528714                 jmp     loc_404830
.text:00528719 ; --------------------------------------------------
.text:00528719                 jmp     short loc_528706
.text:0052871B ; --------------------------------------------------
.text:0052871B loc_52871B:
.text:0052871B                 mov     eax, ebx
.text:0052871D                 pop     edi
.text:0052871E                 pop     esi
.text:0052871F                 pop     ebx
.text:00528720                 mov     esp, ebp
.text:00528722                 pop     ebp
.text:00528723                 retn

Из этого кода можно узнать следующее: сперва от введенного серийного номера вычисляется хэш MD5. В самой программе хранится несколько десятков заранее сгенерированных хэшей от правильных серийных номеров, и проверка регистрации сводится к поочередному сравнению рассчитанного хэша с готовыми. Найдено совпадение - программа зарегистрирована, если не найдено - работает в триальном режиме. Такая схема регистрации используется в некоторых других программах, и определенная логика тут тоже есть. Алгоритм MD5 необратим, и взламывается только прямым перебором, а при достаточной длине серийного номера его подбор даже на современных компьютерах займет недопустиимо длительное время. Обход защиты в нашем случае будет заключаться в том, что мы подменим первые 32 байта блока готовых хэшей на нужные нам данные. Придумаем какой-нибудь красивый серийник, например, "PERM-CRACK-LABORATORY-RULEZ", и посчитаем от него хэш MD5. Получится текстовая строка "7dd47442009f46f61db100b3e3b1a510". Заменим ей первые 32 символа блока:


Заменяем первый хэш в блоке

Сохраним изменения, запустим файл, и попытаемся его зарегистрировать с нашим красивым серийным номером. Получаем радостное сообщение "Registration Successful!", а текст в строке состояния меняется на "Registered Version". Что, собственно, нам и надо было получить.


Регистрация программы

При повторном запуске кнопка регистрации уже неактивна.


Программа успешно зарегистрирована

Для очистки совести создадим какой-нибудь простой скрипт, откомпилируем его и запустим. Никаких сообщений о триальности больше нет. По такой же схеме с заменой хэша обходится защита и других программ компании Abyssmedia.
Теги:
защита, взлом
Добавлено: 21 Сентября 2013 03:38:29 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...