Creating a SuperClean KeyGen
By Enforcer

Disclaimer
If you like it buy it.

Tools used
ollydbg v1.09d
http://grinders.withernsea.com/tools/odbg109d.rar
masm32 package
http://grinders.withernsea.com/tools/masm32v8.zip


In this tutorial I will create a Keygen for SuperClean 2.67. When we
Enter a name the program uses that name to generate a serial. It then
compares the generated serial to the serial that the user entered.
The first thing we need to do is find the point where the serial is
generated. Open the program in ollydbg and place a breakpoint on 
GetWindowTextA. The usual way to set a breakpoint is to hit CTRL+N to
bring up the names window then select the name of the API function in 
this case GetWindowTextA. This didn't work, setting breakpoints like 
this only sets a breakpoint where olly can determine that a call has 
been made to that function. If a function is listed in the import table
then olly can determine that any call to that function's entry in the
import address table is infact a call to that function and will add 
that call into the names window. But that is not the only way to call 
an imported function. An imported function can be called using
LoadLibrary/GetProcAddress or the area of code wich makes the call 
could be encrypted and only decrypted just before it is called. In both
of these cases olly may be unable to list this function call in the
names window.
Hit CTRL+G and type GetWindowTextA we land at the actuall code of this
function. press F2 to place a breakpoint, this way we catch every call
to GetWindowTextA. Doing it this way with olly may not work on windows
9x I can't test in on those systems though. start the program and enter
a serial the program stops at the breakpoint in GetWindowTextA. In the
stack window at the bottom left you'll see the arguments that were
passed to GetWindowTextA. Select Buffer, right click it and chose
follow in dump.
Now hit ALT+F9 to return from the call to GetWindowTextA. Select the
first byte of the name you entered in the dump, set a memory on access
breakpoint and hit f9. The first area of code we land in is in KERNEL32 its not going to be where the serial check is done. Hit f9 untill we
are back into SuperClean. look at this peice of code:
00419841  |> 0FBE1C38       /MOVSX EBX,BYTE PTR DS:[EAX+EDI]
move a charactor of the name into EBX
00419845  |. 03DA           |ADD EBX,EDX
Add the value in EDX (26h) to the name charactor
00419847  |. 03CB           |ADD ECX,EBX
Add this value to the value stored in ecx
00419849  |. 40             |INC EAX
Add 1 to EAX so we are now at the next charactor
0041984A  |. 3BC6           |CMP EAX,ESI
0041984C  |.^7C F3          \JL SHORT SuperCle.00419841
check if we reached the end of the name if we didn't go thru the loop
again. So this loop generates a value in ecx that is 26h+value
of first charactor + value of second charactor and so on. Next wsprintf
is used to put the decimal representation of the value in ecx into a 
string. The following loop dose a similar thing, There are 4 loops each
generates a section of the serial. What you use to write your keygen is
up to you. You can code this in any language you want. I'll use MASM. 
You can get MASM as part of the MASM32 package
(www.masm32.com) this includes the Microsoft Macro Assembler Plus other
usefull tools and tutorials. There are 2 things we need to do. First
create a function that contains those 4 loops and generate the serial.
Second we need to code a way for the user to enter his name and then
display the serial. Mine will just be a basic console window, writing a
user iterface in asm is time consuming. If you know some other language
like c++ you could code a nice looking interface in it and either
convert the code to that language or link in the object file. 
Below is the complete source code to the KeyGen
that is part of this tutorial. cut and paste it to a new file and save
it as SuperCleanKeyGen.asm
To assemble with MASM:
ml /c /coff /nologo SuperCleanKeyGen.asm
And link it to produce the .exe file:
Link /SUBSYSTEM:CONSOLE  SuperCleanKeyGen.obj

ml.exe and link.exe are located in your MASM32\BIN folder.

;start of KeyGen code, cut here.
.386
;We want our keygen to be compatible with 386 processors and above.
.model flat, stdcall
;flat memory model, use standard calling convention.
option casemap:none 
;Case Sensitive mode.
include C:\masm32\include\windows.inc 
include C:\masm32\include\kernel32.inc 
include C:\masm32\include\user32.inc
include C:\masm32\include\masm32.inc 

includelib C:\masm32\lib/kernel32.lib 
includelib C:\masm32\lib\masm32.lib 
includelib C:\masm32\lib\user32.lib
;;change the drive letter if you need to.
.data
Seed1 dd 026h
Seed2 dd 034h
Seed3 dd 0ch
Seed4 dd 0eh
;Seed 1-4 used to generate serial
SerialFormatString db "%d-",0
LastSerialFormatString db "%d",0
;These strings are used with wsprintf to convert a value into a string
;notice the %d
szIntro db "SuperClean V2.67 Keygen (Coded by Enforcer)", 0dh, 0ah, "Please visit http://Cracking.accessroot.com",0dh,0ah,0
szEnter db "Enter your name: ",0
szSerial db "Your serial is : %s",0dh, 0ah, "Press enter to close",0dh,0ah,0
;0dh and 0ah are equivilant to "\r\n" in c wich means a new line
.data?
TheName db 32 dup(?)
;Name you entered is stored here
Serial db 32 dup(?)
;Generated serial is stored here
SerialSection db 32 dup(?)
;used to temporarily store sections of the serial before they are added
;to the complete serial
Buffer db 120 dup(?)
.code 
KeyGen PROTO
;prototype of our KeyGen function
start: 
    invoke StdOut, addr szIntro
;display the introduction message
    invoke StdOut, addr szEnter
;ask the user for his name.
    lea edi, TheName
    invoke StdIn, edi, 32
;get the name that the user entered and store it in TheName
    invoke lstrlen, addr TheName
    mov BYTE PTR [eax+edi-2], 0
;lstrlen gives us the length of the string. add a strings length to
;it's address and subtract 2 and we are at the second last charactor of
;the string. We want to set it to zero so that the last 2 charactors
;are removed. This is because the StdIn function adds 0dh and 0ah to
;the string and we only want the name that was entered. 
    invoke KeyGen
;call the keygen function    
    invoke wsprintf, addr Buffer, addr szSerial, addr Serial
    invoke StdOut, addr Buffer
    invoke StdIn, 0, 0
;wait for the user to press enter again so that if he double clicked
;the program the window won't close before he has a chance to read the
;serial 
    invoke ExitProcess, 0     

    KeyGen PROC
        lea edi, TheName
        invoke lstrlen, edi
        mov esi, eax
;store the length of the entered name into esi (this register is
;preserved by windows API functions so it is safe to use it to store
;data        
	xor eax, eax
        mov ecx, eax
;set eax and ecx to zero
        mov edx, Seed1
;put the value of Seed1 into edx
@@:     movsx ebx, BYTE PTR [eax+edi]
        add ebx, edx
        add ecx, ebx
        inc eax
        cmp eax, esi
        jl @b
;first loop wich generates a value from the entered name
        invoke wsprintf, addr Serial, addr SerialFormatString, ecx 
;write the first part of the serial        
	xor ecx, ecx
        mov eax, ecx
        mov edx, Seed2
@@:     movsx ebp, BYTE PTR [EAX+EDI]
        imul EBP, EDX
        add ecx, ebp
        inc eax
        cmp EAX, ESI
        jl @b
        invoke wsprintf, addr SerialSection, addr SerialFormatString, ecx 
        invoke lstrcat, addr Serial, addr SerialSection
;Next part of the serial is generated and added to the complete serial        
	xor ecx, ecx
        mov eax, ecx
        mov edx, Seed3
@@:     movsx ebp, BYTE PTR [eax+edi]
        add ebp, edx
        add ecx, ebp
        inc eax
        cmp eax, esi
        jl @b
        invoke wsprintf, addr SerialSection, addr SerialFormatString, ecx                                     ; /<%ld>
        invoke lstrcat, addr Serial, addr SerialSection
        xor ecx, ecx
        mov eax, ecx
        mov edx, Seed4
@@:     movsx ebp, BYTE PTR [EAX+EDI]
        imul ebp, edx
        add ecx, ebp
        inc eax
        cmp eax, esi
        jl @b
        invoke wsprintf, addr SerialSection, addr LastSerialFormatString, ecx
        invoke lstrcat, addr Serial, addr SerialSection
        ret
    KeyGen ENDP
end start