|
Программирование ICQ 378204653 от Turbokherson |
|
Главная » 2012 » Февраль » 21 » Легальный взлом как разминка для ума
11:38 Легальный взлом как разминка для ума |
IT-шники часто придумывают себе упражнения для ума, пытливый ум
постоянно требует разминки. Хочу рассказать об одном из самых жестких и
спорных способах – взлом специально защищенных программ-головоломок
(Часто их называют crackme).
Одно из мест, где такие головоломки собраны — crackmes.de.
Здесь находятся много интересных программ, на которых можно испробовать
свои силы по взлому. Никакого криминала – программы специально написаны
для этой цели (так называемые crackme и reverseme);
Часто любят говорить «Все защиты можно взломать». Поковыряв некоторые из crackme вы возможно измените своё мнение.
Итак приступим:
Общая схема работы многих crackme — а давайте какую-то процеду в коде
зашифруем, и «верный-неверный пароль» — в зависимости от сделанного хеша
из расшифрованных этим паролем данных?
Или как вариент — заюзаем SEH (Structured Exception Handling – механизм
обработки аппаратных и программных исключений), в который положим
месседжбокс о плохом пароле, перед этим передав управление на наш
«расшифрованный» код, при этом если пароль – правильный, то в
расшифрованном коде будут «верные» опкоды команд, а если нет, то
процессор сгенерит исключение о неверном опкоде и «кошерно» задействует
SEH, в котором у нас стоит уведомление об ошибке. Надо сказать, что в
общем этот вариант не «святой» поскольку после расшифровки возможны и
«полувалидные» опкоды- к примеру jmp-команда за пределами этой нашей
процедуры.
Но на первых порах и этого достаточно.
Итак берём крекми отсюда: crackmes.de/users/sharpe/unlockme_crackme_8_by_sharpe/download или отсюда:
crackmes.de/users/sharpe/unlockme_crackme_7_by_sharpe/download
(седьмой, кстати, не взломан пока) и загружаем в дебаггер- я
использовал олю (OllyDBG)- програмка – очень маленькая- сегмент кода
всего 0х2В6=694 байта, очень легко найти часть кода отвечающего за
чтение пароля:
0040107F |. 3D F3030000 CMP EAX,3F3
00401084 |. 75 4E JNZ SHORT 004010D4
00401086 |. 6A 21 PUSH 21 ; /Count = 21 (33.)
00401088 |. 68 88314000 PUSH 403188 ; |Buffer = eight.00403188
0040108D |. 68 F1030000 PUSH 3F1 ; |ControlID = 3F1 (1009.)
00401092 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
00401095 |. E8 04020000 CALL 0040129E ; \GetDlgItemTextA
0040109A |. 83F8 07 CMP EAX,7 здесь сравниваем длину пароля
0040109D |. 76 1F JBE SHORT 004010BE переход на смерть
0040109F |. 83F8 20 CMP EAX,20 здесь тоже сравниваем длину пародя
004010A2 |. 73 1A JNB SHORT 004010BE
004010A4 |. E8 D9000000 CALL 00401182 преобразователь пароля
004010A9 |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
004010AC |. E8 FD000000 CALL 004011AE расшифровщтк кода
004010B1 |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
004010B4 |. E8 61010000 CALL 0040121A не интересно
004010B9 |. E9 85000000 JMP 00401143 ; eight.00401143
004010BE |> 6A 30 PUSH 30 а здесь прыгать не надо)))
004010C0 |. 68 34314000 PUSH 403134 ; |Title = "-=[ Unlock Code Error"
004010C5 |. 68 4A314000 PUSH 40314A ; |Text = "The entered Unlock Code is invalid.
004010CA |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004010CD |. E8 D8010000 CALL 004012AA ; \MessageBoxA
004010D2 |. EB 6F JMP SHORT 00401143 ; eight.00401143
Итак, на основании этого видим что длина пароля долна быть в диапазоне
8-32 знака, и если это так то прыгаем в функцию преобразования
изначального пароля:
00401182 /$ 57 PUSH EDI
00401183 |. 33FF XOR EDI,EDI
00401185 |. BE 88314000 MOV ESI,403188 ; здесь в регистр пишем указатель на пароль
0040118A |. B9 20000000 MOV ECX,20
0040118F |. C705 A8314000 >MOV DWORD PTR DS:[4031A8],0 ;здесь мы запишем преобразован «хеш»
00401199 |> AC /LODS BYTE PTR DS:[ESI]
0040119A |. 85C0 |TEST EAX,EAX
0040119C |. 74 08 |JE SHORT 004011A6 ; eight.004011A6
0040119E |. 8BC8 |MOV ECX,EAX ;здесь мы сохраним «хеш» с пароля
004011A0 |. 03F8 |ADD EDI,EAX ;процедура преобразования пароля
004011A2 |. D3C7 |ROL EDI,CL ; процедура преобразования пароля
004011A4 |.^EB F3 \JMP SHORT 00401199 ; eight.00401199
004011A6 |> 893D A8314000 MOV DWORD PTR DS:[4031A8],EDI; сохраняем и выходим
004011AC |. 5F POP EDI
004011AD \. C3 RETN
А вот здесь живет расшифровщик кода:
004011AE /$ 55 PUSH EBP
004011AF |. 8BEC MOV EBP,ESP
004011B1 |. 83EC 04 SUB ESP,4
004011B4 |. 68 88314000 PUSH 403188 ; здесь вновь проверяем длину пароля
004011B9 |. E8 C2000000 CALL 00401280 ; но это – не обязательно
004011BE |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
004011C1 |. 837D FC 01 CMP DWORD PTR SS:[EBP-4],1
004011C5 |. 77 16 JA SHORT 004011DD ; eight.004011DD
004011C7 |. 6A 30 PUSH 30
004011C9 |. 68 34314000 PUSH 403134 ; |Title = "-=[ Unlock Code Error"
004011CE |. 68 4A314000 PUSH 40314A ; |Text = "The entered Unlock Code is invalid.
004011D3 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hOwner
004011D6 |. E8 CF000000 CALL 004012AA ; \MessageBoxA
004011DB |. EB 1E JMP SHORT 004011FB ; eight.004011FB
004011DD |> B8 49114000 MOV EAX,401149 ; А вот здесь начинается расшифровка пароля
004011E2 |. B9 7F114000 MOV ECX,40117F
004011E7 |. 2BC8 SUB ECX,EAX
004011E9 |. 33DB XOR EBX,EBX
004011EB |> 8B1418 /MOV EDX,DWORD PTR DS:[EAX+EBX]
004011EE |. 3315 A8314000 |XOR EDX,DWORD PTR DS:[4031A8]; как видем простая ксор-функция
004011F4 |. 891418 |MOV DWORD PTR DS:[EAX+EBX],EDX
004011F7 |. 43 |INC EBX
004011F8 |. 49 |DEC ECX
004011F9 |.^75 F0 \JNZ SHORT 004011EB ; и выходим
004011FB |> C9 LEAVE
004011FC \. C2 0400 RETN 4
Итак, теперь понятно: но как найти правильный хеш-код?
Перебором?
Это очень долго: надо сначала расшифровать, потом посчитать «энтропию»
полученного кода и возможно код с минимумом «энтропии»- рабочий, но для
этого надо писать или использовать уже написанные дизассемблерные
движки;
а можно использовать SEH, в теле которого прописать код брумфорсера, но
тогда даже одна «ложно-правильная» инструкция может полностю изменить
верный ход исполнения программы.
Но я заметил, что хоть программа написана на чистом ассемблере, но автор
всё-же много использовал в своём коде «открытие» стека, поэтому давайте
думать, что первые правильные 4 байта в нашем «зашифрованном» коде:
PUSH EBP
MOV EBP,ESP
Значение: 0х55, 0х8В, 0хЕС
А сейчас(до прохождения процедуры шифрования) значения: 0x66, 0x71,
0x77, но мы же помним (можем посмотреть) свойства «ксор» функции и
увидеть что тогда конечный хеш станет извесным:
Не забываем о «little-endian» соглашении:
77 71 66 ^
АА ВВ СС ^
ВВ СС ^
СС
**********
ЕС 8В 55
Итак, посчитав это дело в «Калькуляторе» мы видем, что СС=0х33; ВВ=0хС9; АА=0х61,
Полученная последовательность: ХХ61C93.
Последний байт, к сожалению, пришлось искать перебором с использованием
«self-keygening»a (патчинга бинарника), и в конце получаем: E961C933.
А расшифрованная процедура в действительности содержит много мусора(«обфускация»)
Но «открытие стека» нас спасло, и расшифрованая процедура (в теле):
00401149 $ 55 PUSH EBP
0040114A . 8BEC MOV EBP,ESP
0040114C . D3C8 ROR EAX,CL
0040114E . 58 POP EAX
0040114F . EB 04 JMP SHORT 00401155 ; eight.00401155
00401151 D6 DB D6
00401152 FE DB FE
00401153 . 32C9 XOR CL,CL
00401155 > BE 9C314000 MOV ESI,40319C ; ASCII "Secret: Marius!"
0040115A . C706 53656372 MOV DWORD PTR DS:[ESI],72636553
00401160 . C746 04 65743A>MOV DWORD PTR DS:[ESI+4],203A7465
00401167 . C746 08 4D6172>MOV DWORD PTR DS:[ESI+8],6972614D
0040116E . C746 0C 757321>MOV DWORD PTR DS:[ESI+C],217375
00401175 . EB 00 JMP SHORT 00401177 ; eight.00401177
00401177 > 58 POP EAX
00401178 . FFE0 JMP EAX
0040117A F7 DB F7
0040117B ED DB ED
0040117C 12 DB 12
0040117D DA DB DA
0040117E 3F DB 3F ; CHAR '?'
0040117F 4E DB 4E ; CHAR 'N'
00401180 40 DB 40 ; CHAR '@'
00401181 C4 DB C4
Всё что делает ета процедура-записывает слово: Secret: Marius! по соответственому указателю.
Далее осталось узнать исходный пароль – Ну, тут – брутфорс вам в помощь))))
Процедуру преобразования можна «ripp»ать у нашей програмы и оформить это дело как ассемблерную вставку.
mov dword ptr [znach], 0
xor edi, edi
mov esi, [str1]
m:
lodsb
test al, al
jz m1
mov ecx, eax
add edi, eax
rol edi, cl
jmp m
Да, исходный пароль-005sj[Vg
Только, если брутфорс будете писать под какую-то экзотику типа cuda или
под шейдеры- помните там нет инструкции циклического сдвига- rol eax, 5 и
ёё надо заменить на два простых сдвига (один влево и один вправо) и
потом «or» над полученным; реализация в виде: #define ROT (n, m)
(((n)<<(m))|((n)>>(32-(m))))
В следующих постах вы узнаете о других интересных способах взлома неломаемых защит.
PS. Автор статьи (ash — его пока нет на хабре) попросил меня опубликовать эту статью.
|
Просмотров: 666 |
Добавил: Turbokherson
| Рейтинг: 0.0/0 |
|
|