Програмная эмуляция HASP ключейBy exefoliator, 2000. Перевод by HexКонтора Alladin Knowledge Systems (далее AKS) создала набор HASP (Hardware against software piracy - Железо для защиты от пиратства) ключей которые обычно называют донглами (dongles) для защиты от нелицензионного использования/распостранения программ. AKS во всю раструбила, что HASP ключи делают программы неломаемыми. И все потому, что ихние чипы которые они юзают в ключах не могут быть эмулированы на машине Тьюринга. (т.е. на обычном компе).
2. Линия продуктов HASP и HASP функции (API) HASP-3 поддерживает только 3 основные функции: ISHASP (дает информацию о подключении HASP ключа - т.е. подключени или нет), HASPSTATUS (Возвращает тип ключа HASP) и HASPCODE (возвращает 64 битный код в зависимости от входного (seed) 16 битного кода). Остальные ключи поддерживают эти 3 функции + функции для записи/чтения в память, получение ID кода и доступа к таймеру. Все эти функции перед вызовом принимают набор данных заносимые в регистры AX, BX ,CX и DX (даже в win32). Функции вызова могут быть разные, но параметры всегда передаются одинаково. Т.е. в программе есть функция обращения к HASP ключу, которая в зависипости от входных параметров вызывает ту или иную функцию ключа и получает/передает данные, а потом возвращает в те же регистры ответ от HASP ключа. Функции| Параметры вызова| Возращаемое значение| ISHASP BH <- 1, BL <- LPT №. AX = 0 (нету HASP) или 1 (HASP есть) HASPCODE BH <- 2, BL <- LPT №|. AX = return code 1 AX <- seed код |BX = return code 2 CX <- password1 |CX = return code 3 DX <- password2 |DX = return code 4 HASPSTATUS BH <- 5, BL <- LPT №. |AX = размер памяти CX <- password1 |BX = тип HASP DX <- password2 |CX = LPT к которому подключено.Легко понять что они делают и также легко их сэмулировать. Т.е. в bh всегда передается номер функции, а вот входные параметры могут юзать разные регистры.
3. Средства защиты которые может содержать HASP Код для защиты от вирусов/вмешательства это просто что-то типа проверки контрольной суммы. Шаблонная защита кода означает то что в коде идут специальные структуры типа '$HASP$PCS' встретив которые специальная функция HASP заменяет эти байты на реальный код программы. И, наконец, конверты HASP, которые якобы невозможно сломать. При использовании конверта код программы криптуется, а HASP ключе лежат коды для раскриптовки. Все криптографические процедуры в конвертах это просто XOR закриптованного блока с полученым из ключа 64 битным значением. Весь прикол в том что это значение берется из ключа. А дальше чтобы не вызвать Exception полученый из ключа код сравнивается с правильным значением ключа раскриптовки. Т.е. идет проверка как в аникдоте про экзамены : "В чем измеряется сила тока? Варианты ответа: - А не в амперах ли? …" :) Процедура раскриптовки работает так:
(1) Распаковывает в память код конверта. Вся эмуляция заключается в том чтобы найти процедуру вызова HASP ключа. Далее анализируются вызовы всех функций, т.е. запоминают все seed и ответы. А дальше заменяют процедуру вызова HASP ключа на следующего вида програмку… 4. Общий вид эмулятора Hasp ключа 80 FF 01 cmp bh,1 ; вызвали ISHASP? 75 05 jne @CheckTwo ; если нет 31 C0 xor eax,eax ; иначе 40 inc eax ; ...возвращаем в eax = 1... EB 67 jmp @EndHProc ; и выходим @CheckTwo: 80 FF 02 cmp bh,2 ; вызвали HASPCODE? 74 0A je @MakeCode ; если да EB 60 jmp @EndHProc ; иначе ничего не делать @HASPData: db x0 x1 x2 x3 x4 x5 x6 x7 ; статические данные для HASP @MakeCode: 31 C9 xor ecx,ecx ; 31 DB xor ebx,ebx ; E8 00 00 00 00 call @NextInst ; @NextInst: 5E pop esi ; @NextHBit: 53 push ebx ; сохранить число бай 66 BB 89 19 mov bx,1989h F7 E3 mul eax,ebx 83 C0 05 add eax,5 ; seed <- seed*1989h+5 0F B7 C0 movzx eax,ax ; seed <- seed and FFFFh 50 push eax ; сохранить seed C1 E8 09 shr eax,9 80 E0 3F and al,3Fh ; al <- bit offset 89 C3 mov ebx,eax C1 EB 03 shr ebx,3 ; ebx <- номер байта. 80 E0 07 and al,7 ; al <- номер бита. 51 push ecx ; сохранить текущий код 88 C1 mov cl,al B0 01 mov al,1 D2 E0 shl al,cl ; al <- битовая маска 84 44 33 EF test byte ptr [ebx+esi-11h],al ; бит установлен? B0 00 mov al,0 ; предположим что нет. 74 01 je @BitClear ; jump если ок 40 inc eax ; иначе выставляем бит @BitClear: 59 pop ecx ; ecx <- строка кода D0 E5 shl ch,1 ; идем на следующий бит 08 C5 or ch,al ; добавить последний бит 58 pop eax ; eax <- seed 5B pop ebx ; ebx <- число бит 41 inc ecx ; inc число бит 80 F9 08 cmp cl,8 ; 8 битов? 75 C7 jne @NextHBit ; jump если нет F6 C3 01 test bl,1 ; 74 03 je @EvenByte ; 5A pop edx ; получаем код возврата 88 F1 mov cl,dh ; добавляем верхние 8 бит @EvenByte: 51 push ecx ; сохраняем код возврата 31 C9 xor ecx,ecx ; очищаем строку кода 43 inc ebx ; inc число байтов 80 FB 08 cmp bl,8 ; 8байтов? 75 B6 jne @NextHBit ; jump если нет 5A pop edx ; edx <- ret code 4 59 pop ecx ; ecx <- ret code 3 5B pop ebx ; ebx <- ret code 2 58 pop eax ; eax <- ret code 1 @EndHProc: C3 ret ; возврат к месту вызова.P.s. Место вызова HASP функции легко найти через bpx FreeEnvironmentStringsA. Потом поднятся на несколько уровней вверх. Обычно перед таким вызовом идет cmp bh,32 это проверка на номер вызываемой функции. Т.е. у хаспа тока 50 функций :)
|