Intro
Now really original and interesting asm-coded win32 crackmes are pretty rare people preferring to write in hll's and producing 300k of code..... But here is a really interesting and novel, asm-coded, nice analysis crackme :)
Target
The crackme states "+++++ PacMe was made by Kwazy Webbit of DREAD --- INFO: Keyfile protection. No patching allowed.", so we have to produce a keyfile.
Analysis
The approach I took was a straightforward disassembly, and analysis by hand. I have just pulled out the interesting pieces of code below, but it is possible to quickly disassemble the whole program and take a good look at it.
;******************************************************************* ; below is a small routine which just adds all the characters in ; a string (our name) to arrive at a pseudo random byte for xorring ; with the real serial (the problem pathway). ; for 'Cronos' this is 74h ;******************************************************************* create_xor_value: ; XREFS First: 1000:00401724 Number : 1 1000:00401000 33c0 xor eax, eax 1000:00401002 33d2 xor edx, edx 1000:00401004 33c9 xor ecx, ecx 1000:00401006 8a0dfa344000 mov cl, [namelength] 1000:0040100c be88324000 mov esi, offset 403288h ; XREFS First: 1000:00401014 Number : 1 1000:00401011 ac lodsb 1000:00401012 03d0 add edx, eax 1000:00401014 e2fb loop 401011h 1000:00401016 8815fb344000 mov [xorvalue], dl 1000:0040101c c3 ret ;******************************************************************* ; and this is the small routine which just xors the pathway string ; (the serial) with the number generated from our name. when we have ; the solution we have to xor each byte with the value to get the ; final key for the keyfile. ;******************************************************************* xor_pathway: ; XREFS First: 1000:004010e8 Number : 1 1000:0040101d 8a15fb344000 mov dl, [xorvalue] 1000:00401023 b912000000 mov ecx, 12h 1000:00401028 b8e8344000 mov eax, offset pathway ; XREFS First: 1000:00401030 Number : 1 1000:0040102d 3010 xor [eax], dl 1000:0040102f 40 inc eax 1000:00401030 e2fb loop 40102dh 1000:00401032 c3 ret ;******************************************************************* ; this subroutine makes one move in the maze according to the value ; of al. the key is: ; 0-move up ; 1-move right ; 2-move down ; 3-move left ;******************************************************************* make_move: ; XREFS First: 1000:00401110 Number : 1 1000:00401033 55 push ebp 1000:00401034 8bec mov ebp, esp 1000:00401036 83c4f8 add esp, -08h 1000:00401039 8b1584314000 mov edx, [mapoffset] 1000:0040103f 8955fc mov [ebp-04h], edx 1000:00401042 0ac0 or al, al 1000:00401044 7509 jnz 40104fh 1000:00401046 832d8431400010 sub dword ptr [mapoffset], 10h 1000:0040104d eb1f jmp 40106eh ; XREFS First: 1000:00401044 Number : 1 1000:0040104f 3c01 cmp al, 01h 1000:00401051 7508 jnz 40105bh 1000:00401053 ff0584314000 inc dword ptr [mapoffset] 1000:00401059 eb13 jmp 40106eh ; XREFS First: 1000:00401051 Number : 1 1000:0040105b 3c02 cmp al, 02h 1000:0040105d 7509 jnz 401068h 1000:0040105f 83058431400010 add dword ptr [mapoffset], 10h 1000:00401066 eb06 jmp 40106eh ; XREFS First: 1000:0040105d Number : 1 1000:00401068 ff0d84314000 dec dword ptr [mapoffset] ; XREFS First: 1000:0040104d Number : 3 1000:0040106e 8b1584314000 mov edx, [mapoffset] 1000:00401074 8a02 mov al, [edx] ;******************************************************************* ; note a quick check to see if we hit a wall is passed back to the ; caller ;******************************************************************* 1000:00401076 3c2a cmp al, "*" 1000:00401078 7506 jnz 401080h 1000:0040107a 33c0 xor eax, eax 1000:0040107c c9 leave 1000:0040107d c3 ret 1000:0040107e eb db eb 1000:0040107f 33 db 33 ;'3' ; XREFS First: 1000:00401078 Number : 1 ;******************************************************************* ; and here we have the check to see if we have arrived at the ; destination point yet and completed our task. ;******************************************************************* 1000:00401080 3c58 cmp al, "X" 1000:00401082 752f jnz 4010b3h 1000:00401084 6a00 push 00h 1000:00401086 8d1559334000 lea edx, [s_Success__] 1000:0040108c 52 push edx 1000:0040108d 8d15ec324000 lea edx, [s_Congratulations___Mail_me__KwazyWebb] 1000:00401093 52 push edx 1000:00401094 6a00 push 00h 1000:00401096 8d15ac174000 lea edx, [_MessageBoxA] 1000:0040109c ffd2 call edx 1000:0040109e 8d157b324000 lea edx, [s_Cracked_by___] 1000:004010a4 52 push edx 1000:004010a5 ff3520344000 push dword ptr [403420h] 1000:004010ab 8d15dc174000 lea edx, [_SetWindowTextA] 1000:004010b1 ffd2 call edx ;******************************************************************* ; otherwise we just make the move in the maze ;******************************************************************* ; XREFS First: 1000:00401082 Number : 1 1000:004010b3 8b1584314000 mov edx, [mapoffset] 1000:004010b9 c60243 mov byte ptr [edx], "C" 1000:004010bc 8b55fc mov edx, [ebp-04h] 1000:004010bf c60220 mov byte ptr [edx], 20h 1000:004010c2 b801000000 mov eax, 01h 1000:004010c7 c9 leave 1000:004010c8 c3 ret ;******************************************************************* ; this routine passes two-bits at a time from a byte into the maze ; moving routine, which moves a 'C' through a maze in memory, until ; the target is reached, or until you hit a wall..... this all being ; from the serial number, and the correct traversal of the maze is ; the correct serial number....... ;******************************************************************* main_check: ; XREFS First: 1000:00401742 Number : 1 1000:004010c9 55 push ebp 1000:004010ca 8bec mov ebp, esp 1000:004010cc 83c4fc add esp, -04h 1000:004010cf 6865334000 push offset reset_maze 1000:004010d4 68bc314000 push offset reset_maze2 1000:004010d9 e83a070000 call _lstrcpyA 1000:004010de c70584314000cc314000 mov dword ptr [mapoffset], offset map 1000:004010e8 e830ffffff call xor_pathway 1000:004010ed c645fe00 mov byte ptr [ebp-02h], 00h 1000:004010f1 33c0 xor eax, eax 1000:004010f3 33c9 xor ecx, ecx ; XREFS First: 1000:00401128 Number : 1 1000:004010f5 c645ff08 mov byte ptr [ebp-01h], 08h ; XREFS First: 1000:0040111f Number : 1 1000:004010f9 806dff02 sub byte ptr [ebp-01h], 02h 1000:004010fd 0fb64dfe movzx ecx, [ebp-02h] 1000:00401101 81c1e8344000 add ecx, offset pathway 1000:00401107 8a01 mov al, [ecx] 1000:00401109 8a4dff mov cl, [ebp-01h] 1000:0040110c d2e8 shr al, cl 1000:0040110e 2403 and al, 03h 1000:00401110 e81effffff call make_move 1000:00401115 85c0 test eax, eax 1000:00401117 7411 jz 40112ah 1000:00401119 0fb655ff movzx edx, [ebp-01h] 1000:0040111d 85d2 test edx, edx 1000:0040111f 75d8 jnz 4010f9h 1000:00401121 fe45fe inc byte ptr [ebp-02h] 1000:00401124 807dfe12 cmp byte ptr [ebp-02h], 12h 1000:00401128 75cb jnz 4010f5h ; XREFS First: 1000:00401117 Number : 1 1000:0040112a c9 leave 1000:0040112b c3 ret ;******************************************************************* ; take note of this piece of code. It opens the keyfile (name is ; 'kwazyweb.bit') and reads one byte, followed by a string of length ; equal to the first byte, directly next to a string saying ; 'cracked by ' and so we deduce this is our name. this is followed ; by a 18 byte string, the key, which is used in the routines above. ; the key itself consists of 18 bytes which are made up of four sets ; of two bits, each set of two bits is a number 0-3 which determines ; the direction a 'C' in a maze is moved, until the 'C' crashes into ; a wall '*', or gets to the target, an 'X' via the paths '.'. ;******************************************************************* 1000:0040169a 6a00 push 00h 1000:0040169c 6880000000 push 80h 1000:004016a1 6a03 push 03h 1000:004016a3 6a00 push 00h 1000:004016a5 6a03 push 03h 1000:004016a7 6800000080 push 80000000h 1000:004016ac 8d1592314000 lea edx, [s_KwazyWeb_bit] 1000:004016b2 6872732e2e push "..sr" 1000:004016b7 686c616d65 push "emal" 1000:004016bc 686f6d6520 push " emo" 1000:004016c1 686e672073 push "s gn" 1000:004016c6 6866757369 push "isuf" 1000:004016cb 6820636f6e push "noc " 1000:004016d0 684a757374 push "tsuJ" 1000:004016d5 83c41c add esp, 1ch 1000:004016d8 52 push edx 1000:004016d9 e81c010000 call _CreateFileA 1000:004016de 83f8ff cmp eax, -01h 1000:004016e1 7464 jz 401747h 1000:004016e3 a344344000 mov [403444h], eax 1000:004016e8 6a00 push 00h 1000:004016ea 6848344000 push offset 403448h 1000:004016ef 6a01 push 01h 1000:004016f1 68fa344000 push offset namelength 1000:004016f6 ff3544344000 push dword ptr [403444h] 1000:004016fc e811010000 call _ReadFile 1000:00401701 0fb605fa344000 movzx eax, [namelength] 1000:00401708 85c0 test eax, eax 1000:0040170a 743b jz 401747h 1000:0040170c 6a00 push 00h 1000:0040170e 6848344000 push offset 403448h 1000:00401713 50 push eax 1000:00401714 6888324000 push offset 403288h 1000:00401719 ff3544344000 push dword ptr [403444h] 1000:0040171f e8ee000000 call _ReadFile 1000:00401724 e8d7f8ffff call create_xor_value 1000:00401729 6a00 push 00h 1000:0040172b 6848344000 push offset 403448h 1000:00401730 6a12 push 12h 1000:00401732 68e8344000 push offset pathway 1000:00401737 ff3544344000 push dword ptr [403444h] 1000:0040173d e8d0000000 call _ReadFile 1000:00401742 e882f9ffff call main_check ; XREFS First: 1000:004016e1 Number : 2 1000:00401747 ff3544344000 push dword ptr [403444h] 1000:0040174d e8a2000000 call _CloseHandle ; XREFS First: 1000:00401694 Number : 1 1000:00401752 eb15 jmp 401769h ; XREFS First: 1000:00401658 Number : 1 1000:00401754 ff7514 push dword ptr [ebp+14h] 1000:00401757 ff7510 push dword ptr [ebp+10h] 1000:0040175a ff750c push dword ptr [ebp+0ch] 1000:0040175d ff7508 push dword ptr [ebp+08h] 1000:00401760 e817000000 call _DefWindowProcA 1000:00401765 c9 leave 1000:00401766 c21000 ret 10h ; XREFS First: 1000:004012f9 Number : 12 1000:00401769 33c0 xor eax, eax 1000:0040176b c9 leave 1000:0040176c c21000 ret 10h |
All along in the disassembly I have been indicating a maze in memory, and this is probably best seen with a hexeditor when the presence of the maze is fairly obvious. It is shown below, in ASCII form. |
**************** C*......*...**** .*.****...*....* .*..**********.* ..*....*...*...* *.****.*.*...*** *.*....*.******* ..*.***..*.....* .*..***.**.***.* ...****....*X..* **************** |
The solution is moving the 'C' to the 'X', using only the paths '.'. And here it is in binary, and in hex, using the directions given in the code above. |
Our binary moves: (00=0=up,01=1=right,10=2=down,11=3=left) 10101001 10101011 10100101 00010000 01010100 00111111 00110000 01010101 01100101 00010110 01010110 10111110 11110011 11101010 11101001 01010000 01010101 10101111 Hex Equivalent: a9 ab a5 10 54 3f 30 55 65 16 56 be f3 ea e9 50 55 af |
Finally we xor with our magic value (74h for 'Cronos') to give the following final hex file: |
07 43 72 6F 6E 6F 73 00 // note, this is the 'Cronos' string. DD DF D1 64 20 4B 44 21 // and the solution above xorred with 74h 11 62 22 CA 87 9E 9D 24 21 DB |
And so thats it, we simply create a file called KwazyWeb.bit and put the above bytes in, and rerun and we are finished.
Conclusions
One of the best crackmes I have seen for while, well worth studying and tracing through.
{Cronos}