
#cracking4newbies keygen tutorial...
written by #cracking4newbies for newbies

oh, turn wordwrap on too.
unless you are looking at the source, then if possible turn it off

Lets start with the basics.... 

What is a keygen?  A keygen, or key generator, it's a program written for a specific program so the user can enter any name and then have the registration code for that name.  That simple.

Why make a keygen when just a serial can be used?  Well part of the fun of cracking is making your own creations. Also it is kinda lame to produce only one serial for a particular proggie ie:  Myname [MY GROUP '97] SERIAL:1234-5678, when the user would like to have his/her name as the registered owner. It takes a bit more skill to write one, and as a cracker, if you code it in asm, you will find it is a little easier to crack.  Besides it seems kind of "elite" to make a keygen :)

How do i make a keygen?   Ahhh, good question.... This is asked quite a lot.  Basically you need to know HOW the program verifies whether the serial number you entered is correct.  To verify it, the proggie has to actually encrypt the users input data (whether it is serial number, name, or combination of both) and then compare that answer to the info you entered.  If it is incorrect, then we get a messagebox that tells us so.

 To start off, we need to know whether there is only one serial number that will work, or whether it depends on what information we enter.  Only one serial number allowed doesn't qualify for a keygen.  If the program uses the information we enter to determine what the serial number is going to be, then that is where we need to start.

 I always use basic numbers, or letters so i know what they are when i see them ie: 08642 or qazwsx. That way i don't get them mixed up with some data that might be in memory at the time.. also when you use numbers, programs can  take those numbers and convert them to hexidecimal and then store them in a register or memory location.  When u enter your data, remember that the number could be converted to hexidecimal ie: 123 would be 7Bh. You may see that in a register, so watch out for it!!!  Sometimes programs need a serial like: 1234-5678-9024.  You should see an echo of it in memory, as with any other info you enter.  The program may convert that to hexidecimal ( minus the dashes) and store it somewhere, or it might take each number and do its math on it... meaning that it might take the 1 (31h) and multiply it by a certain value, then loop untill all the numbers have gone through the cycle, or something similar.  PLEASE REMEMBER that not every proggie uses the same tricks. Some will convert the 1234 to hex, while others might use ascii to hex (asm term) or ascii to integer (C term) to make eax=1234 instead of the hexidecimal value of 1234... just be wary when ur looking around.

 Now for the stratagy:  When we enter our info, we want to see what is done with it.  The best way to do that is set a break point range (bpr) on the intended info.  I usually type my info in, then bpx hmemcpy in sice, then hit  enter, hit f5 untill all the data is read, but b/4 we get to the messagebox.  Hit f12 untill your back to 32 bit code, or 16bit (depending on what the proggie is written in). Then i disable my bpx hmemcpy, and set a break point on a certain line (so i don't have to go through the whole process of hmemcpy again), but if the program uses hmemcpy to move the serial some more, the bpr on the info usually picks it up.  After i bpx a certain line, i s 0 l ffffffff 'my info' and when i find it, BPR <start address> <end address> rw  (w/o the < > ) and the rw stands for read/write ie: bpr 013f:123 013f:129 rw. I set the range because some programs take only part of the serial and do something with it, whether that is read only part of it, or move it to another spot in memory. Now search for it again, by typing just S and then hit enter (this continues the last search done from the current position) and if you find it in the Cxxxxxxxx range, don't bpr on it. Likewise if you find it in the 8xxxxxxx range, don't set a bpr on it. This part of memory is windows video buffer i think (anyway windows uses it).

 Some proggies take the users name and capitalize it, you should notice this, also notice whether certain characters are allowed ie: numbers, brackets, dashes, all the other characters... When the program capitalizes the name it may skip over certain characters and do nothing with them, or if you put a space in the name, it may convert the space to an underscore or some other character...TAKE NOTE OF WHAT GOES ON !!!!!!!!!!!

 If the program doesn't worry about the users name, it might concentrate on the serial number provided.  This we also have to watch.  Earlier i mentioned that proggies may convert the numbers to hex, or ascii to hex, or just read them from memory, YOU HAVE TO NOTICE WHAT IT DOES when it reads/modified the number.  Sometimes this isn't easy to see, or you might have caught part of the algo, and missed the first very important part. If so, you need to back track and find out what you missed... The key to understanding keygens it UNDERSTANDING HOW WHAT THE ALGORITHM DOES.. thus the name- keygens.

 What is left out? Are there dashes in the serial still? Are certain characters no longer there? Do spaces equal spaces, or are they taken out, or replaced with underlines, or zero's?  This is the most important part. Pay close attention.. at this point the serial number might be in hex form, or ascii character to hex representation, also known as ascii/integer representation. Meaning.. in memory instead of seeing 31h 32h 33h 34h 2Dh 35h 36h 37h 38h you will see 01h 02h 03h 04h 2Dh 05h 06h 07h 08h (the dash may not be there). These are all questions that we should be asking ourselves.  There are a million different things to do to the serial number, but remember we need to duplicate it.

 All of this so far is done b/4 the algorithm is reached.  When we finally ge to it, we want to write down (on paper) what it does.  Do this line by line... but at the top have the serial number, or name it uses so you can easily look and see where it gets the info.  Start out by explaining all the variables, like..... eax now holds our serial in hex form, ecx holds the total number of digits entered, or [esi+bx] is the buffer where our name is stored (after it is capitalized). make sure you know what all the variables are b/4 u start writing lines. If eax=100h b/4 it starts, make a note of it.  Sometimes there are already numbers in the registers that are part of the algo.  This is essential.

 Now write every line down on our paper.  I write them exactly as shown in sice.  The only difference is i comment every line that causes a register to change.  I put in perenthesis what the registers hold after the instruction i s executed, that way when i finish mine and need to debug it, i know what numbers should be where. This will tell me where i went wrong. Some algos use the Zero flag for special jumps.. when this happens i write that down too.  When i see something like mov ecx,[eax+4] i write down what that memory location would be, whether its my serial or just the hex value of my serial. If it is the buffer where my name is stored, i write that down too. At the end of the algorithm, the correct serial number is either in memory or in a register. Make a special point to wite down how it is stored.  The registration number could be in eax.  If eax= 12c4328a, the registration could be the decimal value of eax, or it could actually be 12c4328a.  Make sure you know what u have to do to be able to print it to the screen.  When i have the full algorithm on paper, i sit down and sort out what i don't need. If the program pushes something to the stack that isn't important to me, I leave it out. (today i just found an algo that uses 57 lines of code, and i cut it down to 24)

 By this time, you should have a basic understanding of how the program generates the serial. Now we duplicate it. 

#1. get input
#2. make name all caps
#3. change all Q's and Z's to R's
#4. get all letters of the name and do the math
#5. eax=hex value of our serial
#6. convert to decimal
#7. print to screen
#8. done!!!

OR:
#1. get input
#2. convert serial number to hex, and move into eax
#3. do math with serial number
#4. edx=23abc3e5.... and 23abc3e5 is our registration code...
#5. put edx into memory in ascii form 
#6. print to screen
#7. done!!!

 Whatever u do, make sure u have your outline. That way when you start writing it, you will know what is needed.

----------------------------------------------------------------------------

NOW is the time for OUR keygen... i've provided some code you can track down and break on.

For this example i am going to use the Name: stickless  (no caps) and the registration number 987654.

First of all, enter your name, and serial number in the spaces provided. Don't hit enter.  

1. In sice set bpx hmemcpy, and exit again
2. Hit enter, and hit f5 1 time
3. Now hit f12 untill you are back into the w32filer code
4. Search for 33 d2 33 c0 3b c8 7e 17 0f be and set a break point on that     location.
5. Search for 0f be 0a 83 f9 20 74 0d 8a 0a and also set a break point on     that address.  ( s 0 l ffffffff 0a 83 f9 20 74 0d 8a 0a ) is how
6. Now on the first line after you enter w3filer code, set a bpx on it.
    Also bd the bpx hmemcpy. (I do that so i don't have to go back through     hmemcpy if i mess up.)
7. If all goes well you can hit f5 and it will break on the line that starts     moving your serial to another place, then capitalizes it.
     (if not, then exit select ok and follow the first call after      writeprivatprofilestringa, and you will find it.) Single step through      this part of the program so you can see what happens.
8. REMEMBER to write down on a piece of paper exactly what we see the program     doing. We will need this for our keygen.
8a. You should see each character being loaded, then compared to see if it is     a captial letter already, if not, then it is checked to see if it is a     space. If it is, then it skips over it to the next letter. 
9. after this is done, there is another call. This one calculates the total    number of letters that are in the name. It is then compared to 4, to see     if there were enough characters entered. 
10. You may be able to see the next break point we searched for. If not, set     a temporary break point on a line where you are at, then hit f5.  If we      found the correct bytes and set a bpx on them, then we should stop at the     actual algorithm. If not, then we'll have to hit ok and go through this      process again.
11. When we break on the algorithm we will see these lines:

	xor edx,edx 	-clears edx for a new start
	xor eax,eax	-new start
	cmp ecx,eax	-ecx holds the total number of digits we entered
	jle xxxxxxxx	-xxxxxxxx is some line number that continues the algo
 loop:	movsx ebx,byte ptr [eax+esi] 	-gets the first letter, then next
	shl ebx,03	-shifts the value of the letter left 3 times
	movsx edi,byte ptr [esi+esi] 	-gets same letter in edi
	imul edi,eax	-eax holds the spot in our name. first letter = 0
	add ebx,edi	-add the hex value of the letter to ebx	
	add edx,ebx	-now add that number to edx
	inc eax		-increase our counter (for our name)
	cmp ecx,eax	-does the counter equal the total number of digits?
	jg loop		-if it is greater than our total digits, then go on
			-the program loops untill all letters of our name     			-have been read and converted
	mov eax,[00416720] 	-this is the hexidecimal representaion of the
				-serial number provided. If you ? eax, you 
				-will see the serial number
	sar eax,03	-shift arithmatic right
	add edx,eax	-at this point edx now holds our serial number..	
			-however, there is a little twist to the story :)
			-edx=6856d39.. if you ? edx you get 0109407545.. 
			-however if you enter that number, it won't work
			-the reg code IS 6856d39

***********  REALLY BIG NOTE HERE!! DON'T IGNORE THIS*******************


	WRITE ALL OF THIS DOWN ON PAPER WHILE YOUR DOING IT.
	I write it exactly as i see it, and put comments on every line.
	You can never have too many comments, unless they don't make sense.
	In the place of [eax+esi] i write "points to my name" behind it.
	Remember, to make your keygen, you need to know what to put in it,
	and what order.  Currently i have this written down on paper:

1. Enter name
2. Move it and take out the spaces
3. Capitalize it
4. Get the number of characters entered
5. Cmp that number to 4
6. Enter algorithm
7. I have the algo on paper and have it commented :)
8. After algo is over with, edx hold the hexidecimal represention of my    serial number


                  WRITE EVERYTHING DOWN AND COMMENT IT!!!!!!

*******************************ok ur done***********************************

If you trace a little while longer, then you will see that number being compared to the number you entered. There is a return and eax=0 if all is well. If not, then we go to the messagebox.


I am done with my tutorial.  All that is left is the source for my keygen.
Study it, and duplicate it, steal any code u need, or modify it all you want. I don't care, as long as you learn how things work.

Encluded should be the program, and another copy of the source. I suggest you compile it with the int3's included and set a bpint 3 in sice, and single step through all of it. You will learn a lot more by doing that than just reading the code.  I know i have rambled on for a long time now so i'll stop.

I hope this brought a few of you closer to understanding keygens and how to make them.  I have plans for another tutorial on them, but ran out of time to put it in here. This next one will use a different type of algorithm, and i'll show u some more asm code. Using the two tutes, you should be able to write your own for most programs. have fun and stay happy :)
*
*
*
 This is the basic format for making a keygen for wfiler32.. the following is an example of how to do it.


-------------cut and paste the rest so you don't have to type it------------

;keygen for wfiler32
;made by #cracking4newbies for newbies :)


.model small                                            
.stack 100h
.386
.data           
hello   db 'Please enter your name here : $'            
ask_serial db 0dh,0ah,0dh,0ah, 'Enter The serial number (in the registration box) : $'
uprint  db 0dh,0ah,0dh,0ah,'Your registration code is : $'
infa    db 0dh,0ah,0dh,0ah,'#cracking4newbies keygen for wfiler32 $'
;the next 3 lines are for getting input and the params it has to meet

;maxkey  db 20                           ;maximum characters-set to 20
;charinp db ?                            ;not surehow many characters we are going to type
serinum    db 20 
serinp  db ?
buffer  db 20 dup(0)                    ;characters r stored-there are 20 max
note    db 0dh,0ah,0dh,0ah,'Please enter more than 8 characters for your name.$'
key     db 11 dup(0)      
bufferb db 20 dup(0)
nametotal db 20
namehow db ?
bufferc db 20 dup(0)
key2    db 11 dup(0)
       
.code                                   ;my code begins here
start:

main    proc                            ;sets up procedure/is also the starting point
        mov ax, @data                   ;canīt modify ds directly
        mov ds, ax                      ;move it into another reg first 
              
        mov ah,7                        ;attrib to scroll window, 7 scroll down
        mov al,0                        ;do the entire window
        mov ch,0                        ;this points to the upper left row
        mov cl,0                        ;this points to the upper left column
        mov dh,24                       ;this points to the lower right row
        mov dl,79                       ;this points to the lower right column
        mov bh,7                        ;normal attrib for blank lines
        int 10h                         ;call bios
        xor ax,ax                       ;make sure that ax(ah+al) are clear
              
;this next section is to set the cursor upwards in the screen
                       
        mov ah,2                        ;ah=2/int10h set the cursor position
        mov bh,0                        ;select video page 0
        mov dx,0501h                    ;cursor 5 rows down in the first column
        int 10h                         ;call bios
        
	mov ah,09h			;ah=9/int21=dos function print to screen
	mov dx,offset infoa		;points to where data infoa is stored
	int 21h				;call dos int 21
      
        mov ah,09h                      ;ah=9/int21 dos function print to screen
        mov dx,offset hello             ;points to where data hello is stored
        int 21h                         ;dx points to it or it wonīt print
                             
        mov ah, 0ah                     ;ah=0ah/int21 dos procedure for asking
        mov dx, offset nametotal        ;dx has to point to the first of the
        int 21h                         ;paramaters-starts with max keys allowed
        
	;int 3h                         ;take the semi-colon out to debug the source
        
	call checknum 			;check to see if enough letters were entered
        
	mov ah,09h			;as for the serial number
        mov dx,offset ask_serial	;dx points to the location in memory of the txt
        int 21H				;call dos interupt

        mov ah, 0aH			;ah=0ah/int21 gets buffered input
        mov dx, offset serinum		;store the input in a buffer named serinum
        int 21h				;execute ah=0ah
        ;int 3h				;remove semicolon and recompile to debug it
        
	call caps			;call the capitalize procedure

        call str2num			;this converts a string of numbers to hexidecimal value
        
	call calc			;this is the actual algo for w32filer
                
        mov ax,4c00h                    ;termination string
        int 21h                         ;go bye bye
                
        main endp

;this section checks to see how many characters were entered
;if less than 4 then no good

checknum proc
        mov si, offset namehow      ;total number of characters entered
        mov cl,byte ptr [si]        ;mov 1 byte (cl only holds 1 byte)
        cmp cl,04h		    ;cmp the total number to 4
        jle nogood		    ;if less than 4 then let user know
        ret			    ;if it is more than 4, then return from call
nogood: mov dx,offset note	    ;there are too few letters in the name
        mov ah,09h		    ;so we have to let the user know
        int 21h
        mov ax,4c00h		    ;lets kill the program
        int 21h			    ;ax=4c00h/int21h end the program
checknum endp

;this section checks the name for caps and if already capital, then it leaves
;it alone, otherwise it converts it...also i checked for a space... didn't ;want
;that to get captialized too :)

caps    proc
        push ecx                ;save data
        push edx                ;save data
        push esi                ;save data
        xor edx,edx             ;we clear all to get a fresh start
        xor ecx,ecx             ;we clear all to get a fresh start
        mov si, offset bufferc  ;point to name
        mov cl,[si]             ;lets load it up and do some checking
all:    cmp cl,61h              ;is the letter less than  "a" (if less than, it is a capital letter)
        jl g02                  ;yes then lets just print it and not make it                                 ;uppercase
        cmp cl,7ah              ;is it greater than "z"
        jg g02                  ;yes then lets just print it
        sub cl,20h
        mov [si],cl             ;[si] is where we got the letter from, now                                   ;lets replace it with a capital one
g02:    mov cl,[si+1]           ;get next character
        inc si                  ;point to next character
        cmp cl,0dh              ;is this the code for the return?
        jnz all                 ;no, then lets do this stuff again
alldon: pop esi                 ;restore data
        pop edx                 ;restore data
        pop ecx                 ;restore data
        ret
caps    endp



;
;	ASCII decimal string to 32bit number
;			Copyright (c) 1997 Brand Huntsman
;		_QZ <brand@qzx.com> 16feb97
;
;i had to modify this section to work for more than 4 digits
;and his original code was wrong, or i don't have the same setup as him
                       
str2num PROC
	;ds and es should point to this segment

	cld			;go forward
        mov si,offset buffer	;buffer=storage area where our serial number is stored
        mov di,offset bufferb	;temorary storage area
	xor ecx,ecx		;get a clean start

again:
	lodsb			;loads the byte that es:si points to into eax
        xor ah,ah		;clear the high bits of ax, so al holds our number
	or ax,ax		;does al hold an actual number? or is it blank?
	jz alldone		;if nothing, then we're done
	sub ax,48		;subtract 30h from our number (1= 31h) so it subtracts 30h from it, and we get 01h
	cmp ax,10		;cmp ax for a valid number from 0 - 9
        jb goodnum		;if higher, then don't jump

;bad numumber
	stc
        jmp alldone		;done with our math, now lets add the numbers up

goodnum:
        mov [di], byte ptr al	;the number was 0-9 so we save it into memory (our temorary storage)
	inc cx			;cx is our counter.. how many numbers did we look at?
        inc di			;di now points to the next byte in memory for our temporary storage
	jmp short again		;lets do it again

alldone:
	std			;go in reverse
	mov si,di		;make both si and di point to the same spot in memory
	dec si			;account for overrun
	xor ebx,ebx		;clear some registers for a fresh start
	xor eax,eax
	xor edx,edx
	inc edx			;edx is now being used to count our "digits" place (1234 
				;is 1thousand 2hunder thirty four, where the 4 is the ones digit, 3 is the tens digit, and 2 is the hundreds digit)

addemup:
        xor eax,eax		;clear eax for a fresh start, we don't want anything in it that may corrupt our data
	lodsb			;load the byte that is at es:di into eax
	imul eax,edx	 	;multiply our digit by the place it should be in ( 1234 again.. this starts with the digit on the far right, which is the ones spot 4*1=4) then it loops and 3*10=30
	add ebx,eax		;add that to running total (the first time through, ebx is empty)
	imul edx,10		;multiply position times 10 (so we can move to the next number and it will be the correct spot.. ones digit, 10's digit, 100's digit, 1000's digit.....)
	loop addemup		;b/4 when we increased cx (which was our counter), now loop will continue to loop untill cx=0
        mov ecx,ebx		;ebx now holds our serial so we move it into ecx for later use
	ret
				;ebx = number
				;if carry set then bad number
ENDP str2num
            

;this is the actual algo for w3
;take a look and see what happens :))
;very neet stuff here !!!!!


calc    proc
        xor eax,eax		;clear the registers for a fresh start
        xor ebx,ebx
        push ecx		;we just moved the serial number into ecx, now we want to save it
        xor ecx,ecx		;clear the rest of the registers
        xor edx,edx

otra:   mov si,offset bufferc	   ;bufferc points to our name(which is capitalized now)
mas:    movsx ebx, byte ptr [si]   ;copy first char to start off, then increase to the next and loop
        cmp bl,20h		   ;is the character a space?
        je mas2
        cmp bl,0dh		;is the character the return code for enter ( 0dh= enter)
        je otra2		;if is the return code for enter, then finish our algo
        shl ebx, 03h            ;shift left
        movsx edi,byte ptr [si]   ;copy the character into edi (the same one that was just loaded into ebx
        imul edi, eax           ;multiply edi by the number in eax (just part of the algo)
        add ebx, edi            ;add hex of our letter to ebx
        add edx, ebx            ;add our "running total" to edx (the remainder from the imul) 
        
        inc eax			;increas eax because it is needed in the algo
mas2:   inc si			;since si points to our name, we need to go through each character of it, so we increase the pointer
        jmp mas                 ; do it all again
                                            
otra2:  pop eax      		;get the serial that we converted so it was in eax
        sar eax, 03             ;sar (shift arithmetic right) our serial
        add edx, eax            ;add it to our "running total" from our name
        mov ebx,edx		;edx now holds our serial :)
        call convert2		;we are going to make it so we can print it to screen

        ;at this point, edx now holds my serial !!!!!
        
        ret
calc endp

;this section now puts the final serial in to memory.. since it is in ebx
;we move it to eax, then do our calculations
;we also have to write it backwards in memory
;because this procedure starts with low bit and goes high


convert2 proc
        mov si,offset bufferb	;point to our storage area
        add si,0bh		;now we want to move 11 bytes after it so when we write it backwards, then there will be no problems
        mov byte ptr [si],'$'	;you need a $ at the end of it so dos knows when to stop printing
        dec si			;we are working backwards.. so decrease our pointer
        mov ebp,10h		;we are going to divide by 16d to get our actual characters out of eax..if eax=ab348d12 then our registration number is that number, not the decimal representation of it
putnum: ;inc si			;didn't need to inc si but i was too lazy to take it out :)
        mov eax,ebx		;ebx held our serial, so now we need it in  eax
        xor edx,edx		;when we divide, we need edx to be clear
        div ebp			;divide our serial by 10h so we get the far right number/letter to our serial
        mov ecx,edx		;mov ecx our number/letter
        mov eax,ebx		;after we divide, ebx holds our new number minus what we divided out
        sub edx,edx		;clear edx
        add cl,30h		;add 30h to our digit to get it back to a number
        div ebp			;divide eax by 10h again (our next letter is in edx)
        mov ebx,eax		;ebx holds our serial minus the numbers we divided out
        cmp cl,39h		;if our number we added 30h to isn't a valid number, then we need to convert it to a letter between a - f
        jbe sonow		;valid number, then jump
        add cl,27h		;not valid number, then add 27h to make it a letter
sonow:  mov [si],cl		;mov cl (whether letter or number) to the place in memory where si points to
        dec si			;we are working backwards here, so remember to decrease si
        or ebx,ebx		;does ebx have any numbers left?
        jnz putnum		;if there is something, then start again
        inc si			;after we are out of numbers, we need to point to the first letter/number of our serial
        lea dx, [si]		;load that address into dx so we can print it to screen
        call write		;call my print procedure
        ret
convert2 endp

;this section just prints a little stuff on the screen
;very basic

write proc
  	push edx		;save the pointer for our serial number  
  	mov dx,offset uprint	;mov the pointer for our text we want to say into dx
  	mov ah,09h		;now print it
  	int 21h   
  	pop edx			;restore our pointer to our data
	mov ah,09h		;and print it to the screen
  	int 21h
  	ret
write endp  
end main        


I could have optimized the code a litte better, and i don't claim to be a god in asm.  So if you notice something you are welcome to change it and recompile it to see if it still works.  I'm a newbie just like the rest of you. Maybe a little more advanced, nothing more.


have fun, and happy cracking :)        

 