Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Ломаем CRACKL@B CrackMe #4

Обсудить статью на форуме

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: MoonShiner <moonshiner@freemail.ru>

Рад приветствовать всех своих коллег, которые читают данную статью! Это моя первая статья (по кряку:-), так что прошу сильно не ругать и наезжать только по существу. Хочу сразу отметить, что я не въезжал во все хитрости построения и работы данного крякмиса, так как в силу природной лености и нехватки времени меня больше занимало именно достижение результата. Для удобства я разбил описание на 5 частей.

1. Распаковка


Распаковка производилась стандартным образом. Остановка на точке входа, "bpmb esp-4 rw" и отпускаем прогу. Прервемся, увидим, что на OEP не тянет, снова давим F5. В итоге мы выскочим на конструкцию следующего вида:

seg004:0047C197 popa
seg004:0047C198 jmp short loc_45FF18

Таким образом, 45FF18 - оригинальная точка входа (можно проверить). Далее, сдираем дамп, восстанавливаем импорт и приклеиваем его к дампу. Имеем exe-шник, размер которого у меня получился равным 704512 байтам.

2. Поиск первого кода


Мне было лень совать этот файл в DeDe или IDA, поэтому практически все операции я проделывал в айсе и Qview. Вводим свое имя и какой-нибудь левый первый пароль, например:

Name: MoonShiner
Code1: 12222227

Жмем ОК и замечаем, что прога молчит. А по идее, в случае верного кода хоть что-то сказать она должна:-) Значит лезем в айса и ставим бряк на LocalLock (поясню, что для нашего ленивого собрата - это некая замена hmemcpy:-) Жмем ОК и вываливаемся в айса. Далее начинаем топтать F12, пока не пройдем все подпрограммы и не выйдем сюда:

seg000:0045EEEA lea edx, [ebp-24h]
seg000:0045EEED mov eax, [ebp-0Ch]
seg000:0045EEF0 mov eax, [eax+2FCh]
seg000:0045EEF6 call sub_43AE58
seg000:0045EEFB lea edx, [ebp-28h]
seg000:0045EEFE mov eax, [ebp-0Ch]
seg000:0045EF01 mov eax, [eax+300h]
seg000:0045EF07 call sub_43AE58
seg000:0045EF0C lea edx, [ebp-2Ch]
seg000:0045EF0F mov eax, [ebp-0Ch]
seg000:0045EF12 mov eax, [eax+304h]
seg000:0045EF18 call sub_43AE58
seg000:0045EF1D lea edx, [ebp-30h]
seg000:0045EF20 mov eax, [ebp-0Ch]
seg000:0045EF23 mov eax, [eax+308h]
seg000:0045EF29 call sub_43AE58
seg000:0045EF2E mov eax, [ebp-20h]
seg000:0045EF31 call sub_40416C
seg000:0045EF36 cmp eax, 3 ; проверка на длину имени
seg000:0045EF39 jge short loc_45EF4A
seg000:0045EF3B mov eax, offset unk_45F38C
seg000:0045EF40 call sub_42ABC0
seg000:0045EF45 jmp loc_45F32C

Идем дальше. По адресу 45EF4D видим процедуру которая проверяет длину 1-го кода:

seg000:0045EF4D call sub_40416C
seg000:0045EF52 cmp eax, 3
seg000:0045EF55 jge short loc_45EF66

Доходим до 45EF69:

seg000:0045EF69 call sub_40416C
seg000:0045EF6E test eax, eax
seg000:0045EF70 jle short loc_45EF8A

Это проверка на ненулевую длину строки, в которой хранится имя.
Трейсим дальше. Приходим к следующему коду:

seg000:0045EF7A mov eax, [ebp-20h]
seg000:0045EF7D movzx eax, byte ptr [eax+esi-1]
seg000:0045EF82 add ebx, eax
seg000:0045EF84 inc esi
seg000:0045EF85 dec dword ptr [ebp-38h]
seg000:0045EF88 jnz short loc_45EF7A

Как можно видеть, здесь происходит суммирование всех символов имени в регистре ebx. Уже можно догадаться, что конечный результат будут как то участвовать в процедуре проверки кодов. Чуть ниже мы натыкаемся на следующий код:

seg000:0045EFA4 mov edx, [ebp-3Ch]
seg000:0045EFA7 mov eax, [ebp-24h]
seg000:0045EFAA call sub_4042B8
seg000:0045EFAF jnz short loc_45EFDA

Посмотрев, куда указывают eax и edx, мы видим, что один указывает на введенный нами 1-й код, а другой - на какой то еще (уж не правильный ли? :-). Этот код в моем случае - Newbie1026. А 1026, это ни что иное, как 10-чное представление суммы кодов символов нашего имени (помните, я говорил выше, что эта сумма как то поучаствует в проверке кодов). Таким образом мы можем вдолбить в поле 1-го кода Newbie1026, увидеть надпись "Stage 1 - OK" и порадоваться, что хоть и на новичка, но уже тянем:-)

3. Поиск второго кода


Теперь мы хотим считаться нормальными крякерами. Вводим лажу в строке второго кода и видим мессэдж, что длина левая. С целью исправить это недоразумение снова лезем в айса:

seg000:0045F01C call sub_40416C
seg000:0045F021 mov edx, [ebp-14h]
seg000:0045F024 add edx, edx
seg000:0045F026 cmp eax, edx
seg000:0045F028 jz short loc_45F039

Видим, что происходит проверка длины 2-го кода. В моем случае, длина его получилась равной 28h символов. Если копнуть глубже, то можно убедиться, что длина 2-го кода зависит от имени и 1-го кода, а конкретно, она равна сумме их длин, помноженной на 2. Клепаем какой-нибудь код этой длины и останавливаемся здесь:

seg000:0045F048 lea eax, [ebp-34h]
seg000:0045F04B call sub_4043C4
seg000:0045F050 lea eax, [eax+esi-1]
seg000:0045F054 push eax
seg000:0045F055 mov eax, esi
seg000:0045F057 mov ecx, 0Fh
seg000:0045F05C cdq
seg000:0045F05D idiv ecx
seg000:0045F05F xor eax, eax
seg000:0045F061 mov al, ds:byte_460EE8[edx]
seg000:0045F067 mov edx, [ebp-34h]
seg000:0045F06A movzx edx, byte ptr [edx+esi-1]
seg000:0045F06F xor eax, edx
seg000:0045F071 pop edx
seg000:0045F072 mov [edx], al
seg000:0045F074 inc esi
seg000:0045F075 dec dword ptr [ebp-38h]
seg000:0045F078 jnz short loc_45F048

Не буду вдаваться в тонкости, просто отмечу, что здесь происходит поксоривание символов строки, состоящей из символов имени и первого кода со строкой Bad_guy-а (смотрите сами, что там лежит).
Топчем F10 далее, пока не окажемся здесь:

seg000:0045F120 cmp eax, edx
seg000:0045F122 jnz short loc_45F127
seg000:0045F124 inc dword ptr [ebp-1Ch]
seg000:0045F127 inc esi
seg000:0045F128 dec dword ptr [ebp-38h]
seg000:0045F12B jnz loc_45F092

Посмотрев на содержимое eax, мы заметим, что в al лежать первые 2 символа нашего 2-го кода. А в edx, соответственно, первые 2 символа правильного второго пароля. Вооружаемся карандашом, бумажкой и поставив бряк на 0045F120 и постоянно нажимая на F5 и прерываясь по этому адресу передираем из edx правильные символы. У меня получилось 1B07F3DFCBB7A38F7B67533F2B1703EFDBC7B39F. Вколачиваем это дело в строку 2-го кода и видим радостную надпись "Stage 2 - OK".

4. Поиск 3-го кода


Здесь дело обстоит заметно веселее, но для тех, кто колупал первый крякмис Bad_guy-а, нахождение 3-го кода не составит большого труда. Сначала отметим, что крякмис требует, чтобы длина 3-го кода была равна 8-ми символам. И главное - крякмис орет, что 3-й код не является числом типа Integer. А это дает очень многое! Во-первых, становится ясно, что над 3-м кодом проводятся какие-то сугубо арифметические действия как над числом. А во-вторых, можно предположить, что это просто какой-то адрес, необходимый для работы программы (но это легко предположить тому, кто ломал первый крякмис:-).
Идем до адреса 0045F1A0:

seg000:0045F1A0 mov ds:dword_462C30, eax
seg000:0045F1A5 mov eax, ds:dword_462C30
seg000:0045F1AA xor eax, 5E571599h
seg000:0045F1AF mov [ebp-8], eax

Замечаем, что в eax лежит введенный нами 3-й код. Дальше идет его поксоривание и сохранение. Далее идет длинный цикл, который обломит нам весь кайф от применения брутфорса. Так что с брутфорсом пока потерпим и глянем, что творится дальше:

seg000:0045F1FC mov eax, [ebp-6Ch]
seg000:0045F1FF mov edx, offset unk_45F480
seg000:0045F204 call sub_4042B8
seg000:0045F209 jz short loc_45F23D
seg000:0045F20B jmp short loc_45F20E

Видно, что происходит сравнение 2-х величин - получившейся из 3-го кода путем извращений с циклами md5 и "правильного" значения. Если пойдем дальше, то заметим, что на этом дело не кончается, управление на начало обработки формы не передается, значит есть еще какие-то веселые штуки:-)

seg000:0045F215 xor eax, eax
seg000:0045F217 push ebp
seg000:0045F218 push offset unk_45F233
seg000:0045F21D push dword ptr fs:[eax]
seg000:0045F220 mov fs:[eax], esp
seg000:0045F223 call ds:dword_462C30
seg000:0045F229 xor eax, eax
seg000:0045F22B pop edx
seg000:0045F22C pop ecx
seg000:0045F22D pop ecx
seg000:0045F22E mov fs:[eax], edx
seg000:0045F231 jmp short loc_45F23D

В 462С30 лежит наш 3-й код, то есть действительно он должен представлять собой адрес некой процедуры. Глянем на адрес 45F23D.

seg000:0045F23D mov eax, ds:dword_462C30
seg000:0045F242 xor eax, 5E571599h

Далее снова идут циклы. Таким образом, понимаем, что все завязано на ds:dword_462C30. Тут не обойтись без IDA (я то обошелся, но об этом изврате расскажу далее:-). Пихаем распакованный файлик в IDA и смотрим, кто ломится к ds:dword_462C30. Идем по первому cross-ref-у:

seg000:0045EC84 mov ds:dword_462C30, 5E12F8A9h
seg000:0045EC8E retn

Попробуем вбить в качестве 3-го кода 0045EC84 и топаем до следующего места:

seg000:0045F294 mov eax, [ebp-74h]
seg000:0045F297 mov edx, offset unk_45F480
seg000:0045F29C call sub_4042B8
seg000:0045F2A1 jnz short loc_45F2CC

Сравнение проходит на "ура"! Отпускаем прогу и сообщаем всему миру, что вы - Profi :-)
Я, при поиске 3-го кода, решил состряпать брутфорсер и оставил его на ночь. Уж слишком спать хотелось. Это весьма неоптимальный вариант в данном случае и сам брутфорсер я описывать не буду. В нем я просто сузил перебираемый диапазон и оставил его на ночь. Код подобрался за пол-ночи.

5. Поиск 4-го кода


Profi быть хорошо, но Guru - лучше :-). Поэтому займемся поиском последнего кода. Прога как и в предыдущем случае орет, что длина должна быть 8 символов, да и числом типа Integer это дело не является. Поэтому вбиваем что-нибудь типа 100000AB и начинаем трейсить:

seg000:0045F303 xor eax, 607ED242h
seg000:0045F308 mov ds:dword_462C30, eax
seg000:0045F30D jmp short loc_45F310

По адресу 0045F303 в eax лежит 4-й код. Далее поксоривание и сохранение.

seg000:0045F315 mov eax, [ebp-0Ch]
seg000:0045F318 add eax, 310h
seg000:0045F31D mov [ebp-4], eax
seg000:0045F320 mov ecx, ds:dword_462C30
seg000:0045F326 mov ebx, [ebp-4]
seg000:0045F329 call dword ptr [ebp-8]

Как можно видеть, какие бы коды мы не вводили, CALL по адресу 0045F329 будет вызывать процедуру, лежащую по адресу 0045ED30. То есть, мы можем "оптимизировать" код, вдолбив вместо инструкций с адреса 0045F315 следующее:

seg000:0045F315 mov eax, 0045ED30
seg000:0045F31A nop
seg000:0045F31B nop
seg000:0045F31C nop

Чтобы было понятнее, скажу сразу - это нам понадобится для будущего написания брутфорсера.
Начинаем гулять по процедуре 0045ED30. Не обращая внимания на происходящий там кошмар, топаем до следующих инструкций:

seg000:0045EE3E call $+5
seg000:0045EE43 pop esi
seg000:0045EE44 lea edx, [ebp-0Dh]
seg000:0045EE47 mov al, [edx]
seg000:0045EE49 mov [esi+21h], al
seg000:0045EE4C inc edx
seg000:0045EE4D mov al, [edx]
seg000:0045EE4F mov [esi+26h], al
seg000:0045EE52 inc edx
seg000:0045EE53 mov al, [edx]
seg000:0045EE55 mov [esi+2Bh], al
seg000:0045EE58 inc edx
seg000:0045EE59 mov al, [edx]
seg000:0045EE5B mov [esi+30h], al
seg000:0045EE5E inc edx
seg000:0045EE5F mov al, [edx]
seg000:0045EE61 mov [esi+37h], al

Видим, что по смещению edx берутся лежащие там байты и вставляются в идущий ниже код. Таким образом, можно предположить, что этот код был попорчен автором, а 4-й пароль после соответствующих преобразований должен являть собой набор верных байтов для восстановления кода.
Я не стал разбираться в алгоритме, а просто решил написать для поиска верного кода брутфорсер. Дело осложнялось тем, что не было в явном виде проверок валидности ни кода, ни байтов. Но можно было попытаться угадать некоторые из этих 5-ти байтов, чтобы стало возможным написание брутфорсера. Угадывал я их следующим образом:

Начнем с первого неизвестного байта по смещению 0045EE64. Нам нужен такой байт, чтобы несколько следующих команд превратились в верные и правдоподобные. Для этого я делал в айсе "U 0045EE64", "U 0045EE64", "U 0045EE64", и т.д. То есть, дизассемблировал с конкретного адреса. Посмотрел на команду по адресу 0045EE67.

seg000:0045EE67 mov ebx, [eax]
seg000:0045EE69 call near ptr 924B6Ch

Адрес второго CALL-а может быть иным, но это не суть важно. Главное - первая команда. Исходя из вышерасположенного кода, можно заметить, что регистр eax будет запоганен. То есть перед тем, как выполнится занесение в регистр ebx нужно что-то внести в eax ;-). Если мы поставим по адресу 0045EE64 байт 8B, то код у нас будет иметь такой вид:

seg000:0045EE64 mov eax, [ebp-04]
seg000:0045EE67 mov ebx, [eax]
seg000:0045EE69 call near ptr 924B6Ch

То есть, первые 2 команды похожи на правду. Таким образом, с достаточно большой степенью вероятности можно утверждать, что первый байт - 8B.

Следующие байты, мне не удалось точно идентифицировать, зато удалось определить байт по смещению 0045EE7A. Если туда подставить E8, то получим CALL 43AE88. А это, если туда посмотреть, очень похоже на правду. Таким образом, я ограничился найденными 2-мя байтами и начал писать брутфорсер.

Для простоты, все можно проделывать прямо в айсе. Сначала я нашел пустое место - 463000 и весь брутфорсер засунул туда. Но для начала, по адресу 0045EE43 я вписал переходник. Таким образом, получилось следующее:

seg000:0045EE3E call $+5
seg000:0045EE43 jmp 00463000
seg000:0045EE48 nop
seg000:0045EE49 mov [esi+21h], al

По адресу 00463000 я вписал следующий код:
00463000:
pop esi ; восстанавливаю затертые
lea edx,dword ptr [ebp-d] ; переходником команды
cmp byte ptr [edx], 8B ; проверяю 1-й байт
jnz 463030 ; если облом - прыгаю
cmp byte ptr [edx+4], E8 ; проверяю 2-й байт
jnz 463030 ; если облом - прыгаю
mov al, byte ptr [edx] ; если совпали, то
jmp 45EE49 ; прыгаю в код заполнения

00463030:
inc dword ptr [00463060] ; увеличиваю пароль на 1
mov eax, dword ptr [00463060] ; это ясно:-)
add esp, 58 ; корректирую стек
push 0045F303 ; вношу адрес начала проверки
mov ebp, 0012FBE0 ; корректирую ebp
ret ; ну и прыгаю

По адресу 00463060 я кладу наш пароль. Изначально он равен 00000000. Ввожу в строку 4-го пароля 00000000 (необязательно, но для простоты), ставлю "контрольный" бряк на 45EE49. Ясно, что он сработает, если совпадут значения 2-х определенных нами байтов. И отпускаю прогу. Вылезаем на 45EE49. Аккуратно проходим заполнение тех 5-ти байтов. Смотрим на получившийся код. Код получился так себе :-) Значит, в принудительном порядке переводим выполнение на EIP=463030. Вываливаемся снова. Опять проходим и смотрим, что получается. У меня вроде бы с 4-го раза получился правдоподобный код. Тогда глядим, что у нас лежит в 00463060. У меня было "3E 98 00 00". Запускаем оригинальный крякмис, заполняем все поля и вводим в качестве 4-го пароля "0000983E". Жмем ОК, смотрим, что нам пишут. Потом хвастаемся друзьям, которые в этих делах абсолютно не рубят и идем пить с ними пиво. Только не забудем вначале закрыть крякмис, чтобы прочитать послание Bad_guy-а ;-)

P.S. Возможны мелкие недочеты, хотя статью старался написать без ошибок.

P.P.S. Благодарю Bad_guy-а, за полученное удовольствие от взлома его крякмиса. Поздравляю Madness-а, которому принадлежит первенство в раскрытии этого крякмиса. Передаю привет следующим позитивным чувакам: MozgC, Bad_guy, nice, WELL, -=ALEX=-, dragon, .::D.e.M.o.N.i.X::. и вообще, всем, кто меня знает. Привет группе TSRH и всем людям, которые помогали мне и которым помогал я.

26.05.04
MoonShiner

Комментарий Bad_guy’я:
Отличная статья - я всё понял :) Кое-где конечно можно было и не брутфорсить, но в целом MoonShiner провёл взлом почти так как было запланировано при написании крякмиса. Благодарю MoonShiner’a за проделанную работу и написание статьи. Madness’у также респект за первенство !

Что касается самого крякмиса: был написан он на Дельфи, с ассемблерными вставками нечто вроде:

proc := @Guru;
try
call proc
except end;

Потом такие вещи как "proc := @Guru;" были использованы и затёрты вручную антидизассемблерным кодом EB01XXh, удалены правильные пять байт, которые восстанавливались в рантайме при правильном коде, потом на секцию кода был поставлен атрибут E0000020h (запись/чтение/исполняемый код), так что защита опять же сложная в реализации (как и CRACKL@B CrackMe #1). Ну и был допущен небольшой баг - если в качестве 3го кода ввести адрес того места, где выдаётся сообщение о правильности 3го кода, то сообщение естественно выдавалось, хотя и переход на 4ый уровень было сделать нельзя. Особо хочется подчеркнуть, что в качестве дополнительного задания предлагалось не только распаковать крякмис, но и запаковать его обратно, чтобы он работал и был меньше в размере, чем запакованный исходный. Для сложности файл упакован UPX 0.72 (к которому не существует встроенного распаковщика, а внешние - не перестраивают формат UPX, в нормальный), это позволяет серьёзно осложнить последующую упаковку распакованного файла, а тем более получение его меньшего размера, однако .::D.e.M.o.N.i.X::. заявил, что у него это получилось - мои поздравления.

Обсуждение статьи: Ломаем CRACKL@B CrackMe #4 >>>


Комментарии к статье: Ломаем CRACKL@B CrackMe #4

Madness 27.05.2004 00:36:27
Кроме 0045EC84 как код3 подходит еще и 0045EC82 :)
Я обошелся без брутфорсеров вообще, потому код4 подобрал красивый - 00020000, этот код идет в процедуру 45ED30, а вот для ввода он не особо красивый вышел - 607CD242.

Bad_guy, про код3, это не бага, а фича :)
---
MoonShiner 27.05.2004 11:02:43
Ну если на то пошло, то и 0045EC80 тоже сгодится:) А как ты в 4-м случае вообще без брутфорсеров обошелся? Алгоритм ковырял что ли?
---
DZmey 27.05.2004 16:12:52
MoonShiner, реальная статья...
---
MoonShiner 27.05.2004 17:21:53
Всем спасибо:)
---
бара 30.05.2004 14:44:40
45ec80 тоже фурычит...
Статья хорошая. Одобрям-с.
---
MoonShiner 31.05.2004 20:16:47
Щас не помню, но 0045EC80 вроде не подходило, домой приду - проверю. А по поводу 4, я ж писал, я код (асм который) сначала дописал, а потом и ключ получил, через зад короче, можно было и проще найти.
ЗЫ. Да простит меня MoonShiner, но статья не очень imho. Не интересно тут с брутфорсом, намного приятней подобрать все самому, а не напрягать по этому поводу комп.
---
Madness 31.05.2004 20:18:26
Ой, че та проглючило, это я писал.
---
Godness 31.05.2004 21:02:06
MoonShiner, для прог на делфи имхо есть более простой способ, чем LocalLock :-)
bpx CallWindowProcA if *(esp+c)==d do \"d *(esp+14)\"
аналогично, чтобы выловить момент, когда прога устанавливает техт в контроле -> if *(esp+c)==c ...работает железно
---
Cust 24.06.2004 09:49:49
Не удержался и прочел эту инфу. Сам честно дошел до серединки между Profi и Norm.
---
lord_Phoenix 26.02.2005 17:48:43
Отличный крякми!
Отличная статья!
---

Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS