Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
 |
|

09.01.2007, 23:48
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
Solutions
Описание: Это тема представляет из себя сборник решений наиболее интерсных задачек(CrackMe). Думаю новичкам и не только будет полезно почитать решения таких людей как hidden, ProTeuS, Ra$cal. ИМХО не писать же из-за пары интересных приёмов статьи.
Условие: Не выкладывать решения до прохождения, расчитанным автором crackme, определённого числа людей или истечения срока давности!
Формат: Придерживайтесь следующего формата!
Код:
CrackMe: ...
Цель: пропатчить/закейгенить/найти верный пароль/...
Сложность: легко/средне/сложно
Коментарий: Ваши комментарии. Если есть.
link: где искать
Решение: Само решение
|
|
|
..::[FaTmiKE 2oo5]::.. CrackMe #2 |

09.01.2007, 23:49
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
..::[FaTmiKE 2oo5]::.. CrackMe #2
CrackMe: ..::[FaTmiKE 2oo5]::.. CrackMe #2
Цель: закейгенить
Сложность: легко
Коментарий: KeyGen писать не будем, только найдём способ генерации.
link: http://www.crackmes.de/archive/
Решение:
Обходим упаковщик, тк распаковка не воходит в наши планы. Так и не посмотрел какой но судя по pusha - popa - UPX.
Два способа обхода этого препятствия:
f8 > hr esp > run > hd esp
или
Ctrl-F > popa > f2 > f9 > f2 > f8
В первую очередь пореверим крякмис на возможность String Reference взлома. Другими словами пороверим наличие в открытом виде таких строк, как "Registred", "good","sucsessfull","Cool","Xaker","Cracker","pas sword". Для этого жмём F10 (эквивалент нажатия на правую клавишу), Search for > All referenced text strings. Ничего полезного((!
Поищем функции ввода, вывода, и проставим бряки. Для этого в command bar'е наберём "bpx MessageBoxA". Перед нами предстали все апи. Но MessageBoxA и GetWindowTextA среди них нет. Но где то они вызываться должны!! С этими словами, я полез в Executable modules(Alt-E). Выбираем user32.dll, тк именно там храняться интересующие нас функции, и Ctrl-N. Ищем MessageBoxA, enter (входим в функцию). Ставим бряк на retn 10. Почему? Вдруг автору крякми вздумается украсть пару байт или проверить первый байт на присутствие int 3 (это breackpoint F2, можно так сказать). F9.
Вводим что-нибудь и жмём "Go!". Вылетает сообщение, о необходимости регистрации. Жмём Ok и брякаемся на retn 10. F8 и мы вновь в программе. Поднимимся немного выше. Что то маловато кода. Только функции зашифровки/расшифровки текста и MessageBoxA.
Код:
004018E0 3E:8B0D 78924000 MOV ECX,DWORD PTR DS:[409278] ; Crackme2.004010F0
004018E7 FFD1 CALL ECX
004018E9 3E:8B0D 80924000 MOV ECX,DWORD PTR DS:[409280] ; Crackme2.00401290
004018F0 FFD1 CALL ECX
004018F2 A1 4C924000 MOV EAX,DWORD PTR DS:[40924C]
004018F7 6A 40 PUSH 40
004018F9 68 0C924000 PUSH Crackme2.0040920C ; ASCII "Information"
004018FE 68 10904000 PUSH Crackme2.00409010 ; ASCII "This function is only available in the registered version!"
00401903 50 PUSH EAX
00401904 3E:8B0D 68924000 MOV ECX,DWORD PTR DS:[409268] ; Crackme2.004080B8
0040190B 3E:FF11 CALL DWORD PTR DS:[ECX]
0040190E 3E:8B0D 78924000 MOV ECX,DWORD PTR DS:[409278] ; Crackme2.004010F0
00401915 FFD1 CALL ECX
00401917 3E:8B0D 80924000 MOV ECX,DWORD PTR DS:[409280] ; Crackme2.00401290
0040191E FFD1 CALL ECX
00401920 C3 RETN
Чтож мы пойдём другим путём. Перезапустим программу и доберёмся до точки входа, вобщем опять обходим упаковщик.
Проскроллируем ниже, поищем функцию GetModuleHandleA.
Код:
00407006 FF15 14804000 CALL DWORD PTR DS:[408014] ; kernel32.GetModuleHandleA
0040700C 50 PUSH EAX
0040700D E8 8EA3FFFF CALL Crackme2.004013A0
После GetModuleHandleA ничего нет, зато идёт функция CALL Crackme2.004013A0 в которой наверняка всё и спрятанно. Заходим в неё.
Вот и то, что мы искали:
Код:
004013E9 6A 00 PUSH 0
004013EB 68 50144000 PUSH Crackme2.00401450
004013F0 6A 00 PUSH 0
004013F2 6A 65 PUSH 65
004013F4 50 PUSH EAX
004013F5 FF15 A8804000 CALL DWORD PTR DS:[4080A8] ; USER32.DialogBoxParamA
push NULL
push ADDR DlgProc
push NULL
push ADDR DlgName
push hInstance
call DialogBoxParam
или более привычный для меня вариант
invoke DialogBoxParam, hInstance, ADDR DlgName,NULL,addr DlgProc,NULL
Нам нужен адрес функции диалогового окна, DlgProc равный, в нашем случае, 00401450. Отправляемся по нему, Ctrl-G > 00401450.
Вот она, DlgProc, во всей красе.
Код:
00401450 55 PUSH EBP ; DlgProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
00401451 8BEC MOV EBP,ESP
00401453 83EC 68 SUB ESP,c68
00401456 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] ; eax <- uMsg
00401459 53 PUSH EBX
0040145A 56 PUSH ESI
0040145B 83E8 10 SUB EAX,10
0040145E 57 PUSH EDI
0040145F 0F84 BC020000 JE Crackme2.00401721 ; WM_CLOSE
00401465 2D 00010000 SUB EAX,100
0040146A 0F84 22020000 JE Crackme2.00401692 ; WM_INITDIALOG
00401470 48 DEC EAX
00401471 74 0B JE SHORT Crackme2.0040147E ; WM_COMMAND
00401473 33C0 XOR EAX,EAX
00401475 5F POP EDI
00401476 5E POP ESI
00401477 5B POP EBX
00401478 8BE5 MOV ESP,EBP
0040147A 5D POP EBP
0040147B C2 1000 RETN 10 ; DlgProc endp
Протрссировав функцию, я определил
Код:
0040145F 0F84 BC020000 JE Crackme2.00401721 ; WM_CLOSE
переходом в случаее, получения uMsg равного WM_CLOSE.
Код:
0040146A 0F84 22020000 JE Crackme2.00401692 ; WM_INITDIALOG
переходом в случаее, получения uMsg равного WM_INITDIALOG
WM_*** - сообщения от Windows, которые должна обработать DlgProc.
Код:
WM_CLOSE equ 10h
WM_INITDIALOG equ 110h
WM_COMMAND equ 111h
Нас интересует случай когда uMsg равен WM_COMMAND (обработка сообщений нажатия на кнопку, открытия меню и тп).
mov eax,wParam
wParam - ID кнопки, меню и тп.
Код:
0040147E 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
Равняем по 3e8h (1000d).
Код:
00401481 05 18FCFFFF ADD EAX,-3E8
Делаем вывод, что ID кнопок от 1000 до 1009 тк дальше идёт проверка.
Код:
00401486 83F8 09 CMP EAX,9
00401489 0F87 F8010000 JA Crackme2.00401687
Код:
0040148F 33C9 XOR ECX,ECX
00401491 8A88 58174000 MOV CL,BYTE PTR DS:[EAX+401758]
00401497 FF248D 44174000 JMP DWORD PTR DS:[ECX*4+401744]
ecx*4+xxxxxxxx =)), видимо где то харнятся адреса меток по которым подаётся управление. Но нас это не интересует.
Ставим бряк на jmp и жмём f9. Вводим вместо имени и пароля 01234, 56789 соответсвенно. Для удобства все символы разные. Посмотрим, что делается после нажатия "Go!". Мы попадаем на функцию.
Код:
004014E3 FF15 58924000 CALL DWORD PTR DS:[409258] ; Crackme2.004018E0
Зайдем в неё, Enter. Чтож это мы уже видели. F9. Теперь попробуем нажать Registred. Брякаемся на всё том же прыжке и переходим по нему.
Чтож трейсим)). Ниже встречаются вызовы GetDlgItemTextA. Введёные слова записываются в стек. После второй GetDlgItemTextA встречаем:
Код:
0040154C 837D 10 13 CMP DWORD PTR SS:[EBP+10],13
00401550 0F85 31010000 JNZ Crackme2.00401687
Из чего можно сделать вывод, что символов в пароле должо быть 19, тк по ebp+10 хранится размер введёного пароля. Чтож жмём f9 и меняем пароль на 0123456789123456789. И идём дальше.
Код:
00401556 8A0D 1C924000 MOV CL,BYTE PTR DS:[40921C]
0040155C B0 2D MOV AL,2D
0040155E 3AC8 CMP CL,AL
00401560 0F85 21010000 JNZ Crackme2.00401687
AL=2D ('-')
CL=34 ('4')
Из чего можно сделать вывод, что через каждые 4 символа должнен быть "-". Меняем пароль на 0123-4567-8912-3456.
Проходим проверки, всё гуд)). Трейсим!! Дальше нам встречается цикл:
Код:
00401592 0FBE4C05 98 MOVSX ECX,BYTE PTR SS:[EBP+EAX-68]
00401597 03F1 ADD ESI,ECX
00401599 40 INC EAX
0040159A 3BC2 CMP EAX,EDX
0040159C ^7C F4 JL SHORT Crackme2.00401592
Суммируются некоторые символы.
И умноножение на некое DEADBEFF.
Код:
0040159E 69F6 EFBEADDE IMUL ESI,ESI,DEADBEEF
В esi остаётся своеобразный хэш. Числа будут совпадать не так часто, а число будет строго определённого формата, так что, можно назвать и хэшем.
Код:
004015A4 8975 0C MOV DWORD PTR SS:[EBP+C],ESI
004015A7 8B15 44914000 MOV EDX,DWORD PTR DS:[409144] ; Crackme2.004091A4
004015AD FF75 0C PUSH DWORD PTR SS:[EBP+C]
004015B0 8D85 CCFFFFFF LEA EAX,DWORD PTR SS:[EBP-34]
004015B6 52 PUSH EDX
004015B7 50 PUSH EAX
004015B8 3E:8B0D 74924000 MOV ECX,DWORD PTR DS:[409274] ; Crackme2.004080C0
004015BF 3E:FF11 CALL DWORD PTR DS:[ECX]
Можно распознать как:
Код:
push 75AC7566 ; - наш "хэш"))
push "%X" ; Unsigned hexadecimal integer
push 0012FA38 ; Буфеp для пpиема отфоpматиpованных символов
CALL wsprintfA
Вобщем эта функция переводит наше hex-число в ASUII строку.
Код:
004015C5 8A55 CC MOV DL,BYTE PTR SS:[EBP-34]
004015C8 A0 19924000 MOV AL,BYTE PTR DS:[409219]
004015CD 3AD0 CMP DL,AL
004015CF 0F85 B2000000 JNZ Crackme2.00401687
...
...
0040162B 8A45 D3 MOV AL,BYTE PTR SS:[EBP-2D]
0040162E 8A0D 29924000 MOV CL,BYTE PTR DS:[409229]
00401634 3AC1 CMP AL,CL
00401636 75 4F JNZ SHORT Crackme2.00401687
Судя по представленному выше коду в пароле нужно заменить 12 на 75, 56 на AC, 91 на 75, 45 на 66.
Формируем новый пароль a75b-cACd-e75f-g66h. Ну ещё добавил ab cd ef gh для наглядности. Хотя вместо них можно поставить что угодно.
Пробуем пароль. Попадаем в ольку, проходим все прверки. Дальше идут функции GetDlgItem, EnableWindow.
Код:
ControlID = 3EF (1007.)
hWnd = 0048061C ('..::[FaTmiKE 2oo5]::..',class='#32770')
CALL GetDlgItem
Enable = FALSE
hWnd = 00460798 (class='Edit',parent=0044061C)
CALL EnableWindow
Что значит дезактивация поля. Идём до конца. Нам несколько раз встречаются EnableWindow, что придаёт нам уверенности в правильном ответе)). Жмём F9. И переходим к нашей программе.Поля и кнопка регистрации, как я сказал больше не активны.
Момент истины, барабанная дробь)). Жмём "Go!". Мдя... Только для зарегестрированных пользователей! Крякмис всётаки не хочет нас таковыми считать)))!
Придётся перезапускаться. Ставим старые breackpoint'ы. Вводим старые имя и пароль. Проходим проверки. И вот, что мы проглядели:
Код:
0040164D 890D 58924000 MOV DWORD PTR DS:[409258],ECX
Ничего не напоминает? А как вам этот адресок?
Код:
004014E3 FF15 58924000 CALL DWORD PTR DS:[409258] ; Crackme2.004018E0
По ходу автор меняет адрес функции вывода о необходимости регистрации новым адресом. Тогда всё понятно)). Пробуем опять нажать "Go!". Вновь брякаемся на jmp. Заходим.
Код:
004014E3 FF15 58924000 CALL DWORD PTR DS:[409258] ; Crackme2.004012B0
Как мы и предполагали, содержимое 409258 поменялось на 004012B0.
Код:
004012B0 55 PUSH EBP
004012B1 8BEC MOV EBP,ESP
004012B3 83EC 10 SUB ESP,10
004012B6 53 PUSH EBX
004012B7 56 PUSH ESI
Что то новое)). Сотрим!!
Код:
004012B9 0FBE05 18924000 MOVSX EAX,BYTE PTR DS:[409218]
004012C0 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
...
004012F6 C1E0 08 SHL EAX,8
004012F9 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004012FC 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
004012FF 0B4D F4 OR ECX,DWORD PTR SS:[EBP-C]
00401302 0B4D F8 OR ECX,DWORD PTR SS:[EBP-8]
00401305 0B4D F0 OR ECX,DWORD PTR SS:[EBP-10]
Программа раскладывает наши ab cd по регисистрам, кладёт в стек значения, сдвигает значения на 8, 10, 18 влево. В результате, получая что то вроде этого:
xx000000
00yy0000
0000zz00
000000uu
Затем с помощью or собирает всё в один регистр ecx
xxyyzzuu
в нашем случае:
ECX 61626364 или abcd
ECX сохраняется и тоже самое проделывается с efgh. Далее идёт некая функция зайдём в неё.
Код:
00401115 8B15 48914000 MOV EDX,DWORD PTR DS:[409148]
По 409148 судя по всему какаято функция, в ecx попадает те самые abcd
Код:
00401124 33D1 XOR EDX,ECX
РасXORивается значение некой функции и записывается наместо
Код:
0040112C 8915 48914000 MOV DWORD PTR DS:[409148],EDX
Следующий байт рахоривается по efgh и тд. Встаёт законный вопрос. Где тогда узнать abcdefgh. На это у меня один ответ. Если не устанавливается seh-обработчик, то скорее всего автор сам узнает о правильности прохореных команд. Ничего не остаётся как идти дальше. Выйдя из этой функции мы встречаем ещё одну. В которой расположены следующие строки.
Код:
00401776 813D 98914000 E8>CMP DWORD PTR DS:[409198],97BE8
00401780 0F85 32010000 JNZ Crackme2.004018B8
00401786 813D 5C914000 FF>CMP DWORD PTR DS:[40915C],0D8BD1FF
00401790 0F85 22010000 JNZ Crackme2.004018B8
Мдя...
Придётся опять перезапускать и проходить до того места где всё расхоривается. Улавиливаете чем хорить байты в 409198 и 40915c. Правильно тем чем сравнивется.
итак до расхоривания у нас было:
Код:
00409198 A4 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00409199 2C 4C SUB AL,4C
0040919B 4B DEC EBX
0040919C 54 PUSH ESP
0040915C AB STOS DWORD PTR ES:[EDI]
0040915D 98 CWDE
0040915E C3 RETN
0040915F 5E POP ESI
Теперь хорим тем, что должно было быть.
Код:
4b4c2ca4
xor
00097be8
____________
4b45574c (KEWL)
5ec398ab
xor
0d8bd1ff
___________
53484954 (SHIT)
Вставляем в пасс новые буковки))
Password: K75E-WACL-S75H-I66T
Проверяем!
|
|
|

09.01.2007, 23:51
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
hiddCrackMeImp
CrackMe: hiddCrackMeImp
Цель: найти последовательность действий для регистрации
Сложность: средне
Решение:
Запускаем, видим функцию. Нужно зайти, тк лично у меня по f8 прога упала.
Код:
00401BB7 > E8 16000000 CALL HidCreck.00401BD2
Трейсим, функция преобразовывается налицо. И получается следующий цикл который тоже что то расшифровывает.
Код:
00401BE2 8D41 FF LEA EAX,DWORD PTR DS:[ECX-1]
00401BE5 83E0 0F AND EAX,0F
00401BE8 8A0428 MOV AL,BYTE PTR DS:[EAX+EBP]
00401BEB 30040E XOR BYTE PTR DS:[ESI+ECX],AL
00401BEE ^E2 F2 LOOPD SHORT HidCreck.00401BE2
Пройдя этот цикл и mov следующий за ним переж нами появится ret.
Пройдя его, мы идём дальше. И после прохода следующей функции
Код:
00401009 E8 02040000 CALL HidCreck.00401410
,мы видим, что подгружаются новые библиотеки. Это даёт нам право предполагать, что внутри лежит загрузчик и импортёр апи. Перезапускаемся и заходим в функцию. Поанализировав её, мы замечаем следующие строки:
Код:
0040143E 66:8338 8B CMP WORD PTR DS:[EAX],0FF8B
00401442 75 03 JNZ SHORT HidCreck.00401447
Если первые байты апи mov edi,edi (0FF8B), то они пропускается, что дезориентирует Олю. Просто перебиваем условный на безусловный переход. И ставим бряк на cmp. Жмём f9, в eax появляются загружаемые функции. Ищем что-нибудь подозрительное. И находим))).
Код:
EAX 77D48666 user32.RegisterHotKey
Единственная функция получения данных)). И слава Богу)) Далее я полез в Executable Modules (Ctrl-E) > user32.dll > ctrl-N > RegisterHotKey. Ставим бряк на первый байт. F9. Сработало моментально:
Код:
0006F848 00401BB5 /CALL to RegisterHotKey from HidCreck.00401BB0
0006F84C 003204CE |hWnd = 003204CE (class='HiddenClass')
0006F850 00000001 |HotKeyID = 1
0006F854 00000007 |Modifiers = MOD_ALT|MOD_CONTROL|MOD_SHIFT
0006F858 00000075 \Key = VK_F6
Нужно нажать Ctrl-Alt-Shift-F6. Жмём в Olly F9, и полученную комбинацию в окне крякмиса. И снова брякаемся на апи.
Код:
0006FD80 00401BB5 /CALL to RegisterHotKey from HidCreck.00401BB0
0006FD84 003204CE |hWnd = 003204CE (class='HiddenClass')
0006FD88 00000001 |HotKeyID = 1
0006FD8C 00000007 |Modifiers = MOD_ALT|MOD_CONTROL|MOD_SHIFT
0006FD90 00000072 \Key = VK_F3
Нужно нажать Ctrl-Alt-Shift-F3.
Код:
0006FD80 00401BB5 /CALL to RegisterHotKey from HidCreck.00401BB0
0006FD84 003204CE |hWnd = 003204CE (class='HiddenClass')
0006FD88 00000001 |HotKeyID = 1
0006FD8C 00000007 |Modifiers = MOD_ALT|MOD_CONTROL|MOD_SHIFT
0006FD90 00000077 \Key = VK_F8
Нужно нажать Ctrl-Alt-Shift-F8
Код:
0006FD80 00401BB5 /CALL to RegisterHotKey from HidCreck.00401BB0
0006FD84 003204CE |hWnd = 003204CE (class='HiddenClass')
0006FD88 00000001 |HotKeyID = 1
0006FD8C 00000007 |Modifiers = MOD_ALT|MOD_CONTROL|MOD_SHIFT
0006FD90 00000074 \Key = VK_F5
Нужно нажать Ctrl-Alt-Shift-F5
Ну вот!! registred))
Лично мой путь был более длинным(( Я ставил бряк на CreateWindowExA, искал функцию окна, там нашол сравнение при получении uMsg равного 111h и ток потом до меня допёрло, для чего нужна была эта функция. Я просто не ждал, что регистрация будет проходить так необычно))
|
|
|

09.01.2007, 23:53
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
First CrackMe by ProTeuS
CrackMe: First CrackMe by ProTeuS
Цель: найти верный пароль
Сложность: средне
link: http://www.forum.antichat.ru
Решение:
Запускаем, вводим чтонить!
Брякаемся по 004578AE.
Код:
004578AE 21 DB 21 ; CHAR '!'
004578AF A7 DB A7
004578B0 CD FE INT 0FE
004578B2 0D DB 0D
Первый вывод - зашифрованная функция. Следовательно в стеке должен лежать
адрес возврата (помимо SEH-обработчика). Смотрим в стек. Так оно и есть)).
Код:
0012F920 004579C5 RETURN to CrackMe.004579C5
Идём по адресу!!
Код:
004579B7 . 64:FF30 PUSH DWORD PTR FS:[EAX]
004579BA . 64:8920 MOV DWORD PTR FS:[EAX],ESP
004579BD . 8D05 AC784500 LEA EAX,DWORD PTR DS:[4578AC]
004579C3 . FFD0 CALL EAX ; <- Вот вызов криптованной функции
004579C5 . 33C0 XOR EAX,EAX
004579C7 . 5A POP EDX
Поднимимся выше. Видим интересные функции.
Код:
0045796C . E8 3FE5FAFF CALL <JMP.&kernel32.GetCurrentProcess> ; |[GetCurrentProcess
00457971 . 50 PUSH EAX ; |hProcess
00457972 . E8 51E6FAFF CALL <JMP.&kernel32.ReadProcessMemory> ; \ReadProcessMemory
...
004579A0 . E8 8BE6FAFF CALL <JMP.&kernel32.WriteProcessMemory> ; \WriteProcessMemory
Начало функции в которую мы попали:
Код:
0045793C . 55 PUSH EBP
0045793D . 8BEC MOV EBP,ESP
0045793F . 83C4 F0 ADD ESP,-10
00457942 . 53 PUSH EBX
00457943 . 56 PUSH ESI
Ctrl-F2(перезапускаемся). Ctrl-G > 0045793C. Ставим бряк. F9.
Вводим чтонить. И брякаемся. Дальше трейсим.
Код:
0012F5F8 00457977 /CALL to ReadProcessMemory from CrackMe.00457972
0012F5FC FFFFFFFF |hProcess = FFFFFFFF
0012F600 004578AC |pBaseAddress = 4578AC
0012F604 0045AC03 |Buffer = CrackMe.0045AC03
0012F608 00000001 |BytesToRead = 1
0012F60C 0012F61C \pBytesRead = 0012F61C
4578AC - не далеко от адреса по которому упала прога. Истина гдето рядом))
Код:
0045798D . 3013 XOR BYTE PTR DS:[EBX],DL
____________________________________
DL=01
DS:[0045AC03]=99
Настоящее начало криптованной функции. В 90% случаях функции начинаются
с push ebp. Алго криптования нам известен)). 99 xor 55 = 0CCh = 204d
Пасс: 204
|
|
|

10.01.2007, 13:21
|
|
Флудер
Регистрация: 27.12.2005
Сообщений: 2,372
Провел на форуме: 5339610
Репутация:
4360
|
|
CrackMe: CrackMe by [Great]
Цель: найти верный пароль
Сложность: средне
Решение:
Выложу сам свое решение нормальное 
Во-первых прога запакована UPX'ом, поэтому быстро распаковываем.
Открываем прогу в олли, ждем окончания анализа, запускаем по F5, и.... она закрывается. Причем вместе с олли. Аналогичная фишка и в других отладчиках, например, встроенном в MS Visual Studio. Что-то тут не так 
Вообще можно обойтись плагином IsDebuggerPresent hide для олли, но ввиду того, что он есть не у всех, мы пойдем влоб)
Код:
004010B5 |. B8 01000000 MOV EAX, 1
004010BA |. 40 INC EAX
004010BB |. 68 8C114000 PUSH ucrackme.0040118C
004010C0 |. 64:8B40 FE MOV EAX, DWORD PTR FS:[EAX-2]
004010C4 |. 50 PUSH EAX
004010C5 |. 64:8925 00000>MOV DWORD PTR FS:[0], ESP
Это, очевидно, установка SEH, только слегка измененная, чтобы Олли её не опознал, как таковую  Дальше идет код, который всегда вызовет исключение нарушения доступа, слегка замаскированный. Поэтому просто ставим бряк на 0040118c и жмем F9(Run). Брякаемся на 40118c. Идет расшифровка строк kernel32.dll и IsDebuggerPresent и запуск этой функции:
Код:
0040120F . FF55 FC CALL DWORD PTR [EBP-4] ; kernel32.IsDebuggerPresent
Конечно же, без плагина, она возвратит 1. Смело ставим в EAX 0 и двигаемся дальше. Нопим call EnumWindows, т.к. она ищет окно Olly и грохает его. Подходим к DialogBoxParamA. DlgProc устроена так, что после нажатия ОК она возвращает указатель на строку и дропает окно. Поэтому вводим что-нибудь и нажимаем ОК. Видим:
Код:
004012DA . 68 90304000 PUSH ucrackme.00403090 ; ASCII "ertwrwe"
004012DF . E8 DC010000 CALL ucrackme.004014C0
004012E4 . 83C4 04 ADD ESP, 4
004012E7 . 8BF0 MOV ESI, EAX
004012E9 . 68 64304000 PUSH ucrackme.00403064 ; ASCII "rqugvPo`ac[mehgvPrduqsnva"
004012EE . E8 CD010000 CALL ucrackme.004014C0
004012F3 . 83C4 04 ADD ESP, 4
004012F6 . 3BF0 CMP ESI, EAX
ertwrwe - это введено в поле. Очевидно, это сравнене длин. Смело нопим, чтобы не мешало или просто ставим курсор на инструкцию JE, Ctrl-*, делаем флаг Z=1. Перескакиваем вывод ругательства из-за неправильной длины. Далее идет цикл проверки:
Код:
00401365 . 0FBE8A 903040>MOVSX ECX, BYTE PTR [EDX+403090]
0040136C . 8B45 F8 MOV EAX, DWORD PTR [EBP-8]
0040136F . 33D2 XOR EDX, EDX
00401371 . BE 0B000000 MOV ESI, 0B
00401376 . F7F6 DIV ESI
00401378 . 0FBE92 803040>MOVSX EDX, BYTE PTR [EDX+403080]
0040137F . 33CA XOR ECX, EDX
00401381 . 0FBEC1 MOVSX EAX, CL
00401384 . 8B4D F8 MOV ECX, DWORD PTR [EBP-8]
00401387 . 0FBE91 643040>MOVSX EDX, BYTE PTR [ECX+403064]
0040138E . 3BC2 CMP EAX, EDX
Самый обычный XOR циклически с ключем. Расшифровывая быстренько правильный пароль, получим super_mega_lamer_password.
Перезапускаем, вводим super_mega_lamer_password и Registration completed!
Последний раз редактировалось _Great_; 10.01.2007 в 13:24..
|
|
|

19.01.2007, 16:15
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
CrackMe #3 by anorganix
CrackMe: CrackMe #3 by anorganix
Цель: найти верный пароль
Сложность: средне
link: http://arteam.accessroot.com/releases/ (Crackmes 1 To 8 By Anorganix)
Решение:
Грузим прогу в Olly!
Код:
100A45BC > 9C PUSHFD
100A45BD 60 PUSHAD
100A45BE E8 00000000 CALL CrackMe3.100A45C3
100A45C3 5D POP EBP
Это даёт нам понять, что прога чем то запакованна. F8 и ставим бряк на esp (в command bar ввести hr esp). F9 и брякаемся тут:
Код:
100A482D 9D POPFD
100A482E -E9 15F3FAFF JMP CrackMe3.10053B48
Удаляем бряк (в command bar ввести hd esp-4). F8 и мы на oep! Мдя o e p....
Код:
10053B48 55 DB 55 ; CHAR 'U'
10053B49 8B DB 8B
10053B4A EC DB EC
10053B4B 83 DB 83
10053B4C C4 DB C4
10053B4D F0 DB F0
10053B4E B8 DB B8
10053B4F 60390510 DD CrackMe3.10053960
10053B53 E8 DB E8
10053B54 6C DB 6C ; CHAR 'l'
10053B55 22 DB 22 ; CHAR '"'
10053B56 FB DB FB
10053B57 FF DB FF
10053B58 E8 DB E8
Меня утешило то, что я знал: 55h - "push ebp", 8BECh - "mov ebp,esp" и тп. А следовательно можно попытаться объяснить это Olly, разуж Ctrl-A не всилах нам помочь.
F10 > Analysis > During next analysis ... > command. После третьей команды я опять попробовал нажать Ctrl-A и, о чудо, Olly всё проанализировала как надо!!
Код:
10053B48 . 55 PUSH EBP
10053B49 . 8BEC MOV EBP,ESP
10053B4B . 83C4 F0 ADD ESP,-10
10053B4E . B8 60390510 MOV EAX,CrackMe3.10053960
10053B53 . E8 6C22FBFF CALL CrackMe3.10005DC4
10053B58 . E8 73FDFFFF CALL CrackMe3.100538D0
10053B5D . 84C0 TEST AL,AL
10053B5F . 75 09 JNZ SHORT CrackMe3.10053B6A
10053B61 . E8 8EFDFFFF CALL CrackMe3.100538F4
10053B66 . 84C0 TEST AL,AL
10053B68 . 74 05 JE SHORT CrackMe3.10053B6F
10053B6A > E8 3903FBFF CALL CrackMe3.10003EA8
10053B6F > A1 3C500510 MOV EAX,DWORD PTR DS:[1005503C]
10053B74 . 8B00 MOV EAX,DWORD PTR DS:[EAX]
10053B76 . E8 D5D9FFFF CALL CrackMe3.10051550
10053B7B . A1 3C500510 MOV EAX,DWORD PTR DS:[1005503C]
10053B80 . 8B00 MOV EAX,DWORD PTR DS:[EAX]
10053B82 . BA C03B0510 MOV EDX,CrackMe3.10053BC0 ; ASCII "CrackMe #3"
10053B87 . E8 D4D5FFFF CALL CrackMe3.10051160
10053B8C . 8B0D 684F0510 MOV ECX,DWORD PTR DS:[10054F68] ; CrackMe3.10056C00
10053B92 . A1 3C500510 MOV EAX,DWORD PTR DS:[1005503C]
10053B97 . 8B00 MOV EAX,DWORD PTR DS:[EAX]
10053B99 . 8B15 C4320510 MOV EDX,DWORD PTR DS:[100532C4] ; CrackMe3.10053310
10053B9F . E8 C4D9FFFF CALL CrackMe3.10051568
10053BA4 . A1 3C500510 MOV EAX,DWORD PTR DS:[1005503C]
Я начал трейсить!! И после
Код:
10053B6A > E8 3903FBFF CALL CrackMe3.10003EA8
Прога вылетела! Пришлось проходить всё заново! Беглый анализ функции дал понять, что она проверяла под отладчиком мы или нет! Не долго думая, я решил обойти злощастную функцию! Дойдя до неё, я поменял eip (с помощью New origin here). F9 и прога запустилась и вылетела. Что удивило вылетела в отладчике и норамльно функционировала со мной! Единственное что пришло в голову, так это - пред тем как прога убивает себя она создаёт новый процесс! А с помощь чего можно создать процес? Правильно CreateProcessA! Поищем эту апи. И вот код:
Код:
10053657 |. 6A 04 PUSH 4
10053659 |. 6A 00 PUSH 0
1005365B |. 6A 00 PUSH 0
1005365D |. 6A 00 PUSH 0
1005365F |. 8D95 C0FEFFFF LEA EDX,DWORD PTR SS:[EBP-140]
10053665 |. 33C0 XOR EAX,EAX
10053667 |. E8 78F3FAFF CALL crackme3.100029E4
1005366C |. 8B85 C0FEFFFF MOV EAX,DWORD PTR SS:[EBP-140]
10053672 |. E8 E10DFBFF CALL crackme3.10004458
10053677 |. 50 PUSH EAX ; |CommandLine
10053678 |. 6A 00 PUSH 0 ; |ModuleFileName = NULL
1005367A |. E8 3D29FBFF CALL <JMP.&kernel32.CreateProcessA> ; \CreateProcessA
1005367F |. C785 18FFFFFF >MOV DWORD PTR SS:[EBP-E8],10007
10053689 |. 8D85 18FFFFFF LEA EAX,DWORD PTR SS:[EBP-E8]
1005368F |. 50 PUSH EAX ; /pContext
10053690 |. 8B85 0CFFFFFF MOV EAX,DWORD PTR SS:[EBP-F4] ; |
10053696 |. 50 PUSH EAX ; |hThread
10053697 |. E8 F029FBFF CALL <JMP.&kernel32.GetThreadContext> ; \GetThreadContext
1005369C |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
1005369F |. 50 PUSH EAX ; /pBytesRead
100536A0 |. 6A 04 PUSH 4 ; |BytesToRead = 4
100536A2 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8] ; |
100536A5 |. 50 PUSH EAX ; |Buffer
100536A6 |. 8B45 BC MOV EAX,DWORD PTR SS:[EBP-44] ; |
100536A9 |. 83C0 08 ADD EAX,8 ; |
100536AC |. 50 PUSH EAX ; |pBaseAddress
100536AD |. 8B85 08FFFFFF MOV EAX,DWORD PTR SS:[EBP-F8] ; |
100536B3 |. 50 PUSH EAX ; |hProcess
100536B4 |. E8 7B2AFBFF CALL <JMP.&kernel32.ReadProcessMemory> ; \ReadProcessMemory
100536B9 |. 6A 40 PUSH 40
100536BB |. 68 00300000 PUSH 3000
100536C0 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
100536C3 |. 50 PUSH EAX
100536C4 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C]
100536C7 |. 8B40 34 MOV EAX,DWORD PTR DS:[EAX+34]
100536CA |. 50 PUSH EAX
100536CB |. 8B85 08FFFFFF MOV EAX,DWORD PTR SS:[EBP-F8]
100536D1 |. 50 PUSH EAX
100536D2 |. E8 BD2AFBFF CALL <JMP.&kernel32.VirtualAllocEx>
100536D7 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
100536DA |. 50 PUSH EAX ; /pBytesWritten
100536DB |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] ; |
100536DE |. 50 PUSH EAX ; |BytesToWrite
100536DF |. 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18] ; |
100536E2 |. 50 PUSH EAX ; |Buffer
100536E3 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C] ; |
100536E6 |. 8B40 34 MOV EAX,DWORD PTR DS:[EAX+34] ; |
100536E9 |. 50 PUSH EAX ; |Address
100536EA |. 8B85 08FFFFFF MOV EAX,DWORD PTR SS:[EBP-F8] ; |
100536F0 |. 50 PUSH EAX ; |hProcess
100536F1 |. E8 BE2AFBFF CALL <JMP.&kernel32.WriteProcessMemory> ; \WriteProcessMemory
100536F6 |. 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
100536F9 |. 50 PUSH EAX ; /pBytesWritten
100536FA |. 6A 04 PUSH 4 ; |BytesToWrite = 4
100536FC |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C] ; |
100536FF |. 83C0 34 ADD EAX,34 ; |
10053702 |. 50 PUSH EAX ; |Buffer
10053703 |. 8B45 BC MOV EAX,DWORD PTR SS:[EBP-44] ; |
10053706 |. 83C0 08 ADD EAX,8 ; |
10053709 |. 50 PUSH EAX ; |Address
1005370A |. 8B85 08FFFFFF MOV EAX,DWORD PTR SS:[EBP-F8] ; |
10053710 |. 50 PUSH EAX ; |hProcess
10053711 |. E8 9E2AFBFF CALL <JMP.&kernel32.WriteProcessMemory> ; \WriteProcessMemory
10053716 |. 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-1C]
10053719 |. 8B40 34 MOV EAX,DWORD PTR DS:[EAX+34]
1005371C |. 8B55 E4 MOV EDX,DWORD PTR SS:[EBP-1C]
1005371F |. 0342 28 ADD EAX,DWORD PTR DS:[EDX+28]
10053722 |. 8945 C8 MOV DWORD PTR SS:[EBP-38],EAX
10053725 |. 8D85 18FFFFFF LEA EAX,DWORD PTR SS:[EBP-E8]
1005372B |. 50 PUSH EAX ; /pContext
1005372C |. 8B85 0CFFFFFF MOV EAX,DWORD PTR SS:[EBP-F4] ; |
10053732 |. 50 PUSH EAX ; |hThread
10053733 |. E8 342AFBFF CALL <JMP.&kernel32.SetThreadContext> ; \SetThreadContext
10053738 |. 8B85 0CFFFFFF MOV EAX,DWORD PTR SS:[EBP-F4]
1005373E |. 50 PUSH EAX ; /hThread
1005373F |. E8 002AFBFF CALL <JMP.&kernel32.ResumeThread> ; \ResumeThread
10053744 |. 33C0 XOR EAX,EAX
10053746 |. 5A POP EDX
Поставив бряк на CreateProcessA, я нажал F9 (не забывайте обходить ту вредную функцию). Брякаемся и вот параметры функции:
Код:
0012FC6C 1005367F /CALL to CreateProcessA from crackme3.1005367A
0012FC70 00000000 |ModuleFileName = NULL
0012FC74 00DB3A30 |CommandLine = "C:\crackme3u.exe"
0012FC78 00000000 |pProcessSecurity = NULL
0012FC7C 00000000 |pThreadSecurity = NULL
0012FC80 00000000 |InheritHandles = FALSE
0012FC84 00000004 |CreationFlags = CREATE_SUSPENDED
0012FC88 00000000 |pEnvironment = NULL
0012FC8C 00000000 |CurrentDir = NULL
0012FC90 0012FCC0 |pStartupInfo = 0012FCC0
0012FC94 0012FD04 \pProcessInfo = 0012FD04
Действительно создаёт новый процес и тормозит его! А как же нам попасть туда? Аттачится конечно! Но вот беда, Olly видит процес только после выполнения
Код:
1005373F |. E8 002AFBFF CALL <JMP.&kernel32.ResumeThread> ; \ResumeThread
А после выполнения этой функции программу на ep нам не застать! Лан жмём F9 в Olly прога вылетает, новый процесс остаётся! Открываем ещё раз Olly (ну чтоб было два процесса)! Аттачимся!
Открываем карту памяти и вот что замечаем:
Код:
Memory map, item 15
Address=00400000
Size=000A0000 (655360.)
Owner=CrackMe3 00400000 (itself)
Section=
Contains=PE header
Type=Priv 00021040
Access=RWE
Initial access=RWE
Новый image base => новый ep, код которого записывается старым процесом. Посмотрим новый EP!
Код:
00400068 BC950700 DD 000795BC ; AddressOfEntryPoint = 795BC
Ладно всё что нужно мы узнали закрываем окно! Перезапускаем прогу и опять проходим до CreateProcessA. Идём до WriteProcessMemory. И пока не выполняем её! Вот параметры этой функции:
Код:
0012FC80 100536F6 /CALL to WriteProcessMemory from crackme3.100536F1
0012FC84 000000A8 |hProcess = 000000A8 (window)
0012FC88 00400000 |Address = 400000
0012FC8C 00D13A24 |Buffer = 00D13A24
0012FC90 000A0000 |BytesToWrite = A0000 (655360.)
0012FC94 0012FDF0 \pBytesWritten = 0012FDF0
Отправляемся по адресу, с которого ведётся запись в новый процесс! 00D13A24 - это image base в новом процессе, а значит по 00D13A24+795BC будет код ep. Отправляемся по 00D8CFE0. Этот код вызвал у меня истерический смех:
Код:
$+795BC > 9C PUSHFD
$+795BD > 60 PUSHAD
$+795BE > E8 00000000 CALL 00D8CFE7
$+795C3 > 5D POP EBP
$+795C4 > 83ED 07 SUB EBP,7
Судя по всему процесс будет ещё распаковываться =)) Спросите зачем я вас сюда завёл! Смотрите, если в каком-нибудь процессе возникнет исключение, то мы можем поймать его Olly, правильно сконфигурировав её. Итак перебиваем pushfd на int3. Именно int3; не int 3; разница в целый байт! Нам нужен int3 = 0CCh. Теперь конфигурируем Olly. В Options > Just-in-time debugging > Make OllyDbg just-in-time debugger. Теперь когда процесс вызовит исключение, а он вызовит первой же коммандой =), Olly среагирует на это и мы окажемся но ep!
F9 и открывается новый процесс Olly! Ура мы на EP! Возвращаем на место pushf и обходим пакер, благо использовался старый!
Мдя.. На первый взгляд ничего не изменилось...
Код:
00454DFC 55 PUSH EBP
00454DFD 8BEC MOV EBP,ESP
00454DFF 83C4 F0 ADD ESP,-10
00454E02 B8 1C4C4500 MOV EAX,CrackMe3.00454C1C
00454E07 E8 540EFBFF CALL CrackMe3.00405C60
00454E0C E8 7BFDFFFF CALL CrackMe3.00454B8C
00454E11 84C0 TEST AL,AL
00454E13 75 09 JNZ SHORT CrackMe3.00454E1E
00454E15 E8 96FDFFFF CALL CrackMe3.00454BB0
00454E1A 84C0 TEST AL,AL
00454E1C 74 05 JE SHORT CrackMe3.00454E23
00454E1E E8 39EFFAFF CALL CrackMe3.00403D5C
00454E23 A1 98604500 MOV EAX,DWORD PTR DS:[456098]
00454E28 8B00 MOV EAX,DWORD PTR DS:[EAX]
00454E2A E8 71DFFFFF CALL CrackMe3.00452DA0
00454E2F A1 98604500 MOV EAX,DWORD PTR DS:[456098]
И та функця проверки осталась. На этот раз мы в неё зайдём, только через enter. И поставим бряк на первый байт! Теперь если туда попадёт управление мы будем об этом знать! "-" и обходим с помощью New origin here! F9.
Попадание на ep нам практически ничего не дало! Пытал прогу и на String reference и бряки на апи ставил, естественно на последние байты, но это ничего не дало. ппц! Но у меня в запасе был ещё один приём. Я ввёл dimok и вылетело сообщение о неправильности пароля. В ArtMoney нашёл адреса, в которых лежит это слово. Поставил на них бряки и ещё раз нажал ввод!
Бряк сработал мгновенно я оказался внутри какойто функции!
Посомотрим на стек, там несколько раз встречается слово dimok. Но мы ищем первый адрес вазврата в секцию кода и находим
Код:
0012F45C |00437B10 RETURN to CrackMe3.00437B10 from CrackMe3.00406278
Идём по адресу!
Код:
00437B03 50 PUSH EAX
00437B04 8B86 74010000 MOV EAX,DWORD PTR DS:[ESI+174]
00437B0A 50 PUSH EAX
00437B0B E8 68E7FCFF CALL CrackMe3.00406278 ; JMP to USER32.CallWindowProcA
00437B10 8943 0C MOV DWORD PTR DS:[EBX+C],EAX
00437B13 8B03 MOV EAX,DWORD PTR DS:[EBX]
00437B15 83F8 0C CMP EAX,0C
00437B18 75 1B JNZ SHORT CrackMe3.00437B35
00437B1A 8B53 08 MOV EDX,DWORD PTR DS:[EBX+8]
00437B1D 52 PUSH EDX
Снимаем старые бряки и поставим новый на 437b1a. Нажмём на кнопочку, и бряк срабатывает!
Код:
00437B1A 8B53 08 MOV EDX,DWORD PTR DS:[EBX+8]
00437B1D 52 PUSH EDX
00437B1E 8B4B 04 MOV ECX,DWORD PTR DS:[EBX+4]
00437B21 8BD0 MOV EDX,EAX
00437B23 8BC6 MOV EAX,ESI
00437B25 E8 56B7FFFF CALL CrackMe3.00433280
Один из параметров этой функции адрес Warning. Следовательно функция проверки гдето выше, а то куда мы попали это функции отрисовки MessageBoxA. Начинаем трассировать. В стеке должны храниться адреса строк о неправильности. Мыже находимся в вызываемой функции отрисовки. Короче жмём F8 пока в стеке нам не встретятся строчки о неправильности! Дальше нам встретится
Код:
0012F93C 00DB2448 ASCII "dimok"
0012F940 00DB3B90 ASCII "351239814584495632156"
0012F944 00DB23F8 ASCII "651236594485418932153-XNA"
0012F948 00DB2420 ASCII "ANX-351239814584495632156"
а после этого следует адрес возврата
Код:
0012F950 |00434C7A RETURN to CrackMe3.00434C7A
идём по нему и мы окажемся в этой функции, если подняться выше.
Код:
004549BC 55 PUSH EBP
004549BD 68 CC4A4500 PUSH CrackMe3.00454ACC
004549C2 64:FF30 PUSH DWORD PTR FS:[EAX]
004549C5 64:8920 MOV DWORD PTR FS:[EAX],ESP
004549C8 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
Кароче, если вы её проанализируете, то поймёте, что пароль ANX-351239814584495632156.
|
|
|

05.02.2007, 01:32
|
|
Постоянный
Регистрация: 16.08.2006
Сообщений: 640
Провел на форуме: 1354067
Репутация:
599
|
|
Ra$cal KeyGenMe 2
Написал как автор крякми. То есть на что я делал ставку. Ждём солюшена человека, взломавшего сей крякми...
Итак. Основная фича этого творения - антиотладка используется с интересной целью. Не просто выдаёт месаджбокс и выходит. А данные получаемые от проверок изменяют внутренний ключ, который участвует в проверке. Таким образом если программа отлаживается и хоть одна проверка обнаружила отладчик, то найденный ключ не подойдёт при запуске программы без отладчика. Теперь про реализацию...
Сначала была придумана константа - 0x7DA3EF10. Далее вспомнил какие проверки знаю. Всего решил сделать 5 штук. Соотв решил какие биты в константе должны быть изменены. 3 бита должны быть изменены, 2 должны остаться. 0x7923EF14. Далее для сложности обнаружения обращений к этому дворду (в олли очень просто найти всю работу с конкретным адресом в секции данных. то есть легко локализовать и изменения и использование этой константы) сделал так. Дворд был разбит на 2: ControlDW_L = 0x5ca3ef14 и ControlDW_H = 0xba617923. В сладших словах находятся части константы. А для собсно скрытия обращений сделал ещё две переменные. Итог - static DWORD DummyBefore = 0x547298f0, ControlDW_L = 0x5ca3ef14, ControlDW_H = 0xba617923, DummyAfter = 0xba45910f;
Компилятор сделает так что эти переменные в памяти находятся последовательно. Следовательно чтоб обратиться к нужной достаточно получить адрес подставной переменной и и прибавить/удалить 4. Или 8. Вобщем как это работает:
Код:
_asm{
lea eax, DummyBefore;
add eax, 8;
mov eax, [eax]; получили ControlDW_H
}
Дальше...
Для реализации идеи пришлось придумывать, как связать возвращаемое значение проверки (причём не просто cmp jnz, а именно то значение, которое возвращает апи(например) при наличии отладчика и при его отсутствии). Так для IsDebuggerPresent задумано, что при отсутствии отладчика он вернёт 0. То есть если вернёт 1 константа будет испорчена...
Код:
temp = IsDebuggerPresent();
_asm{
lea eax, DummyBefore;
add eax, 8;
mov ecx, temp;
xor [eax], ecx;
}
Ещё из применённых проверок.
Код:
004016D0 >/$ 55 PUSH EBP
004016D1 |. 8BEC MOV EBP,ESP
004016D3 |. 83EC 08 SUB ESP,8
004016D6 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
004016D9 |. 50 PUSH EAX ; /pThreadId
004016DA |. 6A 00 PUSH 0 ; |CreationFlags = 0
004016DC |. 6A 00 PUSH 0 ; |pThreadParm = NULL
004016DE |. 68 30164000 PUSH KeyGenMe.CheckMemoryCrc ; |ThreadFunction = KeyGenMe.CheckMemoryCrc
004016E3 |. 6A 00 PUSH 0 ; |StackSize = 0
004016E5 |. 6A 00 PUSH 0 ; |pSecurity = NULL
004016E7 |. FF15 1C104000 CALL NEAR DWORD PTR DS:[<&KERNEL32.CreateThread>] ; \CreateThread
004016ED |. C745 F8 00000000 MOV DWORD PTR SS:[EBP-8],0
004016F4 |. EB 09 JMP SHORT KeyGenMe.004016FF
004016F6 |> 8B4D F8 /MOV ECX,DWORD PTR SS:[EBP-8]
004016F9 |. 83C1 01 |ADD ECX,1
004016FC |. 894D F8 |MOV DWORD PTR SS:[EBP-8],ECX
004016FF |> 817D F8 88130000 CMP DWORD PTR SS:[EBP-8],1388
00401706 |. 7D 30 |JGE SHORT KeyGenMe.00401738
00401708 |. 817D F8 D0070000 |CMP DWORD PTR SS:[EBP-8],7D0
0040170F |. 7E 25 |JLE SHORT KeyGenMe.00401736
00401711 |. 817D F8 C4090000 |CMP DWORD PTR SS:[EBP-8],9C4
00401718 |. 7D 1C |JGE SHORT KeyGenMe.00401736
0040171A |. C705 18214000 01>|MOV DWORD PTR DS:[CanCheck],1
00401724 |. 6A 00 |PUSH 0 ; /Timeout = 0. ms
00401726 |. FF15 18104000 |CALL NEAR DWORD PTR DS:[<&KERNEL32.Sleep>] ; \Sleep
0040172C |. C705 18214000 00>|MOV DWORD PTR DS:[CanCheck],0
00401736 |>^ EB BE \JMP SHORT KeyGenMe.004016F6
00401738 |> 8BE5 MOV ESP,EBP
0040173A |. 5D POP EBP
0040173B \. C3 RETN
Вот пример. Цикл в 5000 итераций. Причём с сомнительным содержимым. Тут надежда что поставят бряк на 3 последние команды цикла. А суть простая - Sleep (0) приводит к прекращению обработки текущего потока (его квант процессорного времени обнуляется) и начале работы другого потока процесса (если такой есть). А он, как видим немного выше, как раз создаётся. Как видно из инфы в pdb, функцию я назвал CheckMemoryCrc.Так вот Sleep (0) приведёт к тому, что второй поток будет сработывать при вызове Sleep(0)...
Код:
00401630 >/. 55 PUSH EBP
00401631 |. 8BEC MOV EBP,ESP
00401633 |> 813D 14214000 C7>/CMP DWORD PTR DS:[ThreadCounter],0C7
0040163D |. 75 32 |JNZ SHORT KeyGenMe.00401671
0040163F |. 8B0D 28204000 |MOV ECX,DWORD PTR DS:[MemoryCrc]
00401645 |. BA 01000000 |MOV EDX,1
0040164A |. 22D1 |AND DL,CL
0040164C |. C1C9 10 |ROR ECX,10
0040164F |. 22D1 |AND DL,CL
00401651 |. C1C9 08 |ROR ECX,8
00401654 |. 22D1 |AND DL,CL
00401656 |. C1C2 06 |ROL EDX,6
00401659 |. 8D05 18204000 |LEA EAX,DWORD PTR DS:[DummyBefore]
0040165F |. 83C0 08 |ADD EAX,8
00401662 |. C1C2 04 |ROL EDX,4
00401665 |. 3110 |XOR DWORD PTR DS:[EAX],EDX
00401667 |. C705 28204000 00>|MOV DWORD PTR DS:[MemoryCrc],0
00401671 |> 813D 14214000 C8>|CMP DWORD PTR DS:[ThreadCounter],0C8
0040167B |. 7E 0B |JLE SHORT KeyGenMe.00401688
0040167D |. 833D 18214000 01 |CMP DWORD PTR DS:[CanCheck],1
00401684 |. 75 02 |JNZ SHORT KeyGenMe.00401688
00401686 |. EB 40 |JMP SHORT KeyGenMe.004016C8
00401688 |> A1 14214000 |MOV EAX,DWORD PTR DS:[ThreadCounter]
0040168D |. 83C0 01 |ADD EAX,1
00401690 |. A3 14214000 |MOV DWORD PTR DS:[ThreadCounter],EAX
00401695 |. C705 28204000 00>|MOV DWORD PTR DS:[MemoryCrc],0
0040169F |. 833D 14214000 0F |CMP DWORD PTR DS:[ThreadCounter],0F
004016A6 |. 75 05 |JNZ SHORT KeyGenMe.004016AD
004016A8 |. E8 03010000 |CALL KeyGenMe.HRChecker
004016AD |> B9 D0164000 |MOV ECX,KeyGenMe.MemoryCheckFaker
004016B2 |. 8B51 68 |MOV EDX,DWORD PTR DS:[ECX+68]
004016B5 |. 8915 28204000 |MOV DWORD PTR DS:[MemoryCrc],EDX
004016BB |. 6A 00 |PUSH 0 ; /Timeout = 0. ms
004016BD |. FF15 18104000 |CALL NEAR DWORD PTR DS:[<&KERNEL32.Sleep>] ; \Sleep
004016C3 |.^ E9 6BFFFFFF \JMP KeyGenMe.00401633
004016C8 |> 5D POP EBP
004016C9 \. C3 RETN
Здесь тоже цикл и Sleep (0). То есть тут просто синхронизированы потоки. Далее.
Установка бряка в олли осуществляется просто. В целевой процесс пишут байт 0xCC по нужному адресу. Поэтому я читаю 4 байта с конца функции (куда я ожидаю установки бряка).
Код:
004016B2 |. 8B51 68 |MOV EDX,DWORD PTR DS:[ECX+68]
004016B5 |. 8915 28204000 |MOV DWORD PTR DS:[MemoryCrc],EDX
Прикинув как выглядят байты 0x8B, 0x5D, 0xC3 и 0xCC я нашёл, что СС - нечётное число, остальные чётные. Соответственно первый бит равен единице, если бряк не установлен, и 0, если установлен. Эта проверка должна изменить константу. Если хоть один бряк установлен бит будет обнулён.
Код:
0040163F |. 8B0D 28204000 |MOV ECX,DWORD PTR DS:[MemoryCrc]
00401645 |. BA 01000000 |MOV EDX,1
0040164A |. 22D1 |AND DL,CL
0040164C |. C1C9 10 |ROR ECX,10
0040164F |. 22D1 |AND DL,CL
00401651 |. C1C9 08 |ROR ECX,8
00401654 |. 22D1 |AND DL,CL
00401656 |. C1C2 06 |ROL EDX,6
00401659 |. 8D05 18204000 |LEA EAX,DWORD PTR DS:[DummyBefore]
0040165F |. 83C0 08 |ADD EAX,8
00401662 |. C1C2 04 |ROL EDX,4
00401665 |. 3110 |XOR DWORD PTR DS:[EAX],EDX
Плюс ещё есть вызов 004016A8 |. E8 03010000 |CALL KeyGenMe.HRChecker
Эта проверка проверят, установлен ли хардбряк. Для этого вызывает исключение и проверяет переданнвый контекст потока в функцию обработчик исключения, в котором было исключение. Отладчик для полноты картины ставит в контекст ВСЕХ потов хард бряки, заданные пользователем в каком-то одном. Чтобы мы не пропустили никаких интересующих нас событий. Следовательно, даже если бряк поставлен в другом потоке, в нашем созданном потоке он тоже будет. Поэтому в контексте можно проверить их наличие.
Код:
00401748 |. 33DB XOR EBX,EBX
0040174A |. 0B59 04 OR EBX,DWORD PTR DS:[ECX+4]
0040174D |. 0B59 08 OR EBX,DWORD PTR DS:[ECX+8]
00401750 |. 0B59 0C OR EBX,DWORD PTR DS:[ECX+C]
00401753 |. 0B59 10 OR EBX,DWORD PTR DS:[ECX+10]
00401756 |. 0B59 18 OR EBX,DWORD PTR DS:[ECX+18]
00401759 |. 8D05 24204000 LEA EAX,DWORD PTR DS:[DummyAfter]
0040175F |. 83E8 04 SUB EAX,4
00401762 |. 3118 XOR DWORD PTR DS:[EAX],EBX
Эта проверка тоже не должна изменить никакой бит, ибо используется значение регитсров dr, и если хоть 1 задан, то константа опять не будет валидной.
Собсно есть ещё проверки, но логика их такая же. Перечислю только их суть - проверка отладочного порта и фича с обработкой CloseHandle с неправильным параметром.
Теперь что с алгоритмом. Как я и говорил он простой. Напишу тока код моего генератора
Код:
DWORD Control = 0x7DA3EF10;
void Generate(char* UserName, char* Password)
{
DWORD Hash = 0;
long Summ = 0;
DWORD Pass = 0;
for (int i = strlen (UserName); i >= 0; i--){
Hash ^= UserName[i];
_asm{
rol Hash, 8;
}
Summ += UserName[i];
}
Pass = (Summ + Hash) ^ Control;
_itoa(Pass, Password, 16);
int len = strlen (Password);
if (len < 8){
int d;
d = 8 - len;
memcpy (Password + d, Password, len);
memset (Password, '0', d);
Password [8] = '\0';
}
}
|
|
|

13.04.2007, 09:00
|
|
Постоянный
Регистрация: 20.08.2006
Сообщений: 327
Провел на форуме: 2472378
Репутация:
1077
|
|
CrackME by _taha_
CrackMe: CrackME by _taha_(мой тобишь)
Цель: найти верный пароль
Сложность: легко
link: искать в разделе крякмисы
Поскольку на мой кякмис было только три ответа, я решил последовать примеру Rascal’a и написать небольшой солюшен. Сейчас я расскажу о неновых, зато довольно интересных, антиотладочных приёмах затронутых в этом крякмисе. Из множества приёмчиков я отобрал именно эти.
Итак начнём... Открываем файл в OllyDbg. Первое, что бросается в глаза не стандартное начало. Это явно не стартап..
Первое что вы увидели это переход, войдя в него - инкремент [ESP], затем стандартное продолжение установки обработчика исключений.
Код:
0040103C |. 64:FF35 00000>PUSH DWORD PTR FS:[0] ; |
00401043 |. 64:8925 00000>MOV DWORD PTR FS:[0],ESP ; |
Из чего вы должны были сделать вывод, что следующий, после call, байт – это мусор, запутывающий дизассемблер Olly. Поэтому вместо этого
Код:
call opa
db 68h
mov eax, [esp+0Ch]
inc dword ptr [eax+0B8h]
xor edx,edx
вы видели это
Код:
00401000 >/$ E8 34000000 CALL _CrackME.00401039
00401005 |. 68 8B44240C PUSH 0C24448B
0040100A |. FF80 B8000000 INC DWORD PTR DS:[EAX+B8]
Теперь понятно почему я выбрал байт 68h. Olly отказывается верить, что там нет push’а. Далее идёт исключительная ситуация, int3. В результате чего мы попадаем на адрес 401006. Здесь вы должны заметить, что программа проверяет хардваровые бряки.
Код:
0040101E |. 66:3115 26304>XOR WORD PTR DS:[403026],DX
Если breakpoint’ов нет, то в dx должен быть ноль. Соответсвенно константа [403026] не пострадает. А пока перенесёмся на следущую после int3 команду. Восстанавливается старый обработчик исключний. А уже ненужный кадр стека не затерается как обычно, а увеличивается на 24h, в результате чего в стеке останется указатель на строку “%s%s%s%s”, и используется в качестве параметра к функции OutputDebugStringA. Это exploit, так сказать. OutputDebugStringA отправляет Olly строку “%s%s%s%s”, которую та не может коректно обработать. В результате Olly просто вылетает. Поэтому нужно использовать либо пофикшеные модификации отладчика, либо выравнить стек, а функцию забить нопами.
Далее вроде всё тихо, всё за исключением одной функции
0040106C |. E8 6A010000 CALL _CrackME.004011DB
Код:
mov eax, fs:[30h] ;
lea eax, [eax+2] ; Это своеобразный вызов IsDebuggerPresent
movzx ebx, byte ptr [eax] ;
test ebx, ebx
je ex_
xor [00403026],0EA43h ; херю константу
ex_:
mov byte ptr [eax],90h
ret
Дальше интересней.. Проверить я проверил, но в подлиности результата в 99% случаев можно сомневаться, тк редкий реверсИр не использует плагин для скрытия. И проблема большенства из них в том, что они патчат не PEB, а функцию IsDebuggerPresent. Естественно API IsDebuggerPresent будет возвращать ноль в любом случае. И это как раз проблема плагина. Я кладу в PEB число 90h и если при следующем вызове IsDebuggerPresent возвратит не 90h, то смело можно предполагать – нас отлаживают. Убедится в этом вы можете, найдя эти строки
Код:
004010B9 . E8 4C010000 CALL <JMP.&kernel32.IsDebuggerPresent> ; [IsDebuggerPresent
004010BE . 3D 90000000 CMP EAX,90
004010C3 . 75 09 JNZ SHORT _CrackME.004010CE
004010C5 . 66:8135 28304>XOR WORD PTR DS:[403028],0DEAD
Перейдём к GetDlgItemTextA и продолжим исследовать. Дальше идёт вот эта функция
00401145 . E8 3D000000 CALL _CrackME.00401187
Исследовав внутренности этой функции, вы должны были понять, что хэшируется. Но это не всё! Одна из главных “интересностей” крякмиса скрывается ИМЕНО ЗДЕСЬ.
Код:
0040118E |. 8B1424 MOV EDX,DWORD PTR SS:[ESP]
00401191 |. 66:8B12 MOV DX,WORD PTR DS:[EDX]
Этот код сохранит в dx следующие после CALL _CrackME.00401187 два байта, которые будут учавствовать в хэшировании. И что же тут интересного? – спросит читатель. А дело в том, что когда программа трассируется по F8, Olly ставит на следующий после call байт бряк – int3 и отпускает программу в “свободный полёт”. Когдаже программа “нагуляется” по внутреностям CALL _CrackME.00401187 и перейдёт на следующий байт, Olly всё вернёт на место. Соответсвено после прохождения функции по F7 и вызова её по F8, будут разные результаты. Что повлияет на результат.
Далее идёт вызов Int1, что должно повлечь исключительную ситуацию. Фитча в том, что Olly не считает прирывание INT1 исключением если оно идёт с префиксом, а вот Windows считает.
Код:
0040114A . F3:64: PREFIX REP: ; Superfluous prefix
0040114C . F1 INT1
Так что, без отладчика мы должны попасть на SEH-обработчик. Итак пойдём на действующий обработчик.
Код:
004011B4 /$ 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] ; Structured exception handler
004011B8 |. 8B1D 42354000 MOV EBX,DWORD PTR DS:[403542] ; _CrackME.0040114D
004011BE |. 8998 B8000000 MOV DWORD PTR DS:[EAX+B8],EBX
004011C4 |. 8B90 A8000000 MOV EDX,DWORD PTR DS:[EAX+A8]
004011CA |. 80FA CC CMP DL,0CC
004011CD |. 74 09 JE SHORT _CrackME.004011D8
004011CF |. 66:8135 26304>XOR WORD PTR DS:[403026],9696
004011D8 |> 33C0 XOR EAX,EAX
004011DA \. C3 RETN
Как вы можете заметить, здесь устанавливается EIP и ещё раз проверяется была ли трассеровка по F8.
С анти дебагом всё! Дальше идёт сравнение:
Код:
0040114D . 3B05 26304000 CMP EAX,DWORD PTR DS:[403026]
00401153 . 75 13 JNZ SHORT _CrackME.00401168
Как вы могли заметить, [403026] складывается из тех двух word’ов, которые менялись в процессе отладки.
Если вы проделали всё правильно, то у вас должно храниться по этому адресу число 2D5253F3h.
Теперь о том как найти пароль. Ведь хэш – это необратимое преобразование, следовательно ничего кроме брута вам не остается. Как вы должны были подметить, пароль состоит из 4’х символов. К тому же, как я написал пароль состоит из русских букв. Заметьте это значительно снижает область брута. Приводить код брутера не буду, только дам вам вот эти линки:
http://www.reversing.be/article.php?story=20050302175850923&query=brutefor cing
http://www.reversing.be/article.php?story=20050414211341413&query=brutefor cing
Замечу только, что если всё проделанно верно, то пароль брутится считанные секунды.
|
|
|

03.08.2007, 14:41
|
|
Постоянный
Регистрация: 25.05.2007
Сообщений: 448
Провел на форуме: 4226446
Репутация:
1564
|
|
CrackMe: CrackMe by taha
Цель: найти пару имя+ключ
Сложность: легко
link: в разделе реверсинг
Решение:
В этой статье я постараюсь максимально подробно описать взлом данного крекми, но если у вас есть замечания/дополнения/ прием не нравится какой-либо (или способ лучше есть), пишите в пм или icq-буду рада конструктивной критике.
Приступим
Итак, загружаем crackme в отладчик
Entry point
Код:
00401185 > B9 C7010000 MOV ECX,1C7
0040118A BB 78104000 MOV EBX,CrackME.00401078
0040118F 21CB AND EBX,ECX
00401191 81F1 FF000000 XOR ECX,0FF
00401197 09F2 OR EDX,ESI
00401199 83C1 4D ADD ECX,4D
0040119C BE 220F4000 MOV ESI,CrackME.00400F22
Видно,что на обычную точку входа это мало похоже. Значит, это начало расшифровки кода. А если быть точнее- выполнение вспомогательных операций. В частности в по окончанию этого фрагмента в ecx окажется количество зашифрованных байт а именно 185h (хекс).
Шифровщик простой - ксорный.
Код:
004011A7 80340E 18 XOR BYTE PTR DS:[ESI+ECX],18 ; с каждым проходом значение уменьшается, двигаемся к началу
Исходя из начальных значений можно посчитать с какого адреса начинается расшифровка кода.
В esi в самом начале цикла 400FFF=>адрес с которого начинается расшифровка=00400FFF+185=401184.
Так как ecx после каждого прохода цикла декрементируется => расшифровываться код начинает с конца.
Самый конец цикла
Код:
004011E2 83EC 01 SUB ESP,1
004011E5 83C4 05 ADD ESP,5
004011E8 ^ FF6424 FC JMP DWORD PTR SS:[ESP-4] ; CrackME.004011A7
Ставим точку останова на этот джамп, в дампе идем по адресу 401000 и наблюдаем за тем,
как расшифровывается код. Пока идет расшифровка кода - управление передается на адрес 004011A7.
В ecx в этот момент считается количество оставшихся байт... Когда код расшифруется- джамп передаст управление на адрес 00401001... Начинаем трассировать.
Вызов функций в уже раскриптованом коде имеет вид, подобный этому
Код:
00401035 . /EB FF JMP SHORT CrackME.00401036
00401037 . 15 C4204000 ADC EAX,<&USER32.DialogBoxParamA>
Интересно... Это значит, что срабатывает джамп JMP SHORT CrackME.00401036 и передает управление на
инструкцию call [адрес] (опкод FF15 хххххххх).
Но это еще не все. Довольно неприятна и такая конструкция
Код:
00401090 . /74 01 JE SHORT CrackME.00401093
00401092 . |3B83 C404E800 CMP EAX,DWORD PTR DS:[EBX+E804C4]
Из-за этого всего оля неправильно анализирует инструкции. Напишем скрипт, исправляющий это дело. Конечно, в данном конкретном случае не вижу особого смысла этого делать. Так как замусоривание не очень страшное и глобальное) Честно говоря, взломала без скрипта, - итак все было вполне понятно=) Если бы не статья- скрипт бы писать, конечно, не стала.
Код:
var nachalo ; все, что начинается с var - объявление переменных
var conez
var str_2
var str_3
mov str_3,00402000 ; куда данные инструкции впихнуть должно быть 5 байт свободно! указать можно и свой адрес
mov nachalo,00401001 ; начало исправляемого кода == entry point
mov conez,004011e8 ; конец исправляемого кода
start:
cmp nachalo,conez ; мы в конце?
je final ; тогда на выход
mov [str_3],[nachalo]
mov str_2,str_3
inc str_2 ; первый байт в последовательности меняющийся, его пропускаем
cmp [str_2],15ffeb ; если последовательность совпадает-идем исправлять
je ispr_call ;если равно- замусоренная инструкция call
cmp [str_2],3b0174 ; если последовательность совпадает-идем исправлять
je ispt_inst
inc nachalo
jmp start ; на начало
final:
ret
ispr_call:
mov [str_2],15ff90 ; нопим злой негодяйский байт
dec str_2
mov [nachalo],[str_2]
inc nachalo ; идем вперед
jmp start ; на начало
ispt_inst:
mov [str_2],909090 ; нопим три паразитных байта
dec str_2
mov [nachalo],[str_2]
inc nachalo ; идем вперед
jmp start ; на начало
Суть в том, что я пробегаюсь по коду и ищу опкоды замусоренных команд. Нехорошо, то, что обе постоянные последовательности имеют размер 3 байта- было бы двойное слово-было б гораздо удобнее. Поэтому приходится хитрить. Недаром буфер должен быть 5 байт. То есть мы читаем очередной дворд, пишем его в буфер, инкрементируем, пропускаем переменный (изменяющийся от инструкции к инструкции) байт и тогда уже сравниваем. Чтобы было понятней, о чем я говорю, рассмотрим все ту же обработанную инструкцию call:
Код:
00401035 . /EB FF JMP SHORT CrackME.00401036
00401037 . 15 C4204000 ADC EAX,<&USER32.DialogBoxParamA>
Итак смотрим первые 4 байта eb,ff,15,0c4.. Посмотрим аналогичную инструкцию
Код:
00401003 /EB FF JMP SHORT CrackME.00401004
00401005 15 82204000 ADC EAX,<&KERNEL32.GetModuleHandleA>
Первые 4 байта eb,ff,15,82. Значит меняется только один байт. Аналогично поступаем с другой замусоренной инструкцией. Потом записываем нопы, декрементируем, возвращаясь на начало буфера и записываем содержимое на место старой команды. И так пока не проштудируем весь код. Остальной мусор (мелочи жизни) вычищается плагином analyse this!. Возможно, способ который я избрала довольно примитивен, так как эта последовательность может принадлежать, например другой инструкции... и тогда мы занопим совсем не то, что надо. Но опять же писала скрипт для этого крекми, объем кода в котором совсем не большой. И для данного конкретного случая он вполне подходит.
После работы скрипта код выглядит так
Код:
00401023 |> \830424 09 ADD DWORD PTR SS:[ESP],9
00401027 \. C3 RETN
00401028 15 DB 15
00401029 . 6A 00 PUSH 0 ; /lParam = NULL
0040102B . 68 45104000 PUSH CrackME.00401045 ; |DlgProc = CrackME.00401045
00401030 . 6A 00 PUSH 0 ; |hOwner = NULL
00401032 . 6A 25 PUSH 25 ; |pTemplate = 25
00401034 . 50 PUSH EAX ; |hInst
00401035 . 90 NOP ; |
00401036 . FF15 C4204000 CALL DWORD PTR DS:[<&USER32.DialogBoxParamA>] ; \DialogBoxParamA
0040103C . 6A 00 PUSH 0 ; /ExitCode = 0
0040103E . 90 NOP ; |
0040103F . FF15 86204000 CALL DWORD PTR DS:[<&KERNEL32.ExitProcess>] ; \ExitProcess
00401045 . 55 PUSH EBP
Красотища)))))
Теперь поиск всех вызовов имортируемых функций (Search for -> All intermodular call's).
Отлично. Найдены все функции. А их всего ничего
USER32.DialogBoxParamA
kernel32.ExitProcess
USER32.GetDlgItemTextA
USER32.GetDlgItemTextA
SHLWAPI.StrToIntA
USER32.MessageBoxA
USER32.EndDialog
И проанализировано верно)
Что ж. Пора запускать программу. Жмем f9. Высвечивается диалог для ввода имени и пароля. Теперь назначение по крайне мере двух вызовов функции GetDlgItemTextA нам ясно) Первый читает имя, второй-код. Это я узнала, загрузив файл в Restorator и посмотрев идентификаторы эдитов для ввода имени 101 (в хексе -65h), а пароля-102 (66 в хексе). Теперь смотрим на параметры функции GetDlgItemTextA. В первом случае как раз в качестве ид-а идет 65h, а во втором - 66h. После прочтения имени и пароля вызывается функция StrToIntA, принимающая в качестве параметра указатель на строку, которую требуется перевести в число.
В качестве параметра в данном случае-строка с паролем. Из этого можно сделать вывод, что пароль состоит из цифр. Потом берется имя юзера и с ним проводятся следующие манипуляции
Код:
004010B9 . 52 PUSH EDX ;строка с паролем
004010BA . 90 NOP
004010BB . FF15 1E214000 CALL DWORD PTR DS:[<&SHLWAPI.StrToIntA>] ;Великая функция
004010C1 . 31C9 XOR ECX,ECX
004010C3 . 21CB AND EBX,ECX
004010C5 . 8D75 E0 LEA ESI,DWORD PTR SS:[EBP-20] ;строка с именем
004010C8 > 8A1E MOV BL,BYTE PTR DS:[ESI] ;дальше манипуляции с именем
004010CA . 84DB TEST BL,BL
004010CC . 74 08 JE SHORT CrackME.004010D6
004010CE . 31D9 XOR ECX,EBX
004010D0 . C1C1 04 ROL ECX,4
004010D3 . 46 INC ESI
004010D4 .^ EB F2 JMP SHORT CrackME.004010C8
004010D6 > 31DB XOR EBX,EBX
004010D8 . 66:39C1 CMP CX,AX ; ключевое сравнение
004010DB . 0F94C3 SETE BL ; false-true
004010DE . 8B049D F4114000 MOV EAX,DWORD PTR DS:[EBX*4+4011F4]
004010E5 . 35 78563412 XOR EAX,12345678
004010EA . FFE0 JMP EAX
Особое внимание надо уделить инструкции SETE. Данная инструкция работает следующим образом. Сначала перед ней идет сравнение,она анализирует флаги и устанавливает значение своего операнда (bl) логическим значением 0 или 1 (false или true). То есть, если cx будет равен ax- после выполнения инструкции sete в bl окажется "истина", то есть 1. Ну и следующая инструкция напрямую зависит от значения ebx
Код:
004010DE . 8B049D F4114000 MOV EAX,DWORD PTR DS:[EBX*4+4011F4]
Если ebx будет 1 - значение в еах окажется 12744695, потом оно проксорится следующей инструкцией
Код:
004010E5 . 35 78563412 XOR EAX,12345678
и получим адрес перехода... И прыгнем на него инструкцией jmp eax. В хорошем случае прыгаем на 004010ED. Вплохом случае ebx будет равен 0, в eax мы получим 12744721, а после ксора - совершенно другой адрес перехода - 00401159.
И еще. Сначала я, как порядочная, ввела свой семисимвольный ник, но крекми наглым образом проигнорировал этот факт и урезал до 6-ти символов.... Хм( Присмотрелась к функции чтения имени
Код:
00401073 . 6A 07 PUSH 7 ; /Count = 7
00401075 . 8D55 E0 LEA EDX,DWORD PTR SS:[EBP-20] ; |
00401078 . 52 PUSH EDX ; |Buffer
00401079 . 6A 65 PUSH 65 ; |ControlID = 65 (101.)
0040107B . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
0040107E . 90 NOP ; |
0040107F . FF15 C8204000 CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>] ; \GetDlgItemTextA
00401085 . 6A 00 PUSH 0
Нда. Если бы в count было 8- ник бы прочитался нормально)
В общем далее вникать в суть происходящего дальше не имеет смысла, так как у нас есть функция StrToIntA. Как она работает-известно.
Что должно получится-нам тоже известно - это содержимое регистра cx.
Возьмем, например, число 1111 и переведем его в хекс. Получим 457. Введем 1111 в поле пароль и посмотрим что вернет функция
StrToIntA. А вернет она..... то самое 457... Это означает, что в поле пароля мы должны ввести число, полученое путем
перевода регистра cx в десятичную систему. Все элементарно=)
Вот и все...
Последний раз редактировалось 0x0c0de; 03.08.2007 в 18:34..
|
|
|

25.03.2008, 14:16
|
|
Reservists Of Antichat - Level 6
Регистрация: 04.02.2007
Сообщений: 1,152
Провел на форуме: 3008839
Репутация:
1502
|
|
Crackmy2 by Xserg
CrackMe:
Цель: найти верный пароль
Сложность: автором позиционируется как "сложно"
Коментарий: предупреждаю - буду краток.
link: http://ifolder.ru/5872875
Решение:
Запускаем крякми... Имя, пароль... Вводим чён-ть... Need good password.
Запускаем под Олей - debug detected.
Ну что ж, будем лечить. Трассируем программу с начала.
Узнаём начало DialogProc 401810. Оставляем бряк после DialogBoxIndirectParamA, так как там мы окажемся после ввода пароля, а так же ставим бряк на саму DialogProc. Пускаем программу (F9) брякаемся, идём - всё пролетает до RETN 10. Поэтому жмём ещё раз F9. Видим - по адресу 401836 создаётся таймер. Смотрим процедуру таймера - ничего интересного она не делает - что-то увеличивает, что-то уменьшает и тп. Значит ясно - нужен для антиотладки. Отключать его нельзя, ибо вероятна проверка на его запущенность.
Соображаем... А давайте поставим огромный интервал? Доходим до самого вызова, а дальше в стеке правим в 12FC88 100ms на сколько влезет. Например 0FFFFFFF ms (не забываем писать байты в обратном порядке!).
Теперь снимаем бряк с 401810 - ничего нового уже не происходит, происходит обыкновенная прорисовка окна.
Посмотрим дальше. Видим взятие имени и пароля.
Теперь либо ставим бряк на попадающиеся на глаза команды по адресам типа 40185F - GetDlgItem, то есть те команды, которые мы только что проскачили, трассируя программу до формы, либо ищем эти команды в прыжках на импортируемые функции, видим там Local call from xxxx и ставим бряк на xxxx.
F9.
Вводи чтон-ть в логин и пасс, нажимаем ок. Брякаемся на GetDlgItem. Трассируем... До EndDialog ничего интересного нет. После EndDialog трассировать бесполезно, поэтому нажимаем F9 и ждём пока сработает наш бряк в 401802.
Сработал! Трассируем (заходя во все call'ы)... Видим создание потока. Наверняка тоже для антиотладки!
Смотрим ThreadFunction... 40101D... Там что-то страшное... ладно, поставим туда бряк и попробуем запуститься по F9.
Трассируя её, смотрим, что у нас там происходит. Проверяется содержимое dword [403063], если там ноль, то выводим сообщение про отладчик, иначе уменьшаем это значение на 1. Сейчас там 1F. А давайте поставим FFFFFFFF. Итак, у нас есть очень много времени, чтобы закончить это крякми. Снимем бряки и запустим его выполняться. (В опциях надо поставить, чтобы все ошибки обрабатывала программа). Ждём-с... Замечательно! Пишет, что пасс неверен, но ничего не говорит про отладчик!
Посмотрим на код - в нём появились команды типа MessgeBox, появились слова "need good password"
Запомним то место, где мы видим MessageBox(401567), перезапустим программу и, сделав те же манипуляции с таймером и с числом 1F, поставим бряк Memory Breakpoint on write на 401567. Смотрим после каждого бряка, что там. Однажды видим появился call! Смотрим назад - там "Congratulations", а перед этим проверка пароля. Нехитрый анализ показывает, что прыжок в случае неверного пароля идёт с 4014AD. Поставим бряк на предшествующий CMP. Жмём F9... Попадаем как раз туда. теперь осталось собрать пароль  Побайтно смотрим буковки из AL...
Для имени Ter я получил пароль X43Vr3U6qQ74Up9Q. Закрываем всё, запускаем крякми, вставляем буковки...
__________________
Bedankt euch dafür bei euch selbst.
H_2(S^3/((z1, z2)~(exp(2pi*i/p)z1, exp(2pi*q*i/p)z2)))=Z/pZ
Последний раз редактировалось desTiny; 25.03.2008 в 20:21..
|
|
|
|
 |
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|