Keygenning tsh33p's Keygenme #1

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)
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.