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
Замечу только, что если всё проделанно верно, то пароль брутится считанные секунды.