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

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


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

Альтернативный взлом CRACKL@B CrackMe #1

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

Очень удобно, когда все крэкерские инструменты, книги и статьи в одном месте. Используйте сборник от EXELAB - вот тут.

Автор: -=ZoRn=- <ZoRn84@bk.ru>

Для начала небольшое лирическое отступление
Я из разряда тех кого называют новичками как по написанию статей так и по взламыванию
защит (написал пока только два кейгена (для Loupe и BadCopy99 - взял с cracklab.narod.ru),
не считая этот. Если будет время может напишу статью про них "для начинающих"(про Loupe,
с BadCopy99 все слишком просто)). Так, что это моя первая статья, если что не кидайте камни :)

По поводу этики и всяких там авторских прав:
будем ломать прогу, которая сделана для того, чтобы ее сломали, так что здесь все впорядке.

Ну-с приступим
Нам потребуется:
-W32Dasm 10.0 (by killer)
-DeDe (у меня 3.50.04)
-Hex редактор (я использовал HIEW 6.11)
-Restorator 3.00 (опционально)
Ну и само сабой
-Some brains


Дальше идет ход моих мыслей во время взлома (мыслей было много все не вспомню :)
Для начала прогу надо распаковать. Если вам это не удалось дальше можете не читать
(все равно ни хрена не поймете).

Так как прога написана на Делфях идеальным вариантом будет запихнуть ее в DeDe,
чтобы выяснить в каком куске кода заключена проверка сериала (а так же чтобы не
лезть во всекие VCL-процедуры). Ищем процедуру Button1Click (перед этим удостоверившись,
что имено по этой кнопке кликаем, чтобы зарегаться). И начинаем разбираться

0044A46A 55 push ebp

* Possible String Reference to: ’йyѓыяйPяяя_^[‹е]ГђЎЂШD’
|
0044A46B 6812B04400 push $0044B012

***** TRY
|
0044A470 64FF30 push dword ptr fs:[eax]
0044A473 648920 mov fs:[eax], esp
0044A476 8D55F8 lea edx, [ebp-$08]

* Reference to control TForm1.Edit2 : TEdit
|
0044A479 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.GetText(TControl):TCaption;
|
0044A47F E89CBBFDFF call 00426020 (*1)
0044A484 8B45F8 mov eax, [ebp-$08]

* Reference to: system.@LStrLen:Integer;
|
0044A487 E8EC96FBFF call 00403B78
0044A48C 83F814 cmp eax, +$14 (*2)
0044A48F 0F85D4080000 jnz 0044AD69
0044A495 8D55F4 lea edx, [ebp-$0C]

* Reference to control TForm1.Edit1 : TEdit
|
0044A498 8B83DC020000 mov eax, [ebx+$02DC]

Сначала считывается введенный код из Edit2 (*1), потом длина кода сравнивается
с 20 (14h) (*2), исли не равно прыгаем в это место

0044AD69 8D9538FEFFFF lea edx, [ebp+$FFFFFE38]
0044AD6F B0D2 mov al, $D2

* Reference to : TForm1.Proc_004499F4()
|
0044AD71 E87EECFFFF call 004499F4
0044AD76 FFB538FEFFFF push dword ptr [ebp+$FFFFFE38]
0044AD7C 8D9534FEFFFF lea edx, [ebp+$FFFFFE34]
0044AD82 B0FB mov al, $FB

* Reference to : TForm1.Proc_004499F4()
|
0044AD84 E86BECFFFF call 004499F4
0044AD89 FFB534FEFFFF push dword ptr [ebp+$FFFFFE34]
0044AD8F 8D9530FEFFFF lea edx, [ebp+$FFFFFE30]
0044AD95 B020 mov al, $20

* Reference to : TForm1.Proc_004499F4()
|
0044AD97 E858ECFFFF call 004499F4
0044AD9C FFB530FEFFFF push dword ptr [ebp+$FFFFFE30]
0044ADA2 8D952CFEFFFF lea edx, [ebp+$FFFFFE2C]
0044ADA8 B0E5 mov al, $E5
.....

(
Мож кому пригодится:
cmp : Сравнение двух значений
test знач.,знач. : Проверка знач. на 0
прыжки после проверки
je/jz : прыжок если равно/если 0
ja/jnbe - jg/jnle : прыжок если больше/ не меньше или равно
jb/jnae - jl/jnge : прыжок если меньше/ не больше или равно
jae/jnb - jge/jnl : прыжок если больше или равно/ не меньше
jbe/jna - jle/jng : прыжок если меньше или равно/ не больше
)
Тут видим кучу процедур TForm1.Proc_004499F4() - это та самая защита от String Reference
взлома. После всей это байды получается строка "Ты еще ничего не сделал" (на каждый символ по процедуре).
Дальше мыеще встретимся с этим. Забегая наперед скажу, что именно это нам даст необходимое место
для написания кейгена (если кто еще не понял кейген будет на основе самой программы).
Значит если нужно двадцать символов вводим их. Видим следующую строку "До взлома еще очень далеко"
(Получается так же как и первая. Вообще то тут все строки так получаются).
Смотрим как это получается

0044A4DF 8D55EC lea edx, [ebp-$14]

* Reference to control TForm1.Edit2 : TEdit
|
0044A4E2 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.GetText(TControl):TCaption;
|
0044A4E8 E833BBFDFF call 00426020
0044A4ED 8B45EC mov eax, [ebp-$14]
0044A4F0 8A4438FF mov al, byte ptr [eax+edi-$01]
0044A4F4 04D0 add al, -$30
0044A4F6 2C0A sub al, $0A
0044A4F8 0F8289010000 jb 0044A687(*1)
0044A4FE 04F9 add al, -$07
0044A500 2C06 sub al, $06
0044A502 0F827F010000 jb 0044A687(*2)
0044A508 8D55E4 lea edx, [ebp-$1C]
0044A50B B0C4 mov al, $C4
...

Сначала считывается строка из Edit2 потом в (*1) символ проверяется на 0..9, т.е
из кода символа вычитается 30h, а потом проверяется, в (*2) проверяется на A..F.
Получается, что код должен состоять из шестнадцатиричных цифр 0..F. Вводим -
видим надпись "До взлома еще далеко". Самое легкое позади. Пускаем в дело W32Dasm.
Пока Дасм дасмит прогу смотрим где эта строка выводится.

0044A6E2 58 pop eax

* Reference to: system.@LStrCmp;
|
0044A6E3 E8A095FBFF call 00403C88
0044A6E8 0F84AF010000 jz 0044A89D (*1)
0044A6EE 8D9568FFFFFF lea edx, [ebp+$FFFFFF68]
0044A6F4 B0C4 mov al, $C4

* Reference to : TForm1.Proc_004499F4()
|
0044A6F6 E8F9F2FFFF call 004499F4
0044A6FB FFB568FFFFFF push dword ptr [ebp+$FFFFFF68]
0044A701 8D9564FFFFFF lea edx, [ebp+$FFFFFF64]
0044A707 B0EE mov al, $EE

* Reference to : TForm1.Proc_004499F4()
|
0044A709 E8E6F2FFFF call 004499F4
0044A70E FFB564FFFFFF push dword ptr [ebp+$FFFFFF64]
0044A714 8D9560FFFFFF lea edx, [ebp+$FFFFFF60]
0044A71A B020 mov al, $20

* Reference to : TForm1.Proc_004499F4()
|
0044A71C E8D3F2FFFF call 004499F4
0044A721 FFB560FFFFFF push dword ptr [ebp+$FFFFFF60]
0044A727 8D955CFFFFFF lea edx, [ebp+$FFFFFF5C]
0044A72D B0E2 mov al, $E2
и т.д.

В (*1) что то проверяется и если равно перепрыгиваем строку.
Вывод: это что то надо подсмотреть.
Судя по названию функции system.@LStrCmp сравниваются две строки.
Наша в edx, нужная в eax перед вызовом функции.
В Дасме Debug/Load proccess(загружаем прогу в память), Shift+F12(Goto code location),
44A6E3(Собственно code location), F2(ставим бряк), F9(запускаем прогу).
Вводим в проге имя и любой сериал (обязательно 20 шестнадцатиричных цифр)
например 01234567890123456789 нажимает Register. Брякаемся перед вызовом system.@LStrCmp.
Смотрим, что у нас в edx, а там у нас первые 8 символов введенного кода (01234567),
а в eax то что должно быть у нас (у меня было CA5E0424). Должно-будет.
Вводим вместо первых 8 то что в eax. Мой вариант: CA5E0424890123456789
Ввидим надпись "Поднапригись !". Смотрим где эта надпись. Она у нас самая короткая,
должно быть немного вызовов поцедуры TForm1.Proc_004499F4().

0044A93D 58 pop eax

* Reference to: system.@LStrCmp;
|
0044A93E E84593FBFF call 00403C88
0044A943 0F842A010000 jz 0044AA73
0044A949 8D95F8FEFFFF lea edx, [ebp+$FFFFFEF8]
0044A94F B0CF mov al, $CF

* Reference to : TForm1.Proc_004499F4()
|
0044A951 E89EF0FFFF call 004499F4
0044A956 FFB5F8FEFFFF push dword ptr [ebp+$FFFFFEF8]
0044A95C 8D95F4FEFFFF lea edx, [ebp+$FFFFFEF4]
0044A962 B0EE mov al, $EE

* Reference to : TForm1.Proc_004499F4()
|
0044A964 E88BF0FFFF call 004499F4
0044A969 FFB5F4FEFFFF push dword ptr [ebp+$FFFFFEF4]
0044A96F 8D95F0FEFFFF lea edx, [ebp+$FFFFFEF0]
0044A975 B0E4 mov al, $E4

* Reference to : TForm1.Proc_004499F4()
|
0044A977 E878F0FFFF call 004499F4
0044A97C FFB5F0FEFFFF push dword ptr [ebp+$FFFFFEF0]
0044A982 8D95ECFEFFFF lea edx, [ebp+$FFFFFEEC]
0044A988 B0ED mov al, $ED

Та же картина - сравниваются две строки: последние 4 введенных символа с нужными.
Подсмотрим. Введем и увидим аж два сообщения,
что ключик липовый. Первое выводится тем же макаром, что и остальные, а вот второе
при exception’e. Замена условного перехода на безусловный ничего не даст (будет
выводится не два, а одно сообщение - которое при exception’e). Подсмотреть тоже не удастся.
в edx будет константа (точно не помню чему равна, если интересно можете посмотреть)
которая никак не смахивает на введенные нами 89012345. Поначалу я думал, что это и не константа
вовсе, а какое-то значение вычисляемое из первых 8 символов кода каким то криптографическим
алгоритмом (оказалось все намного проще, ну затупил с кем не бывает...) и зациклился на этом.
Поначалу даже написал (то есть встроил в прогу) переборщик, но прога зависала после перебора
примерно FFFF значений (проверял с помощью MessageBox’a). Даже письмо Bad_guy написал.
С мольбой о помощи. Зайти на форум мозгА не хватило. Через несколько дней зашел.
И нашел что искал. Цитирую:
---------------------------------------------
Проверяйте, имя dragon, код D0C8345C9917A3000E4B.

В общем я нашёл эту процедуру, которая регистрирует прогу. Я уже всё перебрал,
но наконец, мне взбрело в голову поискать в листинге IDA редкие инструкции. Вот
ищу, по алфавиту, и мне в глаза бросилась aaa по адресу 449F7C. Начало этой
процедуры - 449F34. В ней же я увидел xor eax, 96969696h, т.е. стало понятно,
что эта процедура что-то расшифровывает. Я сунул в 44D880 этот адрес, и всё,
типа зарегил. По алгоритму проверки подобрал код. Короче, код подбирается так -
первые 8 символов подсматриваются, затем ксорим 5CD3407D с адресом 449F34,
получаем 5C97DF49, затем этот результат ксорим с перевёрнутыми первыми 8
символами(у меня 5C34C8D0), и ставим этот результат в середину, причём тоже
наоборот. Последние 4 символа тоже подсматриваются. Вот и весь CrackMe

---------------------------------------------
Спасибо dragon’у, а то еще б неделю мучался бы. Наверное.
Короче не стал я разбираться кто там что шифрует - меня заинтересовала эта
часть:
---------------------------------------------
Короче, код подбирается так -
первые 8 символов подсматриваются, затем ксорим 5CD3407D с адресом 449F34,
получаем 5C97DF49, затем этот результат ксорим с перевёрнутыми первыми 8
символами(у меня 5C34C8D0), и ставим этот результат в середину, причём тоже
наоборот.
---------------------------------------------

Впринципе тут уже весь алгоритм расписан (да и Bad_guy уже исходники показывал).
Но до этого места я сам дошел, так что не надо говорить что пишу я на готовом.
Только нужно уточнить одну деталь можно не переворачивать первые 8 символов, а
перевернуть константу 5C97DF49 (49DF975C), тогда и результат надо будет вставлять не наоборот.

Теперь будем писать кейген:

Сразу скажу если будете смотреть мой кейген (если конечно Bad_guy его выложит)
там много лишнего кода (остатки после переборщика - не стал вычищать), типа

0044A8BC 8BC5 mov eax, ebp
0044A8BE 83E824 sub eax, +$24

(таких участков несколько) это вместо

* Reference to control TForm1.Edit2 : TEdit
|
0044A4E2 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.GetText(TControl):TCaption;
|
0044A4E8 E833BBFDFF call 00426020
0044A4ED 8B45EC mov eax, [ebp-$14]

то есть я считывал в eax не из Edit2, а из памяти. Спросите почему так замудрено -
можно было lea eax,[ebp-24], это ведь тоже самое и будете правы, просто я потом вспомнил
про эту команду.(После написания статьи я понял что эти части все таки нужны)

Для начала нужно найти адрес памяти куда будем писать значение (которое потом выведем в Edit2)
Я выбрал адрес [ebp-24](от фонаря) и не прогадал
(Во первых: значение ebp - константа на протяжении функции
Во вторых: адрес [ebp-24] используется где то до того как мы туда запишем значение,
и потом больше не используется ни кем (кроме нас)
)
Теперь надо подумать.....
Если значение можно подсмотреть значит его можно записать....
Например в [ebp-24], так и делаем.
Но сначала занопим проверку на длину кода

0044A476 8D55F8 lea edx, [ebp-$08]

* Reference to control TForm1.Edit2 : TEdit
|
0044A479 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.GetText(TControl):TCaption;
|
0044A47F E89CBBFDFF call 00426020
0044A484 8B45F8 mov eax, [ebp-$08]

* Reference to: system.@LStrLen:Integer;
|
0044A487 E8EC96FBFF call 00403B78
0044A48C 83F814 cmp eax, +$14
0044A48F 90 nop (*)
0044A490 90 nop (*)
0044A491 90 nop (*)
0044A492 90 nop (*)
0044A493 90 nop (*)
0044A494 90 nop (*)
0044A495 8D55F4 lea edx, [ebp-$0C]

И сделаем безусловный переход при проверке на содержащиеся символы

0044A4DF 8D55EC lea edx, [ebp-$14]

* Reference to control TForm1.Edit2 : TEdit
|
0044A4E2 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.GetText(TControl):TCaption;
|
0044A4E8 E833BBFDFF call 00426020
0044A4ED 8B45EC mov eax, [ebp-$14]
0044A4F0 8A4438FF mov al, byte ptr [eax+edi-$01]
0044A4F4 04D0 add al, -$30
0044A4F6 2C0A sub al, $0A
0044A4F8 E98A010000 jmp 0044A687 (*)
0044A4FD 0004F9 add [ecx+edi*8], al

Теперь после вычисления первых 8 символов запишем их в [ebp-24] и прыгнем
на дальнейшее выполнение программы

0044A6E2 58 pop eax //адрес первых восеми символов
//Дальше мой код
0044A6E3 51 push ecx //для сохранности
0044A6E4 8B08 mov ecx, [eax] //помещение 1..4 символы в ecx
0044A6E6 894DDC mov [ebp-$24], ecx //запись 1..4 символов в память
0044A6E9 8B4804 mov ecx, [eax+$04] //помещение 5..8 символы в ecx
0044A6EC 894DE0 mov [ebp-$20], ecx //запись 5..8 символов в память
0044A6EF B930303030 mov ecx, $30303030 //помещение "0000" в ecx
0044A6F4 894DE4 mov [ebp-$1C], ecx //заполнение оставшихся
0044A6F7 894DE8 mov [ebp-$18], ecx //символов
0044A6FA 894DEC mov [ebp-$14], ecx //нулями
0044A6FD B114 mov cl, $14 (*1)
0044A6FF 884DD8 mov [ebp-$28], cl (*2)
0044A702 59 pop ecx //востанавливаем ecx
0044A703 E995010000 jmp 0044A89D //прыгаем на продолжение программы

Немного слов о (*1) и (*2). Дело в том, что при использовании VCL-процедур используются
паскалевские строки (наш случай) (в сишных строках строка заканчивается нуль-байтом (00h)).
В этих строках перед строкой указывается длина строки, а на конце не обязательно должен быть 00h
Чтобы VCL-процедуры (например system.@LStrCopy)правильно обрабатывали нашу строку
запишем перед строкой 14h (т.е. 20 символов)
Первая часть кода записана. Записываем последние 4 символа

0044A93D 58 pop eax //последние 4 символа
0044A93E 51 push ecx
0044A93F 8B08 mov ecx, [eax]
0044A941 894DEC mov [ebp-$14], ecx
0044A944 59 pop ecx
0044A945 E929010000 jmp 0044AA73

Здесь вроде все понятно.

Теперь самое интересное - вычисление 9..16 символов и запись их в память


//Этот код я не трогал
0044AB5F 58 pop eax //Вычисленное значение (первый раз неверное)

* Reference to: system.@LStrCmp;
|
0044AB60 E82391FBFF call 00403C88 //Сравнение вычисленного значения с константой (которую я не помню)
0044AB65 747F jz 0044ABE6 //Прыжок если строки равны
//Дальше полностью мой код
0044AB67 60 pusha //Сохранение всех регистров
0044AB68 B300 mov bl, $00 //Счетчик на 2 цикла
0044AB6A 8B45DC mov eax, [ebp-$24] //Помещение в eax первых 4 символов правильного кода
0044AB6D B104 (6) mov cl, $04 //Включение счетчика на 4 цикла
0044AB6F 3C3A (3) cmp al, $3A //Сравнение на 0..9
0044AB71 7210 (1*) jb 0044AB83 //Прыжок если так
0044AB73 2C37 sub al, $37 //Преобразование из буквы в число (например "A" в 0Ah)
0044AB75 C1C808 (2) ror eax, $08 //Циклический сдвиг вправо но 8 бит (1 байт), т.е. было 012345 стало 450123
0044AB78 FEC9 dec cl //Уменьшение счетчика на 1
0044AB7A 84C9 test cl, cl //Проверка счетчика на 0
0044AB7C 75F1 (3*) jnz 0044AB6F //Прыжок если не ноль
0044AB7E EB07 (4*) jmp 0044AB87 //Прыжок в любом случае
0044AB80 90 nop
0044AB81 90 nop
0044AB82 90 nop
0044AB83 2C30 (1) sub al, $30 //Преобразование из символа в число (было "3" стало 03h)
0044AB85 EBEE (2*) jmp 0044AB75
0044AB87 FEC3 (4) inc bl //Увеличение счетчика
0044AB89 33C9 xor ecx, ecx //Очищение ecx
0044AB8B B102 mov cl, $02 //Счетчик на два цикла
0044AB8D C1E208 (5) shl edx, $08 //Сдвиг влево на 8 бит (было 12345678 стало 34567800)
0044AB90 8AD0 mov dl, al //Перемещение числа кода в dl
0044AB92 C0E204 shl dl, $04 //Сдвиг влево на 4 бит регистра dl (было edx=12345678 стало edx=12345680)
0044AB95 C1E808 shr eax, $08//Сдвиг вправо на 8 бит
0044AB98 02D0 add dl, al //сложение al и dl (было edx=123456780 eax=98765402 стало edx=123456782)
0044AB9A C1E808 shr eax, $08//Сдвиг вправо на 8 бит
0044AB9D E2EE (5*) loop -$12 //Выполнение цикла пока в ecx не будет 0 (сначала ecx уменьшается на 1 потом сравнивается с 0)
0044AB9F 8B45E0 mov eax, [ebp-$20] //Считывание 5..8 символов и памяти
0044ABA2 80FB02 cmp bl, $02 //Если цикл выполнился один раз
0044ABA5 75C6 (6*) jnz 0044AB6D //Выполняем второй раз
0044ABA7 81F25C97DF49 xor edx, $49DF975C //xor’им первые 8 символов с константой 049DF975Ch
0044ABAD B300 mov bl, $00 //Полученное пере’xor’енное значение и есть 5..16 цифры кода
0044ABAF B104 mov cl, $04 //Записываем их в память
0044ABB1 C1C208 rol edx, $08
0044ABB4 8AC2 mov al, dl
0044ABB6 C0E804 shr al, $04
0044ABB9 3C0A cmp al, $0A
0044ABBB 7225 jb 0044ABE2
0044ABBD 0437 add al, +$37
0044ABBF C1C808 ror eax, $08
0044ABC2 8AC2 mov al, dl
0044ABC4 240F and al, $0F
0044ABC6 3C0A cmp al, $0A
0044ABC8 725B jb 0044AC25
0044ABCA 0437 add al, +$37
0044ABCC C1C808 ror eax, $08
0044ABCF 80F903 cmp cl, $03
0044ABD2 7455 jz 0044AC29
0044ABD4 E2DB loop -$25
0044ABD6 8D5DE8 lea ebx, [ebp-$18]
0044ABD9 8903 mov [ebx], eax
0044ABDB 61 popa
0044ABDC 90 nop
0044ABDD E9BBFCFFFF jmp 0044A89D //Возвращаемся для вычесления последних 4 цифр и сравнения кода
//(он ведь у нас правильный в памяти),
//при правильном коде прыжок на процедуру вывода кода.
0044ABE2 0430 add al, +$30
0044ABE4 EBD9 jmp 0044ABBF
//Процедура вывода кода
0044ABE6 60 pusha
0044ABE7 8D55DC lea edx, [ebp-$24] //В edx адрес кода

* Reference to control Edit2 : TEdit
|
0044ABEA 8B83E0020000 mov eax, [ebx+$02E0]

* Reference to: controls.TControl.SetText(TControl;TCaption);
|
0044ABF0 E85BB4FDFF call 00426050
0044ABF5 61 popa
0044ABF6 E95F010000 jmp 0044AD5A

Теперь немного о процедуре controls.TControl.SetText
Посмотреть адрес этой процедуры можно в DeDe здесь он 426050
На вход в edx нужно передать адрес выводимой строки (в паскалевском формате - см. выше)
в eax адрес компонента в который выводить (тоже посмотрел в DeDe).

Теперь немного косметики:
После всего сделанного (покрайней мере у меня) выскакивает Access violation.
Мелочь конечно но портит всю красоту. Избавиться мне от него не удалось, так
что я решил сделать так, как будто так и должно быть.
Открываем получившийся файл в Restorator’e и ищем в разделе String что то вроде
Access violation bla bla bla и заменяем на любую другую строку, у кого как фантазии хватит.
Так же можно поизменять св-ва форм и компонентов (чем я и занялся), тут тоже все зависит от вашей фантазии.
Можно например у Edit2 поставить свойство ReadOnly = True (зачем в кейгене ввод в поле сериала ?)
За этим все.

Обсуждение статьи: Альтернативный взлом CRACKL@B CrackMe #1 >>>


Комментарии к статье: Альтернативный взлом CRACKL@B CrackMe #1


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



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


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