Pacme [Kwazy Webbit]

by

{Cronos}

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}