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


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

Для разнообразия сегодня исследуем какую-нибудь игрушку. Пусть это будет Amazon Chess - красивые шахматы, где в качестве игровых фигур выступают полуобнаженные амазонки. Если же вид вооруженных блондинок и брюнеток отвлекает от игры, то можно переключить на режим обычной шахматной доски. Смущает только цена в десятку баксов.

Итак, качаем дистрибутив, устанавливаем, запускаем. Сразу открывается окно, в котором нам предлагают ввести серийный номер и зарегистрировать игру. На ввод всякого левака получаем ожидаемое "Invalid serial number".


Строка найдена

Исполняемый файл ничем не упакован, строка находится легко. Теперь в дизассемблере посмотрим код, который на нее ссылается.
...
CODE:004AF0FE                 push    dword ptr fs:[eax]
CODE:004AF101                 mov     fs:[eax], esp
CODE:004AF104                 lea     edx, [ebp+var_8]
CODE:004AF107                 mov     eax, [ebx+324h]
CODE:004AF10D                 call    @Mask@TCustomMaskEdit@GetText$qqrv
; Mask::TCustomMaskEdit::GetText(void)
; Получить текст из поля ввода
CODE:004AF112                 mov     eax, [ebp+var_8]
CODE:004AF115                 lea     edx, [ebp+var_4]
CODE:004AF118                 call    @Sysutils@UpperCase$qqrx17System
; Sysutils::UpperCase(System::AnsiString)
; Перевести его в верхний регистр
CODE:004AF11D                 mov     eax, [ebp+var_4]
; Вызвать процедуру проверки серийника
CODE:004AF120                 call    sub_4A8CB8
CODE:004AF125                 test    al, al
; Если она вернула AL!=0, то серийник правильный
CODE:004AF127                 jnz     short loc_4AF150
CODE:004AF129                 push    0               ; uType
CODE:004AF12B                 mov     ecx, offset dword_4AF1A4 ; lpCaption
CODE:004AF130                 mov     edx, offset aInvalidSerialN
; Сообщение "Invalid serial number"
CODE:004AF135                 mov     eax, ds:off_4B9EA0
CODE:004AF13A                 mov     eax, [eax]      ; int
CODE:004AF13C                 call    @Forms@TApplication@MessageBox$qqrpxct1i
; Forms::TApplication::MessageBox(char *,char *,int)
CODE:004AF141                 xor     edx, edx
CODE:004AF143                 mov     eax, [ebx+324h]
CODE:004AF149                 call    @Mask@TCustomMaskEdit@SetText
; Mask::TCustomMaskEdit::SetText(System::AnsiString)
CODE:004AF14E                 jmp     short loc_4AF177
CODE:004AF150 ; ------------------------------------------
; Игра успешно зарегистрирована
CODE:004AF150 loc_4AF150:
CODE:004AF150                 mov     eax, [ebp+var_4]
CODE:004AF153                 call    sub_4A8D78
CODE:004AF158                 mov     eax, ebx
CODE:004AF15A                 call    sub_4AF1E8
CODE:004AF15F                 push    0               ; uType
CODE:004AF161                 mov     ecx, offset dword_4AF1A4 ; lpCaption
CODE:004AF166                 mov     edx, offset aAmazonChessIsR
; Собщение "Amazon Chess is registered"
CODE:004AF16B                 mov     eax, ds:off_4B9EA0
CODE:004AF170                 mov     eax, [eax]      ; int
CODE:004AF172                 call    @Forms@TApplication@MessageBox
; Forms::TApplication::MessageBox(char *,char *,int)
CODE:004AF177                 xor     eax, eax
CODE:004AF179                 pop     edx
CODE:004AF17A                 pop     ecx
CODE:004AF17B                 pop     ecx
...

Дальше есть два варианта - пропатчить процедуру проверки, чтобы она всегда возвращала AL=1, или попробовать разобрать алгоритм проверки.
; Если патчить, то это делается в самом начале процедуры
CODE:004A8CB8                 push    ebp   ; <-- MOV AL,1; RET
CODE:004A8CB9                 mov     ebp, esp
CODE:004A8CBB                 add     esp, 0FFFFFFF8h
CODE:004A8CBE                 push    ebx
CODE:004A8CBF                 push    esi
CODE:004A8CC0                 push    edi
CODE:004A8CC1                 xor     edx, edx
CODE:004A8CC3                 mov     [ebp+var_8], edx
CODE:004A8CC6                 mov     [ebp+var_4], eax
CODE:004A8CC9                 mov     eax, [ebp+var_4]
CODE:004A8CCC                 call    @System@@LStrAddRef$qqrpv
; System::__linkproc__ LStrAddRef(void *)
CODE:004A8CD1                 xor     eax, eax
CODE:004A8CD3                 push    ebp
CODE:004A8CD4                 push    offset loc_4A8D47
CODE:004A8CD9                 push    dword ptr fs:[eax]
CODE:004A8CDC                 mov     fs:[eax], esp
CODE:004A8CDF                 xor     ebx, ebx
CODE:004A8CE1                 cmp     [ebp+var_4], 0
CODE:004A8CE5                 jz      short loc_4A8CF4
CODE:004A8CE7                 mov     eax, [ebp+var_4]
CODE:004A8CEA                 call    sub_4049D0
; Проверить длину введенного серийного номера
CODE:004A8CEF                 cmp     eax, 17h
CODE:004A8CF2                 jz      short loc_4A8D01
CODE:004A8CF4 loc_4A8CF4:
CODE:004A8CF4                 lea     eax, [ebp+var_4]
; Дополнить до маски "00000-00000-00000-00000"
CODE:004A8CF7                 mov     edx, offset _str_00000_00000_000.Text
CODE:004A8CFC                 call    @System@@LStrLAsg$qqrpvpxv
; System::__linkproc__ LStrLAsg(void *,void *)
CODE:004A8D01 loc_4A8D01:
CODE:004A8D01                 mov     esi, 3E8h
CODE:004A8D06                 mov     edi, offset off_4B8A88
CODE:004A8D0B loc_4A8D0B:
CODE:004A8D0B                 lea     edx, [ebp+var_8]
CODE:004A8D0E                 mov     eax, [ebp+var_4]
; Сканеры криптоалгоритмов показывают, что здесь вызывается функция расчета
; хэша MD5 от серийника
CODE:004A8D11                 call    sub_4A9990
; Расчетная MD5 проверяется по очереди с заранее сохраненными значениями
CODE:004A8D16                 mov     edx, [ebp+var_8]
CODE:004A8D19                 mov     eax, [edi]
CODE:004A8D1B                 call    @System@@LStrCmp$qqrv
; System::__linkproc__ LStrCmp(void)
CODE:004A8D20                 jnz     short loc_4A8D26
CODE:004A8D22                 mov     bl, 1
CODE:004A8D24                 jmp     short loc_4A8D2C
CODE:004A8D26 ; ---------------------------------------------------
CODE:004A8D26 loc_4A8D26:
CODE:004A8D26                 add     edi, 4
CODE:004A8D29                 dec     esi
CODE:004A8D2A                 jnz     short loc_4A8D0B
CODE:004A8D2C loc_4A8D2C:
CODE:004A8D2C                 xor     eax, eax
CODE:004A8D2E                 pop     edx
CODE:004A8D2F                 pop     ecx
CODE:004A8D30                 pop     ecx
CODE:004A8D31                 mov     fs:[eax], edx
CODE:004A8D34                 push    offset loc_4A8D4E
CODE:004A8D39 loc_4A8D39:
CODE:004A8D39                 lea     eax, [ebp+var_8]
CODE:004A8D3C                 mov     edx, 2
CODE:004A8D41                 call    @System@@LStrArrayClr$qqrpvi
; System::__linkproc__ LStrArrayClr(void *,int)
CODE:004A8D46                 retn
CODE:004A8D47 ; ---------------------------------------------------
CODE:004A8D47 loc_4A8D47:
CODE:004A8D47                 jmp     unknown_libname_67
CODE:004A8D4C ; ---------------------------------------------------
CODE:004A8D4C                 jmp     short loc_4A8D39
CODE:004A8D4E ; ---------------------------------------------------
CODE:004A8D4E loc_4A8D4E:
CODE:004A8D4E                 mov     eax, ebx
CODE:004A8D50                 pop     edi
CODE:004A8D51                 pop     esi
CODE:004A8D52                 pop     ebx
CODE:004A8D53                 pop     ecx
CODE:004A8D54                 pop     ecx
CODE:004A8D55                 pop     ebp
CODE:004A8D56                 retn

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


Заменяем хэш в блоке

Первый хэш в блоке заменен на MD5 от cерийника "11111-11111-11111-11111", сохраним изменения и попробуем зарегистрировать игру. На этот раз регистрация пройдет успешно. Ну а пропатченный вариант даже не требует ввода серийника.


Игра успешно "зарегистрирована"

Музыкальное сопровождение в игре можно заменить на свое, музыка хранится в открытом виде в файлах main_theme.mp3 и title_theme.mp3
Теги:
защита, взлом
Добавлено: 21 Сентября 2013 01:28:24 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...