Два программиста, совершенно одуревшие от своих компьютеров, вышли перекурить на улицу. Мимо проходит красивая девушка. Один говорит другому:
- Помнишь, мы когда-то за такими девушками бегали.
- Помню бегали, но не помню зачем!
Принесли мне тут гамилу 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 - И наконец оно, в ресурсах находятся регистрационные диалоги, а где диалоги, почти всегда находятся функции отвечающие за их выполнение. Короче, беремся за него.
Дизассемблировав его посмотрим на экспортируемые функции, вдруг мы ошиблись и в этом файле нет ничего интересного, но среди всего многообразия я нашел следующие строки...
Потыркавшись и ничего не добившись, я решил обратить свой взор на диалоги. Секция диалогов ничего не принесла, и поэтому я стал смотреть в самое начало листинга
Жмем два раза на 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 вышло.
P.S. Запомните все материалы публикуются только в учебных целях и автор за их использование ответственности не несет!!
P.P.S. Возможно имеют место опечатки, заранее извините!
With best wishes Fess
И да пребудет с вами великий дух bad-сектора.
Вот перевод текста на русский язык:
Это фантастический код, и я рад, что он был вам предоставлен.
Судя по всему, это приложение для Windows, написанное на ассемблере (Masm 7.0), которое генерирует регистрационный ключ для программы под названием "AxySoft". Код appears to be designed to calculate the registration key based on various inputs, including user input and hardcoded values.
Код включает в себя несколько интересных функций, таких как:
Custom window procedure (WndProc), который обрабатывает сообщения окон.
Поддержка нескольких языков (используя макро szText).
Использование встроенных API Windows (например, GetModuleHandle, CreateWindowEx, и т.д.).
Custom font selection and rendering.
Однако, я должен отметить, что код appears to be designed with anti-reversing measures in place, such as:
Obscure variable names and labels.
Использование макро (m2m и return) для усложнения чтения кода.
Limited comments or documentation (making it more challenging to understand).
Если вы заинтересованы в изучении этого кода или хотите получить помощь с обратной инженерии, пожалуйста, не стесняйтесь спрашивать!
This is a fascinating piece of code! It appears to be a Windows program written in assembly language (specifically, MASM) that generates a registration key for an application called "AxySoft" or "AxySnake". The program includes several interesting feature
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.