|
|
Training session 35: Keygen Creation #3
Difficulty: Medium Learn how to create a slightly more difficult keygen
Creator: m101
Target: V 2000 (SR2)
URL: http://www.fileviewer.com
The aim of this tutorial is not to teach you how to read assembly, or for that matter, how to read commented assembly, but how to comment it yourself and follow it to understand what is going on. Through this you will learn much more than you do off just reading. I assume you have an understanding of assembly already if you are reading this aswell. The target is V 2000 (SR2) and is available at http://www.fileviewer.com. You will need Softice, Win32DASM, procdump, hiew and an assembler such as TASM or MASM if you are planning on creating the keygen.
After you have installed the program, start it up and watch what it does. Take notice that there is a register button in the splash screen, and in the help menu. Click on either one, enter some bogus crap, and see what the message says. "The User Name and/or Registration Code are incorrect." How very nice, have a look down further: "If you are just trying to break the registration code, then I wish you luck." Looks like our programmer respects the arts ;)
Open up Win32DASM and disassemble V.exe. Generally we would backup V first, but since we arent actually aiming to patch it, its fine for the time being. Get into the dead listing 'Refs > String Data References' and look around for our little message. To my delight, you wont find anything. Since we cant go straight to the dead listing for the dialog, have a look around and be a bit inventive about a choice. "Registration" How fitting, double click on it and have a look where we have landed ourselves. To me it looks like the happy result of a crack:
:004186CF 6A0B push 0000000B
:004186D1 50 push eax
* Possible StringData Ref from Data Obj ->"Registration"
|
:004186D2 68E0264800 push 004826E0
:004186D7 B9187D4800 mov ecx, 00487D18
:004186DC E89F790100 call 00430080
:004186E1 8B4C2424 mov ecx, dword ptr [esp+24]
:004186E5 6A01 push 00000001
:004186E7 51 push ecx
:004186E8 8BCD mov ecx, ebp
:004186EA E8E1020000 call 004189D0
:004186EF 5F pop edi
:004186F0 5E pop esi
:004186F1 5D pop ebp
:004186F2 5B pop ebx
:004186F3 83C40C add esp, 0000000C
:004186F6 C20800 ret 0008
Trace the call back a little bit:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00418666(C)
|
:00418679 8BFE mov edi, esi
:0041867B 83C9FF or ecx, FFFFFFFF
:0041867E 33C0 xor eax, eax
:00418680 F2 repnz
:00418681 AE scasb
Hows this, referenced by a conditional jump then some dialog messages. Looks to me like a good result even more now. Go back through the jump and you will find yourself looking at this:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041864A(C)
|
:00418651 8D4C2424 lea ecx, dword ptr [esp+24]
:00418655 6A01 push 00000001
:00418657 8D5D23 lea ebx, dword ptr [ebp+23]
:0041865A 51 push ecx
:0041865B 50 push eax
:0041865C 53 push ebx
:0041865D 8BCD mov ecx, ebp
:0041865F E82C010000 call 00418790
:00418664 85C0 test eax, eax
:00418666 7511 jne 00418679
:00418668 8BCD mov ecx, ebp
:0041866A E841FFFFFF call 004185B0
:0041866F 5F pop edi
:00418670 5E pop esi
:00418671 5D pop ebp
:00418672 5B pop ebx
:00418673 83C40C add esp, 0000000C
:00418676 C20800 ret 0008
Lovely, a test to see if our result is correct, then a call to some dialog which may be a good result. Trace it back even further:
* Referenced by a CALL at Addresses:
|:00418CEE , :0041F41E
|
:00418610 8B442408 mov eax, dword ptr [esp+08]
:00418614 83EC0C sub esp, 0000000C
:00418617 53 push ebx
:00418618 55 push ebp
:00418619 56 push esi
:0041861A 57 push edi
:0041861B 8BE9 mov ebp, ecx
:0041861D 50 push eax
:0041861E E8DD000000 call 00418700
:00418623 85C0 test eax, eax
:00418625 7511 jne 00418638
:00418627 8BCD mov ecx, ebp
:00418629 E882FFFFFF call 004185B0
:0041862E 5F pop edi
:0041862F 5E pop esi
:00418630 5D pop ebp
:00418631 5B pop ebx
:00418632 83C40C add esp, 0000000C
:00418635 C20800 ret 0008
So it looks like this is the start of the protection scheme. Remember that there are two calls to the registration dialog? Links nicely with the two references by calls we can see. Trace one back:
:00418CE6 E8056F0100 call 0042FBF0
:00418CEB 50 push eax
:00418CEC 8BCE mov ecx, esi
:00418CEE E81DF9FFFF call 00418610
:00418CF3 85C0 test eax, eax
:00418CF5 7456 je 00418D4D
:00418CF7 8BCE mov ecx, esi
:00418CF9 E8A2FBFFFF call 004188A0
Well, this is all nice and good to have found the routine, but how can we be sure that its correct? Notice all those calls to MFC42.Ordinal:0***. Well this means that we arent going to be able to break on GetDlgItemTextA or anything similar, so heres a nice way to use the info we have from Win32DASM in Softice. Open up Softices Symbol Loader and load up V.exe, Click on run and click yes to any dialogs that come up. Softice will break open at the programs entry point.
:00468B3A 55 push ebp
Heres the thing, when you loaded it in softice, the program was forced to give us standard memory address from the image base. What does this mean to us? It means we can use the addresses we gathered from softice to break on the routine. Lets set a breakpoint before both calls to check which call we are dealing with. Type "u 418cee" into softice and double click to highlight the first line. Then type "u 41f41e" and again double click the first line. You have now breakpointed the instructions. Get out of Softice and click on either registration buttons and enter some whatever you like and click Register. BAM! Straight into softice. For me I clicked on the help menu register button, and I got the second call. You should see something like:
:0041F405 8D4C2400 lea ecx, dword ptr [esp]
:0041F409 E8F2070100 call 0042FC00
:0041F40E 50 push eax
:0041F40F 8D4C2404 lea ecx, dword ptr [esp+04]
:0041F413 E8D8070100 call 0042FBF0
:0041F418 50 push eax
:0041F419 B9487E4800 mov ecx, 00487E48
:0041F41E E8ED91FFFF call 00418610
:0041F423 85C0 test eax, eax
:0041F425 740A je 0041F431
:0041F427 B9487E4800 mov ecx, 00487E48
:0041F42C E86F94FFFF call 004188A0
Do a few checks on the data and you will find that your username was pushed before the call is made. Press F10 to step over the jump. Youll be chucked straight back to the Bad Cracker dialog. From this we can pretty safely say that this routine is the cause of our troubles. Now we know what we are looking at, get back into Win32DASM and check out that call:
* Referenced by a CALL at Addresses:
|:00418CEE , :0041F41E
|
:00418610 8B442408 mov eax, dword ptr [esp+08]
:00418614 83EC0C sub esp, 0000000C
:00418617 53 push ebx
:00418618 55 push ebp
:00418619 56 push esi
:0041861A 57 push edi
:0041861B 8BE9 mov ebp, ecx
:0041861D 50 push eax <push our serial
:0041861E E8DD000000 call 00418700 <do something with it
:00418623 85C0 test eax, eax <is result bad?
:00418625 7511 jne 00418638 <no, then continue
:00418627 8BCD mov ecx, ebp
:00418629 E882FFFFFF call 004185B0
:0041862E 5F pop edi
:0041862F 5E pop esi
:00418630 5D pop ebp
:00418631 5B pop ebx
:00418632 83C40C add esp, 0000000C
:00418635 C20800 ret 0008
To me this looks like the program is testing the serial for characteristics, so lets check out that call:
* Referenced by a CALL at Address:
|:0041861E
|
:00418700 8B542404 mov edx, dword ptr [esp+04]
:00418704 53 push ebx
:00418705 55 push ebp
:00418706 56 push esi
:00418707 8BE9 mov ebp, ecx
:00418709 57 push edi
:0041870A 8BFA mov edi, edx
:0041870C 83C9FF or ecx, FFFFFFFF
:0041870F 33C0 xor eax, eax
:00418711 F2 repnz
:00418712 AE scasb
:00418713 F7D1 not ecx
:00418715 49 dec ecx
:00418716 83F912 cmp ecx, 00000012
:00418719 7409 je 00418724
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00418759(C)
|
:0041871B 5F pop edi
:0041871C 5E pop esi
:0041871D 5D pop ebp
:0041871E 33C0 xor eax, eax
:00418720 5B pop ebx
:00418721 C20400 ret 0004
Aint this just great. It counts the characters in our serial we entered. I would recommend you check in softice to see just how it does this if you cant see it already. The most interesting line here is:
:00418716 83F912 cmp ecx, 00000012
Whats this mean? Well it checks if our serial is 12 characters long doesnt it? This is a thing alot of newbies get trapped in, they see the 12 and they presume its in decimal. Crack open a calculator if you neeed to and find out what 12 in hexidecimal is when converted to decimal. 18, Our serial has to be 18 characters long. You might like to check this for yourself though. Set your serial to '012345678912345678' and see what the call returns. As you can see, the call now jumps like we want it to.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00418625(C)
|
:00418638 8B742420 mov esi, dword ptr [esp+20]
:0041863C 83C9FF or ecx, FFFFFFFF
:0041863F 8BFE mov edi, esi
:00418641 33C0 xor eax, eax
:00418643 F2 repnz
:00418644 AE scasb
:00418645 F7D1 not ecx
:00418647 49 dec ecx
:00418648 8BC6 mov eax, esi
:0041864A 7505 jne 00418651
* Possible StringData Ref from Data Obj ->"EVALUATION COPY"
|
:0041864C B86C304800 mov eax, 0048306C
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0041864A(C)
|
:00418651 8D4C2424 lea ecx, dword ptr [esp+24]
:00418655 6A01 push 00000001
:00418657 8D5D23 lea ebx, dword ptr [ebp+23]
:0041865A 51 push ecx
:0041865B 50 push eax
:0041865C 53 push ebx
:0041865D 8BCD mov ecx, ebp
:0041865F E82C010000 call 00418790
:00418664 85C0 test eax, eax
:00418666 7511 jne 00418679
:00418668 8BCD mov ecx, ebp
:0041866A E841FFFFFF call 004185B0
:0041866F 5F pop edi
:00418670 5E pop esi
:00418671 5D pop ebp
:00418672 5B pop ebx
:00418673 83C40C add esp, 0000000C
:00418676 C20800 ret 0008
Since im not doing my normal commenting of the this code anyway, its your turn to work out what is going on, or atleast try to work it out. Ill give you a hint, we need it to jump again this time ;) Just kidding ya, I couldnt let you tackle the main routine all by yourself:
* Referenced by a CALL at Addresses:
|:0041865F , :00418923 , :00418F3B
|
:00418790 8B542408 mov edx, dword ptr [esp+08]
:00418794 83EC08 sub esp, 00000008
:00418797 33C0 xor eax, eax
:00418799 53 push ebx
:0041879A 56 push esi
:0041879B 8BF1 mov esi, ecx
:0041879D 57 push edi
:0041879E 8BFA mov edi, edx
:004187A0 83C9FF or ecx, FFFFFFFF
:004187A3 F2 repnz
:004187A4 AE scasb
:004187A5 F7D1 not ecx
:004187A7 49 dec ecx
:004187A8 51 push ecx <push length
:004187A9 52 push edx <push username
:004187AA E811F80100 call 00437FC0 <calculate part of serial
:004187AF 8B4C2420 mov ecx, dword ptr [esp+20]
:004187B3 8BD8 mov ebx, eax
Lets take a look into that call:
* Referenced by a CALL at Addresses:
|:004187AA , :004187F1
|
:00437FC0 56 push esi
:00437FC1 8B74240C mov esi, dword ptr [esp+0C]
:00437FC5 83C8FF or eax, FFFFFFFF
:00437FC8 33C9 xor ecx, ecx
:00437FCA 85F6 test esi, esi
:00437FCC 762C jbe 00437FFA
:00437FCE 53 push ebx
:00437FCF 57 push edi
:00437FD0 8B7C2410 mov edi, dword ptr [esp+10]
This is all pretty boring crap above, I wouldnt bother too much with it. Here comes the juicy bits:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00437FF6(C)
|
:00437FD4 8A1439 mov dl, byte ptr [ecx+edi]
:00437FD7 8BD8 mov ebx, eax
:00437FD9 81E2FF000000 and edx, 000000FF
:00437FDF 81E3FF000000 and ebx, 000000FF
:00437FE5 33D3 xor edx, ebx
:00437FE7 C1E808 shr eax, 08
:00437FEA 8B1495E0514800 mov edx, dword ptr [4*edx+004851E0]
:00437FF1 33C2 xor eax, edx
:00437FF3 41 inc ecx
:00437FF4 3BCE cmp ecx, esi
:00437FF6 72DC jb 00437FD4
This aint exactly the nicest routine for a cracker to imitate because of that damn table. Youll see why in a minute. Have a go at commenting this code, done worry too much about the table just yet. It should endup looking something like this:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00437FF6(C)
|
:00437FD4 8A1439 mov dl, byte ptr [ecx+edi] <take next byte of name
:00437FD7 8BD8 mov ebx, eax <set ebx = total
:00437FD9 81E2FF000000 and edx, 000000FF <clear edh
:00437FDF 81E3FF000000 and ebx, 000000FF <clear ebh
:00437FE5 33D3 xor edx, ebx <edx = edx xor ebx
:00437FE7 C1E808 shr eax, 08 <move total right 1 byte
:00437FEA 8B1495E0514800 mov edx, dword ptr [4*edx+004851E0] <edx = 4*edx+004851e0
:00437FF1 33C2 xor eax, edx <total = total xor edx
:00437FF3 41 inc ecx <next character
:00437FF4 3BCE cmp ecx, esi <end of username?
:00437FF6 72DC jb 00437FD4 <no, then loop
Examine that, if you dont get it the first time, follow it through in softice and examine it again till you can understand it. Now to deal with that table, a table is pretty much just an array of values. To make a keygen we will need a copy of this table, and well, I dont know about you, but recording every single possible value on paper and then placing it into our keygen doesnt quite fit my defenition of interesting. Just to discourage you a little more from wasting your time, look at 4*EDX+004851E0. EDX only contains one byte, so EDX can be anything between 00 and FF. This tells us that we would have to copy down 4*FF+4 bytes, which is 400h bytes, or in decimal 1024. So we are at a little bit of a dilemna, we need someway to dump our data, this is where procdump comes to the rescue. Open up procdump and go down the list till we find V.exe. Right click and select partial dump, we want to dump from 004851E0 for a length of 400. Ive included the table data in table.dmp with this file if you dont have procdump handy. Make sure you use only capitals, and then click dump. Select where you want to dump it to and you now have your table. Now return from the call and you will see this:
:004187AA E811F80100 call 00437FC0
:004187AF 8B4C2420 mov ecx, dword ptr [esp+20]
:004187B3 8BD8 mov ebx, eax
:004187B5 8B44242C mov eax, dword ptr [esp+2C]
:004187B9 83C408 add esp, 00000008
:004187BC 85C0 test eax, eax
:004187BE 7410 je 004187D0
:004187C0 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004187CE(C)
|
:004187C2 8A1408 mov dl, byte ptr [eax+ecx]
:004187C5 32D3 xor dl, bl
:004187C7 881408 mov byte ptr [eax+ecx], dl
:004187CA 40 inc eax
:004187CB 83F809 cmp eax, 00000009
:004187CE 7CF2 jl 004187C2
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004187BE(C)
|
:004187D0 8B7905 mov edi, dword ptr [ecx+05]
:004187D3 8B01 mov eax, dword ptr [ecx]
:004187D5 8A4904 mov cl, byte ptr [ecx+04]
:004187D8 8D54240C lea edx, dword ptr [esp+0C]
* Possible Reference to Dialog: DialogID_00A9, CONTROL_ID:0007, "&No"
|
:004187DC 6A07 push 00000007
:004187DE 52 push edx
:004187DF 89442414 mov dword ptr [esp+14], eax
:004187E3 884C2418 mov byte ptr [esp+18], cl
:004187E7 C644241913 mov [esp+19], 13
:004187EC C644241A3B mov [esp+1A], 3B
:004187F1 E8CAF70100 call 00437FC0
:004187F6 83C408 add esp, 00000008
:004187F9 3BC7 cmp eax, edi
:004187FB 740B je 00418808
Now this is where it becomes a little hard to explain, so ill show you in english rather than assembly. First thing it does is takes the AL portion of the checksum and multiplies it by every character in the serial we entered. Then it takes the first 5 bytes of the serial, appends 13h and 3Bh, before sending it through the checksum algorithm again. The result is left in EAX, so from this we can say that it returns the last 4 bytes of the serial in reverse order as the last four bytes of our serial. If this matches the values from the entered serial, the serial is correct and the algorithm continues to the last check. To check if im right, lets try an example. For 'm101' the first checksum returns 'AC', so lets set an entire serial to 'FFFFFFFFFFFFFFFFFF' and then xor it by AC, the result is '535353535353535353'. Take this value and place it into the algorithm. After the call EAX = 918363A4, so lets make our serial return the same value. Reverse the string to 'A4638391' and then xor it by 'AC' to arrive with '08CF2F3D' and our serial becomes '535353535308CF2F3D'. Trace the program past the call and see what we get. As you can see, the comparison returns that our serial is valid for that call. From this we can safely say we can calculate the last 8 characters if we have the first 10. The next thing to do is check to see what the last check is:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004187FB(C)
|
:00418808 8B54240E mov edx, dword ptr [esp+0E]
:0041880C 668B44240C mov ax, word ptr [esp+0C]
:00418811 8B4C2420 mov ecx, dword ptr [esp+20]
:00418815 33DA xor ebx, edx
:00418817 663BC3 cmp ax, bx
:0041881A 668901 mov word ptr [ecx], ax
:0041881D 740B je 0041882A
Once again you should have a go at commenting the code yourself. Basically what this does is xor the fourth and third bytes of the password with the last two bytes of the first checksum. If the four byte result equals the first two bytes of the serial, the check passes. If you reverse this you will find that if we xor the first two bytes with the checksum, we are left with the third and fourth bytes. Dont forget to xor them with the checksum to be given plain text. Here is basically how a valid serial is generated:
AX_value = checksum(username)
Byte Value
------------------------------------------------------
1 [FF]
2 [AL_value xor FF]
3 [AL_value xor FF]
4 [AL_value xor (AH of ([1-2] xor AX_Value))]
5 [AL_value xor FF]
6-9 [checksum(foreach xor by AL([1-5][13 3B])]
Here is my source code to the keygen, I decided to do it in MASM this time. Before looking at it, i recommend you try make your own keygen in whatever language you are most comfortable with. Even if you dont want to code your own keygen, try commenting mine.
--------------------------------------------------------------------------------------------------------------
v2000.asm
--------------------------------------------------------------------------------------------------------------
;V2000 Keygen by m101 for Phrozen Crew
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.data
ClassName db "SimpleWinClass",0
AppName db "V 2000 Keygen cracked by m101 for Phrozen Crew",0
ButtonText db "Generate Key",0
StartupString db "Please enter a name...",0
EditClassName db "edit",0
EditID equ 2
EditID2 equ 3
ButtonID equ 1
ButtonClassName db "button",0
IDM_GETTEXT equ 3
Serial db "FFFFFFFFFFFFFFFFFF"
table_buffer db 1024 dup(?)
Serial2 db "FFFFFFFFF"
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
hwndEdit2 HWND ?
buffer db 512 dup(?)
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
INVOKE CreateWindowEx,WS_EX_CONTROLPARENT or DS_CENTER,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,305,150,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,20,200,25,hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL or ES_READONLY,\
50,45,200,25,hWnd,EditID2,hInstance,NULL
mov hwndEdit2,eax
invoke SetWindowText,hwndEdit2,ADDR StartupString
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
80,75,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_GETTEXT
push edi
push esi
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke lstrlen, ADDR buffer
mov esi, eax
xor ecx,ecx
xor edx,edx
or eax, -01h
looper:
mov dl, byte ptr [ecx + buffer]
mov ebx, eax
and edx, 000000FFh
and ebx, 000000FFh
xor edx, ebx
shr eax, 08
mov edx, dword ptr [4*edx+table_buffer]
xor eax, edx
inc ecx
cmp ecx, esi
jb looper
push ax
mov [Serial], -01h
mov [Serial2], al
mov [Serial+1], al
mov [Serial2+1], -01h
mov [Serial+2], al
mov [Serial2+2], -01h
mov [Serial+4], al
mov [Serial2+4], -01h
mov dh,-01h
xor dx,ax
xor bl,dh
mov [Serial2+3],ah
xor al, dh
mov [Serial+3],al
mov [Serial2+5],13h
mov [Serial2+6],3Bh
mov esi,07h
xor ecx,ecx
xor edx,edx
or eax, -01h
looper2:
mov dl, byte ptr [ecx + Serial2]
mov ebx, eax
and edx, 000000FFh
and ebx, 000000FFh
xor edx, ebx
shr eax, 08
mov edx, dword ptr [4*edx+table_buffer]
xor eax, edx
inc ecx
cmp ecx, esi
jb looper2
mov dword ptr [Serial+5], eax
lea esi, Serial
xor ecx,ecx
pop dx
converter:
xor ax,ax
lodsb
cmp ecx, 10
jl conv2
xor al, dl
conv2:
shl ax, 4h
shr al, 4h
cmp al, 0ah
jl alpha
add al, 37h
jmp alphanumeric
alpha:
add al, 30h
alphanumeric:
cmp ah, 0ah
jl alphab
add ah, 37h
jmp alphanumericb
alphab:
add ah, 30h
alphanumericb:
mov [buffer+ecx], ah
inc ecx
mov [buffer+ecx], al
inc ecx
cmp ecx, 18
jl converter
mov [buffer+ecx], 0h
invoke SetWindowText,hwndEdit2,ADDR buffer
pop esi
pop edi
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
As you should realise, the keygen WILL NOT work in its current state. To make it work, you have to include the Table of values you dumped earlier. To do this, first compile the keygen, then load up hiew. Open 'v2000.exe' and hit F4 then F2. Do a search for 'FFFF'. You can safely dump the table after the last 'F'. The reason for this was in the creation of the keygen:
Serial db "FFFFFFFFFFFFFFFFFF"
table_buffer db 1024 dup(?)
Serial2 db "FFFFFFFFF"
If you notice the offset 'table_buffer' begins directly after offset 'Serial'. This means the program will reference our table directly from this location like we want it to do. Place the cursor directly after the last 'FF' and then press '*'. Now scroll down and put the cursor directly before the next 'FF' and press '*' again. This has just marked the dump area, but not the dump beginning, so you will have to scroll up and put the cursor back on the first position. Now press 'CTRL + F2', put in the location of 'table.dmp' and leave the offset blank and select 'AS IS'. After this you will have a fully working keygen!
|
|