Cracking b0ne's KeyMe#1 - by Sunshine

Target : KeyMe#1
Downloaded from : Crackmes.de
Author of target: b0ne
Requirements:

* Ollydbg (I used Shadow Ollydbg)
* an ascii table
* optional: a hex/dec calculator

Additional: * something to drink; I prefer always coffee or beer :-)
* good music; I listened to KoRn :-)

Download whole package here! (includes tutorial, crackme and bruteforcer).

So, today we crack a nice easy key crackme. When you run the file from the console, it wants you type in a key. Enter a random key and you get the message "Wrong serial" followed by another try to enter a valid key. Also note that you you don't have to type in a name, just a key.

Open the file in Ollydbg, right-click in the main window and choose 'Search for' -> 'All referenced text strings'. In the new window which pops up double-click 'Key: ' cause after this string is printed to the console, you have to enter the key, so this should be the right place. You land at 4013C7. When you scroll some pages down. you see several checks and at 4015E1 the good 'Well done' message. Ok, seems to be the right place.
So set a breakpoint, for example at 4013EA, run the crackme, enter a key and trace the code with F8. If you come to a condition your key doesn't fulfill, just re-run the crackme and enter a key that matches the condition.

Condition 1:

004013F7 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
004013FA . 50            PUSH EAX            ; |Arg1
004013FB . E8 407B0000   CALL keyme.00408F40 ; get key length
00401400 . 83C4 10       ADD ESP,10
00401403 . 83F8 10       CMP EAX,10          ; is key == 0x10?
00401406 . 0F85 EE010000 JNZ keyme.004015FA  ; if not, bye

Easy. Our key must exactly be 0x10 = 16 characters long. Ok, let's go on...

Condition 2:

0040140F . 6A 00         PUSH 0              ; |Arg2 = 00000000
00401411 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
00401414 . 50            PUSH EAX ; |Arg1
00401415 . E8 92640100   CALL keyme.004178AC ; Get first character of entered key (=key[0])
0040141A . 83C4 10       ADD ESP,10
0040141D . 8038 40       CMP BYTE PTR DS:[EAX],40 ; key[0] <= 0x40?
00401420 . 0F8E D4010000 JLE keyme.004015FA ; if so, bye
00401426 . 83EC 08       SUB ESP,8
00401429 . 6A 00         PUSH 0              ; |Arg2 = 00000000
0040142B . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
0040142E . 50            PUSH EAX
0040142F . E8 78640100   CALL keyme.004178AC ; Get first character of entered key (=key[0])
00401434 . 83C4 10       ADD ESP,10
00401437 . 8038 5A       CMP BYTE PTR DS:[EAX],5A ; key > 0x5A?
0040143A . 0F8F BA010000 JG keyme.004015FA   ; if so, bye

You'll come across several calls to keyme.004178AC. This just returns the desired single character of entered key. Here 0 is pushed as arg2 so it returns the first character, let's call it key[0]. So key[0] must be greater than 0x40 = '@' and less than or equal 0x5A = 'Z'. In other words, first character must a capital letter ('A'...'Z').

Condition 3:

00401443 . 6A 0B         PUSH 0B                  ; Arg2 = 0000000B
00401445 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
00401448 . 50            PUSH EAX                 
00401449 . E8 5E640100   CALL keyme.004178AC      ; Get 12th character of key
0040144E . 83C4 10       ADD ESP,10
00401451 . 8038 20       CMP BYTE PTR DS:[EAX],20 ; key[11] == 0x20?
00401454 . 0F85 A0010000 JNZ keyme.004015FA       ; if not, bye

So key[11] must be 0x20, that means it must be a space. Ok, let's go on...

Condition 4:

0040145D . 6A 08         PUSH 8                   ; |Arg2 = 00000008
0040145F . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
00401462 . 50            PUSH EAX
00401463 . E8 44640100   CALL keyme.004178AC      ; Get 9th character of key
00401468 . 83C4 10       ADD ESP,10
0040146B . 8038 2E       CMP BYTE PTR DS:[EAX],2E ; key[8] == 0x2E?
0040146E . 0F85 86010000 JNZ keyme.004015FA       ; if not, bye

So key[8] must be 0x2E, that means a dot ('.'). Till now the key must look like "Xxxxxxxx.xx xxxx".

Condition 5:

00401482 > /837D D0 0A   CMP DWORD PTR SS:[EBP-30],0A  ; loop finished?
00401486 . |7E 02        JLE SHORT keyme.0040148A      ; if no, jump over next instruction
00401488 . |EB 21        JMP SHORT keyme.004014AB      ; jump out of loop
...
0040149F . 8D45 DC       LEA EAX,DWORD PTR SS:[EBP-24] ; load sum
004014A2 . 0110          ADD DWORD PTR DS:[EAX],EDX    ; sum = sum + character value
004014A4 . 8D45 D0       LEA EAX,DWORD PTR SS:[EBP-30] ; load loop counter
004014A7 . FF00          INC DWORD PTR DS:[EAX]        ; increase loop counter
004014A9 .^ EB D7        JMP SHORT keyme.00401482      ; jump to start of loop
...
004014EF . 817D DC F3030 CMP DWORD PTR SS:[EBP-24],3F3 ; sum == 0x3F3?
004014F6 . 0F85 FE000000 JNZ keyme.004015FA            ; if not, bye

So in this loop, the ascii values of the first eleven characters of the entered key are added. The sum of these values is stored on the stack at [EBP-24]. So key[0] + key[1] + ... + key[10] must be 0x3F3 (= 1001 decimal).

Condition 6:

004014B2 . C745 D0 0C000 MOV DWORD PTR SS:[EBP-30],0C  ; init loop counter with 0xC
004014B9 > 837D D0 0F    CMP DWORD PTR SS:[EBP-30],0F  ; loop finished?
004014BD . 7E 02         JLE SHORT keyme.004014C1      ; if no, jump over next instruction
004014BF . EB 21         JMP SHORT keyme.004014E2
     ; jump out of loop
...
004014D6 . 8D45 D8       LEA EAX,DWORD PTR SS:[EBP-28] ; load sum
004014D9 . 0110          ADD DWORD PTR DS:[EAX],EDX    ; sum = sum + character value
004014DB . 8D45 D0       LEA EAX,DWORD PTR SS:[EBP-30] ; load loop counter
004014DE . FF00          INC DWORD PTR DS:[EAX]        ; increase loop counter
004014E0 .^ EB D7        JMP SHORT keyme.004014B9      ; jump to start of loop
004014E2 > 817D D8 D1010 CMP DWORD PTR SS:[EBP-28],1D1 ; sum == 0x1D1?
004014E9 . 0F85 0B010000 JNZ keyme.004015FA            ; if not, bye

Well, this loop is quite analog to the previous one. Here the ascii values from the last four values are added and stored on the stack at [EBP-28]. That means key[12] + key[13] + key[14] + key[15] must be 0x1D1 (=465 decimal). A valid key till now for example would be "Addddddd.dd tttu".

Condition 7:

00401511 . 6A 0F         PUSH 0F                  ; |Arg2 = 0000000F
00401513 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
00401516 . 50            PUSH EAX ; |Arg1
00401517 . E8 90630100   CALL keyme.004178AC      ; Get 16th character of key
0040151C . 83C4 10       ADD ESP,10
0040151F . 8945 C8       MOV DWORD PTR SS:[EBP-38],EAX
00401522 . 83EC 08       SUB ESP,8
00401525 . 6A 0E         PUSH 0E                  ; |Arg2 = 0000000E
00401527 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
0040152A . 50            PUSH EAX
0040152B . E8 7C630100   CALL keyme.004178AC      ; Get 15th character of key
00401530 . 83C4 10       ADD ESP,10
00401533 . 89C2          MOV EDX,EAX
00401535 . 8B4D C8       MOV ECX,DWORD PTR SS:[EBP-38]
00401538 . 8A01          MOV AL,BYTE PTR DS:[ECX] ; AL = 16th character
0040153A . 3A02          CMP AL,BYTE PTR DS:[EDX] ; AL == 15th character ?
0040153C . 0F85 B8000000 JNZ keyme.004015FA       ; if not, bye

This code snippet checks if the last character is the same as the character before the last character. That means key[14] must be equal to key[15].

Condition 7:

00401545 . 6A 0D         PUSH 0D                  ; |Arg2 = 0000000D
00401547 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
0040154A . 50            PUSH EAX
0040154B . E8 5C630100   CALL keyme.004178AC      ; Get 14th character
00401550 . 83C4 10       ADD ESP,10
00401553 . 8038 6F       CMP BYTE PTR DS:[EAX],6F ; key[13] == 0x6F?
00401556 . 0F85 9E000000 JNZ keyme.004015FA       ; if not, bye

Obviously key[13] must be 0x6F which is 'o'.

Condition 8:

0040155F . 6A 0C         PUSH 0C                       ; |Arg2 = 0000000C
00401561 . 8D45 E8       LEA EAX,DWORD PTR SS:[EBP-18]
00401564 . 50            PUSH EAX
00401565 . E8 42630100   CALL keyme.004178AC           ; Get 13th character
0040156A . 83C4 10       ADD ESP,10
0040156D . 0FBE00        MOVSX EAX,BYTE PTR DS:[EAX]   ; eax = value of 13th character
00401570 . 3B45 DC       CMP EAX,DWORD PTR SS:[EBP-24] ; eax == 0x72?
00401573 . 0F85 81000000 JNZ keyme.004015FA            ; if not, bye

Here it is checked if key[12] is equal to the value of [EBP-24]. If you look a bit above at 401507, you see that the value 0x72 is moved to [EBP-24] and is never changed. So key[12] must be 0x72 = 'r'.
So till now a valid key would be "Addddddd.dd roxx" cause the 'r' and 'o' are fixed, both last characters must be same and the sum of the last four characters must be 0x1D1.
(0x1D1 - 0x6F - 0x72) / 2 = 0x78 = 'x'.

Condition 9:

00401585 . 6A 02       PUSH 2                   ; |Arg2 = 00000002
00401587 . 8D45 E8     LEA EAX,DWORD PTR SS:[EBP-18]
0040158A . 50          PUSH EAX
0040158B . E8 1C630100 CALL keyme.004178AC      ; Get 3rd character
00401590 . 83C4 10     ADD ESP,10
00401593 . 8038 39     CMP BYTE PTR DS:[EAX],39 ; 3rd character > 0x39?
00401596 . 7F 62       JG SHORT keyme.004015FA  ; if so, bye
00401598 . 83EC 08     SUB ESP,8
0040159B . 6A 02       PUSH 2                   ; |Arg2 = 00000002
0040159D . 8D45 E8     LEA EAX,DWORD PTR SS:[EBP-18]
004015A0 . 50          PUSH EAX
004015A1 . E8 06630100 CALL keyme.004178AC      ; Get 3rd character
004015A6 . 83C4 10     ADD ESP,10
004015A9 . 8038 2F     CMP BYTE PTR DS:[EAX],2F ; 3rd character <= 0x2F
004015AC . 7E 4C       JLE SHORT keyme.004015FA ; if so, bye

The 3rd character must be between 0x30 = '0' and 0x39 = '9', so it must be number.

Condition 10:

004015B1 . 6A 01       PUSH 1                     ; |Arg2 = 00000001
004015B3 . 8D45 E8     LEA EAX,DWORD PTR SS:[EBP-18]
004015B6 . 50          PUSH EAX
004015B7 . E8 F0620100 CALL keyme.004178AC        ; Get 2nd character
004015BC . 83C4 10     ADD ESP,10
004015BF . 8945 C4     MOV DWORD PTR SS:[EBP-3C],EAX
004015C2 . 83EC 08     SUB ESP,8
004015C5 . 6A 0C       PUSH 0C                    ; |Arg2 = 0000000C
004015C7 . 8D45 E8     LEA EAX,DWORD PTR SS:[EBP-18]
004015CA . 50          PUSH EAX
004015CB . E8 DC620100 CALL keyme.004178AC        ; Get 13th character
004015D0 . 83C4 10     ADD ESP,10
004015D3 . 89C2        MOV EDX,EAX
004015D5 . 8B4D C4     MOV ECX,DWORD PTR SS:[EBP-3C]
004015D8 . 8A01        MOV AL,BYTE PTR DS:[ECX]   ; AL = 2nd character
004015DA . 3A02        CMP AL,BYTE PTR DS:[EDX]   ; AL == 13th character?
004015DC . 75 1C       JNZ SHORT keyme.004015FA   ; if not, bye

This code snippet gets the 2nd and the 13th character and checks if they are equal. So key[1] must be key[12]. As we know from condition 12 that key[12] must be 'r', key[1] must also 'r'.

Summary

Ok, these were all conditions. Here is a summary of them (note I represent the key as key[0]...key[15]:

Condition 1: length of key = 0x10 (16 chars long)
Condition 2: key[0] = 'A'...'Z', key must be a capital letter
Condition 3: key[11] = ' ' (a space)
Condition 4: key[8] = '.' (a dot)
Condition 5: key[0] + key[1] + ... + key[10] = 0x3F3
Condition 6: key[12] + key[13] + key[14] + key[15] = 0x1D1
Condition 7: key[13] = 'o'
Condition 8: key[12] = 'r'
Condition 9: key[2] = '0'...'9' (a number)
Condition 10: key[1] = key[12] = 'r'

Well, as the author states, there are a lot of keys which satisfy the conditions. The first valid key I constructed with pen&paper and a ascii table was "Ar9nnggg.dd roxx". But he also said in the readme file that you can recognize the right key. After some looking at my first key, suddenly "Crackmes.de roxx" came into my mind. But the third character must be a number, so some easy calculating leads us to "Cr4ckmes.de roxx". I think that's the right one.

I also coded a little bruteforcer which calculate tons of valid keys. You find it inside the zip package.

Hopefully the crackme was fun for you and you learned something :-)

Sunshine, May 2k7


This site is part of Sunshine's Homepage