Cracking "Simple crackme by Ozzman v2.0" - by Sunshine


Target : Simple crackme by Ozzman v2.0
File : crackme2.exe (16.896 bytes)
Downloaded from : EOD's Crackme Site
Author : Ozzman
Level : Newbie (like me...)
Tools : Wdasm, Softice, Hex Editor (I used Hex Workshop)
Info : Keyfile check, not packed, no anti-debugging

Ok, start the crackme and we see just 2 buttons. So click Register and the nice message "Nice try lamah...:) Try again!" pops up. Close it and open a copy of the file (always do this so you don't get an error if you wanna patch that file) in WDasm, go to String References and doubleclick on our message. Scroll up and we'll see this:


:0040382E 53 push ebx
:0040382F 6A00 push 00000000

* Possible StringData Ref from Code Obj ->"ozzman.key"

|
:00403831 680C394000 push 0040390C

* Reference To: kernel32._lopen, Ord:0000h
|
:00403836 E8D1FEFFFF Call 0040370C
:0040383B 8BD8 mov ebx, eax              ; move file handle in ebx
:0040383D 83FBFF cmp ebx, FFFFFFFF       ; check if file handle is invalid
:00403840 0F84A3000000 je 004038E9       ; if so jump to "Nice try lamah..."


(I've skipped now a few lines..)

:00403853 6A28 push 00000028                              ; length of data buffer
:00403855 8B45F8 mov eax, dword ptr [ebp-08]
:00403858 50 push eax                                     ; pointer to buffer for read data
:00403859 53 push ebx                                     ; handle to file

* Reference To: kernel32._lread, Ord:0000h
|

:0040385A E8B5FEFFFF Call 00403714
:0040385F 85C0 test eax, eax
:00403861 7518 jne 0040387B                               ; if successfully read, jump to go on, else bad boy message
:00403863 6A00 push 00000000

* Possible StringData Ref from Code Obj ->"Crackme 2.0 by Ozzman"
|

:00403865 6818394000 push 00403918

* Possible StringData Ref from Code Obj ->"Program not registered!"
|

:0040386A 6830394000 push 00403930
:0040386F 6A00 push 00000000

* Reference To: user32.MessageBoxA, Ord:0000h
|

:00403871 E8DEFEFFFF Call 0040375



So crackme tries to open a key file called "ozzman.key". Then it tries to read 28h bytes from this key file.
Ok let's create this file in the same directory, open it in a hexeditor and insert 28h bytes with random values. Save it.and start the crackme again.
Then fire up softice, set a breakpoint on _lread (bpx _lread) and click Register again. Trace with F10 and you'll see this:



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
| :00403861(C)
|
:0040387B C745FC00000000 mov [ebp-04], 00000000
:00403882 8B75F8 mov esi, dword ptr [ebp-08]                      ; Esi points now to the 28h bytes of our keyfile
:00403885 8B06 mov eax, dword ptr [esi]                           ; Read 4 bytes in eax        
:00403887 89F7 mov edi, esi                                       ; Move pointer to buffer to edi
:00403889 83C714 add edi, 00000014                                ; Add 14h bytes to pointer
:0040388C 89FA mov edx, edi                                       ; Move pointer to buffer to edx 
:0040388E FF45FC inc [ebp-04]
:00403891 8B4DFC mov ecx, dword ptr [ebp-04]


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
| :004038B0(U)
|
:00403894 8B1F mov ebx, dword ptr [edi]                           ; 4 bytes of second half of keyfile in edx 
:00403896 31D8 xor eax, ebx                                       ; xor eax (contains 4 bytes of keyfile) with ebx
:00403898 83C704 add edi, 00000004                                ; add 4 bytes to pointer 
:0040389B E2F7 loop 00403894
:0040389D 8906 mov dword ptr [esi], eax                           ; store xored eax value back in keyfile buffer
:0040389F 83C604 add esi, 00000004
:004038A2 39D6 cmp esi, edx                                       ; All bytes done?
:004038A4 740C je 004038B2                                        ; If so, jump below...
:004038A6 8B06 mov eax, dword ptr [esi]                           ; next 4 bytes in eax
:004038A8 FF45FC inc [ebp-04]
:004038AB 8B4DFC mov ecx, dword ptr [ebp-04]
:004038AE 89D7 mov edi, edx
:004038B0 EBE2 jmp 00403894                                       ; reapet...


First 4 bytes are xored with first bytes of second half of the keyfile (14h, 15h, 16h, 17h bytes) and stored back in esi. Then it increases the pointesr by 4 to read next 4 bytes (of first and second half of keyfile), xor them again and so on... Trace it a few times and have a look at eax and ebx to understand what I mean.




* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004038A4(C)
|

:004038B2 89D6 mov esi, edx
:004038B4 83EE10 sub esi, 00000010
:004038B7 89D7 mov edi, edx
:004038B9 B904000000 mov ecx, 00000004
:004038BE 8B06 mov eax, dword ptr [esi]    <--                    ; eax= value calculated by many fucking xors
:004038C0 3B07 cmp eax, dword ptr [edi]       |                   ; [edi]= original bytes of our keyfile
:004038C2 7525 jne 004038E9                   |                   ; Not equal -> bye
:004038C4 83C604 add esi, 00000004            |
:004038C7 83C704 add edi, 00000004            |
:004038CA E2F2 loop 004038BE               ---
:004038CC 8B45F8 mov eax, dword ptr [ebp-08]
:004038CF E890EBFFFF call 00402464
:004038D4 6A00 push 00000000

* Possible StringData Ref from Code Obj ->"Cool Hacker!!!"
|

:004038D6 6848394000 push 00403948

* Possible StringData Ref from Code Obj ->"Congratulation!!! You find correct key!!!"
|

:004038DB 6858394000 push 00403958
:004038E0 6A00 push 00000000

* Reference To: user32.MessageBoxA, Ord:0000h
|

:004038E2 E86DFEFFFF Call 00403754
:004038E7 EB1B jmp 00403904


So it compares calculated values with original values from our keyfile in a loop. This makes it *very hard* to reverse. Cause the crackme takes bytes from the keyfile, calculates new values by xoring them and finally compares these new values with original values from the keyfile.
Now you think: Well, just trace with softice to 004038C2 jne 004038E9 and always write down eax (which is the calculated value) and put them in our keyfile so the compare succeeds... That doesn't work cause if you change only on byte in the keyfile the calculated value will change! The fucking xors depends more or less on each other and one byte will change the calculation.
So what do now? Completely reversing the whole calculation would take MUCH time...
Hey, but if we fill the whole file with zeros, it must work! Cause 0 xor 0 = 0! So all calculated value are zeros (there are just xor operations...) and all values in the file are zeros.
So a valid keyfile is a file called "ozzman.key" 28h bytes big and just containing zeros! Well, it's quite lame but it works...

Hope you like it and understand everything! C U soon...
Sunshine, February 2003

ozzman.key



00000000 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000010 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020
0000 0000 0000 0000 ........
Generated by Hex Workshop



This site is part of Sunshine's Homepage