
				  .@@  @@     .@@.   @@  @@   .@@
				 @@    @@    @@  @@  @@  @@  @@
				 @@    @@    @@  @@  @@  @@  @@
				 @@@@  @@    @@@@'   @@  @@  @@
				 @@    @@    @@      @@  @@  @@
				 @@    @@    @@      @@  @@  @@
				 **    **    **      **  **  **
				 	'   '     ''   

				    	f   l	e   u	r   
_________________________________________________________________________________________________
  informations - oktacrack

	 difficulty level : 2
	 tools used : ida, softice
_________________________________________________________________________________________________
  tutorial

	 launch the crackme. we can draw line between 8 circles that represents an octagon. so
disassemble the crackme. we see this :

004010E1 _WinMain@16:                            ; CODE XREF: start+13Ap
004010E1                 push    ebp
004010E2                 mov     ebp, esp
004010E4                 sub     esp, 1Ch
004010E7                 push    ebx
004010E8                 push    esi
004010E9                 push    edi
004010EA                 xor     edi, edi
004010EC                 cmp     [ebp+0Ch], edi
004010EF                 jnz     short loc_4010FE
004010F1                 push    dword ptr [ebp+8]
004010F4                 call    loc_4011FF

	so go at loc_4011ff. we have this :

004011FF                 push    ebp
00401200                 mov     ebp, esp
00401202                 sub     esp, 28h
00401205                 push    ebx
00401206                 push    esi
00401207                 push    edi
00401208                 xor     edi, edi
0040120A                 mov     esi, offset aOktacrack ; "Oktacrack"
0040120F                 push    edi
00401210                 push    esi
00401211                 call    ds:FindWindowA
00401217                 mov     ebx, eax
00401219                 cmp     ebx, edi
0040121B                 jz      short loc_40123C
0040121D                 push    ebx
0040121E                 call    ds:IsIconic
00401224                 test    eax, eax
00401226                 jz      short loc_401231
00401228                 push    9
0040122A                 push    ebx
0040122B                 call    ds:ShowWindow
00401231 
00401231 loc_401231:                             ; CODE XREF: sub_4011FF+27j
00401231                 push    ebx
00401232                 call    ds:SetForegroundWindow
00401238                 xor     eax, eax
0040123A                 jmp     short loc_4012B3
0040123C ; ---------------------------------------------------------------------------
0040123C 
0040123C loc_40123C:                             ; CODE XREF: sub_4011FF+1Cj
0040123C                 mov     eax, [ebp+arg_0]
0040123F                 push    esi
00401240                 push    eax
00401241                 mov     [ebp+var_28], 3
00401248                 mov     [ebp+var_24], offset sub_4013A1
0040124F                 mov     [ebp+var_20], edi
00401252                 mov     [ebp+var_1C], edi
00401255                 mov     [ebp+var_18], eax
00401258                 call    ds:LoadIconA

	so we see this line :

00401248                 mov     [ebp+var_24], offset sub_4013A1

	that means that the wndproc is sub_4013a1. so go there and rename it wndproc. we have
this :

004013A1 wndproc         proc near               ; DATA XREF: sub_4011FF+49o
004013A1 
004013A1 var_40          = byte ptr -40h
004013A1 hWnd            = dword ptr  8
004013A1 uMsg            = dword ptr  0Ch
004013A1 wParam          = dword ptr  10h
004013A1 lParam          = dword ptr  14h
004013A1 
004013A1                 push    ebp
004013A2                 mov     ebp, esp
004013A4                 sub     esp, 40h
004013A7                 mov     eax, [ebp+uMsg] ; eax is the message being processed
004013AA                 dec     eax
004013AB                 dec     eax
004013AC                 jz      _destroy        ; WM_DESTROY
004013B2                 sub     eax, 0Dh
004013B5                 jz      _paint          ; WM_PAINT
004013BB                 sub     eax, 6Fh
004013BE                 jz      short _displaychange ; WM_DISPLAYCHANGE
004013C0                 sub     eax, 182h
004013C5                 jz      short _mousemove ; WM_MOUSEMOVE
004013C7                 dec     eax
004013C8                 jz      short _lbuttondown ; WM_LBUTTONDOWN
004013CA                 dec     eax
004013CB                 jz      short _lbuttonup ; WM_LBUTTONUP
004013CD                 push    [ebp+lParam]
004013D0                 push    [ebp+wParam]
004013D3                 push    [ebp+uMsg]
004013D6                 push    [ebp+hWnd]
004013D9                 call    ds:DefWindowProcA ; we haven' t found any interesting message, default processing
004013DF                 jmp     locret_4014AE

	_destroy and _displaychange aren' t interesting. so we look at _lbuttondown. we have
this :

004013FD _lbuttondown:                           ; CODE XREF: wndproc+27j
004013FD                 mov     eax, [ebp+lParam]
00401400                 shr     eax, 10h
00401403                 push    eax             ; yPos
00401404                 movzx   eax, word ptr [ebp+lParam]
00401408                 push    eax             ; xPos
00401409                 call    processbuttondown
0040140E                 pop     ecx
0040140F                 pop     ecx
00401410                 push    dword_407B68
00401416                 call    ds:SetCapture
0040141C                 jmp     loc_4014AC

	so we look processbuttondown. we have this :

004018B0 processbuttondown proc near             ; CODE XREF: wndproc+68p
004018B0 
004018B0 xPos            = dword ptr  4
004018B0 yPos            = dword ptr  8
004018B0 
004018B0                 mov     eax, dword_407854
004018B5                 sub     eax, 0
004018B8                 jz      short loc_401901
004018BA                 dec     eax
004018BB                 jnz     short locret_401929
004018BD                 mov     ecx, [esp+yPos]
004018C1                 mov     eax, [esp+xPos]
004018C5                 push    ecx
004018C6                 push    eax
004018C7                 mov     dword_40784C, eax
004018CC                 mov     dword_407850, ecx
004018D2                 call    sub_40192A
004018D7                 pop     ecx
004018D8                 cmp     eax, 0FFFFFFFFh
004018DB                 pop     ecx
004018DC                 mov     dword_405188, eax
004018E1                 jnz     short locret_401929
004018E3                 and     word_4052AE, 0
004018EB                 shr     dword_4052B0, 8
004018F2                 shr     dword_4052B4, 0Ch
004018F9                 and     dword_407854, 0
00401900                 retn
00401901 ; ---------------------------------------------------------------------------
00401901 
00401901 loc_401901:                             ; CODE XREF: processbuttondown+8j
00401901                 mov     eax, dword ptr byte_4052AC
00401906                 mov     dword_407854, 1
00401910                 imul    eax, 10001h
00401916                 shl     dword_4052B0, 8
0040191D                 shl     dword_4052B4, 0Ch
00401924                 mov     dword ptr byte_4052AC, eax
00401929 
00401929 locret_401929:                          ; CODE XREF: processbuttondown+Bj
00401929                                         ; processbuttondown+31j
00401929                 retn
00401929 processbuttondown endp

	so it looks if a dword is 0, if yes it changes it to 1 and exits. if the dword is 1, it
process the position of the mouse. we can guess that this dword indicate the state of the
program. when we launch it, it shows a text screen, and the dword is 0. then when we click on the
text, the dword is 1, to indicate that it is ready to get the user' s input. se we can rename it
dtProgState. when dtProgState is not 0, nor 1, it doesn' t process the input. we can examinate
sub_40192a. we have this :

0040192A sub_40192A      proc near               ; CODE XREF: processbuttondown+22p
0040192A                                         ; processbuttonup+1Ap
0040192A 
0040192A xPos            = dword ptr  8
0040192A yPos            = dword ptr  0Ch
0040192A 
0040192A                 push    esi
0040192B                 xor     esi, esi
0040192D 
0040192D loc_40192D:                             ; CODE XREF: sub_40192A+2Cj
0040192D                 movzx   eax, byte ptr [esi+405178h]
00401934                 push    eax
00401935                 movzx   eax, byte ptr [esi+405170h]
0040193C                 push    eax
0040193D                 push    dword ptr [esp+14h]
00401941                 push    dword ptr [esp+14h]
00401945                 call    sub_401961
0040194A                 add     esp, 10h
0040194D                 cmp     eax, 40h
00401950                 jl      short loc_40195D
00401952                 inc     esi
00401953                 cmp     esi, 8
00401956                 jl      short loc_40192D
00401958                 or      eax, 0FFFFFFFFh
0040195B                 pop     esi
0040195C                 retn

	so it pushes 2 bytes from 2 strings that seems 8 byte long and the positions of the
mouse, and then check if the result is less than 040h (64d), if not, it continue to check the
8 bytes. if he found nothing, it returns -1. we can feel something. we are working with an
octagon, and it checks 8 bytes. so look at sub_401961. we have this :

00401961 sub_401961      proc near               ; CODE XREF: sub_40192A+1Bp
00401961 
00401961 xPos            = dword ptr  4
00401961 yPos            = dword ptr  8
00401961 xCoord          = dword ptr  0Ch
00401961 yCoord          = dword ptr  10h
00401961 
00401961                 mov     ecx, [esp+yCoord]
00401965                 mov     eax, [esp+xCoord]
00401969                 sub     ecx, [esp+yPos]
0040196D                 sub     eax, [esp+xPos]
00401971                 mov     edx, ecx
00401973                 imul    eax, eax
00401976                 imul    edx, ecx
00401979                 add     eax, edx        ; eax=(xCoord-xPos)^2 + (yCoord-yPos)^2
0040197B                 retn
0040197B sub_401961      endp

	so we can guess that the 2 bytes that we push are the coords of the octagon. the
procedure computes the square of the distance between the octagon point we are checking and the
mouse position. so we can rename it computelength. so if the square of the distance is less than
040h, that is if the distance is less than 8, we return the number of the point. so we can rename
sub_40192a isptincircle. so first we can look at the 2 strings. we can rename them xCoords and
yCoords. we have this :

00405170 xCoords         db 96h                  ; DATA XREF: sub_4015F1+29r
00405170                                         ; sub_401648+4Ar ...
00405171                 db 0CAh
00405172                 db 0E1h
00405173                 db 0CAh
00405174                 db 96h
00405175                 db 62h
00405176                 db 4Bh
00405177                 db 62h
00405178 yCoords         db 4Bh                  ; DATA XREF: sub_4015F1+22r
00405178                                         ; sub_401648+40r ...
00405179                 db 62h
0040517A                 db 96h
0040517B                 db 0CAh
0040517C                 db 0E1h
0040517D                 db 0CAh
0040517E                 db 96h
0040517F                 db 62h

	so we can deduce this :

		(0)
	    (7)     (1)

	  (6)	      (2)

	    (5)     (3)
		(4)

	so now we come back to processbuttondown. it puts the result in dword_405188. so we can
rename it to dtStartPos. if we haven' t clicked in a circle, it puts 0 in dtProgState, so we can
guess that it will display the okta-crack text. we can check _mousemove. we see this :

00401421 _mousemove:                             ; CODE XREF: wndproc+24j
00401421                 mov     eax, [ebp+lParam]
00401424                 shr     eax, 10h
00401427                 push    eax             ; yPos
00401428                 movzx   eax, word ptr [ebp+lParam]
0040142C                 push    eax             ; xPos
0040142D                 call    processmousemove
00401432 
00401432 loc_401432:                             ; CODE XREF: wndproc+5Aj
00401432                 pop     ecx
00401433                 pop     ecx
00401434                 jmp     short loc_4014AC

	so we can look processmousemove. we have this :

0040197C processmousemove proc near              ; CODE XREF: wndproc+8Cp
0040197C 
0040197C xPos            = dword ptr  4
0040197C yPos            = dword ptr  8
0040197C 
0040197C                 cmp     dtStartPos, 0FFFFFFFFh
00401983                 jz      short locret_4019A0
00401985                 cmp     dtProgState, 1
0040198C                 jnz     short locret_4019A0
0040198E                 mov     eax, [esp+xPos]
00401992                 mov     dword_40784C, eax
00401997                 mov     eax, [esp+yPos]
0040199B                 mov     dword_407850, eax
004019A0 
004019A0 locret_4019A0:                          ; CODE XREF: processmousemove+7j
004019A0                                         ; processmousemove+10j
004019A0                 retn
004019A0 processmousemove endp

	so we process the mouse position only if dtProgState is 1, and if dtStartPos isn' t -1,
that is, we haven' t clicked in a circle. it stores the current xPos and yPos of the mouse, to
draw a line when we move. so we can rename dword_40784c dtxCurrent and dword_407850 dtyCurrent.
so now we can examinate _lbuttonup. we have this :

004013E4 _lbuttonup:                             ; CODE XREF: wndproc+2Aj
004013E4                 call    ds:ReleaseCapture
004013EA                 mov     eax, [ebp+lParam]
004013ED                 shr     eax, 10h
004013F0                 push    eax             ; yPos
004013F1                 movzx   eax, word ptr [ebp+lParam]
004013F5                 push    eax             ; xPos
004013F6                 call    processbuttonup
004013FB                 jmp     short loc_401432

	it is similar to _lbuttondown. so we can examinate processbuttonup. we have this :

004019A1 processbuttonup proc near               ; CODE XREF: wndproc+55p
004019A1 
004019A1 xPos            = dword ptr  4
004019A1 yPos            = dword ptr  8
004019A1 
004019A1                 cmp     dtProgState, 1
004019A8                 jnz     short locret_4019E0
004019AA                 cmp     dtStartPos, 0FFFFFFFFh
004019B1                 jz      short loc_4019D9
004019B3                 push    [esp+yPos]
004019B7                 push    [esp+4+xPos]
004019BB                 call    isptincircle
004019C0                 pop     ecx
004019C1                 cmp     eax, 0FFFFFFFFh
004019C4                 pop     ecx
004019C5                 mov     dword_40518C, eax
004019CA                 jz      short loc_4019D9
004019CC                 cmp     eax, dtStartPos
004019D2                 jz      short loc_4019D9
004019D4                 call    sub_4019E1
004019D9 
004019D9 loc_4019D9:                             ; CODE XREF: processbuttonup+10j
004019D9                                         ; processbuttonup+29j ...
004019D9                 or      dtStartPos, 0FFFFFFFFh
004019E0 
004019E0 locret_4019E0:                          ; CODE XREF: processbuttonup+7j
004019E0                 retn
004019E0 processbuttonup endp
004019E0 

	so if dtProgState is not 1, or if dtStartPos is -1, that is, we haven' t clicked in a
circle, we don' t process the mouse position. else we check if we have released the mouse in a
circle. we put the result in dword_40518c, so we can rename it dtEndPos. if we haven' t released
the mouse in a circle, or if we released it in the same circle as the one we clicked in, we put
-1 in dtStartPos and we return. so we look at sub_4019e1. we have this :

004019E1 sub_4019E1      proc near               ; CODE XREF: processbuttonup+33p
004019E1                 mov     eax, dtStartPos
004019E6                 mov     ecx, dtEndPos
004019EC                 lea     ecx, [eax+ecx*8]
004019EF                 mov     eax, dword_407848
004019F4                 xor     eax, dword_405070[ecx*4]
004019FB                 mov     ecx, eax
004019FD                 mov     dword_407848, eax
00401A02                 and     ecx, 0FFFFh
00401A08                 shr     eax, 10h
00401A0B                 mov     edx, ecx
00401A0D                 sub     edx, eax
00401A0F                 cmp     edx, dword_4052B0
00401A15                 jnz     short locret_401A32
00401A17                 imul    eax, ecx
00401A1A                 mov     ecx, dword ptr byte_4052AC
00401A20                 add     eax, ecx
00401A22                 xor     eax, ecx
00401A24                 cmp     eax, dword_4052B4
00401A2A                 jnz     short locret_401A32
00401A2C                 inc     dtProgState
00401A32 
00401A32 locret_401A32:                          ; CODE XREF: sub_4019E1+34j
00401A32                                         ; sub_4019E1+49j
00401A32                 retn
00401A32 sub_4019E1      endp

	so that looks interesting. we have a inc dtProgState. we can guess that we' ll have to
get dtProgState=2 to be regged. if you launch softice and put a 2 in dtProgState, you see the
'you did it' message. we can guess that dword_407848 will be our serial. so rename it to
dtSerial. so that' s how we can enter our serial. dword_405070 seems to be a table, so rename it
to dtTable. so we have this :

	ecx=dtStartPos + (dtEndPos*8)
	serial^dtTable[ecx*4]

we see that the table has been built so that if you draw a link between (0) and (1), or (1) and
(0), it will give the same result. if you draw 2 times the same link, it will xors 2 times the
serial with the same value, so it will cancel the line. now if we look at the table, we see
that :

	a line between (0) and (1) puts a 1 in bit 2
	a line between (0) and (2) puts a 1 in bit 3
	a line between (0) and (3) puts a 1 in bit 4
	a line between (0) and (4) puts a 1 in bit 5
	a line between (0) and (5) puts a 1 in bit 6
	a line between (0) and (6) puts a 1 in bit 7
	a line between (0) and (7) puts a 1 in bit 8
	a line between (1) and (2) puts a 1 in bit 9
	a line between (1) and (3) puts a 1 in bit 10
	a line between (1) and (4) puts a 1 in bit 11
	a line between (1) and (5) puts a 1 in bit 12
	a line between (1) and (6) puts a 1 in bit 13
	a line between (1) and (7) puts a 1 in bit 14
	a line between (2) and (3) puts a 1 in bit 15
	a line between (2) and (4) puts a 1 in bit 19
	a line between (2) and (5) puts a 1 in bit 20
	a line between (2) and (6) puts a 1 in bit 21
	a line between (2) and (7) puts a 1 in bit 22
	a line between (3) and (4) puts a 1 in bit 23
	a line between (3) and (5) puts a 1 in bit 24
	a line between (3) and (6) puts a 1 in bit 25
	a line between (3) and (7) puts a 1 in bit 26
	a line between (4) and (5) puts a 1 in bit 27
	a line between (4) and (6) puts a 1 in bit 28
	a line between (4) and (7) puts a 1 in bit 29
	a line between (5) and (6) puts a 1 in bit 30
	a line between (5) and (7) puts a 1 in bit 31
	a line between (6) and (7) puts a 1 in bit 32

	we see that we cannot put a 1 in bit 1, because dtStartPos and dtEndPos should be the
same. we also see that we cannot put a 1 in bits 16, 17 and 18. then it puts the loword of the
serial in ecx and edx, the hiword in eax, and subs edx and eax, that must be the same value as in
dword_4052b0. so rename dword_4052b0 dtVar1. we have dtVar1=0bh. then it muls eax with ecx, puts
in ecx dword_4052ac, that we can rename dtVar2. dtVar2=0aa77h. it adds eax and ecx, xor eax and
ecx, and this must be dword_4052b4. so rename it dtVar3. dtVar3=072cdh. but in processbuttondown,
we have seen this when we click on the textscreen :

00401901                 mov     eax, dtVar2
00401906                 mov     dtProgState, 1
00401910                 imul    eax, 10001h
00401916                 shl     dtVar1, 8
0040191D                 shl     dtVar3, 0Ch
00401924                 mov     dtVar2, eax

	and when we click out of the circles, the values are corrected :

004018E3                 and     word ptr dtVar2+2, 0
004018EB                 shr     dtVar1, 8
004018F2                 shr     dtVar3, 0Ch
004018F9                 and     dtProgState, 0

so in fact, dtVar1 is 0bh << 8, that is 0b00h. dtVar2 is 0aa77h * 010001h = 0aa77aa77h. dtVar3 is
072cd000h. so we have this :

	LOWORD(serial) - HIWORD(serial) = 0b00h
	([LOWORD(serial) * HIWORD(serial)] + 0aa77aa77h) ^ 0aa77aa77h = 072cd000h

	that is :

	LOWORD(serial) - HIWORD(serial) = 0b00h
	LOWORD(serial) * HIWORD(serial) = 02e3d000h

	so :

	LOWORD(serial) = 0b00h + HIWORD(serial)
	[0b00h + HIWORD(serial)] * HIWORD(serial) = 02e3d000h

	so :

	LOWORD(serial) = 0b00h + HIWORD(serial)
	HIWORD(serial) = 01640h

	so :

	LOWORD(serial) = 02140h
	HIWORD(serial) = 01640h

	so :

	serial = 016402140h = 10110010000000010000101000000b

	so we have to draw a line between :

	bits  : 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
	serial:  1  0  1  1  0  0  1  0  0  0  0  0  0  0  0  1  0  0  0  0 1 0 1 0 0 0 0 0 0

	(0)-(6)
	(1)-(2)
	(1)-(7)
	(3)-(4)
	(3)-(7)
	(4)-(5)
	(4)-(7)

		(0)
	    (7)-;---(1)
	      :'      \
	  (6)' |:.    (2)
		. :
	    (5)  | '(3)
	       '(4)'
_________________________________________________________________________________________________
  final words

	 it was a nice crackme, quite unusual.
_________________________________________________________________________________________________
  roy|fleur

