Target: tsh33p's Keygenme
Author: x-Bi0dESC
Time taken: 1 minute
Difficulty: 1/10
Tool(s) needed: OllyDebugger (http://home.t-online.de/home/Ollydbg/)

Note: R-Click stands for Right Click with the mouse.


INTRO:

	This is going to be short and sweet, it's a very simple crackme
	Ideal for Newbies.

START:

	Ok so we fire up the crackme, and try to enter
	any name and serial.. I tried x-Bi0dESC / 123213
	We click OK to see the outcome to see if there are any obvious
	things we can exploit such as a messagebox or a text box
	changing its text etc.. And we see nothing. This is probably
	the most tricky thing in the crackme :P .. Not really... 
	Ok theres many ways to approach this.. One is to look for an API
	(Application Program Interface) Call (like GetDlgItemTextA) or something
	that retrieves text or we can search for something that indicates we 
	entered a good serial. It's obvious that something will occur to indicate
	that we've entered a good serial.. right? If not how would we know? We wouldn't.

	So we try the obvious things first. 
	Fire up ollydbg ... I'm Assuming It is set up correctly. 
	If not http://www.xs4all.nl/%7Eanvile/n2c/tuts/n2c-OllyTut1.zip And
	http://www.xs4all.nl/%7Eanvile/n2c/tuts/n2c-OllyMan2.zip should show you how.
	
	Ok once in olly load up the exe via the file->open menu. After it analyzes 
	(If it doesn't press ctrl+a to analyze the code) .. R-Click in the CPU
	window and goto 'Search For->All Referenced Text Strings'.
	Ok there appears to exist little amount of strings, in any case
	if we were dealing with a real app we'd r-click goto search
	and search for suspicious strings such as "Thank You" etc..
	Remember A good cracker use's his/her brain not just tools :)
	
	So this is what we should see in the window that pops up:

	Text strings referenced in KEYGENME:CODE
	Address    Disassembly                               Text string
	00401000   PUSHAD                                    (Initial CPU selection)
	004010B6   PUSH KEYGENME.00402000                    ASCII "Keygenme - Coded by tsh33p"
	0040111C   PUSH KEYGENME.0040203E                    ASCII "%X"
	00401165   PUSH KEYGENME.0040201B                    ASCII "Yeah! You done it."
	0040116A   PUSH KEYGENME.0040202E                    ASCII "Congrats... =]."

	There We go It's Obvious which string want to look At:
	00401165   PUSH KEYGENME.0040201B                    ASCII "Yeah! You done it."

	Ok so we double click on this string And it should bring you to the place in the cpu window:

	00401165  |.  68 1B204000   PUSH KEYGENME.0040201B                   ; |Title = "Yeah! You done it."
	0040116A  |.  68 2E204000   PUSH KEYGENME.0040202E                   ; |Text = "Congrats... =]."
	0040116F  |.  FF35 44204000 PUSH DWORD PTR DS:[402044]               ; |hOwner = NULL
	00401175  |.  E8 3F000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA

	So obviously theres going to be some sort of check above it to decide whether to silently
	do nothing (as the program does when an incorrect serial is entered) or to show
	a messagebox telling us that we have entered a good serial.
	So in Olly we scroll up a little and we notice some interesting code :)
	
	00401150  |.  68 82204000   PUSH KEYGENME.00402082                   ; /String2 = ""
	00401155  |.  68 B4204000   PUSH KEYGENME.004020B4                   ; |String1 = ""
	0040115A  |.  E8 6C000000   CALL <JMP.&KERNEL32.lstrcmpA>            ; \lstrcmpA
	0040115F  |.  85C0          TEST EAX,EAX
	00401161  |.  75 26         JNZ SHORT KEYGENME.00401189

	Its the compare between two strings! Ok so Now if we scroll up a little more we see

	004010CD  /$  68 50204000   PUSH KEYGENME.00402050                   ; /lParam = 402050

	Which is the start of the procedure. So set a breakpoint on this by pressing
	F2 and then start the program by pressing F9 ... 

	NOW: Type in any name/serial and click ok... Olly Should have paused the program
	on the breakpoint and now we can begin to trace over the code to monitor what it is 
	doing. F8 is to trace over.. 

	Below is the code that you trace over. I have commented it as there isn't much more i can 
	elaborate on except that you may need to understand what TEST eax, eax does but you should 
	look this up in an assembly reference if you don't understand it's use.. However i'm feeling
	nice today so: Test EAX, EAX  peforms a logical AND.. and sets the Z flag in memory, ie.
	If eax is 0 then the Z-flag returns 0 if eax is 1 then the Z-flag = 0. The Z flag determines
	Wheter conditional jumps should occur or not etc...

	Here is the code:

	004010CD  /$  68 50204000   PUSH KEYGENME.00402050                   ; /lParam = 402050
	004010D2  |.  6A 32         PUSH 32                                  ; |wParam = 32
	004010D4  |.  6A 0D         PUSH 0D                                  ; |Message = WM_GETTEXT
	004010D6  |.  FF35 48204000 PUSH DWORD PTR DS:[402048]               ; |hWnd = C58
	004010DC  |.  E8 DE000000   CALL <JMP.&USER32.SendMessageA>          ; \SendMessageA
	004010E1  |.  83F8 03       CMP EAX,3                                ;  check length
	004010E4  |.  0F8C 93000000 JL KEYGENME.0040117D                     ;  jump if less then 3
	004010EA  |.  8BD0          MOV EDX,EAX                              ;  mov length into eax
	004010EC  |.  33C9          XOR ECX,ECX                              ;  empty ecx
	004010EE  |.  33DB          XOR EBX,EBX                              ;  empty ebx

	------------------------------------ALGORITHM START-----------------------------------------------
	004010F0  |>  0FB681 502040>/MOVZX EAX,BYTE PTR DS:[ECX+402050]      ;  mov char into eax
	004010F7  |.  35 37130300   |XOR EAX,31337                           ;  xor with decimal 201527
	004010FC  |.  05 EFBEADDE   |ADD EAX,DEADBEEF                        ;  add (decimal) 3735928559 to eax
	00401101  |.  69C0 66060000 |IMUL EAX,EAX,666                        ;  Integer Multiply Eax by 1638 (decimal)
	00401107  |.  2D B3BAAD1B   |SUB EAX,1BADBAB3                        ;  eax - decimal 464370355
	0040110C  |.  C1E0 03       |SHL EAX,3                               ;  SHL by 3 (eax * (2^3))
	0040110F  |.  35 0DD04DD3   |XOR EAX,D34DD00D                        ;  xor eax with 3545092109
	00401114  |.  03D8          |ADD EBX,EAX                             ;  add to ebx
	00401116  |.  41            |INC ECX                                 ;  incline counter
	00401117  |.  3BD1          |CMP EDX,ECX                             ;  cmp counter with length
	00401119  |.^ 75 D5         \JNZ SHORT KEYGENME.004010F0             ;  loop
	------------------------------------ALGORITHM END------------------------------------------------

	0040111B  |.  53            PUSH EBX                                 ; /push total value
	0040111C  |.  68 3E204000   PUSH KEYGENME.0040203E                   ; |Format = "%X"
	00401121  |.  68 B4204000   PUSH KEYGENME.004020B4                   ; |s = KEYGENME.004020B4
	00401126  |.  E8 6A000000   CALL <JMP.&USER32.wsprintfA>             ; \convert to string
	0040112B  |.  83C4 0C       ADD ESP,0C
	0040112E  |.  68 B4204000   PUSH KEYGENME.004020B4                   ; /StringOrChar = "45D1BFDD"
	00401133  |.  E8 69000000   CALL <JMP.&USER32.CharUpperA>            ; \convert to uppercase
	00401138  |.  68 82204000   PUSH KEYGENME.00402082                   ; /lParam = 402082
	0040113D  |.  6A 32         PUSH 32                                  ; |wParam = 32
	0040113F  |.  6A 0D         PUSH 0D                                  ; |Message = WM_GETTEXT
	00401141  |.  FF35 4C204000 PUSH DWORD PTR DS:[40204C]               ; |hWnd = FC0
	00401147  |.  E8 73000000   CALL <JMP.&USER32.SendMessageA>          ; \get Serial from text box
	0040114C  |.  85C0          TEST EAX,EAX                             ;  check length
	0040114E  |.  74 39         JE SHORT KEYGENME.00401189               ;  jump if zero length
	00401150  |.  68 82204000   PUSH KEYGENME.00402082                   ; /String2 = "123213"
	00401155  |.  68 B4204000   PUSH KEYGENME.004020B4                   ; |String1 = "45D1BFDD"
	0040115A  |.  E8 6C000000   CALL <JMP.&KERNEL32.lstrcmpA>            ; \Compare two strings (our serial and the real serial)
	0040115F  |.  85C0          TEST EAX,EAX                             ;  if eax == 0 then Dont jump
	00401161  |.  75 26         JNZ SHORT KEYGENME.00401189
	00401163  |.  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
	00401165  |.  68 1B204000   PUSH KEYGENME.0040201B                   ; |Title = "Yeah! You done it."
	0040116A  |.  68 2E204000   PUSH KEYGENME.0040202E                   ; |Text = "Congrats... =]."
	0040116F  |.  FF35 44204000 PUSH DWORD PTR DS:[402044]               ; |hOwner = 00000A40 ('Keygenme - Coded by tsh33p',class='#32770',wndproc=8035C670)
	00401175  |.  E8 3F000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
	0040117A  |.  33C0          XOR EAX,EAX

	.................................................................

	Ok there exists enough information above to write a keygen hopefully.. But first If you
	look here:
	00401155  |.  68 B4204000   PUSH KEYGENME.004020B4                   ; |String1 = "45D1BFDD"

	45D1BFDD is the serial for x-Bi0dESC .. so we have a valid name / serial ... above it
	appears the algorithm to generate the serial.. So look at the comments
	The algorithm starts here:

	004010F0  |>  0FB681 502040>/MOVZX EAX,BYTE PTR DS:[ECX+402050]      ;  mov char into eax

	I will code a quick algorithm in VB6.
	Lets Assume We are dealing with two TextBox's:
	txtName - For the name
	txtSerial - For the serial

	We would probably put this code in the change event of the txtName TextBox

	NOTE: Visual Basic 6 is very bad with handling Big Numbers Especially dealing with
	Binary Operators! ... I have gotten Custom Binary to Integer, Integer To Binary converters
	And Binary Operations TO deal with big numbers so this algorithm is bound to fail if the
	numbers get big however it's only a general idea on how to code it. Also since
	We aren't dealing with Registers the numbers can get out of hand therefore 
	Making VB a bad language to choose for coding keygens... Other lang's that
	Support Inline ASM or even Coding in pure asm such as MASM or FASM is a better Idea
	.. This VB code is just for the concept and I have tested and it fails to work but
	I wish to inlcude it anyway :)
		
	'------------------------------Code Start------------------------------

	Dim EAX,EBX 'Declaring Variables (With no specific Type however Double would be an Ideal type)
	Dim i As Integer 'Counter

	'check name length
	
	If(Len(txtName.text)<3) Then
		txtSerial.Text = "Name Too short"
		Exit Sub 'Like a return statement..
	End If

	'Begin Algo

	For i = 1 to len(txtName.text)
		EAX = Asc(Mid(txtName.text,i,1)) 'Get char
		EAX = EAX Xor 201527 'Note This might not work with big numbers (Xor)
		EAX = EAX + 3735928559
		EAX = EAX * 1638
		EAX = EAX - 464370355
		EAX = EAX * (2^3) 'SHL EAX, 3 ... EAX * 8 .. SHL is the same as EAX * 2^N
		EAX = EAX Xor 3545092109
		EBX = EBX + EAX
	Next i

	'End Algo

	txtSerial.Text = Hex(EBX) 'Note this will probably cause an overflow in VB

	'------------------------------Code End------------------------------

NOTE: 
	
	BECAUSE OF VB'S LACK OF SUPPORT AND BECAUSE VB DOESN'T WORK LIKE ASM WHERE THE
	NUMBERS STORED IN EAX CAN BE MAXIMUM OF 2^32 IF IT'S GOING TO BE BIGGER 
	IT CAUSES THE O-FLAG TO BE SET (SUCH AS WHEN THE IMUL EAX,EAX,666). THIS CAN 
	*SOMETIMES* BE RESOLVED BY DIVIDING THE RESULTANT BY 2^32 HOWEVER IN THIS CASE
	IT FAILS.. BEST STICK WITH ASM CODING WHEN CODING KEYGENS... HOWEVER IT IS STILL
	POSSIBLE TO CODE _ALOT_ OF KEYGENS IN A High Level Language ... ESPECIALLY IF IT SUPPORTS INLINE
	ASM.. SO I WILL RECODE THIS IN PUREBASIC BECAUSE IT SUPPORTS IT ;)
	AND THE REASON I CODED THIS ABOVE IS BECAUSE MORE PEOPLE WOULD KNOW/HAVE VB THEN
	PUREBASIC .. OH AND THIS IS MY FIRST THING _EVER_ THAT I HAVE CODED IN PUREBASIC

		
	'------------------------------Code Start------------------------------

     	uName.s = GetGadgetText(#txtName)
     	 tempChar.l
      	nameLen.b = Len(uName)
      	Debug maxLen
      	If nameLen<3
        	SetGadgetText(#txtSerial,"Name Too short")
       	ElseIf nameLen>=50
        	SetGadgetText(#txtSerial,"Name Too Long")
     	Else  
       		XOR eax,eax
       		XOR ebx,ebx
      	For i = 1 To nameLen
        	tempChar = Asc(Mid(uName,i,1))
        	MOV eax,tempChar
        	XOR eax,201527
        	ADD eax,3735928559
        	IMUL eax,eax, 1638
        	SUB eax,464370355
        	SHL eax,3
        	XOR eax,3545092109
        	ADD ebx,eax
      	Next
      
      	MOV serial, ebx
      	serial = Hex(serial)
      	SetGadgetText(#txtSerial,serial)


	'------------------------------Code End------------------------------

NOTE: 	
	
	I noticed Pure basic deals with decimal all the time which i dont
	like too much :( ... Would be handy if it dealt with hex numbers when 
	working with inline asm too so it'd be easier to rip the code.. 
	Hope this code is understandable ... I've included the sources and the 
	Compiled keygen too .. Above is just the code for the algo...


FINAL THOUGHTS:

	Hope YOU, the NEWBIE have learnt something from this tutorial..
	I was extremely bored today so that is why i typed this up but
	Indeed it was meant for sharing information so i intended on making
	This tutorial as clear as i could. 
	
	Greets To new2cracking, biw, LUCiD, MEPHiST0, Uradox, Pumqara, n]-[va,
	cdk, Jupiter, blah blah blah everyone who speaks to me on irc and all
	My RL friends who will never end up reading this anyway ;) .........
	And YOU for taking the time to read this tutorial.