Навигация по сайту:
Статья "Исследование CrackMe'сов от Fant0m":
<< Все статьи по взлому Версия для печати
Только для образовательных целей!
Автор: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

<< Все статьи по взлому Версия для печати
Комментарии читателей к статье "Исследование CrackMe'сов от Fant0m":

09.08.2011 14:47
Пример 1

С чего ты взял (откуда узнал) что надо это делать до адреса 00401026.

Как мне самому определить до чего именно трассировать?

18.08.2009 13:13
Хороша статья, не хватает ссылки на крякмисы от фантома, где можно их было скачать

03.07.2008 01:00
супер !!! большущий тебе респект за статейку
просто, и наглядно ;)
deR_23

03.07.2008 00:59
супер !!! большущий тебе респект за статейку
просто, и наглядно ;)

17.11.2007 20:53
Респект.

14.10.2007 01:36
что такое АВТОХАКИНГ ,?
LESHIY

21.07.2007 00:09
Молодец, понятно для начинающих..
Саша aka coban2k давал свои разборы полётов с крякмисам=))
Начинающий крякер не разобрал бы=))
А ты ясно описал , сложного нет ничего..
Вообщем молодец!
Плюс тебе!
Добавить свой комментарий:
Ваше имя: Текст сообщения:
Ваш E-Mail:
Введите код:   

ALIEN Hack Team - © 2003-2017
Лицензионное соглашение