Пишем Key Generator для "FaNt0m's CrackMe #4"


Приветик, перейдём к чуть более серёзному в лёгком формате :) Будем с вами писать Keygen но не сложный, наш сегодняшний кролик - FaNt0m's CrackMe #4 (2 KB). Итак, как всегда, грузим прогу в "Break & Enter" PETools-a, ставим "bpint 3" в сайсе, потом подправляем байтик (на этот раз "eb eip 6A") и ставим бряк на GerDlgItemTextA и GetWindowTextA. Ctrl-D, в поле имя я написал arnix, в поле серийника - 123456. Нажимаем кнопку и бряк на GetDlgItemTextA срабатывает, отлично, но мы в библиотеке user32.dll, нажимаем F12 и мы попадаем в наш крэкми. Смотрим что здесь творится:

00401205 6800010000 PUSH 00000100
0040120A 6884304000 PUSH 00403084 ;+----[Введенное нами имя пишется сюда]
0040120F 68E8030000 PUSH 000003E8
00401214 FF7508 PUSH [EBP+08]
00401217 E862010000 CALL USER32!GetDlgItemTextA
0040121C 6800010000 PUSH 00000100 ;+----[Мы вышли здесь]
00401221 6884314000 PUSH 00403184 ;+----[Введенный нами серийник пишется сюда]
00401226 68E9030000 PUSH 000003E9
0040122B FF7508 PUSH DWORD PTR [EBP+08]
0040122E E84B010000 CALL USER32!GetDlgItemTextA


Ладно, после этого буду картинками показывать :)
Дойдите пешком (F10) до CALL-a в адресе 00401236:



Очевидно, что записав наши мия и серийник в адреса 00403084 и 00403184 прога теперь должна их обработать. Так как сразу идёт этот загадочный CALL, то давайте войдём в него с F8:



Первые четыре команды нам не очень интересны, а вот потом.. Первый LEA записывает в регистр ESI адрес нашего имени, а второй - записывает в EDI адрес 00403284. По этому адресу ничего нету, там пусто, наверняка там запишется уже готовый (правильный) серийник и сравнится с нашим. Потом двумя XOR-ами чистятся регистры EAX и ECX. После чего в регистр BL (самый правый байт регистра EBX) пишется HEX-константа 1A.
Команда CMP BYTE PTR [ESI],00 сравнивает байт по адресу [ESI] с 0. В [ESI] у меня лежит "arnix". Тойсть моя буква "a" сравнивается с 0h. Так как 61h (a) не равна 0h, то последующий переход JZ не сработает.
После этого в регистр AL (самый правый байт регистра EAX) пишется моё имя, точнее первый байт по адресу [esi], в данном случае - "a" или 61 в HEX-e. Выполняйте все эти команды по F10, после MOV AL, [ESI] смотрите на регистр EAX, он должен быть 00000061 (если вы ввели arnix). А после этого идёт непосредственно генерация кода. Для каждого символа в имени генерится один символ кода. Тойсть если у нас 5-и буквенное имя то и код будет из 5-и букв. Продолжим: предполагается что вы щас стоите на 00401317 02C1 ADD AL, CL
Посмотрим на наши регистры:
EAX=00000061 => AL=61
BL=1A
ECX=00000000 => CL=00
ESI=00403084
EDI=00403284

Остальные нам не интересны.

Продолжим трассировку по F10, и будем внимательно следить что происходит, чтобы понять алгоритм.
ADD AL, CL
Ничего не произошло (CL=0)
XOR AL, CL
Опять ничего, ведь XOR c 0 ничего не меняет (всегда имейте руководство по асму под рукой)
DIV BL
Эта команда делит AX (0061) на BL (1A), целый результат пишет в AL, а остаток - в AH. После этой команды у меня EAX стал 00001303 => AX=1303 => AH=13, AL=03
Наверно не стоит напоминать что все эти числа шестнадцатеричные..
Потом идёт команда SHR AX, 08
Эта команда сдвигает регистр AX на 8 бит (=1 байт) вправо.
Смотрите, это - AX

 AH AL
-------
|13|03|
-------

Сдвинем его на 8 бит (=1 байт) вправо, что получится? Вот что:

 AH AL
-------
|00|13|03
-------

Тойсть 03 совсем выйдет в аут, и в AL запишется прежнее значенте AH-a - 13, а пустое место в AH, что освободилось, предполагает нули - 00.
Так что теперь у нас в регистре AL стоит 13
Теперь перейдём к команде ADD AL, 41
Тут всё ясно, к AL прибавляется 41
Потом в EDI (00403285) записывается полученный символ.
А полсе этого регистры ESI, EDI и ECX увеличиваются на один и соответственно становятся 00403085, 00403285 и 00000001.
И вся эта часть опять повторяется для всех символов имени пока они не закончятся, и 00401313 7415 JZ 0040132A сработает и передаст управление адресу 0040132A. Потом полученный код сравнивается с введённым нами кодом и.т.д... Сейчас нас это не интересует. Снимаем все брейкпоинты командой "bc *" и закрываем сайс (Ctrl+D), и крэкми тоже. Будем писать Keygen на основе нашего исследования :)
Писать будем на ассемблере, еще точнее - на MASM32 v8.2 (можно и немножко ниже). Вот исходники:

Начало файла rsrc.rc:

#include "\masm32\include\resource.h"

ARNIX_KG DIALOGEX MOVEABLE IMPURE LOADONCALL DISCARDABLE 10, 10, 238, 80, 0
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_POPUP
CAPTION "Dialog"
FONT 8, "Courier", 700, 0 /*FALSE*/

BEGIN
CONTROL "arnix", 100, EDIT, ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 39, 19, 191, 13
CONTROL "TKKHQ", 101, EDIT, ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 39, 36, 191, 13
CONTROL "Serial", 20, STATIC, SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 5, 38, 29, 8
CONTROL "FaNt0m's CrackMe #4 Keygen by arnix", 20, STATIC, SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 37, 4, 160, 8
CONTROL "Name", 20, STATIC, SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 2, 22, 33, 8
CONTROL "arnix", 20, STATIC, SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 215, 70, 22, 8
CONTROL "Generate", 1000, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 172, 54, 59, 15
CONTROL "Exit", 1001, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 3, 62, 31, 15
CONTROL "About", 1002, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 36, 62, 30, 15
END
200 ICON MOVEABLE PURE LOADONCALL DISCARDABLE "icon.ico"

Конец файла rsrc.rc

Начало файла keygen.asm

.386
.model flat, stdcall
option casemap :none ; case sensitive

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\masm32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\masm32.lib

szText MACRO Name, Text:VARARG
LOCAL lbl
jmp lbl
Name db Text,0
lbl:
ENDM

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

.data
bout db "Keygenned by arnix [arnix@freenet.am]",0
bout_tit db "About this lil keygen",0
er db "Errrrror!",0
er2 db "Where is your name?",0
hWnd dd 0
hEdit1 dd 0
hEdit2 dd 0
hButn1 dd 0
hButn2 dd 0
hButn3 dd 0
hInstance dd 0
hIconImage dd 0
hIcon dd 0
lpfnEdit1Proc dd 0
dlgname db "ARNIX_KG",0

.code

start:

invoke GetModuleHandle, NULL
mov hInstance, eax
invoke DialogBoxParam,hInstance,ADDR dlgname,0,ADDR WndProc,0
invoke ExitProcess,eax

WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD

LOCAL Sn[64] :BYTE
LOCAL Nm[64] :BYTE
pusha
.if uMsg == WM_INITDIALOG

mov eax, hWin
mov hWnd, eax

szText dlgTitle,"arnix"
invoke SendMessage,hWin,WM_SETTEXT,0,ADDR dlgTitle

invoke LoadIcon,hInstance,200
mov hIcon, eax

invoke SendMessage,hWin,WM_SETICON,1,hIcon

invoke GetDlgItem,hWin,100
mov hEdit1, eax

invoke GetDlgItem,hWin,101
mov hEdit2, eax

invoke GetDlgItem,hWin,1000
mov hButn1, eax

invoke GetDlgItem,hWin,1001
mov hButn2, eax

invoke GetDlgItem,hWin,1002
mov hButn3, eax

.elseif uMsg == WM_COMMAND
.if wParam == 1002
invoke MessageBox,0,ADDR bout,ADDR bout_tit,MB_OK
.endif
.if wParam == 1000


invoke GetWindowText,hEdit1,ADDR Nm,64

invoke lnstr,ADDR Nm

cmp eax,0
jz _error
PUSH ESI
PUSH ECX
PUSH EBX


LEA ESI, [Nm]
LEA EDI, [Sn]
XOR EAX, EAX
XOR ECX, ECX
MOV BL, 1Ah
_NEXT:
CMP BYTE PTR [ESI], 00h
JZ _EXITING
MOV AL, [ESI]
ADD AL, CL
XOR AL, CL
DIV BL
SHR AX, 08h
ADD AL, 41h
MOV [EDI], AL
INC EDI
INC ESI
INC ECX
JMP _NEXT
_EXITING:
MOV BYTE PTR [EDI], 00h
XOR EAX, EAX

POP EBX
POP ECX
POP ESI



INVOKE SetWindowText, hEdit2, ADDR Sn
jmp _end


_error: invoke MessageBox,0,ADDR er2,ADDR er,MB_OK

_end:

.elseif wParam == 1001
jmp _out

.endif

.elseif uMsg == WM_CLOSE
_out:
invoke EndDialog,hWin,0

.endif
popa
xor eax, eax
ret

WndProc endp
end start

Конец файла keygen.asm

Как видите, часть генерирования кода я написал большими красными буквами, и пытался всё делать максимально похожим на оригинал (вплоть до используемых регистров) чтоб было максимально понятно тем кто в первый раз пишет Keygen. Помоему в разяснении этот код не нуждается, так как я всё уже обяснил. Вам остаётся хорошенько всё понять и возможно закомпилировать keygen, это можно сделать BAT файлом такого содержания:

Начало файла make.bat

\masm32\bin\ml /c /coff keygen.asm
\masm32\bin\rc /r rsrc.rc
\masm32\bin\link /subsystem:windows keygen.obj rsrc.res

Конец файла make.bat

Его, как и предыдущие файлы, нужно ставить в папку "C:\masm32\BIN". Ну, и запустить make.bat, и не забудьте поставить тамже вашу любимую иконку с именем "icon.ico". У вас долен появится файл "keygen.exe" (2 KB), запустив который, увидите что-то вроде этого:



Пока, надеюсь вам было инетересно.

Aram aka arnix [arnix{@}freenet.am]

ICQ: 3530220, 975129
SST: 19000
http://freenet.am/~arnix