		             solution for Kwazy Webbit's PacMe Crackme          
        		           solved By Nuno1 on 24 july 1999              
        		  any comments can be sent to nuno_2@hotmail.com       


Information :
	Cracker    : Nuno1 
	Date       : 24 july 1999
	Level      : 4
	Protection : KeyFile Missing , Simple Encryption Method.

	Tools used :
	  - SoftIce
	  - Borland C for Keyfile Generator.

Hey Crackers !

this is one of the cracks i really enjoy cracking. not an easy one but really not hard one.

-- Information --

when you run the program , you see an UNREGISTERD label , and also a CHECK Button.
you cant write on the UNREGISTERD label . just a check button left ;)

-- The Crack --

because of it , you can understand that its not a serial / code crack .
let see if its a KeyFile crack .. 

bpx on CreateFileA to break if a file is open .

press the check button .. yep .. it jump to the trap .. ;)

CreateFileA function gets on EDX the name of the file .
lets do "d edx" .. you can see a strange filename called "KwazyWeb.bit" .
ok ... copy your autoexec.bat to this directory and rename it KwazyWeb.bit.
lets press the check button again ..
ok .. now press F12 and u will see Eax return a number (if it was -1 it means not exists)
so we made the first step ..
lets contine .. you will see this code :

:004016D9 E81C010000              KERNEL32.CreateFileA             
:004016DE 83F8FF                  cmp eax, FFFFFFFF        <- check if the KwazyWeb.bit exist
:004016E1 7464                    je 00401747
:004016E3 A344344000              mov dword ptr [00403444], eax    <-moving the handle of the file
:004016E8 6A00                    push 00000000 
:004016EA 6848344000              push 00403448                <-pushing a variable
:004016EF 6A01                    push 00000001                <-pushing 1
:004016F1 68FA344000              push 004034FA                <-pushing another variable. 
:004016F6 FF3544344000            push dword ptr [00403444]    <-and the handle of the file
:004016FC E811010000              KERNEL32.ReadFile            <-call the readfile.

ok , whats really going on here.

the ReadFile function get some params .. all we really cares are the PUSH 00000001 and 
PUSH 004034FA .. the PUSH 1 is really the length to read from the file.
the push 4034fa is where to copy the read chars..

ok , so he read one byte to 4034fa.
look at 4034fa after Readfile you will notice the first char that in your file.

lets contine :

:00401701 0FB605FA344000          movzx eax, byte ptr [004034FA]  <- eax get the first char
:00401708 85C0                    test eax, eax                   <- check if it 0
:0040170A 743B                    je 00401747              
:0040170C 6A00                    push 00000000                   
:0040170E 6848344000              push 00403448
:00401713 50                      push eax                        <- push the first char
:00401714 6888324000              push 00403288                   <- another variable
:00401719 FF3544344000            push dword ptr [00403444]       <- the handle of the file.
:0040171F E8EE000000              KERNEL32.ReadFile               <- calling ReadFile

ok .. so now he called readfile again but this time he used the first char as the new
length to read .. is it a len of any string ? maybe but we dont care yet ;).

after that there is a call .. let see what is this call :

:00401000 33C0                    xor eax, eax                  <- eax = 0
:00401002 33D2                    xor edx, edx                  <- edx = 0
:00401004 33C9                    xor ecx, ecx                  <- ecx = 0
:00401006 8A0DFA344000            mov cl, byte ptr [004034FA]   <- cl = length
:0040100C BE88324000              mov esi, 00403288             <- esi = the new chars we read
:00401011 AC                      lodsb                         <- read a char from esi and
                                                                <- and esi + 1
:00401012 03D0                    add edx, eax                  <- edx + char
:00401014 E2FB                    loop 00401011                 <- loop length times
:00401016 8815FB344000            mov byte ptr [004034FB], dl   <- take the low byte of dx and
							        <- keep it in 4034fb
:0040101C C3                      ret

as we can understand .. this is just calculate the sum of the characters we read and keep
it in a variable (4034fb)

lets return to after the call :

:00401729 6A00                    push 00000000       
:0040172B 6848344000              push 00403448
:00401730 6A12                    push 00000012               <- push 12
:00401732 68E8344000              push 004034E8               <- push it
:00401737 FF3544344000            push dword ptr [00403444]   <- push our file handle
:0040173D E8D0000000              Call KERNEL32.ReadFile      <- readfile 
:00401742 E882F9FFFF              call 004010C9               <- ??
:00401747 FF3544344000            push dword ptr [00403444]   <- file handle
:0040174D E8A2000000              Call KERNEL32.CloseHandle   <- closefile

so we see now that it push 12h as the length param , so he take 12h next characters.
after the strange call he close the file .. so maybe all the answers is in this call.

let check it out :

:004010C9 55                      push ebp
:004010CA 8BEC                    mov ebp, esp
:004010CC 83C4FC                  add esp, FFFFFFFC
:004010CF 6865334000              push 00403365  <- looks like a strange looking maze !?
:004010D4 68BC314000              push 004031BC  <- this is the same as above !
:004010D9 E83A070000              Call KERNEL32.lstrcpyA    <- copy to 403365 the 4031bc string
:004010DE C70584314000CC314000    mov dword ptr [00403184], 004031CC 
:004010E8 E830FFFFFF              call 0040101D    <-another call !          


so he copy a strange looking maze and then calling another function .. let see what is this function

:0040101D 8A15FB344000            mov dl, byte ptr [004034FB]  <- the total we calculate before
:00401023 B912000000              mov ecx, 00000012            <- ecx = 12 ?
:00401028 B8E8344000              mov eax, 004034E8            <- eax = 12 characters we read
:0040102D 3010                    xor byte ptr [eax], dl       <- xor the new characters we read
							       <- with the lowbyte of the total we calc.
:0040102F 40                      inc eax                      <- go to the next char.
:00401030 E2FB                    loop 0040102D                <- loop 12h times.
:00401032 C3                      ret

mmmm .. so now we can see he take the 12 numbers we read last and xor it with the lowbyte
total of characters we read before.


let see now whats happend (returning from the call);


:004010ED C645FE00                mov [ebp-02], 00              <-ebp-2 = 0
:004010F1 33C0                    xor eax, eax                  <-eax=0
:004010F3 33C9                    xor ecx, ecx                  <-ecx=0
:004010F5 C645FF08                mov [ebp-01], 08              <-ebp-1 = 8
:004010F9 806DFF02                sub byte ptr [ebp-01], 02     <-ebp-1 - 2
:004010FD 0FB64DFE                movzx ecx, byte ptr [ebp-02]  <-ecx = ebp-2 
:00401101 81C1E8344000            add ecx, 004034E8             <-ecx=ecx + the start of the xored numbers
:00401107 8A01                    mov al, byte ptr [ecx]        <-al = xored number   
:00401109 8A4DFF                  mov cl, byte ptr [ebp-01]     <-cl = ebp -1
:0040110C D2E8                    shr al, cl                    <-al >> cl ???
:0040110E 2403                    and al, 03                    <-al & 3 (11b)
:00401110 E81EFFFFFF              call 00401033                 <-another call
:00401115 85C0                    test eax, eax                 <-eax = 0 ? jmp
:00401117 7411                    je 0040112A
:00401119 0FB655FF                movzx edx, byte ptr [ebp-01]  <-edx = ebp-1
:0040111D 85D2                    test edx, edx                 <-edx = 0 ?
:0040111F 75D8                    jne 004010F9                  <-if not jmp
:00401121 FE45FE                  inc [ebp-02]                  <-if yes, inc ebp2
:00401124 807DFE12                cmp byte ptr [ebp-02], 12     <-ebp-2 <> 12 ??
:00401128 75CB                    jne 004010F5                  <-then jump
:0040112A C9                      leave                         <-else finish
:0040112B C3                      ret

ok , lets start to make it understanding (even before the call we didnt yet examine.
ebp-2 looks like a counter of 12h because it been increased every time and exit when = 12
ebp-1 = 6 at start (notice the first sub of it with 2) and allways dec by 2 and it also a
      counter , because it test when it 0 .
so we first can understand this is loop in a loop.
we call the first loop outloop and the second loop inloop.

in the inloop he takes one xored number shl it with 6 and keep the two first bits and then
the same with with 4 , 2 and 0. then he exit the loop. the outloop go increase ECX and
thats make the inloop get the next xored number. all this goes until the outloop pass 12h
times.

in other words :

every number from the xored numbers are 4 numbers that are from 0 to 3 (00b,01b,10b and 11b)
each two bits in the byte represent a number from 0-3.
so this is 04h * 12h numbers to pass.

now.. let see what the other call do .. 

:00401033 55                      push ebp
:00401034 8BEC                    mov ebp, esp
:00401036 83C4F8                  add esp, FFFFFFF8
:00401039 8B1584314000            mov edx, dword ptr [00403184] <- edx = the place on the MAZE
							        <- that the char "C" found
:0040103F 8955FC                  mov dword ptr [ebp-04], edx   <-ebp-4 = "C" char
:00401042 0AC0                    or al, al                     <- or al,al
:00401044 7509                    jne 0040104F                  <- jmp if al <> 0
:00401046 832D8431400010          sub dword ptr [00403184], 00000010 <-if 0 add to the pointer
                                                                     <-"C" place 10
:0040104D EB1F                    jmp 0040106E                  <- jmp 40106e
:0040104F 3C01                    cmp al, 01                    <- if al = 1
:00401051 7508                    jne 0040105B                  <- if not go to 40105b
:00401053 FF0584314000            inc dword ptr [00403184]      <-  add to the pointer of "C" 1
:00401059 EB13                    jmp 0040106E                  <- jmp 40106e
:0040105B 3C02                    cmp al, 02                    <- al,2
:0040105D 7509                    jne 00401068                  <- if not go to 401068
:0040105F 83058431400010          add dword ptr [00403184], 00000010 <- add to the ptr of "C" 10
:00401066 EB06                    jmp 0040106E                  <- jmp 
:00401068 FF0D84314000            dec dword ptr [00403184]      <- if not 0,1,2 (means 3) 
                        					<- subthe ptr of "C" 1
:0040106E 8B1584314000            mov edx, dword ptr [00403184] <- here all the jmp come to.
								<- edx = new MAZE place
:00401074 8A02                    mov al, byte ptr [edx]        <- al = MAZE
:00401076 3C2A                    cmp al, 2A                    <- al = '*'
:00401078 7506                    jne 00401080                  <- if not jmp
:0040107A 33C0                    xor eax, eax                  <- if yes eax=0
:0040107C C9                      leave                         <- and leave
:0040107D C3                      ret
:0040107E EB33                    jmp 004010B3
:00401080 3C58                    cmp al, 58                    <- if not "*" is it "X"
:00401082 752F                    jne 004010B3                       

i will cut if it IS 58 and jump to if its not 58.

:004010B3 8B1584314000            mov edx, dword ptr [00403184] <- edx = maze place.
:004010B9 C60243                  mov byte ptr [edx], 43        <- maze place = "C"
:004010BC 8B55FC                  mov edx, dword ptr [ebp-04]   <- old maze place
:004010BF C60220                  mov byte ptr [edx], 20        <- maze = " "
:004010C2 B801000000              mov eax, 00000001             <- eax = 1 and exit.
:004010C7 C9                      leave
:004010C8 C3                      ret

ok .. lets start to understand this maze thing

if you will look at EDX whe it get [403184] you will see this maze :

****************
C*      *   ****
 * ****   *    *
 *  ********** *
  *    *   *   *
* **** * *   ***
* *    * *******
  * ***  *     *
 *  *** ** *** *
   ****    *X  *
****************

you can notice the C and X letters . the place we get into start in the C char.

you can count , the number of * at the first line are 16 (10h) .

ok now let see what the function does really.

all it does is check if the number he got is 0,1,2,3.
if 0 , he sub 10h from the maze place that will bring us in the same X-coord in the maze
but one line up (in the Y-Coord). 
if 1 , he increase the maze place.. it means we moved left. 
so every number really get us to a diffrent position.. (0,1,2,3 is the number of postions !)

so here is the moves :
0 - up
1 - right
2 - down
3 - left

ok so he place it in the new place and check if there is a "*" in it .. 
if there is , he return to the called fuction 0. if its not he return 1.
if its 'X' he jump to a place that said SUCCESS .... ha ! thats it ..
we finish debugging it ... but what now ? what we need to do ?

ok ... here it goes .

as we now know the 12h numbers we pass are really a 12h * 4h moves of the maze .
(you can check the numbers of moves in it you will notice its right ;) ).
but the problem is that we cant just write the numbers in the file and let him read it
because its xored with the total characters we read before ... and now we can also notice
those characters are the registration Name !! 
so he XORED those 12h number with the total sum of the Registration Name !!

this method is really called xored encyption , if you have the xored key you just have to
xor the number with the key and you get the same number !

so all we have to do (as i allready did) is to write a program that sum Registration name 
and have a table with all the steps we need to do , and start to xor it with the sum.
keep all of this in the file and it will be cracked ;)

as you can see , this is the maze soulotion (but with the real numbers for the move)

C 011111 011
2 0    211 2111
2 10          2
21 3330 330 332
 2    0 2 332
 2 0111 2
32 0   32 01111 
2 01   2  0   2 
211    2111 332 

and in a better way to view it :
22212223221101
00111003330100
11111211011211
12233233033222
32211100111122
33

just xor this with the total and you finished .. you are welcome to look at my source code.

-- Notes --

this was a fun crackme for me ... i hope there are more nice crackme like that ;)

hope you learn somthing new ;)

Nuno1 - Nuno2@hotmail.com


