Автор: | ViNCE [AHTeam] |
Уровень: | Для начинающих |
Программа: | CrackMe с www.fant0m.cjb.net |
Инструменты: | OllyDebug v1.09d, ProcDUMP, Imprec v1.6 |
iNTRO Начинающим крякерам есть программки для разминки - или просто КРЯКМИ (CrackMe - "Взломай Меня" ). В Инете\РуНете куча крякмисов. Наверное, все известные на Revering-сцене группы (команды) наверстали свои крякмисы... Прям стандарт какой-то :)) Сегодня мы рассмотрим исследование крякмисов от Fant0m'а.
[Fant0m CrackMe #1] Как пишет Fant0m - это его самый первый крякмис и... "расслабьтесь" :)) Запускаем crackme.exe и видим поле для ввода серийника. Вводим, жмём OK - пишет, что "Wron Password! Keep trying, you'll get it!". Хм... Открываем crackme.exe в OllyDebug (далее - просто "Олли"). Сразу видим такой код:
00401000 >/$ 6A 00 PUSH 0 ; /pModule = NULL <<- МЫ ТУТ! 00401002 |. E8 45030000 CALL [JMP.&KERNEL32.GetModuleHandleA] ; \GetModuleHandleA 00401007 |. A3 94304000 MOV DWORD PTR DS:[403094],EAX 0040100C |. E8 35030000 CALL [JMP.&KERNEL32.GetCommandLineA] ; Получаем параметры ; командной строки 00401011 |. A3 98304000 MOV DWORD PTR DS:[403098],EAX 00401016 |. 6A 01 PUSH 1 ; /Arg4 = 00000001 00401018 |. FF35 98304000 PUSH DWORD PTR DS:[403098] ; |Arg3 = 00000000 0040101E |. 6A 00 PUSH 0 ; |Arg2 = 00000000 00401020 |. FF35 94304000 PUSH DWORD PTR DS:[403094] ; |Arg1 = 00000000 00401026 |. E8 07000000 CALL CRACKME1.00401032 ; Собственно, вызов тела крякмиса 0040102B |. 6A 00 PUSH 0 ; /ExitCode = 0 0040102D \. E8 0E030000 CALL [JMP.&KERNEL32.ExitProcess] ; Закрываемся Теперь трассируем с точки входа (00401000) до адреса 00401026 с помощью F8 и заходим в call с помощью F7. Теперь мы в коде крякмиса... Хотя - он нам не нужен :)) Смотрим hex-дамп:
00403000 44 4C 47 43 4C 41 53 53 DLGCLASS 00403008 00 4D 61 69 6E 44 69 61 .MainDia 00403010 6C 6F 67 00 41 62 6F 75 log.Abou 00403018 74 44 69 61 6C 6F 67 00 tDialog. 00403020 4D 61 69 6E 4D 65 6E 75 MainMenu 00403028 00 6D 30 74 4E 61 46 2D .m0tNaF- 00403030 45 6D 4B 43 41 52 63 00 EmKCARc. 00403038 43 68 65 63 6B 20 53 74 Check St 00403040 61 74 75 73 00 57 72 6F atus.Wro 00403048 6E 67 20 50 61 73 73 77 ng Passw 00403050 6F 72 64 21 20 4B 65 65 ord! Kee 00403058 70 20 74 72 79 69 6E 67 p trying 00403060 2C 20 79 6F 75 27 6C 6C , you'll 00403068 20 67 65 74 20 69 74 21 get it! 00403070 00 59 6F 75 20 67 6F 74 .You got 00403078 20 69 74 21 20 59 6F 75 it! You 00403080 72 20 6E 6F 77 20 61 20 r now a 00403088 63 72 61 63 6B 65 72 21 cracker! 00403090 20 3A 29 00 00 00 40 00 :)...@. 00403098 E0 1E 14 00 а. Видим следущие строки: 00403028 00 6D 30 74 4E 61 46 2D .m0tNaF- 00403030 45 6D 4B 43 41 52 63 00 EmKCARc. Должно быть странным, что строка cRACKmE-FaNt0m записана наоборот?! Вот и я так сразу же подумал... Адреса в hex-е пишутся не по порядку, но чтобы строки наоборот - это смешно! Так что берём строку (не переворачивая): m0tNaF-EmKCARc Вводим в крякмис и видим сообщение: You got it! Your now a cracker! Вот и всё!
[Fant0m CrackMe #2] Далее я качнул второй крякмис... Здесь задача поменялась. Теперь Fant0m сделал показ двух нагов: - Вида MessageBox - Вида DialogBox Оба нага вылазят при старте программы. Запускаем crackme.exe в Олли и попадаем в стартовый код (такой же как и в первом крякми), заходим в главную процедуру: 00401026 |. E8 07000000 CALL CRACKME2.00401032 ; \CRACKME2.00401032 и видим код:
00401032 /$ 55 PUSH EBP 00401033 |. 8BEC MOV EBP,ESP 00401035 |. 83C4 B0 ADD ESP,-50 00401038 |. C745 D0 300000>MOV DWORD PTR SS:[EBP-30],30 0040103F |. C745 D4 030000>MOV DWORD PTR SS:[EBP-2C],3 00401046 |. C745 D8 2C1140>MOV DWORD PTR SS:[EBP-28],CRACKME2.00401> 0040104D |. C745 DC 000000>MOV DWORD PTR SS:[EBP-24],0 00401054 |. C745 E0 1E0000>MOV DWORD PTR SS:[EBP-20],1E 0040105B |. FF35 6C304000 PUSH DWORD PTR DS:[40306C] ; CRACKME2.00400000 00401061 |. 8F45 E4 POP DWORD PTR SS:[EBP-1C] 00401064 |. C745 F0 100000>MOV DWORD PTR SS:[EBP-10],10 0040106B |. C745 F4 203040>MOV DWORD PTR SS:[EBP-C],CRACKME2.004030>; ASCII "MAINMENU" 00401072 |. C745 F8 003040>MOV DWORD PTR SS:[EBP-8],CRACKME2.004030>; ASCII "DLGCLASS" 00401079 |. 6A 69 PUSH 69 ; /RsrcName = 105. 0040107B |. FF35 6C304000 PUSH DWORD PTR DS:[40306C] ; |hInst = 00400000 00401081 |. E8 1C020000 CALL [JMP.&USER32.LoadIconA] ; \LoadIconA 00401086 |. 8945 E8 MOV DWORD PTR SS:[EBP-18],EAX 00401089 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX 0040108C |. 68 007F0000 PUSH 7F00 ; /RsrcName = IDC_ARROW 00401091 |. 6A 00 PUSH 0 ; |hInst = NULL 00401093 |. E8 04020000 CALL [JMP.&USER32.LoadCursorA] ; \LoadCursorA 00401098 |. 8945 EC MOV DWORD PTR SS:[EBP-14],EAX 0040109B |. 8D45 D0 LEA EAX,DWORD PTR SS:[EBP-30] 0040109E |. 50 PUSH EAX ; /pWndClassEx 0040109F |. E8 10020000 CALL [JMP.&USER32.RegisterClassExA] ; \RegisterClassExA 004010A4 |. 6A 00 PUSH 0 ; /lParam = 0 004010A6 |. 6A 00 PUSH 0 ; |pDlgProc = NULL 004010A8 |. 6A 00 PUSH 0 ; |hOwner = NULL 004010AA |. 68 09304000 PUSH CRACKME2.00403009 ; |pTemplate = "MAINDIALOG" 004010AF |. FF35 6C304000 PUSH DWORD PTR DS:[40306C] ; |hInst = 00400000 004010B5 |. E8 B8010000 CALL [JMP.&USER32.CreateDialogParamA] ; \CreateDialogParamA 004010BA |. 8945 B0 MOV DWORD PTR SS:[EBP-50],EAX 004010BD |. FF75 14 PUSH DWORD PTR SS:[EBP+14] ; /ShowState 004010C0 |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; |hWnd 004010C3 |. E8 F8010000 CALL [JMP.&USER32.ShowWindow] ; \ShowWindow 004010C8 |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; /hWnd 004010CB |. E8 FC010000 CALL [JMP.&USER32.UpdateWindow] ; \UpdateWindow 004010D0 |. 6A 30 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 004010D2 |. 68 33304000 PUSH CRACKME2.00403033 ; |Title = "Remove me!" 004010D7 |. 68 3E304000 PUSH CRACKME2.0040303E ; |Text = "Nag Nag Nag... Remove me!
Nag Nag Nag..." 004010DC |. 6A 00 PUSH 0 ; |hOwner = NULL 004010DE |. E8 C5010000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 004010E3 |. 6A 00 PUSH 0 ; /lParam = NULL 004010E5 |. 68 10124000 PUSH CRACKME2.00401210 ; |DlgProc = CRACKME2.00401210 004010EA |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; |hOwner 004010ED |. 68 29304000 PUSH CRACKME2.00403029 ; |pTemplate = "NAGDIALOG" 004010F2 |. FF35 6C304000 PUSH DWORD PTR DS:[40306C] ; |hInst = 00400000 004010F8 |. E8 87010000 CALL [JMP.&USER32.DialogBoxParamA] ; Вызываем наг DialogBox Как мы видим... Первый наг расположился в диапазоне от 004010D0 до 004010DE. Чтобы его убить нужно просто поменять код:
004010D0 |. 6A 30 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 004010D2 |. 68 33304000 PUSH CRACKME2.00403033 ; |Title = "Remove me!" 004010D7 |. 68 3E304000 PUSH CRACKME2.0040303E ; |Text = "Nag Nag Nag...
Remove me!
Nag Nag Nag..." 004010DC |. 6A 00 PUSH 0 ; |hOwner = NULL 004010DE |. E8 C5010000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA на:
004010D0 |. 90 90 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 004010D2 |. 90 90909090 PUSH CRACKME2.00403033 ; |Title = "Remove me!" 004010D7 |. 90 90909090 PUSH CRACKME2.0040303E ; |Text = "Nag Nag Nag...
Remove me!
Nag Nag Nag..." 004010DC |. 90 90 PUSH 0 ; |hOwner = NULL 004010DE |. 90 90909090 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA Соответственно вместо прежнего набора команд будут 19 команд NOP (No operation - "Ничего не делать"). Также поступаем и со вторым нагом, меняем:
004010E3 |. 6A 00 PUSH 0 ; /lParam = NULL 004010E5 |. 68 10124000 PUSH CRACKME2.00401210 ; |DlgProc = CRACKME2.00401210 004010EA |. FF75 B0 PUSH DWORD PTR SS:[EBP-50] ; |hOwner 004010ED |. 68 29304000 PUSH CRACKME2.00403029 ; |pTemplate = "NAGDIALOG" 004010F2 |. FF35 6C304000 PUSH DWORD PTR DS:[40306C] ; |hInst = 00400000 004010F8 |. E8 87010000 CALL [JMP.&USER32.DialogBoxParamA] ; Вызываем наг DialogBox на
004010E3 |. 90 90 PUSH 0 ; /lParam = NULL 004010E5 |. 90 90909090 PUSH CRACKME2.00401210 ; |DlgProc = CRACKME2.00401210 004010EA |. 9090 90 PUSH DWORD PTR SS:[EBP-50] ; |hOwner 004010ED |. 90 90909090 PUSH CRACKME2.00403029 ; |pTemplate = "NAGDIALOG" 004010F2 |. 9090 90909090 PUSH DWORD PTR DS:[40306C] ; |hInst = 00400000 004010F8 |. 90 90909090 CALL [JMP.&USER32.DialogBoxParamA] ; Вызываем наг DialogBox Вот и второй наг убит... Можно было сделать ещё проще - убить call'ы по адресам: 004010DE и 004010F8 Или замутить перед вызовом нагов безусловный переходик (jmp), который бы перепрыгивал их... :))
[Fant0m CrackMe #3] Два уже убиты - возьмёмся за третий... Качаем и запускаем. Здесь Fant0m предлагает обойти проверку CD. Т.е. если crackme'с загружен с CD, то всё OK, в противном случае - Error. Получается - что этот крякмис создан для тренировки в обходе простейших CD-защит. Закрываем крякмис и загружаем его через Олли. Тут ничего интересного пока не намечается. Только в дампе мы видим надпись в случае успешного определения CD: "Found a CDROM. Good Job!". Мы видели что сообщение об ошибке вызывается в виде простого MessageBox'а. Ставим в Олли бряк: bpx MessageBoxA Теперь нажимаем в крякмисе в меню "CD Check" и срабатывает бряк. Отлично! Теперь мы видим следующий код:
004011FA |. 6A 00 PUSH 0 ; /RootPathName = NULL 004011FC |. E8 99000000 CALL [JMP.&KERNEL32.GetDriveTypeA] ; \GetDriveTypeA 00401201 |. 83F8 05 CMP EAX,5 00401204 |. 74 17 JE SHORT CRACKME3.0040121D ; Если загружены с CD, то прыгаем ; и сообщаем что всё OK! :)) 00401206 |. 6A 30 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 00401208 |. 68 14304000 PUSH CRACKME3.00403014 ; |Title = "FaNt0m's CrackMe ; #3 -- CD Check" 0040120D |. 68 40304000 PUSH CRACKME3.00403040 ; |Text = "Error finding CDROM" 00401212 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401214 |. E8 51000000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 00401219 |. C9 LEAVE 0040121A |. C2 0400 RETN 4 0040121D |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 0040121F |. 68 14304000 PUSH CRACKME3.00403014 ; |Title = "FaNt0m's CrackMe ; #3 -- CD Check" 00401224 |. 68 54304000 PUSH CRACKME3.00403054 ; |Text = "Found a CDROM! ; Good job!" 00401229 |. 6A 00 PUSH 0 ; |hOwner = NULL 0040122B |. E8 3A000000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA Здесь всё просто: Сначала вызывается функция GetDriveTypeA, которая получает значение типа integer, определяющее тип носителя с которого загружена крякмис.
004011FC |. E8 99000000 CALL [JMP.&KERNEL32.GetDriveTypeA] Далее идёт сравнение:
00401201 |. 83F8 05 CMP EAX,5 Если результат выполнения функции равен 5 (а это значит, что мы загрузились с CD), то осуществляется переход:
00401204 |. 74 17 JE SHORT CRACKME3.0040121D ; if EQUAL (Если равно) И выдаётся сообщение об верном носителе... Что тут делать? Да просто поменять условный переход je на безусловный jmp:
00401204 |. 74 17 JE SHORT CRACKME3.0040121D ; if EQUAL (Если равно) на
00401204 |. EB 17 JMP SHORT CRACKME3.0040121D ; Прыгаем по-любому :)) Запускаем - жмём "CD Check" - выдаёт сообщение, что всё впорядке!
[Fant0m CrackMe #4] Fant0m решил усложнить задачу исследователю и сделал 4-й крякмис. Здесь требуется найти алгоритм создания правильного регистрационного номера от введённого имени пользователя. Открываем крякмис в Олли и отпускаем его на волю. Прога загрузится. Вводим имя (к примеру: ViNCE) и рег.номер: 7777771. В Олли ставим бряк на чтения из поля ввода: bpx GetDlgItemTextA (сразу скажу что бряк на GetWindowTextA не прокатит) Жмём в крякмисе OK и прога прерывается. Чуток трассируем код по F8 и видим такой вот цикл генерации правильного регистрационного номера. В комментариях я укажу все действия алгоритма:
00401310 |> 803E 00 /CMP BYTE PTR DS:[ESI],0 ; Сравниваем - уже конец строки с именем? 00401313 |. 74 15 |JE SHORT CRACKME4.0040132A ; Если да - выходим из цикла генерации 00401315 |. 8A06 |MOV AL,BYTE PTR DS:[ESI] ; Берём n-ный символ имени (точнее его ASCII ; значение (Например: A1 - это 'A') 00401317 |. 02C1 |ADD AL,CL ; Прибавляем к A1 значение CL. Здесь CL - это ; порядковый номер тек.символа в строке с именем ; Но здесь следует учесть, что нумерация идёт с 0. Т.е. в слове ViNCE буква 'N' имеет позицию ; не 3, а 2. Предположим что наша буква 'A' имела позицию в слове 3. Так что выполняется следующая ; операция: ; AL:=AL+CL=A1+03=A4
00401319 |. 32C1 |XOR AL,CL ; Здесь делаем операцию XOR над AL и CL. ; AL:=AL xor CL = A4 xor 3 = A0 0040131B |. F6F3 |DIV BL ; Делим значение AL на константу BL. Смотрим ; содержимое регистра EBX и видим в BL=1A ; Здесь не просто команда деления. Она выполняет два действия: ; - Сперва делится всё как положено: AL:=AL div BL = A0 div 1A = 06 ; - Теперь вычитаем из A0 значение 1A шесть раз и получаем 04. ; - Записываем 04 в AH. В итоге получаем содержимое EAX: 00000406
0040131D |. 66:C1E8 08 |SHR AX,8 ; Осуществляем сдвиг вправо в регистре AX ; и получаем из 0406 => 04 00401321 |. 04 41 |ADD AL,41 ; Прибавляем к 04 константу 41 и получаем: AL=45 00401323 |. 8807 |MOV BYTE PTR DS:[EDI],AL ; Из 45 получаем ещё один символ ; регистрационного кода: 45h => 'E' ; Здесь идут всякие счётчики 00401325 |. 47 |INC EDI ; CRACKME4.00403286 00401326 |. 46 |INC ESI 00401327 |. 41 |INC ECX 00401328 |.EB E6 \JMP SHORT CRACKME4.00401310 ;Возвращаемся к началу цикла Для примера: Имя: ViNCE Номер: IDERZ В результате получаем сообщение об верном номере: "You got it! Congrats! :)"
[Fant0m CrackME #5] Когда я прочитал readme.txt к этому крякмису я был удивлён... Здесь Fant0m просто собрал всё то, что было до этого во всех 4-х крякмисах. Так что начнём по порядку... Запускаем крякмис и в меню "Protection" видим пункты: - Password - NAG - CD Check - Name/Serial Велосипед изобретать не будем - начнём с нахождения пароля. Открываем наш крякмис в Олли и отпускаем его в работу. Теперь открываем первый пункт защиты - "Password". Тут вводим любой код. В Олли ставим бряк: bpx GetDlgItemTextA ;на чтение из поля ввода В КрякМисе жмём "Check" и прога прервётся здесь:
00401353 |. E8 F4030000 CALL [JMP.&USER32.GetDlgItemTextA] ; \GetDlgItemTextA 00401358 |. 68 B8334000 PUSH CRACKME5.004033B8 ; /String2 = "" 0040135D |. 68 A2304000 PUSH CRACKME5.004030A2 ; |String1 = "JD39-CK4-5QV345" 00401362 |. E8 51040000 CALL [JMP.&KERNEL32.lstrcmpA] ; \lstrcmpA Забавно, правда? "Только собрались ехать - а уже на месте" :)) Деактивируем все бряки. Запускаем крякмис и вводим пароль - всё в порядке! :)) Следующий пункт меню "Protection" - это "NAG". Здесь два нага: MessageBox и DialogBox. Ставим в Олли бряк: bpx MessageBoxA Отпускаем крякмис в отладчике и кликаем по меню "NAG". Прога прервётся тут:
00401424 /$ 6A 30 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 00401426 |. 68 4A314000 PUSH CRACKME5.0040314A ; |Title = "Remove me!" 0040142B |. 68 55314000 PUSH CRACKME5.00403155 ; |Text = "Nag Nag Nag
Remove this message box!
Nag Nag Nag" 00401430 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401432 |. E8 33030000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA Ладно - пусть наг выполниться. Трассируем и выходим из процедуры вызова этого нага. Мы окажемся здесь:
004011C8 |> E8 57020000 CALL CRACKME5.00401424 004011CD |. 8D05 C3134000 LEA EAX,DWORD PTR DS:[4013C3] ; << МЫ ЗДЕСЬ В ОТЛАДЧИКЕ 004011D3 |. 6A 00 PUSH 0 ; /lParam = NULL 004011D5 |. 50 PUSH EAX ; |DlgProc => CRACKME5.004013C3 004011D6 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner 004011D9 |. 68 3C304000 PUSH CRACKME5.0040303C ; |pTemplate = "NAGDIALOG" 004011DE |. FF35 B0314000 PUSH DWORD PTR DS:[4031B0] ; |hInst = 00400000 004011E4 |. E8 4B050000 CALL [JMP.&USER32.DialogBoxParamA] ; \DialogBoxParamA После выхода из процедуры вызова нага нас вынесет на адрес 004011CD. Ниже мы видим вызов второго нага - DialogBoxParamA. Как от этого избавиться? Занопить? Nop... Nop... Nop... Нет! Можно сделать более короткий патч - всего из двух байтов. Так как наг вызывается из пункта меню - следовательно где-то в коде есть переключатель, который отвечает за выбранный пункт меню и осуществляет переход туда куда надо. Найти этот переход легко. Всё что связанно с нагами начинается с адреса 004011C8. Ищем выше по коду прыжок на этот адрес. Вот он:
00401167 |. 74 5F JE SHORT CRACKME5.004011C8 Меняем 745F на 9090, т.е. на два NOP'а. Наги мы сняли. Следующая защита - "CD Check". Перезапускаем крякмис в отладчике и отпускаем его работать. Теперь ставим бряк на проверку типа носителя: bpx GetDriveTypeA В меню крякмиса жмём "CD Check" и прога прервётся тут:
00401438 /$ 53 PUSH EBX 00401439 |. 50 PUSH EAX 0040143A |. 6A 00 PUSH 0 ; /RootPathName = NULL ; Т.е. никаких путей мы не передаём! 0040143C |. E8 6B030000 CALL [JMP.&KERNEL32.GetDriveTypeA] ; << В ОТЛАДЧИКЕ МЫ ОКАЖЕМСЯ ЗДЕСЬ! 00401441 |. 33DB XOR EBX,EBX 00401443 |. 43 INC EBX 00401444 |. 43 INC EBX 00401445 |. F6F3 DIV BL 00401447 |. 3C 02 CMP AL,2 00401449 |. 75 1C JNZ SHORT CRACKME5.00401467 ;Где CD? Я его не нашёл... потому матюгнусь 0040144B |. 80FC 01 CMP AH,1 0040144E |. 74 02 JE SHORT CRACKME5.00401452 ; Ребята, я нашёл CD-ROM и потому прыгну... 00401450 |. EB 15 JMP SHORT CRACKME5.00401467 ; Ай-Яй-Яй! CD-ROM не найден! Ж(( 00401452 |> 6A 40 PUSH 40 ; /Style = MB_OK| ; MB_ICONASTERISK|MB_APPLMODAL 00401454 |. 68 88314000 PUSH CRACKME5.00403188 ; |Title = "CD Check" 00401459 |. 68 91314000 PUSH CRACKME5.00403191 ; |Text = "CDROM found!" 0040145E |. 6A 00 PUSH 0 ; |hOwner = NULL 00401460 |. E8 05030000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 00401465 |. EB 15 JMP SHORT CRACKME5.0040147C 00401467 |> 6A 30 PUSH 30 ; /Style = MB_OK| ; MB_ICONEXCLAMATION|MB_APPLMODAL 00401469 |. 68 88314000 PUSH CRACKME5.00403188 ; |Title = "CD Check" 0040146E |. 68 9E314000 PUSH CRACKME5.0040319E ; |Text = "CDROM Not found!" 00401473 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401475 |. E8 F0020000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 0040147A |. EB 00 JMP SHORT CRACKME5.0040147C 0040147C |> 58 POP EAX 0040147D |. 5B POP EBX 0040147E \. C3 RETN Здесь всё просто! Меняем два перехода:
00401449 |. 75 1C JNZ SHORT CRACKME5.00401467 на:
00401449 |. 90 NOP 0040144A |. 90 NOP Вот и вся проверочка! :)) Последняя защита - это "Name/Serial". Перезапускаем крякмис в отладчике и тут же его отпускаем на "волю". Залезаем в меню "Protection->Name/Serial". Обзор этого вида регистрации я опущу, т.к. мне просто было лень изучать алгоритм - а он очень простой. Кому интересно, тот может покопать. Комбинацию для своего имени я нашёл: Имя: ViNCE Номер: FCWV-B Вот такой вот крякмис! :))
[Fant0m CrackMe #6] Вот ещё один интересный крякмис. Здесь требуется подобрать ключевой файл. Fant0m добавляет, что патчить крякмис нельзя! Запускаем прогу и видим менюшку "Check It!". Жмём и нам выдаёт - "KeyFile Not Found!". Вай-вай-вай! :)) Открываем крякмис в Олли и ставим бряк на чтение из файла: bpx ReadFile Теперь отпускаем прогу в Олли - пусть она загрузится. После загрузки жмём "Check It!" и КрякМис прерывается здесь:
004010E1 /$ 6A 00 PUSH 0 ; /hTemplateFile = NULL ; <<ВХОД в процедуру "Check It!" ; << В отладчике мы здесь 004010E3 |. 68 80000000 PUSH 80 ; |Attributes = NORMAL ; Начинаем передавать аттрибуты 004010E8 |. 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING 004010EA |. 6A 00 PUSH 0 ; |pSecurity = NULL 004010EC |. 6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ 004010EE |. 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ 004010F3 |. 68 17304000 PUSH CRACKME6.00403017 ; |FileName = "keyfile.dat" 004010F8 |. E8 BD000000 CALL [JMP.&KERNEL32.CreateFileA] ; \CreateFileA 004010FD |. A3 88304000 MOV DWORD PTR DS:[403088],EAX 00401102 |. 83F8 FF CMP EAX,-1 00401105 |. 75 14 JNZ SHORT CRACKME6.0040111B ; Если файл есть, то продолжаем... ; Переходим к чтению из файла 00401107 |. 6A 10 PUSH 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL 00401109 |. 68 23304000 PUSH CRACKME6.00403023 ; |Title = "Error!" 0040110E |. 68 2A304000 PUSH CRACKME6.0040302A ; |Text = "Key file not found!" 00401113 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401115 |. E8 94000000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 0040111A |. C3 RETN 0040111B |> 6A 00 PUSH 0 ; /pOverlapped = NULL ; Начинаем передавать ; параметры для чтения 0040111D |. 68 96304000 PUSH CRACKME6.00403096 ; |pBytesRead = CRACKME6.00403096 00401122 |. 6A 0A PUSH 0A ; |BytesToRead = A (10.) 00401124 |. 68 8C304000 PUSH CRACKME6.0040308C ; |Buffer = CRACKME6.0040308C 00401129 |. FF35 88304000 PUSH DWORD PTR DS:[403088] ; |hFile = FFFFFFFF 0040112F |. E8 98000000 CALL [JMP.&KERNEL32.ReadFile] ; \ReadFile ;Читаем 00401134 |. 83F8 00 CMP EAX,0 ;Сравниваем с нулём... 00401137 |. 75 15 JNZ SHORT CRACKME6.0040114E ; Если всё считалось нормально, ; то прыгаем к анализу файла 00401139 |. 6A 10 PUSH 10 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL 0040113B |. 68 23304000 PUSH CRACKME6.00403023 ; |Title = "Error!" 00401140 |. 68 3E304000 PUSH CRACKME6.0040303E ; |Text = "Error reading file!" 00401145 |. 6A 00 PUSH 0 ; |hOwner = NULL 00401147 |. E8 62000000 CALL [JMP.&USER32.MessageBoxA] ; Выдаём сообщение, т.к. не ; получилось считать данные :(( 0040114C |. EB 48 JMP SHORT CRACKME6.00401196 Из комментариев итак всё ясно, так что не буду повторяться. Теперь проанализируем собственно процедуру анализа ключевого файла. Она идёт с адреса 0040114E:
0040114E |> 8D15 8C304000 LEA EDX,DWORD PTR DS:[40308C] ;Загружаем содержимое keyfile.dat 00401154 |. 83C2 05 ADD EDX,5 ; А теперь делаем смещение в файле на 5 байт 00401157 |. 803A 31 CMP BYTE PTR DS:[EDX],31 ; Сравниваем, что же у нас лежит 6-м байтом. 0040115A |. 75 10 JNZ SHORT CRACKME6.0040116C ; Если там лежит байт: 31h, то не прыгаем 0040115C |. 83C2 03 ADD EDX,3 ; Смещаемся на два байта к 9-му байту 0040115F |. 803A 33 CMP BYTE PTR DS:[EDX],33 ; Сравниваем значение 9-го байта с 33h 00401162 |. 75 08 JNZ SHORT CRACKME6.0040116C ; Если равно, то не прыгаем 00401164 |. 42 INC EDX ; Смещаемся на 1 байт к 11 байту. 00401165 |. 803A 30 CMP BYTE PTR DS:[EDX],30 ; Сравниваем 11-й байт с 30 00401168 |. 74 02 JE SHORT CRACKME6.0040116C ; Если равно 30, то прыгаем на ошибку 0040116A |. EB 15 JMP SHORT CRACKME6.00401181 ;Прыгаем на сообщение - ВСЁ ВПОРЯДКЕ 0040116C |> 6A 10 PUSH 10 ; /Style = MB_OK| ; MB_ICONHAND|MB_APPLMODAL 0040116E |. 68 23304000 PUSH CRACKME6.00403023 ; |Title = "Error!" 00401173 |. 68 52304000 PUSH CRACKME6.00403052 ; |Text = "Invalid key!" 00401178 |. 6A 00 PUSH 0 ; |hOwner = NULL 0040117A |. E8 2F000000 CALL [JMP.&USER32.MessageBoxA] ; Выдаём сообщение "Invalid Key!" 0040117F |. EB 15 JMP SHORT CRACKME6.00401196 00401181 |> 6A 40 PUSH 40 ; /Style = MB_OK| ; MB_ICONASTERISK|MB_APPLMODAL 00401183 |. 68 76304000 PUSH CRACKME6.00403076 ; |Title = "Correct!!!" 00401188 |. 68 5F304000 PUSH CRACKME6.0040305F ; |Text = "Correct key! Good job!" 0040118D |. 6A 00 PUSH 0 ; |hOwner = NULL 0040118F |. E8 1A000000 CALL [JMP.&USER32.MessageBoxA] ; Выдаём сообщение, о ; том что ключ верный! 00401194 |. EB 00 JMP SHORT CRACKME6.00401196 Вот собственно и весь крякмис.
[Fant0m CrackMe #7] Седьмой крякмис имеет ограничение на количество запусков. Всего лишь 30 раз. Запускаем крякмис и жмём "Check" - нам выдаёт "You have 30 attemps remaining!". Осталось 30 запусков... Запускаем крякмис через Олли и отпускаем его в работу. В Олли ставим бряк: bpx MessageBoxA Нажимаем в крякмисе на меню "Check" и прога прерывается в таком коде:
004010E1 /$ C705 28324000 >MOV DWORD PTR DS:[403228],4 004010EB |. 68 20324000 PUSH CRACKME7.00403220 ; /pHandle = CRACKME7.00403220 004010F0 |. 68 17304000 PUSH CRACKME7.00403017 ; |Subkey = "Software\FaNt0m's Crackme #7" 004010F5 |. 68 01000080 PUSH 80000001 ; |hKey = HKEY_CURRENT_USER 004010FA |. E8 25010000 CALL [JMP.&ADVAPI32.RegOpenKeyA] ; Пытаемся открыть ключ реестра 004010FF |. 85C0 TEST EAX,EAX 00401101 |. 74 3C JE SHORT CRACKME7.0040113F ; Если ключ найден, то прыгаем... 00401103 |. C705 24324000 >MOV DWORD PTR DS:[403224],0 0040110D |. 68 20324000 PUSH CRACKME7.00403220 ; /pHandle = CRACKME7.00403220 00401112 |. 68 17304000 PUSH CRACKME7.00403017 ; |Subkey = "Software\FaNt0m's Crackme #7" 00401117 |. 68 01000080 PUSH 80000001 ; |hKey = HKEY_CURRENT_USER 0040111C |. E8 F7000000 CALL [JMP.&ADVAPI32.RegCreateKeyA] ; Ключа не нашли - создадим! 00401121 |. FF35 28324000 PUSH DWORD PTR DS:[403228] ; /BufSize = 4 00401127 |. 68 24324000 PUSH CRACKME7.00403224 ; |Buffer = CRACKME7.00403224 0040112C |. 6A 04 PUSH 4 ; |ValueType = REG_DWORD 0040112E |. 6A 00 PUSH 0 ; |Reserved = 0 00401130 |. 6A 00 PUSH 0 ; |ValueName = NULL 00401132 |. FF35 20324000 PUSH DWORD PTR DS:[403220] ; |hKey = 5C 00401138 |. E8 F3000000 CALL [JMP.&ADVAPI32.RegSetValueExA] ; Устанавливаем своё значение ; (кол-во запусков) 0040113D |. EB 42 JMP SHORT CRACKME7.00401181 0040113F |> 68 28324000 PUSH CRACKME7.00403228 ; /pBufSize = CRACKME7.00403228 00401144 |. 68 24324000 PUSH CRACKME7.00403224 ; |Buffer = CRACKME7.00403224 00401149 |. 68 B0304000 PUSH CRACKME7.004030B0 ; |pValueType = CRACKME7.004030B0 0040114E |. 6A 00 PUSH 0 ; |Reserved = NULL 00401150 |. 6A 00 PUSH 0 ; |ValueName = NULL 00401152 |. FF35 20324000 PUSH DWORD PTR DS:[403220] ; |hKey = 5C 00401158 |. E8 CD000000 CALL [JMP.&ADVAPI32.RegQueryValueExA] ; \RegQueryValueExA 0040115D |. 85C0 TEST EAX,EAX 0040115F |. FF05 24324000 INC DWORD PTR DS:[403224] 00401165 |. FF35 28324000 PUSH DWORD PTR DS:[403228] ; /BufSize = 4 0040116B |. 68 24324000 PUSH CRACKME7.00403224 ; |Buffer = CRACKME7.00403224 00401170 |. 6A 04 PUSH 4 ; |ValueType = REG_DWORD 00401172 |. 6A 00 PUSH 0 ; |Reserved = 0 00401174 |. 6A 00 PUSH 0 ; |ValueName = NULL 00401176 |. FF35 20324000 PUSH DWORD PTR DS:[403220] ; |hKey = 5C 0040117C |. E8 AF000000 CALL [JMP.&ADVAPI32.RegSetValueExA] ; \RegSetValueExA 00401181 |> FF35 20324000 PUSH DWORD PTR DS:[403220] ; /hKey = 5C 00401187 |. E8 92000000 CALL [JMP.&ADVAPI32.RegFlushKey] ; \RegFlushKey 0040118C |. FF35 20324000 PUSH DWORD PTR DS:[403220] ; /hKey = 0000005C 00401192 |. E8 7B000000 CALL [JMP.&ADVAPI32.RegCloseKey] ; \RegCloseKey 00401197 |. 8D1D 24324000 LEA EBX,DWORD PTR DS:[403224] 0040119D |. 8B03 MOV EAX,DWORD PTR DS:[EBX] 0040119F |. 83F8 1E CMP EAX,1E 004011A2 |. 7D 36 JGE SHORT CRACKME7.004011DA 004011A4 |. 83E8 1E SUB EAX,1E 004011A7 |. F7D8 NEG EAX 004011A9 |. 68 94304000 PUSH CRACKME7.00403094 ; /%s = " attempts remaining!" 004011AE |. 50 PUSH EAX ; |%d 004011AF |. 68 8A304000 PUSH CRACKME7.0040308A ; |%s = "You have " 004011B4 |. 68 A9304000 PUSH CRACKME7.004030A9 ; |Format = "%s%d%s" 004011B9 |. 68 B8304000 PUSH CRACKME7.004030B8 ; |s = CRACKME7.004030B8 004011BE |. E8 2B000000 CALL [JMP.&USER32.wsprintfA] ; \wsprintfA 004011C3 |. 83C4 14 ADD ESP,14 004011C6 |. 6A 40 PUSH 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL 004011C8 |. 68 7B304000 PUSH CRACKME7.0040307B ; |Title = "Time remaining" 004011CD |. 68 B8304000 PUSH CRACKME7.004030B8 ; |Text = "You have 21 attempts remaining!" 004011D2 |. 6A 00 PUSH 0 ; |hOwner = NULL 004011D4 |. E8 27000000 CALL [JMP.&USER32.MessageBoxA] ; << СЮДА НАС ВЫКИНЕТ ОТЛАДЧИК 004011D9 |. C3 RETN 004011DA |> 6A 30 PUSH 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL 004011DC |. 68 34304000 PUSH CRACKME7.00403034 ; |Title = "Time limit expired!" 004011E1 |. 68 48304000 PUSH CRACKME7.00403048 ; |Text = "Your 30 attempt ; limit on this program has expired!" 004011E6 |. 6A 00 PUSH 0 ; |hOwner = NULL 004011E8 |. E8 13000000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA 004011ED \. C3 RETN Вроде много кода я привёл - а здесь всё просто... Главное чтобы у нас не было "Time limit expired...", код которого идёт с адреса 004011DA. Ищем прыжок на этот адрес... Ищем... Ищем... Вот он:
004011A2 |. 7D 36 JGE SHORT CRACKME7.004011DA Берём и просто нопим: 7D36 -> 9090 Чтобы нам не мешали сообщения об триале, убьём следующие вызовы:
004011BE |. E8 2B000000 CALL [JMP.&USER32.wsprintfA] ; \wsprintfA 004011D4 |. E8 27000000 CALL [JMP.&USER32.MessageBoxA] ; \MessageBoxA Просто меняем байты на NOP -> 90. Вот и всё!
[Fant0m CrackMe #8] В readme автор крякмиса обмолвился об том, что хоть 7-й крякмис на сайте был обозначен как "средней сложности", но он в действительности - лёгкий. В 8-м крякмисе требуется распаковать сам крякмис и прилагающуюся dll. В дополнении требуется убрать детекцию SoftICE'а и найти правильный номер для своего имени пользователя. Начнём... Ожидать какого-то очень мощного запаковщика я не стал и поэтому даже не анализировал файл с помощью FileInfo. Мне по барабану... Пакер простой - линейный. Так что не буду приводить весь код, а приведу кусок кода-переходника на OEP (Original Entry Point):
00407898 > FF96 AC7A0000 CALL DWORD PTR DS:[ESI+7AAC] 0040789E > 61 POPAD 0040789F .-E9 5C97FFFF JMP CRACKME8.00401000 По адресу 0040789F происходит переход на OEP. Так что ставим бряк сюда (F2). Теперь просто снимаем дамп в ProcDUMP'е, но не убиваем процесс! Запускаем дедушку Imprec'а и выбираем наш процесс. Подставляем найденный OEP без ImageBase: OEP=00401000, значит вставляем: 00001000. Жмём "Get Imports". Импорт будет найден (там всего 2 адреса). Кликаем по "Fix Dump" и выбираем файл дампа. Всё! Распаковка закончена. Чуть позже я наткнулся на надпись "UPX" - теперь понятно чем запаковали :\ Вторая задача - это найти номерок. Ладно! Открываем крякмис через отладчик и отпускаем... Теперь открываем окошко с вводом регистрационных данных. Вводим имя (я ввёл - ViNCE) и любой номер (я ввёл - 7777771). В Олли ставим бряк: bpx GetDlgItemTextA И жмём в окошке крякмиса - "Verify". Прога прервётся в этом коде:
00401295 6A 64 PUSH 64 00401297 68 74314000 PUSH dumpOFex.00403174 ; ASCII "7777771" 0040129C 68 EA030000 PUSH 3EA 004012A1 FF75 08 PUSH DWORD PTR SS:[EBP+8] 004012A4 E8 B5000000 CALL [JMP.&user32.GetDlgItemTextA] ; Получаем введённое имя ; (СЮДА НАС ОТПРАВИТ ОТЛАДЧИК) 004012A9 6A 64 PUSH 64 004012AB 68 10314000 PUSH dumpOFex.00403110 ; ASCII "ViNCE" ;Сохраняем имя в стек 004012B0 68 E9030000 PUSH 3E9 004012B5 FF75 08 PUSH DWORD PTR SS:[EBP+8] 004012B8 E8 A1000000 CALL [JMP.&user32.GetDlgItemTextA] ; Получаем введённый номер 004012BD 8D05 10314000 LEA EAX,DWORD PTR DS:[403110] 004012C3 50 PUSH EAX 004012C4 8D05 74314000 LEA EAX,DWORD PTR DS:[403174] 004012CA 50 PUSH EAX 004012CB FF15 0C314000 CALL DWORD PTR DS:[40310C] ; CM8.VerifySerial ; Вызываем функцию проверки ; номера из DLL 004012D1 85C0 TEST EAX,EAX 004012D3 74 08 JE SHORT dumpOFex.004012DD 004012D5 8D05 A0304000 LEA EAX,DWORD PTR DS:[4030A0] 004012DB EB 06 JMP SHORT dumpOFex.004012E3 004012DD 8D05 63304000 LEA EAX,DWORD PTR DS:[403063] 004012E3 6A 40 PUSH 40 004012E5 68 54304000 PUSH dumpOFex.00403054 ; ASCII "Serial Results" 004012EA 50 PUSH EAX 004012EB 6A 00 PUSH 0 004012ED E8 8A000000 CALL [JMP.&user32.MessageBoxA] 004012F2 EB 00 JMP SHORT dumpOFex.004012F4 004012F4 B8 01000000 MOV EAX,1 004012F9 C9 LEAVE 004012FA C2 1000 RETN 10 Тут всё понятно. Заходим внутрь процедуры из внешней DLL, по адресу 004012CB. Вот она:
10001287 > 55 PUSH EBP 10001288 8BEC MOV EBP,ESP 1000128A FF75 0C PUSH DWORD PTR SS:[EBP+C] 1000128D E8 85000000 CALL CM8.10001317 10001292 83F8 00 CMP EAX,0 10001295 74 71 JE SHORT CM8.10001308 10001297 83F8 64 CMP EAX,64 1000129A 7D 6C JGE SHORT CM8.10001308 1000129C 50 PUSH EAX 1000129D FF75 08 PUSH DWORD PTR SS:[EBP+8] 100012A0 E8 72000000 CALL CM8.10001317 100012A5 83F8 00 CMP EAX,0 100012A8 74 5E JE SHORT CM8.10001308 100012AA 83F8 64 CMP EAX,64 100012AD 7D 59 JGE SHORT CM8.10001308 100012AF 8B75 0C MOV ESI,DWORD PTR SS:[EBP+C] 100012B2 8D3D 24300010 LEA EDI,DWORD PTR DS:[10003024] 100012B8 59 POP ECX 100012B9 41 INC ECX 100012BA BB 42000000 MOV EBX,42 100012BF 03D9 ADD EBX,ECX 100012C1 0FB606 MOVZX EAX,BYTE PTR DS:[ESI] 100012C4 46 INC ESI 100012C5 33C3 XOR EAX,EBX 100012C7 C1C0 05 ROL EAX,5 <.. Вырезано цензурой ..> 100012E7 B0 11 MOV AL,11 100012E9 EB E6 JMP SHORT CM8.100012D1 100012EB 49 DEC ECX 100012EC 83F9 00 CMP ECX,0 100012EF 74 02 JE SHORT CM8.100012F3 100012F1 EB C7 JMP SHORT CM8.100012BA 100012F3 C607 00 MOV BYTE PTR DS:[EDI],0 100012F6 68 24300010 PUSH CM8.10003024 100012FB FF75 08 PUSH DWORD PTR SS:[EBP+8] 100012FE E8 29000000 CALL CM8.1000132C ; JMP to kernel32.lstrcmpA 10001303 83F8 00 CMP EAX,0 10001306 74 09 JE SHORT CM8.10001311 10001308 B8 01000000 MOV EAX,1 1000130D C9 LEAVE 1000130E C2 0800 RETN 8 Просто трассируем код и попутно увидим правильный номерок. Привожу свою комбу: Имя: ViNCE Номер: 0?00403808 Забавный номер... :))
В этой длинной статейке я рассмотрел все 8 крякмисов от Fant0m'а и конечно же сделал некоторые выводы: - КрякМисы подходят в самый раз для newbie крякеров. - Я лентяй! ...Ведь мог бы написать про распаковку dll и кей ген в CrackME #8
|
|