RCE.SU - реверсинг, кодинг, выделенные сервера, ICQ, proxy

Hasp защита в Базис Конструктор Мебельщик Demo

Это хоть и демо но в ней остался блок для работы с HASP. Естественно даже если мы тут сэмулируем Hasp - фичи не активируются, потому что их тут нет :) Но зато можно потренироваться в эмуляции HASP.

Взять это дело можно вот тут

Инструменты: Softice, Windasm, Hiew.

Сначала откроем BazMebel50.exe в windasm. Вызовы ключа тут отключены т.к. это демо, но нам для обучения нужно чтобы ключ таки вызывался. Как это сделать? Сначала найдем процедуру вызова HASP ключа. Искать ее очень просто, либо по вызову FreeEnvironmentStringsA либо по команде cmp bh, 32 (этой командой проверяется номер функции перед вызовом HASP ключа). Итак сделаем поиск строки "cmp bh, 32" и окажемся вот в таком месте:

:004C68D0 55                      push ebp
:004C68D1 8BEC                    mov ebp, esp
:004C68D3 50                      push eax
:004C68D4 53                      push ebx
:004C68D5 51                      push ecx
:004C68D6 52                      push edx
:004C68D7 57                      push edi
:004C68D8 56                      push esi
:004C68D9 8B7514                  mov esi, dword ptr [ebp+14]
:004C68DC 8B3E                    mov edi, dword ptr [esi]
:004C68DE BB00000000              mov ebx, 00000000
:004C68E3 8BD8                    mov ebx, eax
:004C68E5 8AFB                    mov bh, bl
:004C68E7 B300                    mov bl, 00
:004C68E9 03D9                    add ebx, ecx
:004C68EB 8BC2                    mov eax, edx
:004C68ED 8B4D1C                  mov ecx, dword ptr [ebp+1C]
:004C68F0 8B5518                  mov edx, dword ptr [ebp+18]
:004C68F3 80FF32                  cmp bh, 32 - проверяем чтобы номер функции был < 50
:004C68F6 7205                    jb 004C68FD
:004C68F8 8B7508                  mov esi, dword ptr [ebp+08]
:004C68FB 8B06                    mov eax, dword ptr [esi]
:004C68FD 8B7510                  mov esi, dword ptr [ebp+10]
:004C6900 8B36                    mov esi, dword ptr [esi]
:004C6902 55                      push ebp
:004C6903 E82E090000              call 004C7236 - Тут вызов HASP
:004C6908 5D                      pop ebp
:004C6909 8B7D14                  mov edi, dword ptr [ebp+14]
:004C690C 8907                    mov dword ptr [edi], eax - первое возвращаемое значение
:004C690E 8B7D10                  mov edi, dword ptr [ebp+10]
:004C6911 891F                    mov dword ptr [edi], ebx - второе возвращаемое значение
:004C6913 8B7D0C                  mov edi, dword ptr [ebp+0C]
:004C6916 890F                    mov dword ptr [edi], ecx - третье возвращаемое значение
:004C6918 8B7D08                  mov edi, dword ptr [ebp+08]
:004C691B 8917                    mov dword ptr [edi], edx - четвертое возвращаемое значение
:004C691D 5E                      pop esi
:004C691E 5F                      pop edi
:004C691F 5A                      pop edx
:004C6920 59                      pop ecx
:004C6921 5B                      pop ebx
:004C6922 58                      pop eax
:004C6923 5D                      pop ebp
:004C6924 C21800                  ret 0018
Это стандартная процедура вызова HASP ключа. Теперь надо сделать чтобы она таки вызывалась. Смотрим откуда вызывается эта процедура:
* Referenced by a CALL at Address:
:004B2C40
А там:
* Referenced by a CALL at Addresses:
|:004B2D48   , :004BF452   , :004BF4D9   , :004BF568   , :004BF5E2
|:004BF643   , :005846C8   , :00584703   , :00584781

ну глянем чо там к примеру по адресу 4B2D48:

:004B2D07 803D3D90650000          cmp byte ptr [0065903D], 00
:004B2D0E 753D                    jne 004B2D4D - тут перепрыгивает вызов HASP
.........
                                  
:004B2D43 B802000000              mov eax, 00000002
:004B2D48 E8C3FEFFFF              call 004B2C10 - отсюда мы вышли

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004B2D0E(C)

Вот, это уже хорошо. Теперь делаем запускаем прогу через symbol loader и bpm 0065903D.
Оно сработает вот тут:
:004BE99B C6053C90650000          mov byte ptr [0065903C], 00
:004BE9A2 C6053D90650001          mov byte ptr [0065903D], 01 - Вот оно!
:004BE9A9 C605F468650001          mov byte ptr [006568F4], 01
:004BE9B0 C6054D7E650001          mov byte ptr [00657E4D], 01
:004BE9B7 C6054E7E650000          mov byte ptr [00657E4E], 00
Если сделать чтоб по адресу 0065903D записалось 0, то все вызовы HASP ключа оживут. Оживляем :)

Ставим bpx 4C6903(процедура вызова HASP) Теперь берем бумажку и записываем все вызовы и ихние параметры. Перед тем как записывать параметры, не плохо бы почитать вот тут описалово функций Hasp. Будут вызваны 1, 5 и 3. Функции 1 и 5 и идут без параметров, а вот третьей передается di=0e. Больше вызовов естественно нету т.к. вызов хаспа не дал правильных результатов. Давайте ка глянем а чо ж ему надо чтоб он поверил что ключ присутствует. Вопервых функция 1 должна вернуть 1 в ax, потом после 5-й функции у нас тут проверяется только чтоб в ax не было 0. А вот с третьей функцией сложнее. Поставим bpm на все четыре возвращаемые значения. Bpm сработает тут:

:004BF576 8B55F4                  mov edx, dword ptr [ebp-0C]
:004BF579 89500C                  mov dword ptr [eax+0C], edx
:004BF57C 817DF44D350000          cmp dword ptr [ebp-0C], 0000354D
:004BF583 7407                    je 004BF58C
Хе-хе, третий возвращаемый параметр должен быть равен 354D. Т.е. в [ebp-0C] должно быть 4D 35 00 00 (354D). Правим память и смотрим дальше. Теперь, когда мы сэмулировали правильный ответ, прога будет пробовать снова обращаться к HASP.
Опять функция 3 с параметром di=10 Проверка возвращаемого значения тут:
:004BF5E7 817DF452350000          cmp dword ptr [ebp-0C], 00003552
:004BF5EE 750A                    jne 004BF5FA

И еще раз функция 3 с параметром di=11 Проверка возвращаемого значения тут:
:004BF648 817DF449350000          cmp dword ptr [ebp-0C], 00003549
:004BF64F 750A                    jne 004BF65B

Дальше идет вызов функции 2 с параметром ax=1B
Но тут чуть извратнее. Параметры копируются:
:004B2D4D A194846500              mov eax, dword ptr [00658494]
:004B2D52 8B80C4070000            mov eax, dword ptr [eax+000007C4]
:004B2D58 8B55F0                  mov edx, dword ptr [ebp-10]
:004B2D5B 89500C                  mov dword ptr [eax+0C], edx - первый
:004B2D5E A194846500              mov eax, dword ptr [00658494]
:004B2D63 8B80C8070000            mov eax, dword ptr [eax+000007C8]
:004B2D69 8B55EC                  mov edx, dword ptr [ebp-14]
:004B2D6C 89500C                  mov dword ptr [eax+0C], edx - второй
:004B2D6F A194846500              mov eax, dword ptr [00658494]
:004B2D74 8B80CC070000            mov eax, dword ptr [eax+000007CC]
:004B2D7A 8B55E8                  mov edx, dword ptr [ebp-18]
:004B2D7D 89500C                  mov dword ptr [eax+0C], edx - третий
:004B2D80 A194846500              mov eax, dword ptr [00658494]
:004B2D85 8B80D0070000            mov eax, dword ptr [eax+000007D0]
:004B2D8B 8B55E4                  mov edx, dword ptr [ebp-1C]
:004B2D8E 89500C                  mov dword ptr [eax+0C], edx - четвертый

Ну естественно нужно ставить bpm на dword ptr [eax+0C]. 
Только вот один облом, они почему то не срабатывают :( А глюк такой вылазит вот тут:
:004B4552 803DF468650000          cmp byte ptr [006568F4], 00 - тут у нас 1
:004B4559 7416                    je 004B4571 - тут нет прыжка
:004B455B C6053D90650001          mov byte ptr [0065903D], 01 - единица означает что hasp нету.

А как жеж в [006568F4] появляется единица? А очень просто! Поставив bpm 006568F4 мы увидим:
:004BE99B C6053C90650000          mov byte ptr [0065903C], 00
:004BE9A2 C6053D90650000          mov byte ptr [0065903D], 00 - это мы Hasp включили
:004BE9A9 C605F468650001          mov byte ptr [006568F4], 01 - Вот оно!
:004BE9B0 C6054D7E650001          mov byte ptr [00657E4D], 01
:004BE9B7 C6054E7E650000          mov byte ptr [00657E4E], 00
Упс :) Оказывается для активации ключа надо еще 1 байт поправить. Поправив вот это место возвращаемся к нашим брейкпоинтам, которые мы ставили чтобы понять куда уходят значения после функции 2 с параметром ax=1B. Теперь они таки сработают. Вот тут:
:004B459B A194846500              mov eax, dword ptr [00658494]
:004B45A0 8B80C4070000            mov eax, dword ptr [eax+000007C4]
:004B45A6 81780C76F00000          cmp dword ptr [eax+0C], 0000F076 - правильное значение 1
:004B45AD 753C                    jne 004B45EB
:004B45AF A194846500              mov eax, dword ptr [00658494]
:004B45B4 8B80C8070000            mov eax, dword ptr [eax+000007C8]
:004B45BA 81780C77DF0000          cmp dword ptr [eax+0C], 0000DF77 - правильное значение 2
:004B45C1 7528                    jne 004B45EB
:004B45C3 A194846500              mov eax, dword ptr [00658494]
:004B45C8 8B80CC070000            mov eax, dword ptr [eax+000007CC]
:004B45CE 81780CFFC50000          cmp dword ptr [eax+0C], 0000C5FF - правильное значение 3
:004B45D5 7514                    jne 004B45EB
:004B45D7 A194846500              mov eax, dword ptr [00658494]
:004B45DC 8B80D0070000            mov eax, dword ptr [eax+000007D0]
:004B45E2 81780CADEA0000          cmp dword ptr [eax+0C], 0000EAAD - правильное значение 4
:004B45E9 7404                    je 004B45EF
Вот они все 4 параметра которые нужно вернуть. Правим их в памяти. Вооот ... и прога запускается без надписей "Demo". Активируется кнопка сохранить на панели инструментов и в About уже горит что полная. Но если зайти в меню "файл" или пощелкать по вкладкам выбора примитвовов то происходит еще 1 вызов функции 2 на этот раз с параметром ax=25. Опять ставим брейкпоинты и видим что проверка происходит тут:
:004B4654 A194846500              mov eax, dword ptr [00658494]
:004B4659 8B80C4070000            mov eax, dword ptr [eax+000007C4]
:004B465F 81780C1ACC0000          cmp dword ptr [eax+0C], 0000CC1A
:004B4666 753C                    jne 004B46A4
:004B4668 A194846500              mov eax, dword ptr [00658494]
:004B466D 8B80C8070000            mov eax, dword ptr [eax+000007C8]
:004B4673 81780C8EF10000          cmp dword ptr [eax+0C], 0000F18E
:004B467A 7528                    jne 004B46A4
:004B467C A194846500              mov eax, dword ptr [00658494]
:004B4681 8B80CC070000            mov eax, dword ptr [eax+000007CC]
:004B4687 81780C6AA30000          cmp dword ptr [eax+0C], 0000A36A
:004B468E 7514                    jne 004B46A4
:004B4690 A194846500              mov eax, dword ptr [00658494]
:004B4695 8B80D0070000            mov eax, dword ptr [eax+000007D0]
:004B469B 81780CFBD30000          cmp dword ptr [eax+0C], 0000D3FB
:004B46A2 7404                    je 004B46A8
Ну вроде все. Можно писать эмулятор. Данные есть. Т.е. надо написать программу которая обрабатывает 3 регистра и возвращает правильные цифры в регистры ax, bx, cx и dx
Т.е. будет чо-то типа
cmp bh,1 - вызвали функцию 1?
jnz дальше
mov ax,1
jmp выход

дальше:
cmp bh,2  - вызвали функцию 2?
jnz еще_дальше
cmp ax, 1b
jnz не1b
mov ax,F076
mov bx,DF77
mov cx,C5FF
mov dx,EAAD
jmp выход

не1b:
cmp ax, 25
jnz выход
mov ax,CC1A
mov bx,F18E
mov cx,A36A
mov dx,D3FB
jmp выход

еще_дальше:
cmp bh,3 - вызвали функцию 3?
jnz даль_голубая
cmp di, 0e
jnz не_0е
mov cx,354d
jmp выход

не_0е:
cmp di, 10
jnz не_10
mov cx,3552
jmp выход

не_10:
cmp di, 11
jnz выход
mov cx,3549
jmp выход

даль_голубая:
cmp bh,5 - вызвали функцию 5?
jnz выход
mov ax,1

выход:
ret
И вот такую процедурку мы подсовываем вместо вызова HASP ключа. Это называется громким словом "Эмулятор" :)

Эх, жалко что демка :( Но я не думаю что в полноценной версии защита сильно отличается :)

P.S. Напоминаю! Это тока демка т.е. в ней нет кусков кода для сохранения и т.д. поэтому после эмуляции будет тока свтетится что она полноценная. Я эту прогу брал чисто для примера, чтоб показать процесс эмуляции.


<= Вернуться к статьям


Rambler's Top100