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


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

Программа CollageIt - очень удобная утилита для создания красивых коллажей из множества фотографий. Буквально несколько кликов мышкой и вы получаете готовый результат. Программа почему-то платная, и надо выложить за лицензию почти двадцатку баксов.

Скачиваем дистрибутив, устанавливаем, запускаем. В принципе, все работает даже в бесплатном варианте, за исключением того, что на готовые коллажи наносится некрасивый маркер, и при сохранении нам каждый раз предлагают зарегистрироваться. Хорошо, но сперва попробуем ввести какой-нибудь левый серийник. На это программа отреагирует вот таким сообщением:


Сообщение о неправильной регистрации

Эта строчка находится в ресурсах, код ресурса 106 в десятичной или 6Ah в шестнадцатеричной системе счисления.


Нехорошая строка найдена

Исходные данные для исследования защиты есть, переходим к исполняемому файлу. Он ничем не упакован, можно сразу же отправлять его на дизассемблирвание. Когда дизассемблер закончит свою работу, поищем место, где программа обращается к ресурсам с кодом 6Ah. Первое же вхождение все ставит на свои места:
...
.text:0040AC33                 mov     ecx, [ecx]
.text:0040AC35                 lea     eax, [ebp+var_1C]
.text:0040AC38                 push    eax
; Вызвать функцию проверки
.text:0040AC39                 call    ds:?CheckCode@CRegisterUtility
; CRegisterUtility::CheckCode(ATL::CStringT)
.text:0040AC3F                 movzx   eax, al
; Если она вернула AL=0, то регистрационный код неправильный
.text:0040AC42                 test    eax, eax
; Вывести сообщение о неправильной регистрации
.text:0040AC44                 jz      short loc_40AC94
.text:0040AC46                 mov     esi, ds:?GetInstance@RegConfig@@SAPAV1@XZ
; RegConfig::GetInstance(void)
.text:0040AC4C                 lea     edx, [ebp+var_14]
.text:0040AC4F                 push    edx
.text:0040AC50                 call    esi
; RegConfig::GetInstance(void) ; RegConfig::GetInstance(void)
.text:0040AC52                 mov     ecx, eax
.text:0040AC54                 add     ecx, 8
.text:0040AC57                 call    ds:mfc90u_811
.text:0040AC5D                 call    esi
; RegConfig::GetInstance(void) ; RegConfig::GetInstance(void)
.text:0040AC5F                 mov     ecx, eax
.text:0040AC61                 call    ds:?SaveData@RegConfig@@QAEXXZ
; RegConfig::SaveData(void)
.text:0040AC67                 lea     eax, [ebp+var_18]
; Загрузить сообщение об успешной регистрации
.text:0040AC6A                 push    69h
.text:0040AC6C                 push    eax
.text:0040AC6D                 call    sub_417570
.text:0040AC72                 mov     byte ptr [ebp+var_4], 2
.text:0040AC76                 mov     ecx, [ebp+var_18]
.text:0040AC79                 push    0
.text:0040AC7B                 push    ecx
.text:0040AC7C                 call    ds:?BCGPMessageBox@@YAHPBGI@Z
; BCGPMessageBox(ushort const *,uint)
.text:0040AC82                 mov     ecx, [ebp+var_20]
.text:0040AC85                 mov     edx, [ecx]
.text:0040AC87                 mov     eax, [edx+160h]
.text:0040AC8D                 add     esp, 10h
.text:0040AC90                 call    eax
.text:0040AC92                 jmp     short loc_40ACB1
.text:0040AC94 ; --------------------------------------------
.text:0040AC94 loc_40AC94:
.text:0040AC94                 lea     ecx, [ebp+var_18]
; Загрузить строку ресурсов с кодом 6Ah
.text:0040AC97                 push    6Ah
.text:0040AC99                 push    ecx
.text:0040AC9A                 call    sub_417570
.text:0040AC9F                 mov     byte ptr [ebp+var_4], 3
.text:0040ACA3                 mov     edx, [eax]
.text:0040ACA5                 push    0
.text:0040ACA7                 push    edx
; Вывести сообщение о неправильной регистрации
.text:0040ACA8                 call    ds:?BCGPMessageBox@@YAHPBGI@Z
; BCGPMessageBox(ushort const *,uint)
.text:0040ACAE                 add     esp, 10h
...

Дизассемблер показал даже имя вызываемой функции, и это неспроста. Это имя содержится в секции импорта, значит сама функция проверки содержится в какой-то другой внешней библиотеке. В какой именно - тоже покажет дизассемблер.


Список импортируемых функций

В папке программы лежит файл AlbumDesignCore.dll, теперь загоняем в дизассемблер его, а основную программу запускаем под отладчиком. Затем в отлаживаемой программе надо поставить точку останова на начало функции CheckCode:
.text:10043690 ; public: bool __thiscall CRegisterUtility::CheckCode
.text:10043690                 push    ebp
.text:10043691                 mov     ebp, esp
.text:10043693                 push    ecx
.text:10043694                 mov     [ebp+var_4], ecx
.text:10043697                 mov     eax, [ebp+var_4]
.text:1004369A                 add     eax, 8
.text:1004369D                 push    eax
.text:1004369E                 mov     ecx, [ebp+var_4]
.text:100436A1                 mov     edx, [ecx+4]
.text:100436A4                 push    edx
.text:100436A5                 mov     eax, [ebp+arg_0]
.text:100436A8                 push    eax
.text:100436A9                 call    ?CheckRandomSerialCode
.text:100436AE                 add     esp, 0Ch
.text:100436B1                 mov     esp, ebp
.text:100436B3                 pop     ebp
.text:100436B4                 retn    4

Как видите, основная проверка выполняется в функции CheckRandomSerialCode той же самой библиотеки. И вот тут начинается самое интересное, а именно алгоритм проверки правильности серийного номера.
...
.text:100431FC                 call    ds:mfc90u_290
.text:10043202                 mov     [ebp+var_4], 0
.text:10043209                 lea     ecx, [ebp+var_14]
.text:1004320C                 call    ds:mfc90u_3185
; Первая проверка - длина серийника должна быть 1Dh (29) символов
.text:10043212                 cmp     eax, 1Dh
; Переход, если длина соответствует
.text:10043215                 jz      short loc_10043233
.text:10043217                 mov     [ebp+var_2D], 0
.text:1004321B                 mov     [ebp+var_4], 0FFFFFFFFh
.text:10043222                 lea     ecx, [ebp+var_14]
.text:10043225                 call    ds:mfc90u_600
.text:1004322B                 mov     al, [ebp+var_2D]
.text:1004322E                 jmp     loc_100433FF
.text:10043233 ; --------------------------------------------
.text:10043233 loc_10043233:
; Выполняется проверка формата серийного номера
.text:10043233                 push    5
.text:10043235                 lea     ecx, [ebp+var_14]
.text:10043238                 call    ds:mfc90u_2676
.text:1004323E                 movzx   eax, ax
; В позиции 05h должен быть символ '-'
.text:10043241                 cmp     eax, 2Dh
.text:10043244                 jnz     short loc_1004327F
.text:10043246                 push    0Bh
.text:10043248                 lea     ecx, [ebp+var_14]
.text:1004324B                 call    ds:mfc90u_2676
.text:10043251                 movzx   ecx, ax
; В позиции 0Bh должен быть символ '-'
.text:10043254                 cmp     ecx, 2Dh
.text:10043257                 jnz     short loc_1004327F
.text:10043259                 push    11h
.text:1004325B                 lea     ecx, [ebp+var_14]
.text:1004325E                 call    ds:mfc90u_2676
.text:10043264                 movzx   edx, ax
; В позиции 11h должен быть символ '-'
.text:10043267                 cmp     edx, 2Dh
.text:1004326A                 jnz     short loc_1004327F
.text:1004326C                 push    17h
.text:1004326E                 lea     ecx, [ebp+var_14]
.text:10043271                 call    ds:mfc90u_2676
.text:10043277                 movzx   eax, ax
.text:1004327A                 cmp     eax, 2Dh
; В позиции 17h должен быть символ '-'
.text:1004327D                 jz      short loc_1004329B
.text:1004327F loc_1004327F:
.text:1004327F                 mov     [ebp+var_2E], 0
.text:10043283                 mov     [ebp+var_4], 0FFFFFFFFh
.text:1004328A                 lea     ecx, [ebp+var_14]
.text:1004328D                 call    ds:mfc90u_600
.text:10043293                 mov     al, [ebp+var_2E]
.text:10043296                 jmp     loc_100433FF
...

После разбора первых двух проверок мы знаем длину и формат серийного номера: это должно быть что-то типа "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX". Смотрим дальше в режиме пошаговой трассировки.
...
.text:1004329B                 push    5
.text:1004329D                 push    0
.text:1004329F                 lea     ecx, [ebp+var_34]
.text:100432A2                 push    ecx
.text:100432A3                 lea     ecx, [ebp+var_14]
; Отрезать от серийника первые 5 символов
.text:100432A6                 call    ds:mfc90u_4519
.text:100432AC                 mov     [ebp+var_44], eax
.text:100432AF                 mov     edx, [ebp+var_44]
.text:100432B2                 mov     [ebp+var_48], edx
.text:100432B5                 mov     byte ptr [ebp+var_4], 1
.text:100432B9                 mov     ecx, [ebp+var_48]
.text:100432BC                 call    ds:mfc90u_909
.text:100432C2                 push    eax
.text:100432C3                 lea     ecx, [ebp+var_10]
.text:100432C6                 call    ds:mfc90u_306
.text:100432CC                 mov     byte ptr [ebp+var_4], 3
.text:100432D0                 lea     ecx, [ebp+var_34]
.text:100432D3                 call    ds:mfc90u_600
.text:100432D9                 mov     eax, [ebp+arg_8]
.text:100432DC                 push    eax
.text:100432DD                 lea     ecx, [ebp+var_10]
.text:100432E0                 push    ecx
; Сравнить символы со строкой "CLGIT"
.text:100432E1                 call    sub_10043730
.text:100432E6                 add     esp, 8
.text:100432E9                 movzx   edx, al
.text:100432EC                 test    edx, edx
.text:100432EE                 jz      short loc_10043319
...

В этой проверке выполняется сравнение первых 5 символов серийного номера со строкой "CLGIT", если они не совпадают, то серийный номер неправильный. Трассируем дальше:
...
.text:10043322 loc_10043322:
.text:10043322                 mov     eax, [ebp+var_28]
.text:10043325                 add     eax, 1
.text:10043328                 mov     [ebp+var_28], eax
.text:1004332B loc_1004332B:
.text:1004332B                 cmp     [ebp+var_28], 4
.text:1004332F                 jge     short loc_1004339F
.text:10043331                 push    5
.text:10043333                 mov     ecx, [ebp+var_28]
.text:10043336                 imul    ecx, 6
.text:10043339                 add     ecx, 6
.text:1004333C                 push    ecx
.text:1004333D                 lea     edx, [ebp+var_3C]
.text:10043340                 push    edx
.text:10043341                 lea     ecx, [ebp+var_14]
.text:10043344                 call    ds:mfc90u_4519
.text:1004334A                 mov     [ebp+var_4C], eax
.text:1004334D                 mov     eax, [ebp+var_4C]
.text:10043350                 mov     [ebp+var_50], eax
.text:10043353                 mov     byte ptr [ebp+var_4], 4
.text:10043357                 mov     ecx, [ebp+var_50]
.text:1004335A                 call    ds:mfc90u_909
.text:10043360                 push    eax
.text:10043361                 lea     ecx, [ebp+var_2C]
.text:10043364                 call    ds:mfc90u_306
.text:1004336A                 mov     byte ptr [ebp+var_4], 6
.text:1004336E                 lea     ecx, [ebp+var_3C]
.text:10043371                 call    ds:mfc90u_600
.text:10043377                 lea     ecx, [ebp+var_2C]
.text:1004337A                 call    ds:mfc90u_2697
.text:10043380                 push    eax             ; Str
; Преобразовать строку в шестнадцатеричное число
.text:10043381                 call    ?HexToInt@@YAHPBD@Z
.text:10043386                 add     esp, 4
.text:10043389                 mov     ecx, [ebp+var_28]
.text:1004338C                 mov     [ebp+ecx*4+var_24], eax
.text:10043390                 mov     byte ptr [ebp+var_4], 3
.text:10043394                 lea     ecx, [ebp+var_2C]
.text:10043397                 call    ds:mfc90u_601
.text:1004339D                 jmp     short loc_10043322
...

В этом участке кода последовательно преобразуются оставшиеся 4 пятисимвольных блока цифр серийного номера в их шестнадцатеричные значения. Результат конвертирования записывается в стеке. И, наконец, последняя проверка:
; Взять первое число
.text:1004339F                 mov     edx, [ebp+var_24]
; Добавить к нему третье число
.text:100433A2                 add     edx, [ebp+var_1C]
; Сумма должна быть равна 17CB6h
.text:100433A5                 cmp     edx, [ebp+arg_4]
; Если не равно, то серийный номер неправильный
.text:100433A8                 jnz     short loc_100433B5
; Взять второе число
.text:100433AA                 mov     eax, [ebp+var_20]
; Добавить к нему четвертое число
.text:100433AD                 add     eax, [ebp+var_18]
; Сумма должна быть равна 17CB6h
.text:100433B0                 cmp     eax, [ebp+arg_4]
; Если равно, то серийный номер правильный
.text:100433B3                 jz      short loc_100433DB

Вот и вся проверка. Подведем итог. Серийный номер состоит из 5 блоков по 5 символов, разделенных дефисом "-". Первый блок всегда равен "CLGIT", остальные четыре являются числами и состоят из шестнадцатеричных цифр. Сумма первого числа с третьим, а также второго с четвертым числом в сумме должны давать 17CB6h. Так, валидным серийным номером будет "CLGIT-17CB6-17CB6-00000-00000".


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

После перезапуска заголовок программы изменился на "CollageIt Pro", надоедливые окна исчезли, а готовые коллажи больше не портятся маркерами. Защита оказалась несложной, но интересной за счет выполнения проверки введенного серийного номера во внешней библиотеке. Рабочий кейген теперь напишете самостоятельно.
Теги:
защита, взлом
Добавлено: 17 Сентября 2013 07:14:50 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...