Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Кейген для AxySnake v1.15
Автор: 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-сектора.

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay