KeyGenning TDC Kgme #1

Saturday, August 20 2005 @ 12:27 PM CEST

Contributed by: TDC

Level : newbie


Key Generating Tutorial - TDC #1


Written by: TDC - The Dutch Cracker

Tools used: OllyDbg and MASM32

Level: 1/10

Keygenning TDC #1 crackme. (Source code included in attachment)

Attachment: attachment

Contact info:

ICQ: 264541651


Hello all and welcome to this tutorial. I rated this one level 1/10 because I'll explain most things you need, so this would be a good newbie tutorial I hope.

The tutorial:

Open up OllyDbg and then open "keygenme.exe" or right-click "keygenme.exe" and "Open with OllyDbg". If you don't have the right-click open function then let OllyDbg add it for you. Start-up OllyDbg, go to the Options menu and select "Add to Explorer" there you will find it.

Ok, press F9 (don't set breakpoints yet), and explore the executable. You should see three editboxes, where you will have to fill in two of them. Got that? Good, otherwise pick a cookie :-)

Now, how would the executable get our name and serial? With an API, I'm sure! So... what API then? I'm going to tell you, some basic API's for getting text from editboxes are "GetDlgItemText" and "GetWindowText", they get a value from an editbox and store it somewhere.

How do we find out where it gets our name and serial from the editboxes? Most easy way is setting up some breakpoints on the API's, when the program uses the API to get the text from the editboxes it uses the API, and thus OllyDbg will break. Then you have the right API in front of your eyes.

Right, how do we set up a breakpoint on the API? That's easy, press the lightblue E in OllyDbg or ALT-E on your keyboard. Then right-click our executable from the list and press "View Names" from the menu, or do one left-click on the executable and then CTRL-N on your keyboard. Now you are in a window with the API's that the program uses. You can scroll down to setup breakpoints on GetDlgItemText and GetWindowText, but just typing in the key sequence of the API name is easier, because OllyDbg will then bring you to the API :-)

Found the API GetDlgItemText in the list? Right-click it and press the menu option "Set breakpoint on every reference". Then setup a breakpoint on GetWindowText. (Note: the API's might be called GetDlgItemTextA and GetWindowTextA, the A means 32-bit)

Okay, have you setup the breakpoint? Good. Insert your desired registration name and a fake serial that is easy to remember. Press the Check button. Yay! OllyDbg breaks immediately, the program is now totally under your control, feels powerfull eh :-)

We are now on the point where the call to the API is about to get executed. I have made a dead-listing of the lines with W32Dasm. You don't need W32Dasm for this tutorial.


:00401168 6A5A push 0000005A ; push 90 (5A = 90 in decimal)
:0040116A 68CA644000 push 004064CA ; push address where serial will be stored
:0040116F 6A6C push 0000006C ; push 108, the ID of the editbox serial
:00401171 FF7508 push [ebp+08] ; push window handle from dialogbox of where to get it from
* Reference To: user32.GetDlgItemTextA, Ord:00F4h
:00401174 E8D5010000 Call 0040134E ; call the actual API
:00401179 E836010000 call 004012B4 ; call registration procedure
:0040117E 68CA644000 push 004064CA ; push our serial
:00401183 6890634000 push 00406390 ; push right serial
* Reference To: kernel32.lstrcmpiA, Ord:02B9h
:00401188 E809020000 Call 00401396 ; call API to compare both serials, our serial and the valid one

--- DEAD-LISTING --- END ---

Do you see the second push? That is where your serial will be stored. Why and how do we know? Because if you look at the API reference you will see it, let me explain:

UINT GetDlgItemText(

HWND hDlg,
int nIDDlgItem,
LPTSTR lpString,
int nMaxCount

When assembled, the API from MASM32 like "invoke GetDlgItemText, hWin, 108, offset szSerial, 90" will look like this:

push 5A
push keygenme.4064CA
push 6C
push dword ptr [ebp+08]
call GetDlgItemTextA

That's how it looks in OllyDbg. See? It gets assembled in reverse order, what gets pushed first is the last value that the API will receive, so the ADDR 4064CA is where our serial is stored.

Scroll up a bit (I didn't include this part on the dead-listing). Then, do you see the "cmp eax, 4 " instruction? Well, eax will be the length of your name, the API GetDlgItemText sets eax. So it compares namelength with 3? Yeap! That is correct. What happens next? The "jl" instruction, it means "jump if less". I checked for you where it jumps to. It jumps to a SetWindowText API that sets the text "Please enter more than 3 characters...". So our name must be 4 characters at least, go and change it if it wasn't three characters. To change the name press F9 in OllyDbg and the program will continue. If you look further you also notice a "cmp eax, 9" and a "jge" instruction, so our username may not be 9 characters long, we need a username between 3 - 9 characters, but not 3 and 9 themselves.

Ok, now we are ready to check what is done with our name and how it checks if we entered the correct serial. Hmm, you see that "call" instruction below the "jl" instruction? Press F8 in OllyDbg to step to it, and then press F7 when you are on the call, so it jumps INTO it. I guessed right, here the program generates the valid serial and compares it to ours. How do you know that TDC? Heh Heh! I coded the program that we are keygenning here ;-) Otherwise we would just stepped over the call with F8 and then check what goes on next till we see it gets compared, and then we would reverse it, check where our valid serial came from :-)

We will see a call to the API lstrlen, it will check the length of a value and store it into eax, hmm... the push before the call, isn't that the address to our name? Yes, it is the same as in the GetDlgItemText API. So... why didn't the author (me) store the length after the GetDlgItemText and use that? Dunno, he probably forgot or thought we would change our name after the API's in OllyDbg, or he just wanted to make this keygenme clear for newbies. Yes, I did it to make it clear for newbies :-) Aha, good... let's move on. NO! Wait, turn on your favourite music first if you want and then proceed :-)

I'll make a small dead-listing of the code with W32Dasm so I can point to addresses and I'll comment it here and there.


* Referenced by a CALL at Address:
:004012B4 53 push ebx ; save ebx, ebx is a register that needs to be saved
:004012B5 57 push edi ; save edi, same story for edi
:004012B6 6870644000 push 00406470 ; push our username string
* Reference To: kernel32.lstrlenA, Ord:02BFh
:004012BB E8DC000000 Call 0040139C ; call lstrlen API to get length of name
:004012C0 8BD0 mov edx, eax ; move length to edx
:004012C2 33C9 xor ecx, ecx ; clear ecx
:004012C4 33DB xor ebx, ebx ; clear ebx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
:004012C6 0FB68170644000 movzx eax, byte ptr [ecx+00406470] ; move username character into eax
:004012CD 83C00A add eax, 0000000A ; add 10 decimal
:004012D0 03D8 add ebx, eax ; add eax to ebx ; ebx = the total calculation
:004012D2 41 inc ecx ; increase counter for ecx to get next username character
:004012D3 3BCA cmp ecx, edx ; are we at end of name?
:004012D5 75EF jne 004012C6 ; if not so, go back and pick next character
:004012D7 33C9 xor ecx, ecx ; clear ecx
:004012D9 53 push ebx ; save ebx for later use?
:004012DA 33DB xor ebx, ebx ; clear ebx
:004012DC 81C3596F7500 add ebx, 00756F59 ; add 7696217 decimal to ebx
:004012E2 53 push ebx ; save ebx
:004012E3 33DB xor ebx, ebx ; clear ebx
:004012E5 81C3616C6D00 add ebx, 006D6C61 ; add 7171169 decimal to ebx
:004012EB 53 push ebx ; save ebx
:004012EC 33DB xor ebx, ebx ; clear ebx
:004012EE 81C36F737400 add ebx, 0074736F ; add 7631727 decimal to ebx
:004012F4 53 push ebx ; save ebx
:004012F5 33DB xor ebx, ebx ; clear ebx
:004012F7 81C364696400 add ebx, 00646964 ; add 6580580 decimal to ebx
:004012FD 53 push ebx ; save ebx
:004012FE 33DB xor ebx, ebx ; clear ebx
:00401300 81C369742100 add ebx, 00217469 ; add
:00401306 53 push ebx ; save ebx
:00401307 33DB xor ebx, ebx ; clear ebx
:00401309 81C321212100 add ebx, 00212121 ; add
:0040130F 53 push ebx ; save ebx
:00401310 33DB xor ebx, ebx ; clear ebx
:00401312 5B pop ebx ; get ebx again from the last point where it was saved
:00401313 5B pop ebx ; get next ebx from where it was saved
:00401314 5B pop ebx ; and so on...
:00401315 5B pop ebx ; ...
:00401316 5B pop ebx ; ...
:00401317 5B pop ebx ; ...
:00401318 5B pop ebx ; ... till here ; 7 pops, hmm, 7 pushes also, ebx didn't change from first push
:00401319 69DB697A0000 imul ebx, 00007A69 ; do a last calculation to it, multiply with 31337
:0040131F 53 push ebx ; push ebx for wsprintf API
* Possible StringData Ref from Data Obj ->"%d"
:00401320 68D0634000 push 004063D0 ; push string %d
:00401325 6890634000 push 00406390 ; push ADDR of where the transformation will be saved
* Reference To: user32.wsprintfA, Ord:0262h
:0040132A E807000000 Call 00401336 ; call the actual API

--- DEAD-LISTING --- END ---

Here it moves the first character in eax, does some calculations with it, and adds the value to ebx, ebx will be the total serial, each loop the calculation based on a character of our name will be added to ebx. After that we will see a wsprintf API, here it turns the calculation into decimal string. Look at the API to understand it.

int wsprintf(


If you check it in OllyDbg you see this:

push ebx
push %d
push output address
call wsprintf

Here ebx is our total serial from the algorithm, %d means it'll turn into a decimal string, for example %X would turn them into HEX. And the output address will be in this case the final serial.

That is ALL we need, no more, no less. We know how the algorithm works so we can code our keygenerator.

First, I will make the design of the keygenerator and then the ASM source. With the design I mean the resource file of course :-)

Look at the zipfile for the resource file called "rsrc.rc". Open it with your favourite text editor. I have commented it.

Have you got that? Nice! Let's code the keygenerator itself.

After the user presses the Generate button, the generating procedure will be initiated. To make it easy I made a procedure called Generate of it in the ASM source, so we can call it when the user presses Generate.

Just extract the whole zipfile into one directory in case you haven't already done that. You should take a look at the ASM source and the resource file to see how it all works if you want that. I commented both files pretty thorough (even the make.bat file) so even people complete new to keygenning could understand it.

Now run "make.bat". Just double-click it and you will see a "keygen.exe" appearing. If not, then you probably don't have MASM32 installed at the same drive as where you extracted the zipfile. Good, test the keygenerator, insert a name and press Generate. Yay! Theres a serial, would it work? I'm sure it does :-)


I hope you enjoyed this tutorial. I did this for people who are new to keygenning. If you still have questions about anything written or just something you want to know, feel free to contact me (click my name at the top), or post a comment to this article.


Everyone from BiW-Reversing. The guys from New2Cracking.

Special thanks:

Detten - for wanting to help me with my first steps and with coding.

BoR0 - for giving me much understanding, I really appreciate that.

xb0z - for being a nice person and helping me with debugging.

nAmGiBeHt - also thanks for the helping with debugging.

YOU! - for reading this tutorial and trying to get better.