Кейген для AxySnake v1.15

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

Автор: Fess

Два программиста, совершенно одуревшие от своих компьютеров, вышли перекурить на улицу. Мимо проходит красивая девушка. Один говорит другому:

— Помнишь, мы когда-то за такими девушками бегали.

— Помню бегали, но не помню зачем!

Target: AxySnake v1.15

Tools:

Some brains

Soft-Ice/TRW2000

Win32Dasm 8.93

RegMon 4.13

Masm32 (Masm 7.0)

Все, кроме мозгов, можно найти на www.exetools.com

Вступление

Как это начиналось:

Принесли мне тут гамилу AxySnake v1.15 с кейгеном группы Desperate. Эта игрушка мне напомнила известную мне игрушку AirXonix. Как позже оказалось это было верным — игрушки одной фирмы. Я припомнил давешний взлом со множеством подлянок. И мне захотелось проверить надежность кейгена, как оказалось я правильно сомневался. Работать, он работает, но после нескольких этапов пишет, что код не особенно верный. И я решился поломать сию прогу.

Что за прога:

Очень даже неплохая игрушка 3D ремейк классической игры Червяк или Питон. Долго в нее не заиграешься, а вот расслабиться может помочь. В архиве примерно 7 Мбайт. Системные требования:

3D Graphics card

DirectX 7.0 or higher

Windows 95/98/ME/2000/XP

Processor 200 MHz or higher (>300 MHz — recommended)

32 MB RAM

15 MB free disk space

Sound card — optional

Начало

Чтобы было хоть какое-то разнообразие, я решил сегодня писать кейген на асме. Сразу хочется выразить особую благодарность Dr.Golova за предоставленный отличный пример. На основе которого я и написал свой кейген.

Предудущая игра не была запакована и была написана на MS Visual C 6.0. Не стала исключением и эта. Хочется только поблагодарить авторов за такой простор для работы.

Заглянув в каталог программы, я обнаружил пару dll-лок и 3 exe-шника. Немного поднапряг соображалку, воспользовался просмотрщиком ресурсов и я понял, что

AxySnake.exe — Настоящий запускаемый файл программы

Rekl.exe — Это фигня выдающая рекламу после выхода из игры (в незарегеной версии)

AxySnake.exe — Непонятный файл запускающий основную программу, покопавшись в листинге Win32Dasm’а я догнал, что он проверяет версию DirextX, командную строку и т.п.

proskin.dll — Из названия становится ясно, что это Prosto Skin в ресурсах содержатся картинки, и по размеру файла становится ясно, что это почти все, что там есть.

proton.dll — И наконец оно, в ресурсах находятся регистрационные диалоги, а где диалоги, почти всегда находятся функции отвечающие за их выполнение. Короче, беремся за него.

Дизассемблировав его посмотрим на экспортируемые функции, вдруг мы ошиблись и в этом файле нет ничего интересного, но среди всего многообразия я нашел следующие строки…

?bRegistered@@3HA

?DeleteRegistration@@YAXXZ

?GetRegCode@@YAPADXZ

?GetRegName@@YAPADXZ

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

Жмем два раза на Deluxe и попадаем сюда.

Name: REG_FAULT, # of Controls=004, Caption:»AxySnake Registration», ClassName:»»

001 — ControlID:0001, Control Class:»BUTTON» Control Text:»Try again»

002 — ControlID:0002, Control Class:»BUTTON» Control Text:»Cancel»

003 — ControlID:FFFF, Control Class:»STATIC» Control Text:»E R R O R !»

004 — ControlID:FFFF, Control Class:»STATIC» Control Text:»Registration name or registration code is incorrect.»

Name: REG_OK, # of Controls=003, Caption:»AxySnake Registration», ClassName:»»

001 — ControlID:0001, Control Class:»BUTTON» Control Text:»OK»

002 — ControlID:FFFF, Control Class:»STATIC» Control Text:»REGISTRATION IS SUCCESSFULLY COMPLETED! «

003 — ControlID:FFFF, Control Class:»STATIC» Control Text:»Thank you for registering !»

Два эти диалога показались мне переспективными. Идем в «Поиск» вписываем строку REG_OK. Нажимаем Enter и, о боже, она нашлась!!!!!!

:1000FA54 E8570E0000 call 100108B0 <- Процедура проверки кода

:1000FA59 85C0 test eax, eax

:1000FA5B 7541 jne 1000FA9E

:1000FA5D 50 push eax

* Reference To: USER32.MessageBeep, Ord:01BDh

|

:1000FA5E FF15D4610210 Call dword ptr [100261D4]

(удалено лишнее)

:1000FA71 56 push esi

* Possible StringData Ref from Data Obj ->»REG_FAULT» <- Вроде неправильный код

|

:1000FA72 6840CB0210 push 1002CB40

(лишнее вырезано)

:1000FA8E 56 push esi

* Possible StringData Ref from Data Obj ->»REG_DIALOG»

|

:1000FA8F 684CCB0210 push 1002CB4C

(мусор убран)

:1000FA9C EB4D jmp 1000FAEB

* Referenced by a (U)nconditional or (C)onditional Jump at Address:

|:1000FA5B(C)

|

:1000FA9E E86D6BFFFF call 10006610

(мусор выкинут)

:1000FAC1 6860DF0010 push 1000DF60

:1000FAC6 56 push esi

* Possible StringData Ref from Data Obj ->»REG_OK» <- Вроде правильный код

|

:1000FAC7 6838CB0210 push 1002CB38

Если выделенная процедура возвращает не 0, то регистрация считается верной. Можно попробовать патчем, но сразу огорчу, у такого пути Вас ждет разочарование. Я думаю ни у кого не вызываем сомнений, что регистрационный код лучше патча. И все знают из-за чего, если нет почитайте предыдущие мои тьюториалы и без сомнения узнаете. Итак, что дальше…

Заходим в процедуру и пытаемся разобраться в хитросплетениях магических команд называемых языком ассемблера. Благо здесь нет ничего особо сложного, я в смысле, что здесь не применяется никаких команд сопроцессора и т.п. гадости. На этом этапе Вам без сомнения придется пользоваться отладчиком. Надеюсь, Вы знаете как. Если нет, то попробуйте сначала почитать тьюториал полегче. Короче ставим бряк на точку входа в процедуру, т.е. на 100108B0 (bpx 100108B0). Для наглядности я буду пояснять, что тут и куда (Запомните все числа даны в 16 системе счисления)

:100108B0 A198A40310 mov eax, dword ptr [1003A498] <- Проверка длинны имени на 0

:100108B5 85C0 test eax, eax

:100108B7 0F84E1000000 je 1001099E

:100108BD 8B0D9CA40310 mov ecx, dword ptr [1003A49C] <- Проверка длинны кода на 0

:100108C3 85C9 test ecx, ecx

:100108C5 0F84D3000000 je 1001099E

:100108CB 6818F91210 push 1012F918 <- Передает в процедуру адрес буфера

:100108D0 6838A40310 push 1003A438 <- Передаем в процедуру адрес имени

:100108D5 C68038A4031000 mov byte ptr [eax 1003A438], 00 <- В конце имени пишем байт 0

:100108DC E84FFFFFFF call 10010830

{Здесь вставлена вышеназванная процедура (чтобы не лазить)}

:10010830 55 push ebp <- Сохраняем ebp

:10010831 8B6C2408 mov ebp, dword ptr [esp 08] <- Берем в ebp адрес имени

:10010835 8BCD mov ecx, ebp <- ecx = ebp

:10010837 8A4500 mov al, byte ptr [ebp 00] <- Берем 1 символ

:1001083A 84C0 test al, al <- Проверяем на 0

:1001083C 7410 je 1001084E <- Если да, то переход

:1001083E 3C20 cmp al, 20 <- Сравниваем его с пробелом

:10010840 7404 je 10010846 <- Если да, то переход

:10010842 A880 test al, 80 <- Проверяем 8 бит

:10010844 740C je 10010852 <- Если установлен, то переход

:10010846 8A4101 mov al, byte ptr [ecx 01] <- Берем ecx 1 символ имени

:10010849 41 inc ecx <- Увеличиваем адрес имени

:1001084A 84C0 test al, al <- Сравниваем код символа с кодом 0

:1001084C 75F0 jne 1001083E <- Если нет, то повторяем

:1001084E 33C0 xor eax, eax <- Очищаем eax

:10010850 5D pop ebp <- Возвращаем ebp

:10010851 C3 ret <- Выходим из процедуры

:10010852 53 push ebx < \

:10010853 56 push esi <- Сохраняем регистры

:10010854 57 push edi < /

:10010855 8B7C2418 mov edi, dword ptr [esp 18] <- Берем

:10010859 8BCF mov ecx, edi <- ecx=edi

:1001085B 33C0 xor eax, eax <- eax=0

:1001085D 33F6 xor esi, esi <- esi=0

:1001085F 8BD5 mov edx, ebp <- edx=ebp

:10010861 8901 mov dword ptr [ecx], eax <- Заносим 0

:10010863 33DB xor ebx, ebx <- ebx=0

:10010865 894104 mov dword ptr [ecx 04], eax < \

:10010868 894108 mov dword ptr [ecx 08], eax <- Обнуляем

:1001086B 89410C mov dword ptr [ecx 0C], eax < /

:1001086E 8BC7 mov eax, edi <- eax=edi (Адрес буфера суммы)

:10010870 803A00 cmp byte ptr [edx], 00 <- Сравниваем символ имени по

адресу edx с 0

:10010873 7503 jne 10010878 <- Если не равно, то

:10010875 40 inc eax <- Увеличиваем адрес eax

:10010876 8BD5 mov edx, ebp <- edx=ebp (Устанавливаем на начало имени)

:10010878 8A0A mov cl, byte ptr [edx] <- Берем символ имени по адресу edx

:1001087A 80F920 cmp cl, 20 <- Сравниваем его с пробелом

:1001087D 7414 je 10010893 <- Если да, то переход

:1001087F F6C180 test cl, 80 <- Сравниваем 8 бит

:10010882 750F jne 10010893 <- Если он 1, то переход

:10010884 0008 add byte ptr [eax], cl <- Прибавляем к байту по адресу eax

символ из cl

:10010886 40 inc eax <- Увеличиваем адрес eax

:10010887 46 inc esi <- Увеличиваем счетчик

:10010888 83FE10 cmp esi, 00000010 <- Сравниваем счетчик с 10h

:1001088B 7507 jne 10010894 <- Если не равен, то переход

:1001088D 33F6 xor esi, esi <- Обнуляем счетчик

:1001088F 8BC7 mov eax, edi <- eax=edi (Устан. на начало буфера)

:10010891 EB01 jmp 10010894 <- Переход

:10010893 4B dec ebx <- Уменьшаем ebx на 1

:10010894 42 inc edx <- Увеличиваем указатель имени на 1

:10010895 43 inc ebx <- Увеличиваем счетчик ebpx на 1

:10010896 83FB6F cmp ebx, 0000006F <- Продолжаем все это, пока ebx<6Fh

:10010899 7CD5 jl 10010870 <- Если меньше, то повторить

:1001089B 5F pop edi < \

:1001089C 5E pop esi <- Возвращаем значения

:1001089D 5B pop ebx < /

:1001089E B801000000 mov eax, 00000001 <- eax=1

:100108A3 5D pop ebp <- Возвращаем ebp

:100108A4 C3 ret <- Выходим из процедуры

{ Общий смысл: В буфер по адресу 1012F918 генерируется суммарное представление имени}

{Для краткости, я буду называть ее суммой имени }

{Заканчивается вставленная процедура}

:100108E1 83C408 add esp, 00000008 <- Выравниваем стек

:100108E4 85C0 test eax, eax <- Проверяем eax

:100108E6 0F84B2000000 je 1001099E <- Если он 0, то переход

:100108EC 6878A40310 push 1003A478 <- Ложим в стек адрес введенного кода

:100108F1 E8EAFEFFFF call 100107E0

{Здесь вставлена вышеназванная процедура (чтобы не лазить)}

:100107E0 8B4C2404 mov ecx, dword ptr [esp 04]

:100107E4 56 push esi

:100107E5 33F6 xor esi, esi

:100107E7 803900 cmp byte ptr [ecx], 00 <- Если код символа пароля равен 0,

:100107EA 742A je 10010816 <- то переход

:100107EC 53 push ebx <- Сохраняем ebx

:100107ED 33C0 xor eax, eax <- Обнуление счетчика

:100107EF 8A90B0CB0210 mov dl, byte ptr [eax 1002CBB0] <- Строка "23456..."

:100107F5 8A19 mov bl, byte ptr [ecx] <- Берем символ пароля

:100107F7 3AD3 cmp dl, bl <- Сравниваем

:100107F9 7507 jne 10010802 <- Если не равно переход

:100107FB 8886F8F81210 mov byte ptr [esi 1012F8F8], al <- Записываем состояние счетчика

:10010801 46 inc esi <- esi = esi 1 (тоже счетчик)

:10010802 40 inc eax <- Увелич. счетчик

:10010803 83F820 cmp eax, 00000020 <- Если вся строка закончилась, то

:10010806 7CE7 jl 100107EF

:10010808 8A4101 mov al, byte ptr [ecx 01] <- Берем код символа пароля 1

:1001080B 41 inc ecx <- Увелич. адрес введенного пароля

:1001080C 84C0 test al, al <- Проверка на окончание

:1001080E 75DD jne 100107ED <- Если нет, то повторяем

:10010810 83FE14 cmp esi, 00000014 <- Если было 14h совпадений, то все путем

:10010813 5B pop ebx <- Восстанавливаем ebx

:10010814 7404 je 1001081A <- Если все было путем, то переход

:10010816 33C0 xor eax, eax <- eax=0 (Типа очень плохо)

:10010818 5E pop esi

:10010819 C3 ret <- Выход из процедуры

:1001081A B801000000 mov eax, 00000001 <- eax=1 (Типа хорошо)

:1001081F 5E pop esi

:10010820 C3 ret <- Выход из процедуры

{Общий смысл процедуры: Переконвертировка пароля в строку байтов, заданную}

{счетчиком элемента в строке символов 23456789ABCDEFGHJKLMNPQRSTUVWXYZ }

{Для краткости созданную строку я буду называть индексами пароля}

{Заканчивается вставленная процедура}

:100108F6 83C404 add esp, 00000004

:100108F9 85C0 test eax, eax <- Проверка на правильность

:100108FB 0F849D000000 je 1001099E <- Если да, то переход

{Далее идет проверка правильности кода}

:10010901 B949000000 mov ecx, 00000049 <- ecx= 49

:10010906 33C0 xor eax, eax <- eax=0

:10010908 0FBE9018F91210 movsx edx, byte ptr [eax 1012F918] <- Берем символ из суммы имени

:1001090F 03CA add ecx, edx <- ecx = ecx edx

:10010911 40 inc eax <- Увеличиваем счетчик на 1

:10010912 83F810 cmp eax, 00000010 <- Сравниваем счетчик с 10h

:10010915 7CF1 jl 10010908 <- Если меньше, то переход (повтор цикла)

:10010917 33C0 xor eax, eax <- eax = 0 (Обнуляем счетчик)

:10010919 0FBE90F8F81210 movsx edx, byte ptr [eax 1012F8F8] <- Берем символ индекса пароля

:10010920 0FBE92B0CB0210 movsx edx, byte ptr [edx 1002CBB0] <- По индексу берем символ из строки

:10010927 03CA add ecx, edx <- ecx = ecx edx

:10010929 40 inc eax <- Увеличиваем счетчик на 1

:1001092A 83F811 cmp eax, 00000011 <- Сравниваем счетчик с 11h

:1001092D 7CEA jl 10010919 <- Пока меньше, повторяем цикл

:1001092F A009F91210 mov al, byte ptr [1012F909] <- Берем 18 символ из индекса пароля

:10010934 83E11F and ecx, 0000001F <- ecx = ecx and 1Fh

:10010937 3AC1 cmp al, cl <- Сравниваем

:10010939 7563 jne 1001099E <- Если не равно, то очень плохо

{ Понятно дело, что эти числа должны быть равны, иначе ничего не выйдет }

{ Дальше идут аналогичные циклы для 19 и 20 индекса пароля, разобраться в }

{ которых не составит труда }

:1001093B B932000000 mov ecx, 00000032

:10010940 33C0 xor eax, eax

:10010942 0FBE9018F91210 movsx edx, byte ptr [eax 1012F918]

:10010949 2BCA sub ecx, edx

:1001094B 40 inc eax

:1001094C 83F810 cmp eax, 00000010

:1001094F 7CF1 jl 10010942

:10010951 33C0 xor eax, eax

:10010953 0FBE90F8F81210 movsx edx, byte ptr [eax 1012F8F8]

:1001095A 0FBE92B0CB0210 movsx edx, byte ptr [edx 1002CBB0]

:10010961 03CA add ecx, edx

:10010963 40 inc eax

:10010964 83F812 cmp eax, 00000012

:10010967 7CEA jl 10010953

:10010969 A00AF91210 mov al, byte ptr [1012F90A]

:1001096E 83E11F and ecx, 0000001F

:10010971 3AC1 cmp al, cl <- Сравнение 19 символа

:10010973 7529 jne 1001099E

:10010975 B979000000 mov ecx, 00000079

:1001097A 33C0 xor eax, eax

:1001097C 0FBE90F8F81210 movsx edx, byte ptr [eax 1012F8F8]

:10010983 0FBE92B0CB0210 movsx edx, byte ptr [edx 1002CBB0]

:1001098A 2BCA sub ecx, edx

:1001098C 40 inc eax

:1001098D 83F813 cmp eax, 00000013

:10010990 7CEA jl 1001097C

:10010992 A00BF91210 mov al, byte ptr [1012F90B]

:10010997 83E11F and ecx, 0000001F

:1001099A 3AC1 cmp al, cl <- Сравнение 20 символа

:1001099C 7416 je 100109B4

:1001099E 57 push edi {Это выполняется, если неправильный код}

:1001099F B91A000000 mov ecx, 0000001A

:100109A4 33C0 xor eax, eax

:100109A6 BF38A40310 mov edi, 1003A438

:100109AB F3 repz

:100109AC AB stosd

:100109AD A338F91210 mov dword ptr [1012F938], eax

:100109B2 5F pop edi

:100109B3 C3 ret

:100109B4 B801000000 mov eax, 00000001 <- Записываем 1, что все правильно

:100109B9 A338F91210 mov dword ptr [1012F938], eax <- Переменная правильности тоже 1

:100109BE C3 ret <- Выход из процедуры

Пишем кейген, или высчитываем пароль в голове. Вводим. Появляется табличка извещающая о правильности пароля. Все хорошо. Да, только вот при запуске игры вылетает экран с почти отборным матом. Вроде, все задвинутые пользователи игру покупают, а не ломают. Но я не из таких, а Вы? Поэтому я решил продолжить и разобраться в этой гадости.

Тут уже поднаторевший в этом деле читатель, может сказать, что это все элементарно. Надо просто посмотреть откедова вызывается нехорошая строка. Так и сделаем 🙂 Запускаем Win32Dasm и дизассемблируем основной exe-файл. В секции строк мы видим искомую нами строку. Нажимаем два раза и мы тут.

* Referenced by a CALL at Address:

|:0041245E

|

:00416D60 83EC10 sub esp, 00000010

(Всякой мусор)

:00416D7E 6A28 push 00000028

* Possible StringData Ref from Data Obj ->» LICENSE AGREEMENT VIOLATION «

->»! «

|

:00416D80 68847F4200 push 00427F84

:00416D85 FFD6 call esi

:00416D87 6A03 push 00000003

Как видно, ничего интересного нет, поэтому идем в вызывающую процедуру по адресу 41245E.

:00412396 FF1500514200 Call dword ptr [00425100]

* Reference To: proton.?bRegistered@@3HA, Ord:0064h

|

:0041239C 8B1524524200 mov edx, dword ptr [00425224]<- Проверяем правильность в proton.dll

:004123A2 83C408 add esp, 00000008

:004123A5 391A cmp dword ptr [edx], ebx <- Сравниваем полученное значение с 0

:004123A7 745D je 00412406 <- Если не все путем, то переходим

:004123A9 56 push esi

:004123AA 57 push edi

* Reference To: proton.?GetRegName@@YAPADXZ, Ord:0023h <- Получаем сумму имени

|

:004123AB FF15FC504200 Call dword ptr [004250FC]

:004123B1 B908000000 mov ecx, 00000008

:004123B6 8BF0 mov esi, eax

:004123B8 BF246D4700 mov edi, 00476D24 <- Сумма имени теперь по этому адресу

:004123BD F3 repz

:004123BE A5 movsd

* Reference To: proton.?GetRegCode@@YAPADXZ, Ord:0022h <- Получаем индексный пароль

|

:004123BF FF15F8504200 Call dword ptr [004250F8]

:004123C5 B908000000 mov ecx, 00000008

:004123CA 8BF0 mov esi, eax

:004123CC BF4C6D4700 mov edi, 00476D4C <- Теперь он по адресу

:004123D1 33C0 xor eax, eax

:004123D3 F3 repz

:004123D4 A5 movsd

:004123D5 5F pop edi

:004123D6 891D486D4700 mov dword ptr [00476D48], ebx

{Кстати, вот на этих стандарных адресах они и попались}

{А вот и первый подлячек}

:004123DC B94D000000 mov ecx, 0000004D <- ecx = 4Dh

:004123E1 5E pop esi <- Возвращаем esi

:004123E2 0FBE90246D4700 movsx edx, byte ptr [eax 00476D24] <- Берем символ суммы имени

:004123E9 40 inc eax <- Увеличиваем счетчик на 1

:004123EA 83F810 cmp eax, 00000010 <- Сравниваем счетчик с 10

:004123ED 8D0C51 lea ecx, dword ptr [ecx 2*edx] <- ecx = ecx 2*edx

:004123F0 7CF0 jl 004123E2 <- Пока счетчик меньше 10, повторяем цикл

:004123F2 A04C6D4700 mov al, byte ptr [00476D4C] <- Берем 1 символ индексного кода

:004123F7 83E11F and ecx, 0000001F <- ecx = ecx and 1Fh

:004123FA 3AC1 cmp al, cl <- Сравниваем полученное с 1 символом

:004123FC 7408 je 00412406 <- Если все рулез, то переход

:004123FE 892D486D4700 mov dword ptr [00476D48], ebp

:00412404 EB33 jmp 00412439

(Выкинут мусор)

:0041245E E8FD480000 call 00416D60 <- Вот откуда вызывается предыдущая процедура

* Reference To: proton.?DeleteRegistration@@YAXXZ, Ord:001Bh

|

:00412463 FF15F0504200 Call dword ptr [004250F0] <- Нас хотят лишить регистрации

Вот уже и первый подлячек обнаружился. Как я уже говорил, попались они на стабильном адресе имени. Идем в Поиск набираем 476D24. И он находит ее на строках: 40BD29, 40D794, 40DF0C, 412711, 4152F5, 4123B8. Ого-го сколько подлянок. Не хочу захламлять статью, поэтому найдите и разберитесь с ними сами.

В итоге процедура генерации стала выглядеть так

——————————————

{Файл kg.asm}

——————————————

; Собственно сырец KeyGen’a.

; Следует обратить внимание на процедуру KeyGen в конце этого файла,

; да на inc файл с некоторыми переменными.

;

; #########################################################################

.386

.model flat, stdcall ; 32 bit memory model

option casemap :none ; case sensitive

include kg.inc ; local includes for this file

; #########################################################################

.data

szDisplayName db «AxySnake v1.15 KeyGen by Fess [PTDS]»,0

szAboutCapt db «About…», 0

szAboutText db » Game: AxySnake v1.15 «, 13,10

db «Made by AxySoft URL: www.axysoft.com», 13,10

db » KeyGen by Fess [PTDS]», 13,10

db » mailto: lomovskih@yandex.ru», 13,10

db » Special Thanks by Dr.Golova «, 13,10

db » Visit site: vallkor.chat.ru «, 0

; Для работы с реестром

Software db ‘Software’,0

AxySoft db ‘AxySoft’,0

AxySnake db ‘AxySnake’,0

RegName db ‘RegName’,0

RegCode db ‘RegCode’,0

szREGSZ db ‘REG_SZ’,0

TitleM db ‘Apply..’

TextM db ‘Apply current name and Password’

ZZZ db ‘23456789ABCDEFGHJKLMNPQRSTUVWXYZ’,0

CodeReg db ‘23456789ABCDEFGHJSCB’,0

GenCode db 32 DUP (?)

AddRegName db 32 DUP (?) ;Буфер для суммирования кодов имени

hKey dd ?

lpcbData dd ?

; ################ Дальше идет стандартное masm32начало #################

.code

start:

invoke GetModuleHandle, NULL

mov hInstance, eax

invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT

invoke ExitProcess,eax

; #########################################################################

WinMain proc hInst :DWORD,

hPrevInst :DWORD,

CmdLine :DWORD,

CmdShow :DWORD

;====================

; Put LOCALs on stack

;====================

LOCAL wc :WNDCLASSEX

LOCAL msg :MSG

LOCAL Wwd :DWORD

LOCAL Wht :DWORD

LOCAL Wtx :DWORD

LOCAL Wty :DWORD

;==================================================

; Fill WNDCLASSEX structure with required variables

;==================================================

invoke LoadIcon, hInst, IDI_MAINICON ; Грузим иконку из ресурсов.

mov hIcon, eax

szText szClassName, «KG_WINDOW» ; Создаем новый класс окна.

mov wc.cbSize, sizeof WNDCLASSEX

mov wc.style, CS_HREDRAW or CS_VREDRAW \

or CS_BYTEALIGNWINDOW

mov wc.lpfnWndProc, offset WndProc

mov wc.cbClsExtra, NULL

mov wc.cbWndExtra, NULL

m2m wc.hInstance, hInst

mov wc.hbrBackground, COLOR_BTNFACE 1

mov wc.lpszMenuName, NULL

mov wc.lpszClassName, offset szClassName

m2m wc.hIcon, hIcon

invoke LoadCursor, NULL, IDC_ARROW ; Грузим стандартный курсор.

mov wc.hCursor, eax

m2m wc.hIconSm, hIcon

invoke RegisterClassEx, ADDR wc ; Регистрируем наш класс окна.

;================================

; Centre window at following size

;================================

mov Wwd, MainWndWidth

mov Wht, MainWndHight

invoke GetSystemMetrics, SM_CXSCREEN ; Это чтоб вывести окно

invoke TopXY,Wwd,eax ; В центре экрана.

mov Wtx, eax

invoke GetSystemMetrics, SM_CYSCREEN

invoke TopXY,Wht,eax

mov Wty, eax

; ################## Создаем главную форму ##############################

invoke CreateWindowEx, WS_EX_WINDOWEDGE,

ADDR szClassName,

ADDR szDisplayName,

WS_VISIBLE or WS_CAPTION or WS_SYSMENU,

Wtx, Wty, Wwd, Wht,

NULL,NULL,

hInst,NULL

mov hWnd,eax

; ################## Создаем все остальные контролы #####################

invoke CreateWindowEx, WS_EX_LEFT,

ADDR szBtnClass,

ADDR szBtn1Text,

WS_VISIBLE or WS_CHILD or BS_PUSHLIKE or BS_TEXT,

Button1L, Button1T, Button1W, Button1H,

hWnd, NULL, hInst, NULL

mov Button1, eax

invoke CreateWindowEx, WS_EX_LEFT,

ADDR szBtnClass,

ADDR szBtn2Text,

WS_VISIBLE or WS_CHILD or BS_PUSHLIKE or BS_TEXT,

Button2L, Button2T, Button2W, Button2H,

hWnd, NULL, hInst, NULL

mov Button2, eax

invoke CreateWindowEx, WS_EX_LEFT,

ADDR szStaticClass, NULL,

WS_VISIBLE or WS_CHILD or SS_LEFT,

Label1L, Label1T, Label1W, Label1H,

hWnd, NULL, hInst, NULL

mov Label1, eax

invoke CreateWindowEx, WS_EX_LEFT,

ADDR szStaticClass, NULL,

WS_VISIBLE or WS_CHILD or SS_LEFT,

Label2L, Label2T, Label2W, Label2H,

hWnd, NULL, hInst, NULL

mov Label2, eax

invoke CreateWindowEx, WS_EX_CLIENTEDGE,

ADDR szEditClass, NULL,

WS_CHILD or WS_VISIBLE or WS_BORDER or ES_AUTOHSCROLL,

Edit1L, Edit1T, Edit1W, Edit1H,

hWnd, NULL, hInst, NULL

mov Edit1, eax

invoke CreateWindowEx, WS_EX_CLIENTEDGE,

ADDR szEditClass, NULL,

WS_CHILD or WS_VISIBLE or WS_BORDER or ES_READONLY or ES_AUTOHSCROLL,

Edit2L, Edit2T, Edit2W, Edit2H,

hWnd, NULL, hInst, NULL

mov Edit2, eax

invoke SetWindowText, Label1, ADDR szLabel1Text ; Пишем текст на метки.

invoke SetWindowText, Label2, ADDR szLabel2Text

invoke CreateFont, -11, 0, 0, 0, 400, 0, 0, 0, ; Грузим подходящий шрифт.

DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

DEFAULT_PITCH or FF_DONTCARE, ADDR szFontName

mov hFont, eax

.if hFont != 0 ; Присваиваем этот шрифт всем элементам окна.

invoke SendMessage, Button1, WM_SETFONT, hFont, 0

invoke SendMessage, Button2, WM_SETFONT, hFont, 0

invoke SendMessage, Label1, WM_SETFONT, hFont, 0

invoke SendMessage, Label2, WM_SETFONT, hFont, 0

invoke SendMessage, Edit1, WM_SETFONT, hFont, 0

invoke SendMessage, Edit2, WM_SETFONT, hFont, 0

.endif

invoke SetFocus, Edit1;

; #########################################################################

invoke ShowWindow,hWnd, 1 ; Показать окно.

invoke UpdateWindow,hWnd ; Перерисовать окно. 🙂

;===================================

; Loop until PostQuitMessage is sent

;===================================

StartLoop:

invoke GetMessage,ADDR msg,NULL,0,0

cmp eax, 0

je ExitLoop

invoke TranslateMessage, ADDR msg

invoke DispatchMessage, ADDR msg

jmp StartLoop

ExitLoop:

return msg.wParam

WinMain endp

; #########################################################################

WndProc proc hWin :DWORD,

uMsg :DWORD,

wParam :DWORD,

lParam :DWORD

LOCAL var :DWORD

LOCAL caW :DWORD

LOCAL caH :DWORD

LOCAL Rct :RECT

LOCAL hDC :DWORD

LOCAL Ps :PAINTSTRUCT

LOCAL buffer1[128]:BYTE ; Два буфера для текстовых

LOCAL buffer2[128]:BYTE ; манипуляций и т.п…

.if uMsg == WM_COMMAND ; Обрабатываем поступающие в окно сообщения.

mov eax, lParam

.if eax == Button1 ; Нажата кнопка «About.»

invoke MessageBox, hWnd, ADDR szAboutText, ADDR szAboutCapt, 0

.elseif eax == Button2 ; Нажата кнопка «Close.»

call Reestr ; Записываем результаты в реестр

invoke PostQuitMessage,NULL

return 0

.elseif eax == Edit1 ; Изменилось содержимое поля ввода имени (!!!)

mov eax, wParam

shr eax, 16

.if ax == EN_CHANGE

call KeyGen ; Генерим рег. ключики показываем его.

.endif

.endif

.elseif uMsg == WM_DESTROY

invoke PostQuitMessage,NULL

return 0

.endif

invoke DefWindowProc,hWin,uMsg,wParam,lParam

ret

WndProc endp

; ########################################################################

TopXY proc wDim:DWORD, sDim:DWORD

shr sDim, 1 ; divide screen dimension by 2

shr wDim, 1 ; divide window dimension by 2

mov eax, wDim ; copy window dimension into eax

sub sDim, eax ; sub half win dimension from half screen dimension

return sDim

TopXY endp

; #########################################################################

; ################# Вот это главная ф-ция расчета РН ####################

; #### Сама берет все нужное, обрабатывает ошибки и пишет результат #####

; #########################################################################

KeyGen PROC

pushad

invoke GetWindowText, Edit1, ADDR szRegName, 1024 ; Получить текст

; из Edit1

invoke lstrlen, ADDR szRegName

cmp eax, 3

ja @NameOk

invoke SetWindowText, Edit2, ADDR szNoName ; то уведомить пользователя

popad

ret ; и выйти из функции

@NameOk:

mov byte ptr [szRegCode], 0 ; Если есть — расчитать правильный

; Регистрационный номер.

mov edx, offset CodeReg

mov word ptr [edx 17],0

mov word ptr [edx 19],0

mov edx, offset GenCode

mov esi, offset AddRegName

mov cl,32

@NullS:

mov byte ptr [edx],0

mov byte ptr [esi],0

inc edx

inc esi

dec cl

jnz @NullS

xor eax, eax

xor ecx, ecx

xor ebx, ebx

xor esi, esi

@001:

; Сумма кодов имени

;

mov al, byte ptr [offset szRegName ecx]

test al, al

je @1084E

cmp al, 20h

je @10846

test al, 80h

je @10852

@10846:

mov al, byte ptr [ecx 01]

inc ecx

test al, al

jne @001

@1084E:

xor eax, eax

@10852:

mov edx, offset szRegName

mov eax, offset AddRegName

@10870:

cmp byte ptr [edx], 00

jne @10878

inc eax

mov edx, offset szRegName

@10878:

mov cl, byte ptr [edx]

cmp cl, 20h

je @10893

test cl, 80h

jne @10893

add byte ptr [eax], cl

inc eax

inc esi

cmp esi, 00000010h

jne @10894

xor esi, esi

mov eax, offset AddRegName

jmp @10894

@10893:

dec ebx

@10894:

inc edx

inc ebx

cmp ebx, 0000006Fh

jl @10870

;

; Приколы

;

; Первый прикол — не запускается меню

mov ecx, 4Dh

xor eax, eax

@4123E2:

movsx edx, byte ptr [offset AddRegName eax]

inc eax

cmp eax, 10h

lea ecx, [ecx edx*2]

jl @4123E2

and ecx, 1Fh

movsx edx, byte ptr [offset ZZZ ecx]

xor eax, eax

mov byte ptr [offset CodeReg eax], dl

; Второй прикол — не запускается пункт меню Game

mov ecx, 86h

xor eax, eax

@4152FC:

movsx edx, byte ptr [eax offset AddRegName]

test al, 1

jz @41350B

add ecx, edx

jmp @415310

@41350B:

neg edx

lea ecx, [ecx edx*2]

@415310:

inc eax

cmp eax ,10h

jl @4152FC

and ecx, 1Fh

movsx edx, byte ptr [offset ZZZ ecx]

mov eax, 2

mov byte ptr [offset CodeReg eax], dl

; Третий прикол —

mov ecx, 0000038Ch

xor eax, eax

@40D79B:

movsx edx, byte ptr [eax offset AddRegName]

cmp eax, 00000009

jge @40D7AF

lea edx, dword ptr [edx 2*edx]

lea ecx, dword ptr [ecx 2*edx]

jmp @40D7BC

@40D7AF:

lea esi, dword ptr [4*edx 00000000]

sub esi, edx

neg esi

add ecx, esi

@40D7BC:

inc eax

cmp eax, 00000010h

jl @40D79B

and ecx, 0000001Fh

movsx edx, byte ptr [offset ZZZ ecx]

mov eax, 4

mov byte ptr [offset CodeReg eax], dl

; Четвертый прикол —

@40DF0C:

mov edx, 00000007

xor eax, eax

@40DF13:

movsx ecx, byte ptr [eax offset AddRegName]

cmp eax, 00000008

jge @40DF23

mov esi, ecx

jmp @40DF2A

@40DF23:

mov esi, 00000001

sub esi, ecx

@40DF2A:

imul esi, ecx

add edx, esi

inc eax

cmp eax, 00000010h

jl @40DF13

and edx, 0000001Fh

mov ecx, edx

movsx edx, byte ptr [offset ZZZ ecx]

mov eax, 3

mov byte ptr [offset CodeReg eax], dl

; Пятый прикол —

@412711:

mov ecx, 00000307h

xor eax, eax

@412716:

movsx edx, byte ptr [eax offset AddRegName]

sub ecx, edx

inc eax

cmp eax, 00000010h

jl @412716

and ecx, 0000001Fh

movsx edx, byte ptr [offset ZZZ ecx]

mov eax,1

mov byte ptr [offset CodeReg eax], dl

; Шестой прикол — При выходе с этапа, но не всегда

xor ecx, ecx

xor eax, eax

xor edx, edx

mov esi, offset AddRegName ;476D24

mov al, byte ptr [esi 13]

mov cl, byte ptr [esi 12]

mov dl, byte ptr [esi 04]

imul eax, ecx

mov cl, byte ptr [esi 03]

imul edx, ecx

mov cl, byte ptr [esi 01]

sub eax, edx

mov dl, byte ptr [esi 02]

imul edx, ecx

mov cl, byte ptr [esi 05]

sub eax, edx

mov dl, byte ptr [esi 06]

imul edx, ecx

add eax, edx

mov dl, byte ptr [esi]

sub eax, edx

sub eax, 0000000Dh

and eax, 0000001Fh

movsx edx, byte ptr [offset ZZZ eax]

mov eax, 0Ch

mov byte ptr [offset CodeReg eax], dl

; Генерация кодового представления

xor esi, esi

mov ecx, Offset CodeReg

@107ED:

xor eax, eax

@107EF:

mov dl, byte ptr [eax offset ZZZ]

mov bl, byte ptr [ecx]

cmp dl, bl

jne @10802

mov byte ptr [esi offset GenCode], al

inc esi

@10802:

inc eax

cmp eax, 00000020h

jl @107EF

mov al, byte ptr [ecx 01]

inc ecx

test al, al

jne @107ED

;{18 символ}

mov ecx, 00000049h

xor eax, eax

@10908:

movsx edx, byte ptr [eax offset AddRegName]

add ecx, edx

inc eax

cmp eax, 00000010h

jl @10908

xor eax, eax

@10919:

movsx edx, byte ptr [eax offset GenCode]

movsx edx, byte ptr [edx offset ZZZ]

add ecx, edx

inc eax

cmp eax, 00000011h

jl @10919

and ecx, 0000001Fh

mov byte ptr [offset GenCode eax], cl

mov dl, byte ptr [offset ZZZ ecx]

mov byte ptr [offset CodeReg eax], dl

;{19 символ}

mov ecx, 00000032h

xor eax, eax

@010942:

movsx edx, byte ptr [eax offset AddRegName]

sub ecx, edx

inc eax

cmp eax, 00000010h

jl @010942

xor eax, eax

@10953:

movsx edx, byte ptr [eax offset GenCode]

movsx edx, byte ptr [edx offset ZZZ]

add ecx, edx

inc eax

cmp eax, 00000012h

jl @10953

and ecx, 0000001Fh

mov byte ptr [offset GenCode eax], cl

mov dl, byte ptr [offset ZZZ ecx]

mov byte ptr [offset CodeReg eax], dl

;{20 символ}

mov ecx, 00000079h

xor eax, eax

@1097C:

movsx edx, byte ptr [eax offset GenCode]

movsx edx, byte ptr [edx offset ZZZ]

sub ecx, edx

inc eax

cmp eax, 00000013h

jl @1097C

and ecx, 0000001Fh

mov dl, byte ptr [offset ZZZ ecx]

mov byte ptr [offset CodeReg eax], dl

invoke SetWindowText, Edit2, offset CodeReg ; Поместить полученный РН

; в Edit2

popad

ret ; И выйти из функции.

KeyGen ENDP

Reestr PROC

; При выходе последнее имя и пароль автоматически заносится в реестр

pushad

INVOKE RegCreateKeyA, HKEY_LOCAL_MACHINE, addr Software, addr hKey

INVOKE RegCreateKeyA, hKey, addr AxySoft, addr hKey

INVOKE RegCreateKeyA, hKey, addr AxySnake, addr hKey

INVOKE lstrlen, addr szRegName

INVOKE RegSetValueEx, hKey, addr RegName, 0, REG_SZ, addr szRegName, lpcbData

INVOKE RegSetValueEx, hKey, addr RegCode, 0, REG_SZ, addr CodeReg, lpcbData

INVOKE RegCloseKey, hKey

@NoR:

popad

ret ; и выйти из функции

Reestr ENDP

; #################### Типа конец и все такое. ############################

end start

——————————————

{Файл kg.inc}

——————————————

; include files

; ~~~~~~~~~~~~~

include \MASM32\INCLUDE\windows.inc

include \MASM32\INCLUDE\gdi32.inc

include \MASM32\INCLUDE\user32.inc

include \MASM32\INCLUDE\kernel32.inc

include \MASM32\INCLUDE\Comctl32.inc

include \MASM32\INCLUDE\comdlg32.inc

include \MASM32\INCLUDE\shell32.inc

include \MASM32\include\advapi32.inc

; libraries

; ~~~~~~~~~

includelib \MASM32\LIB\gdi32.lib

includelib \MASM32\LIB\user32.lib

includelib \MASM32\LIB\kernel32.lib

includelib \MASM32\LIB\Comctl32.lib

includelib \MASM32\LIB\comdlg32.lib

includelib \MASM32\LIB\shell32.lib

includelib \MASM32\lib\advapi32.lib

; #########################################################################

;=================

; Local prototypes

;=================

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD

TopXY PROTO :DWORD,:DWORD

FillBuffer PROTO :DWORD,:DWORD,:BYTE

;=============

; Local macros

;=============

szText MACRO Name, Text:VARARG

LOCAL lbl

jmp lbl

Name db Text,0

lbl:

ENDM

m2m MACRO M1, M2

push M2

pop M1

ENDM

return MACRO arg

mov eax, arg

ret

ENDM

.data?

szRegName db 1024 DUP (?) ; Буфферы для введенного имени

szRegCode db 1024 DUP (?) ; и расчитанного ключика.

.data

Button1 dd 0 ; Хэндлы контролов.

Button2 dd 0

Edit1 dd 0

Edit2 dd 0

Label1 dd 0

Label2 dd 0

CommandLine dd 0

hWnd dd 0

hInstance dd 0

hIcon dd 0

hFont dd 0

szBtn1Text db «About.», 0 ; Используемые текстовые строки 🙂

szBtn2Text db «Close.», 0

szLabel1Text db «Enter Name:», 0

szLabel2Text db «Get RegNum:», 0

szNoName db «Enter Name, Dude !!!», 0

szBtnClass db «Button», 0

szEditClass db «Edit» , 0

szStaticClass db «Static», 0

szFontName db «MS Sans Serif», 0

; ########################### Inserted modules ############################

IDI_MAINICON EQU 500 ; Номер иконки в ресурсах.

MainWndHight EQU 083 ; Размеры и положения всех элементов.

MainWndWidth EQU 355

Button1W EQU 065

Button1H EQU 019

Button1T EQU 009

Button1L EQU 277

Button2W EQU 066

Button2H EQU 019

Button2T EQU 031

Button2L EQU 277

Label1W EQU 176

Label1H EQU 013

Label1T EQU 012

Label1L EQU 008

Label2W EQU 176

Label2H EQU 013

Label2T EQU 034

Label2L EQU 008

Edit1W EQU 190

Edit1H EQU 021

Edit1T EQU 008

Edit1L EQU 080

Edit2W EQU 190

Edit2H EQU 021

Edit2T EQU 030

Edit2L EQU 080

; #########################################################################

Процедура генерации опробована и проверена. Сделана на Masm 7.0.

Для имени Fess код должен быть 5WKJ9789ABCD7FGHJQUK.

Спасибо за интерес к моему творчеству!

Удачи в Reversing Engeneering!

Послесловие

Спасибо автору за предоставленный для исследования продукт. Было очень интересно.

Господа Авторы: Спасибо за интересный продукт, если бы еще чуточку улучшили защиту, то возможно пришлось бы изрядно попотеть, а пока только 3 .

Братья Крэкеры: Что ни говори, а игра хорошая. И еще ПРОВЕРЯЙТЕ ВСЕГДА СВОИ КРЭКИ!!! А то видите как с Desperate вышло.

Все ругательства отправлять в null

Все остальное на lomovskih@yandex.ru

P.S. Запомните все материалы публикуются только в учебных целях и автор за их использование ответственности не несет!!

P.P.S. Возможно имеют место опечатки, заранее извините!

With best wishes Fess

И да пребудет с вами великий дух bad-сектора.

{/codecitation}

Добавить комментарий