/\ /\ / \_ _/ \ ____/ /__ T E A M . F I F T Y . T H R E E __\ \____ \__ ____\\- ____ -//____ __/ / /_____ ______\ \__________\ \ _/ /_\ \_________________________-// // ____/ /_\ \_ __\ _\ ____ /___ _ \_ \/ // ___\/_ /__ ))______________\_ _______\_|__ /____\/_____\ /gf _/______________(( \___\\- /___//- /____((- TEAM FiFTY THREE TUTORiALS PACK # SEVENTEEN HASP SL – Копаем Глубже Автор..: potassium//ARTeam Перевод: NightCat//TEAM-53 ВСТУПЛЕНИЕ В моём предыдущем туторе о HASP SL (6.41.95) я продемонстрировал, как легко и быстро найти OEP, сдампить и перестроить цель. Цель давнного туториала - углубиться в анализ того, как вручную обойти anti-debug, выяснить с какой версией мы имеем дело и т.д. Обход anti-debug, нахождение OEP, сдампливание и перестройка, - всё это заняло не больше 2.5 минут! Готовы? Пиво? Есть! Орешки? Есть! ImportRec? Есть! OllyDbg? ЕСТЬ! Ладненько... Поехали! Цель можно загрузить тут - http://fs1.minitab.com/Store/QC2_Setup.exe (61 mg) ОБХОДИМ Anti-Debug НА РУКАХ :) Окей, чтобы сделать всё это больше похожим на "спорт" я не буду использовать никаких анти-дебаговых плагинов, но я всё буду убирать руками используя кое-какие приёмы. Итак. если мы загрузим наш исполняемый файл в Olly и запустим, то получим сообщение: "The Allladin HASP SL Runtime has detected a debugger attached to a protected program. The program has been terminated." Итак, нашу попытку заглянуть внутрь кода обломали злые и плохие дядьки-разработчики протектора. Интересно, а если поставить breakpoint на IsDebuggerPresent, это сработает или нет? Давайте проверим! Окей, мы прервались, EAX = 1 (debugger present). Теперь у нас есть несколько путей: руками изменить EAX -> 0, что конечно же легче всего, но в данном случае я знаю, что эта процедура будет вызываться много раз. Так что всё это изменение будет пустой тратой времени. Давайте ка проследуем за RETN и посмотрим куда нас это приведёт. 00DE0974 8BD8 MOV EBX,EAX 00DE0976 7D 05 JGE SHORT qc.00DE097D 00DE0978 7C 08 JL SHORT qc.00DE0982 00DE097A C786 90669090 66>MOV DWORD PTR DS:[ESI+90906690],57D9066 00DE0984 7C 08 JL SHORT qc.00DE098E 00DE0986 C786 90669090 66>MOV DWORD PTR DS:[ESI+90906690],DB859066 00DE0990 7A 06 JPE SHORT qc.00DE0998 00DE0992 7B 03 JPO SHORT qc.00DE0997 00DE0994 C783 90900F85 DF>MOV DWORD PTR DS:[EBX+850F9090],0DF 00DE099E 74 04 JE SHORT qc.00DE09A4 00DE09A0 75 02 JNZ SHORT qc.00DE09A4 00DE09A2 C786 90576A24 87>MOV DWORD PTR DS:[ESI+246A5790],7059C987 00DE09AC 06 PUSH ES 00DE09AD 71 04 JNO SHORT qc.00DE09B3 Окей, что мы получили какой-то ужасно-кошмарно-дьявольский код... чистое зло. Вы видите, что EAX кладётся в EBX? После. если вы протрейситесь чуть дальше, то вы увидите: 00DE098B 90 NOP 00DE098C 66:90 NOP 00DE098E 85DB TEST EBX,EBX <--- EBX = 1, ведь мы дебажим. 00DE0990 7A 06 JPE SHORT qc.00DE0998 "jump is not taken" 00DE0992 7B 03 JPO SHORT qc.00DE0997 Итак, мы меняем MOV EBX,EAX на MOV EBX,0 или прост отупо меняем JPE на константный. Но если мы всё это сделаем и запустим, то получим то же сообщение: "The Allladin HASP SL Runtime has detected a debugger attached to a protected program. The program has been terminated." О, чёрт, только не снова! А вот почему: 00DE0A1E FF15 20BEDE00 CALL DWORD PTR DS:[<&KERNEL32.GetCurrentProcessId 00DE0A24 50 PUSH EAX <--- PID нашего исполняемого файла 00DE0A25 53 PUSH EBX 00DE0A26 68 00040000 PUSH 400 00DE0A2B FF15 1CBEDE00 CALL DWORD PTR DS:[<&KERNEL32.OpenProcess>] 00DE0A31 8BF8 MOV EDI,EAX 00DE0A33 85FF TEST EDI,EDI 00DE0A35 74 45 JE SHORT qc.00DE0A7C 00DE0A37 68 68C4DE00 PUSH qc.00DEC468 00DE0A3C FF15 24BEDE00 CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleA>] 00DE0A42 85C0 TEST EAX,EAX 00DE0A44 74 2F JE SHORT qc.00DE0A75 00DE0A46 68 4CC4DE00 PUSH qc.00DEC44C ; ASCII "ZwQueryInformationProcess" 00DE0A4B 50 PUSH EAX 00DE0A4C FF15 14BEDE00 CALL DWORD PTR DS:[<&KERNEL32.GetProcAddress>] 00DE0A52 85C0 TEST EAX,EAX 00DE0A54 74 1F JE SHORT qc.00DE0A75 00DE0A56 215D F8 AND DWORD PTR SS:[EBP-8],EBX 00DE0A59 215D FC AND DWORD PTR SS:[EBP-4],EBX 00DE0A5C 8D4D F8 LEA ECX,DWORD PTR SS:[EBP-8] 00DE0A5F 51 PUSH ECX 00DE0A60 6A 04 PUSH 4 00DE0A62 8D4D FC LEA ECX,DWORD PTR SS:[EBP-4] 00DE0A65 51 PUSH ECX 00DE0A66 6A 07 PUSH 7 00DE0A68 57 PUSH EDI 00DE0A69 FFD0 CALL EAX <--- Вызывается ZwQueryInformationProcess 00DE0A6B 85C0 TEST EAX,EAX 00DE0A6D 75 06 JNZ SHORT qc.00DE0A75 00DE0A6F 3945 FC CMP DWORD PTR SS:[EBP-4],EAX 00DE0A72 74 01 JE SHORT qc.00DE0A75 00DE0A74 43 INC EBX 00DE0A75 57 PUSH EDI 00DE0A76 FF15 C4BDDE00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle>] 00DE0A7C 5F POP EDI 00DE0A7D 8BC3 MOV EAX,EBX 00DE0A7F 7A 06 JPE SHORT qc.00DE0A87 00DE0A81 7B 03 JPO SHORT qc.00DE0A86 00DE0A83 C783 90907A04 7B>MOV DWORD PTR DS:[EBX+47A9090],1265027B 00DE0A8D 74 03 JE SHORT qc.00DE0A92 00DE0A8F 75 01 JNZ SHORT qc.00DE0A92 Т.е. открывается процесс нашего исполняемого файла (EAX@Openprocess = exe pid) и затем выбирается адрес функции “ZwQueryInformationProcess”. Затем этот адрес хранится в EAX и вызывается по адресу 00DE0A69. Если "Being Debugged", то в ЕАХ возвращается 0. Окей, где это мы были? Изменяя возвращаемое в ЕАХ значение на 0 для IsDebuggerPresent и изменить EAX на 1 для ZwQueryInformationProcess, то всё у нас прокатит. Ладно, чтобы сохранить вам немного времени, я скажу вам, что случится если вы просто измените значение регистра EAX сразу после возвращения от API. Снова и снова (несколько раз) будет вызванна та же процедура, так что не нужно этого делать. Альтернатива - сделать прямой старый добрый патч. :) Для примера, запомните вот этот кусок кода: 00DE0974 8BD8 MOV EBX,EAX 00DE0976 7D 05 JGE SHORT qc.00DE097D 00DE0978 7C 08 JL SHORT qc.00DE0982 В данном случаем, при запуске вы увидите, что EDX = 0, так что нам нужно изменить MOV EBX,EAX на MOV EBX,EDX. Далее займёмся ZwQueryInformationProcess. У нас было вот что: 00DE0A69 FFD0 CALL EAX 00DE0A6B 85C0 TEST EAX,EAX 00DE0A6D 75 06 JNZ SHORT qc.00DE0A75 Изменение TEST EAX,EAX на INC EAX сработает. Сделано! Теперь должно запуститься... нет? "The Alladin HASP SL Runtime that the memory of component PRVSL (qc.exe) has been tampered with. The program has ben terminated." От бля! Что теперь делать?!??! Всё снова! Загружаем исполняемый файл в Olly и я вам всё сражу. 7C812E03 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18] 7C812E09 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30] 7C812E0C 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2] 7C812E10 C3 RETN 7C812E11 90 NOP 7C812E12 90 NOP 7C812E13 90 NOP 7C812E14 90 NOP 7C812E15 90 NOP Помните старый добрый kernel32.dll? ТАм есть дочерта места, вы так не думаете? Как насчёт того, чтобы сделать этому кернелу кое-какие временные апгрейды? :) 7C812E03 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18] 7C812E09 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30] 7C812E0C 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2] 7C812E10 33C0 XOR EAX,EAX 7C812E12 C3 RETN 7C812E13 90 NOP От так лучше! А вот теперь время побрить :) ntdll.dll (@ZwQueryInformationProcess): 7C90E01B > B8 9A000000 MOV EAX,9A 7C90E020 BA 0003FE7F MOV EDX,7FFE0300 7C90E025 FF12 CALL DWORD PTR DS:[EDX] 7C90E027 C2 1400 RETN 14 7C90E02A 90 NOP 7C90E02B 90 NOP 7C90E02C 90 NOP 7C90E02D 90 NOP Побрили: 7C90E01B > B8 9A000000 MOV EAX,9A 7C90E020 BA 0003FE7F MOV EDX,7FFE0300 7C90E025 FF12 CALL DWORD PTR DS:[EDX] 7C90E027 40 INC EAX 7C90E028 C2 1400 RETN 14 7C90E02B 90 NOP 7C90E02C 90 NOP Конечно нужно будет поставить нуные брейкпоинты, походить по функциям, сделать изменения и затем снять брейкпоинты. Что теперь? Получится у нас или нет? Да! Программа в конце концов запустилась. Мы видим триальное окошко. Ну а теперь (по идее) делам так: жмём alt+m, подсвечиваем секцию .text нашего исполняемого файла, жмём F2 (ставим break-on-access), выбираем “I would like to try...” и жмём “next” на окошке триала и... Бах! Вы на OEP. Но... тут такое не сработает. Хотя тоже не сильно сложно. Посто поставьте F2 (break-on-access) на секцию данных (.data) вместо .text. Olly остановится тут: 00DDE080 8A1C3E MOV BL,BYTE PTR DS:[ESI+EDI] 00DDE083 3A1F CMP BL,BYTE PTR DS:[EDI] 00DDE085 7A 04 JPE SHORT qc.00DDE08B 00DDE087 7B 05 JPO SHORT qc.00DDE08E 00DDE089 C786 90669087 D2>MOV DWORD PTR DS:[ESI+87906690],710770D2 00DDE093 02C7 ADD AL,BH 00DDE095 8690 66909066 XCHG BYTE PTR DS:[EAX+66909066],DL 00DDE09B 90 NOP 00DDE09C 72 03 JB SHORT qc.00DDE0A1 00DDE09E 73 01 JNB SHORT qc.00DDE0A1 00DDE0A0 C2 7D05 RETN 57D 00DDE0A3 7C 08 JL SHORT qc.00DDE0AD Теперь снова жмём alt+m снова и ставим breakpoint (F2) на секцию текста (.text). Запускаем и бум-с, приземляемся на OEP!! Ну адалее стандартная процедура: дампим, перестраиваем и перепаковываем, как хотите. Согласно HASP SL SDK2 (страница 19 в мануале) существуют функции в этом протекторе для включения разных уровней и шифрования и обфускации. Ну и конечно есть фукция обнаружения дебаггера. Вот почему такое разное поведение в разных программах. Например Minitab 14.20 и Quality Companion 2.1.0.0. Сравните эти две секции кода: Minitab 14.20 (HASP SL 6.41) 00BAA4BC 8BD8 MOV EBX,EAX 00BAA4BE 85DB TEST EBX,EBX 00BAA4C0 0F85 AC000000 JNZ Mtb14org.00BAA572 00BAA4C6 57 PUSH EDI 00BAA4C7 90 NOP 00BAA4C8 90 NOP 00BAA4C9 6A 24 PUSH 24 00BAA4CB 90 NOP 00BAA4CC 59 POP ECX 00BAA4CD 8DBD 68FFFFFF LEA EDI,DWORD PTR SS:[EBP-98] 00BAA4D3 F3:AB REP STOS DWORD PTR ES:[EDI] 00BAA4D5 90 NOP 00BAA4D6 8D85 64FFFFFF LEA EAX,DWORD PTR SS:[EBP-9C] 00BAA4DC 50 PUSH EAX 00BAA4DD 90 NOP 00BAA4DE C785 64FFFFFF 94>MOV DWORD PTR SS:[EBP-9C],94 00BAA4E8 FF15 4CF8BA00 CALL DWORD PTR DS:[<&KERNEL32.GetVersion> 00BAA4EE 85C0 TEST EAX,EAX 00BAA4F0 74 7F JE SHORT Mtb14org.00BAA571 00BAA4F2 83BD 74FFFFFF 02 CMP DWORD PTR SS:[EBP-8C],2 00BAA4F9 75 76 JNZ SHORT Mtb14org.00BAA571 00BAA4FB FF15 48F8BA00 CALL DWORD PTR DS:[<&KERNEL32.GetCurrentProcessId> 00BAA501 50 PUSH EAX 00BAA502 53 PUSH EBX 00BAA503 68 00040000 PUSH 400 00BAA508 90 NOP 00BAA509 90 NOP 00BAA50A 90 NOP 00BAA50B FF15 44F8BA00 CALL DWORD PTR DS:[<&KERNEL32.OpenProcess> 00BAA511 8BF8 MOV EDI,EAX 00BAA513 90 NOP 00BAA514 90 NOP 00BAA515 90 NOP 00BAA516 90 NOP 00BAA517 85FF TEST EDI,EDI 00BAA519 74 56 JE SHORT Mtb14org.00BAA571 00BAA51B 68 88FEBA00 PUSH Mtb14org.00BAFE88 ; ASCII "ntdll.dll" 00BAA520 90 NOP 00BAA521 FF15 50F8BA00 CALL DWORD PTR DS:[<&KERNEL32.GetModuleH> 00BAA527 85C0 TEST EAX,EAX 00BAA529 74 3F JE SHORT Mtb14org.00BAA56A 00BAA52B 90 NOP 00BAA52C 90 NOP 00BAA52D 68 6CFEBA00 PUSH Mtb14org.00BAFE6C ; ASCII "ZwQueryInformationProcess" 00BAA532 90 NOP 00BAA533 90 NOP 00BAA534 50 PUSH EAX 00BAA535 90 NOP 00BAA536 90 NOP 00BAA537 90 NOP 00BAA538 FF15 3CF8BA00 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd> 00BAA53E 85C0 TEST EAX,EAX 00BAA540 74 28 JE SHORT Mtb14org.00BAA56A 00BAA542 215D F8 AND DWORD PTR SS:[EBP-8],EBX 00BAA545 90 NOP 00BAA546 215D FC AND DWORD PTR SS:[EBP-4],EBX 00BAA549 8D4D F8 LEA ECX,DWORD PTR SS:[EBP-8] 00BAA54C 90 NOP 00BAA54D 90 NOP 00BAA54E 90 NOP 00BAA54F 51 PUSH ECX 00BAA550 6A 04 PUSH 4 00BAA552 8D4D FC LEA ECX,DWORD PTR SS:[EBP-4] 00BAA555 51 PUSH ECX 00BAA556 6A 07 PUSH 7 00BAA558 90 NOP 00BAA559 90 NOP 00BAA55A 57 PUSH EDI 00BAA55B FFD0 CALL EAX 00BAA55D 85C0 TEST EAX,EAX 00BAA55F 75 09 JNZ SHORT Mtb14org.00BAA56A 00BAA561 90 NOP 00BAA562 3945 FC CMP DWORD PTR SS:[EBP-4],EAX 00BAA565 74 03 JE SHORT Mtb14org.00BAA56A 00BAA567 90 NOP 00BAA568 90 NOP 00BAA569 43 INC EBX 00BAA56A 57 PUSH EDI 00BAA56B FF15 F4F7BA00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandle> 00BAA571 5F POP EDI 00BAA572 8BC3 MOV EAX,EBX 00BAA574 5B POP EBX 00BAA575 90 NOP 00BAA576 C9 LEAVE 00BAA577 C3 RETN ..и из Quality Companion 2.1.0.0 (так же HASP SL 6.41) 00DE0974 8BD8 MOV EBX,EAX 00DE0976 7D 05 JGE SHORT qc.00DE097D 00DE0978 7C 08 JL SHORT qc.00DE0982 00DE097A C786 90669090 66>MOV DWORD PTR DS:[ESI+90906690],57D9066 00DE0984 7C 08 JL SHORT qc.00DE098E 00DE0986 C786 90669090 66>MOV DWORD PTR DS:[ESI+90906690],DB859066 00DE0990 7A 06 JPE SHORT qc.00DE0998 00DE0992 7B 03 JPO SHORT qc.00DE0997 00DE0994 C783 90900F85 DF>MOV DWORD PTR DS:[EBX+850F9090],0DF 00DE099E 74 04 JE SHORT qc.00DE09A4 00DE09A0 75 02 JNZ SHORT qc.00DE09A4 00DE09A2 C786 90576A24 87>MOV DWORD PTR DS:[ESI+246A5790],7059C987 00DE09AC 06 PUSH ES 00DE09AD 71 04 JNO SHORT qc.00DE09B3 00DE09AF 81BE 66908DBD 68>CMP DWORD PTR DS:[ESI+BD8D9066],-98 00DE09B9 F3:AB REP STOS DWORD PTR ES:[EDI] 00DE09BB 70 04 JO SHORT qc.00DE09C1 00DE09BD 71 02 JNO SHORT qc.00DE09C1 00DE09BF 8DBD 7A047B02 LEA EDI,DWORD PTR SS:[EBP+27B047A] 00DE09C5 83C4 8D ADD ESP,-73 00DE09C8 8564FF FF TEST DWORD PTR DS:[EDI+EDI*8-1],ESP 00DE09CC FF7D ??? 00DE09CE 05 7C05C786 ADD EAX,86C7057C 00DE09D3 0087 D2507D06 ADD BYTE PTR DS:[EDI+67D50D2],AL 00DE09D9 7C 03 JL SHORT qc.00DE09DE 00DE09DB C745 FC 669090C7 MOV DWORD PTR SS:[EBP-4],C7909066 00DE09E2 8564FF FF TEST DWORD PTR DS:[EDI+EDI*8-1],ESP 00DE09E6 FF9400 0000FF15 CALL DWORD PTR DS:[EAX+EAX+15FF0000] 00DE09ED ^E0 BD LOOPDNE SHORT qc.00DE09AC 00DE09EF DE00 FIADD WORD PTR DS:[EAX] 00DE09F1 72 03 JB SHORT qc.00DE09F6 00DE09F3 73 01 JNB SHORT qc.00DE09F6 00DE09F5 C2 85C0 RETN 0C085 00DE09F8 7A 06 JPE SHORT qc.00DE0A00 00DE09FA 7B 02 JPO SHORT qc.00DE09FE 00DE09FC 8DBD 9090747A LEA EDI,DWORD PTR SS:[EBP+7A749090] 00DE0A02 83BD 74FFFFFF 02 CMP DWORD PTR SS:[EBP-8C],2 00DE0A09 70 05 JO SHORT qc.00DE0A10 00DE0A0B 71 02 JNO SHORT qc.00DE0A0F 00DE0A0D 65:1290 756A7007 ADC DL,BYTE PTR GS:[EAX+7706A75] 00DE0A14 71 02 JNO SHORT qc.00DE0A18 00DE0A16 C786 90669090 66>MOV DWORD PTR DS:[ESI+90906690],15FF9066 00DE0A20 20BE DE005053 AND BYTE PTR DS:[ESI+535000DE],BH 00DE0A26 68 00040000 PUSH 400 00DE0A2B FF15 1CBEDE00 CALL DWORD PTR DS:[<&KERNEL32.OpenProcess> 00DE0A31 8BF8 MOV EDI,EAX 00DE0A33 85FF TEST EDI,EDI 00DE0A35 74 45 JE SHORT qc.00DE0A7C 00DE0A37 68 68C4DE00 PUSH qc.00DEC468 ; ASCII "ntdll.dll" 00DE0A3C FF15 24BEDE00 CALL DWORD PTR DS:[<&KERNEL32.GetModuleHandleA> 00DE0A42 85C0 TEST EAX,EAX 00DE0A44 74 2F JE SHORT qc.00DE0A75 00DE0A46 68 4CC4DE00 PUSH qc.00DEC44C ; ASCII "ZwQueryInformationProcess" 00DE0A4B 50 PUSH EAX 00DE0A4C FF15 14BEDE00 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd>; kernel32.GetProcAddress 00DE0A52 85C0 TEST EAX,EAX 00DE0A54 74 1F JE SHORT qc.00DE0A75 00DE0A56 215D F8 AND DWORD PTR SS:[EBP-8],EBX 00DE0A59 215D FC AND DWORD PTR SS:[EBP-4],EBX 00DE0A5C 8D4D F8 LEA ECX,DWORD PTR SS:[EBP-8] 00DE0A5F 51 PUSH ECX 00DE0A60 6A 04 PUSH 4 00DE0A62 8D4D FC LEA ECX,DWORD PTR SS:[EBP-4] 00DE0A65 51 PUSH ECX 00DE0A66 6A 07 PUSH 7 00DE0A68 57 PUSH EDI 00DE0A69 FFD0 CALL EAX 00DE0A6B 85C0 TEST EAX,EAX 00DE0A6D 75 06 JNZ SHORT qc.00DE0A75 00DE0A6F 3945 FC CMP DWORD PTR SS:[EBP-4],EAX 00DE0A72 74 01 JE SHORT qc.00DE0A75 00DE0A74 43 INC EBX 00DE0A75 57 PUSH EDI 00DE0A76 FF15 C4BDDE00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>; kernel32.CloseHandle 00DE0A7C 5F POP EDI 00DE0A7D 8BC3 MOV EAX,EBX Ка видно, во втром примере функция обфускации была включена, так что чуть сложнее проследить ход выполнения. С КАКОЙ ВЕРСИЕЙ МЫ ИМЕЕМ ДЕЛО? Всё просто, отличаются наг-окошки. Если это старая "Privilege" версия, то там иконка с буквой "Р". А если это HASP SL, то иконка там с буквой "Н". А вот версия HASP с которой вы работаете может посмотреть в prv_ee.dll, котоаря можеть быть просмотрена практически сразе же после запуска с помощью alt+e. Последняя версия HASP SL похоже 6.41. ЗАКЛЮЧЕНИЕ Не смотря на то, что HASP SL экипирован несколькими сильным фукциями, например anti-tampering, antidebugging, product activation, шифрование главного исполняемого файла и обфускация кода, это всё равно, как мне кажется, слишком слабая в некоторых моментах защита. Не поймите меня неправильно, некоторые функции очень даже сложно, анализировать из-за anti-tampering'a и anti-debugging'a. Но в этом протекторе нужно слишком много доделать,Что назвать его "прокачанным". Что же дальше? Какая-нибудь защита импорта? Более экстремальная обфускация кода? Более сильные anti-debugging приёмны? Только будущее покажет.