Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Sunday, September 26 2021 @ 11:41 PM CEST

TDC's KeyGenME (CrackME #8) Solution Tutorial


TutorialsLevel : newbie

TDC's KeyGenME (CrackME #8) Solution Tutorial

Aimed For : Newbies in reversing, with basic knowledge of assembly instructions
(former experience with easier KeyGenMEs can be helpfull though)

Difficulty: 2/10

Tool Used : OllyDbg

Target : TDC's KeyGenME (CrackME #8) (

Part 1: Preface

What we have to do:
Find a valid serial
Write a keygenerator

First of all, let me explain how keygenning works... Lets suppose that you want to register an app.
How can that be accomplished?
Most apps ask you of a username and a valid serial.
( What do they take as a valid serial?
Each app has its own serial-generating algorithm, that will examine your username character-to-character and produce a serial.
The structure of the algorithm is the app coder's choice.HE decides what a valid serial will be for each username.)
Then, they take your input and based on your username, the generate the valid serial.
Then, they compare the serial you entered to the one they generated and if they are equal - BINGO - you have registered the app!!!
So, in order to fish a serial we take the app that we want to make the keygenerator for, and examine the serial-checking algorithm.
The one of the two serials is the correct one, so we try to find it in memory ;-)
Lets start!
Open up the crackme and click 'Check' just to see what error messages it gives us when we enter a wrong serial
When dealing with larger apps(real life,commercial apps that will probably have more lines of code than just the code for the registration process ;-)) it is very useful to write the text of the error message down so that later you can use it to find the lines of the code that compose the serial checking process.
But in our case, the crackme won't have so many lines so we can just open it in OllyDbg (File-->Open) and scroll down a bit until we find some references of the GetWindowText API or the GetDlgItemText API or the SendMessage/SendDlgItemMessage API combined with the WM_GETTEXT message
These are the most common ways to get the text from an edit box when dealing with asm-compiled apps.

In our case:

0040114E . 6A 11 PUSH 11 ; /Count = 11 (17.)
00401150 . 68 E0324000 PUSH keygenme.004032E0 ; |Buffer = USERNAME
00401155 . FF35 03334000 PUSH DWORD PTR DS:[403303] ; |hWnd
0040115B . E8 9A010000 CALL JMP.&user32.GetWindowTextA ; GetWindowTextA
00401160 . 6A 12 PUSH 12 ; /Count = 12 (18.)
00401162 . 68 F1324000 PUSH keygenme.004032F1 ; |Buffer = SERIAL
00401167 . FF35 07334000 PUSH DWORD PTR DS:[403307] ; |hWnd
0040116D . E8 88010000 CALL JMP.&user32.GetWindowTextA ; GetWindowTextA
-------------------------------------------------------------------------------- a breakpoint (F2) on one of the above lines and hit F9!!!

Part2 : Serial Fishing!!!

OK, OllyDbg breaks on the breakpoint so we Trace Over a little bit with F8...


0040114E . 6A 11 PUSH 11
00401150 . 68 E0324000 PUSH keygenme.004032E0
00401155 . FF35 03334000 PUSH DWORD PTR DS:[403303]
0040115B . E8 9A010000 CALL JMP.&user32.GetWindowTextA ;Get the username
00401160 . 6A 12 PUSH 12 ;
00401162 . 68 F1324000 PUSH keygenme.004032F1 ;
00401167 . FF35 07334000 PUSH DWORD PTR DS:[403307] ;
0040116D . E8 88010000 CALL JMP.&user32.GetWindowTextA ;Get the serial
00401172 . 68 E0324000 PUSH keygenme.004032E0 ;
00401177 . E8 66010000 CALL JMP.&user32.CharLowerA ;Convert username to lower-case
0040117C . 68 E0324000 PUSH keygenme.004032E0
00401181 . E8 F1000000 CALL keygenme.00401277 ;Check if there are any characters except than letters
00401186 . 85C0 TEST EAX,EAX ;if there are, inform the user
00401188 . 0F85 87000000 JNZ keygenme.00401215
0040118E . 68 F1324000 PUSH keygenme.004032F1 ; Arg2=Serial
00401193 . 68 E0324000 PUSH keygenme.004032E0 ; Arg1=Username
00401198 . E8 7E000000 CALL keygenme.0040121B ; Serial Generation Routine!!!!
and on 0x00401198 hit F7 to trace into the subroutine.
and we land here:


0040121B /$ 55 PUSH EBP
0040121C |. 8BEC MOV EBP,ESP
0040121E |. 81C4 00FFFFFF ADD ESP,-100
00401224 |. 56 PUSH ESI
00401225 |. 57 PUSH EDI
00401226 |. 51 PUSH ECX
00401227 |. 53 PUSH EBX ;Nothing that we should care about
00401228 |. 52 PUSH EDX ;until here
00401229 |. 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ;ESI=Address of Username
0040122C |. 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C] ;EDI=Address of Serial
0040122F |. 33C9 XOR ECX,ECX ;/
00401231 |. 33DB XOR EBX,EBX ;|Zero-out the values of the registers
00401233 |. 33D2 XOR EDX,EDX ;
00401235 |. B3 15 MOV BL,15
00401237 |> 8A1431 /MOV DL,BYTE PTR DS:[ECX+ESI] ;/
0040123A |. 325431 01 |XOR DL,BYTE PTR DS:[ECX+ESI+1] ;|
0040123E |. 80C2 29 |ADD DL,29 ;|
00401241 |. 36:889429 00FF>|MOV BYTE PTR SS:[ECX+EBP-100],DL ;|The Serial Generation Algorithm
00401249 |. FEC3 |INC BL ;|(don't worry I'll explain it later)
0040124B |. 41 |INC ECX ;|
0040124C |. 80FB 25 |CMP BL,25 ;|
0040124F |.^75 E6 JNZ SHORT keygenme.00401237 ;
00401251 |. 36:C68429 00FF>MOV BYTE PTR SS:[ECX+EBP-100],0 ;add a 0 at the end of the serial, making it a valid string ;-)
0040125A |. 8DB5 00FFFFFF LEA ESI,DWORD PTR SS:[EBP-100] ;ESI=Address of the place where the fake serial begins(in memory)
00401260 |. F3:A6 REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ;compare our serial to the one generated just before, byte2byte
;when it encounters differrent bytes, it stops the comparing
;because the REPE instruction repeats executing a line of code while the zero flag is set
00401262 |. 803F 00 CMP BYTE PTR DS:[EDI],0 ;Check if the next byte of the correct serial is a 0
;That's a smart way to check if the 2 serials are identical because if they are not,
;the REPE comparing will stop at the position of the 2 differrent bytes and as a result
;the next byte won't be the trailing 0 ;-)
00401265 |. 75 05 JNZ SHORT keygenme.0040126C ;prepare the return values to decide which messagebox will be shown
00401267 |. 33C0 XOR EAX,EAX
00401269 |. 40 INC EAX
0040126A |. EB 02 JMP SHORT keygenme.0040126E
0040126C |> 33C0 XOR EAX,EAX
0040126E |> 5A POP EDX
0040126F |. 5B POP EBX
00401270 |. 59 POP ECX
00401271 |. 5F POP EDI
00401272 |. 5E POP ESI
00401273 |. C9 LEAVE
00401274 . C2 0800 RETN 8

to find out which is the correct serial for the name you entered, hit F9 then click 'Check' again and at 00401260 right click at 'ES:[EDI]=...' below the asm code and select 'Follow in Dump'.
Then, in the window below the place where you right-clicked under the header 'ASCII' there is the correct serial(it starts at the top left and ends at the first 0).

That's it!!!
We found a suitable serial for our Username!!!

Now on to the KeyGenning!!!

Part 3:Writting the Keygen!!! you can see, the serial generation algorithm is a loop that takes every character of our username and XORes it with next(00401237 and 0040123A).
Then, it adds 0x29 to the result of the XORing and saves that byte of data.
That byte of data is a character of the correct serial...
So...the serial is an array of characters each one (let's say n in position) created by XORing your name's n-th character with the (n+1)th and then adding 0x29 to it..


To conclude this tutorial, let me present to you the KeyGenning procedure in win32asm:

username db 17 dup(?)
serial db 18 dup(?)


GenerateSerial proc unAddress:DWORD

mov eax,unAddress
lea esi,serial
xor ecx,ecx
mov dl,byte ptr [eax+ecx]
xor dl,byte ptr [eax+ecx+1]
add dl,29h
mov byte ptr [esi+ecx],dl
inc ecx
cmp ecx,16
jnz again


GenerateSerial endp

To generate the serial, you will need to put the username in the username variable and then use:
invoke GenerateSerial,addr username
However, in order for this keygenerator to be successful, you need to do some checks on the username first, as the crackme does(no numbers, etc...)

There is also one other problem:there are some usernames that will cause the serial to have characters that are not represented equally in each encoding(u may be using a differrent one from the crackme).This, results in some serials being rejected although they are correct...

In the zip file I include a simple keygenerator(with no checks on the username).

That's it...
Another tutorial (my second one) has been completed!!!
Hope you learned something...

Greets and thanx go to all the members of BiW.

What's Related

Story Options

TDC's KeyGenME (CrackME #8) Solution Tutorial | 2 comments | Create New Account
The following comments are owned by whomever posted them. This site is not responsible for what they say.
TDC's KeyGenME (CrackME #8) Solution Tutorial
Authored by: Fredro on Wednesday, February 01 2006 @ 10:12 PM CET
Nice one dude :>
TDC's KeyGenME (CrackME #8) Solution Tutorial
Authored by: Falcon1 on Saturday, February 04 2006 @ 09:21 PM CET
Thanks :)

(I did...)

 Copyright © 2021 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.85 seconds