Cracking
b0ne's KeyMe#1
-
by
Sunshine |
|
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