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

				    	f   l	e   u	r   
_________________________________________________________________________________________________
  informations - penta-crack by mercure

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

	 the main part of this tutorial has been made with ida, and softice has been used to
make some checks. launch the crackme. you see that you can draw line between 5 circles that
represents a pentagon.

	 so dissasemble the crackme with ida. we see this :

004010E1 _WinMain@16     proc near               ; CODE XREF: start+13Ap
004010E1 
004010E1 var_1C          = dword ptr -1Ch
004010E1 var_14          = dword ptr -14h
004010E1 arg_0           = dword ptr  8
004010E1 arg_4           = dword ptr  0Ch
004010E1 arg_C           = dword ptr  14h
004010E1 
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+arg_4], edi
004010EF                 jnz     short loc_4010FE
004010F1                 push    [ebp+arg_0]
004010F4                 call    sub_4011FF

	so look into sub_4011ff. we see 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 aPentacrack ; "Pentacrack"
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

	so this call is making some initializations for the program. we see that the wndproc is
sub_4013a1. so go there and rename the proc to wndproc. we can see how it is working :

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        ; uMsg=02h (WM_DESTROY) ?
004013B2                 sub     eax, 0Dh        ; uMsg=0fh (WM_PAINT) ?
004013B5                 jz      _paint
004013BB                 sub     eax, 6Fh
004013BE                 jz      short _displaychange ; uMsg=07eh (WM_DISPLAYCHANGE) ?
004013C0                 sub     eax, 182h
004013C5                 jz      short _mousemove ; uMsg=0200h (WM_MOUSEMOVE) ?
004013C7                 dec     eax
004013C8                 jz      short _lbuttondown ; uMsg=0201h (WM_LBUTTONDOWN) ?
004013CA                 dec     eax
004013CB                 jz      short _lbuttonup ; uMsg=0202h (WM_LBUTTONUP) ?
004013CD                 push    [ebp+lParam]
004013D0                 push    [ebp+wParam]
004013D3                 push    [ebp+uMsg]
004013D6                 push    [ebp+hWnd]
004013D9                 call    ds:DefWindowProcA ; no interesting message found, default processing
004013DF                 jmp     locret_4014AE

	we can examinate _destroy, it simply exits the program. _displaychange simply displays a
messagebox that says the display has changed. in _mousemove we see this :

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

	processmousemove is this :

00401950 processmousemove proc near              ; CODE XREF: wndproc+8Cp
00401950 
00401950 arg_0           = dword ptr  4
00401950 arg_4           = dword ptr  8
00401950 
00401950                 cmp     dword_405098, 0FFFFFFFFh
00401957                 jz      short locret_401974
00401959                 cmp     dword_407770, 1
00401960                 jnz     short locret_401974
00401962                 mov     eax, [esp+arg_0]
00401966                 mov     dword_407768, eax
0040196B                 mov     eax, [esp+arg_4]
0040196F                 mov     dword_40776C, eax
00401974 
00401974 locret_401974:                          ; CODE XREF: processmousemove+7j
00401974                                         ; processmousemove+10j
00401974                 retn
00401974 processmousemove endp

	it saves some variables, but nothing seems important right now. it looks if dword_405098
is -1, so we can guess that this dword tells if we need to draw a line while the mouse is moving
(if we have clicked in a circle before moving it). we' ll start by examinating _lbuttondown :

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_407A84
00401416                 call    ds:SetCapture
0040141C                 jmp     loc_4014AC

	so it pushes the xPos and yPos of the location where we clicked, and calls
processbuttondown.

004018AD processbuttondown proc near             ; CODE XREF: wndproc+68p
004018AD 
004018AD xPos            = dword ptr  4
004018AD yPos            = dword ptr  8
004018AD 
004018AD                 mov     eax, dtProgState
004018B2                 sub     eax, 0
004018B5                 jz      short loc_4018C5 ; eax=0 ?
004018B7                 dec     eax
004018B8                 jz      short loc_4018D0 ; eax=1 ?
004018BA                 dec     eax
004018BB                 dec     eax
004018BC                 jnz     short locret_4018CF ; eax=3 ?
004018BE                 and     dword_407764, 0
004018C5 
004018C5 loc_4018C5:                             ; CODE XREF: processbuttondown+8j
004018C5                 mov     dtProgState, 1
004018CF 
004018CF locret_4018CF:                          ; CODE XREF: processbuttondown+Fj
004018CF                                         ; processbuttondown+47j
004018CF                 retn
004018D0 ; ---------------------------------------------------------------------------
004018D0 
004018D0 loc_4018D0:                             ; CODE XREF: processbuttondown+Bj
004018D0                 mov     ecx, [esp+yPos]
004018D4                 mov     eax, [esp+xPos]
004018D8                 push    ecx
004018D9                 push    eax
004018DA                 mov     dword_407768, eax
004018DF                 mov     dword_40776C, ecx
004018E5                 call    sub_4018FE
004018EA                 pop     ecx
004018EB                 cmp     eax, 0FFFFFFFFh
004018EE                 pop     ecx
004018EF                 mov     dword_405098, eax
004018F4                 jnz     short locret_4018CF
004018F6                 and     dtProgState, 0
004018FD                 retn
004018FD processbuttondown endp

	at the beginning, it checks if a dword is 0, 1 or 3. if it is 0, it changes it to 3 and
exit. if it is 3, it reinitializes a dword, change the first dword to 1 and exit. if it is 1, we
call sub_4018fe with xPos and yPos as parameters. if you check with softice, you' ll see that at
the beginning of the program, there is a text screen, that disappears if you click once, and
dtProgState is 0. then it is 1, to indicate that the program is ready to receive the input from
the user. we can guess that when we enter too much data and the program displays a 'trying to
bruteforce' message, we are in state 3, as we see that it doesn' t process the message, and
reinitializes a dword at 00407764. we can guess that this dword is our serial. so we rename it.
now we can examinate the call to sub_4018fe. we see this :

b_4018FE      proc near               ; CODE XREF: processbuttondown+38p
004018FE                                         ; processbuttonup+1Ap
004018FE 
004018FE xPos            = dword ptr  8
004018FE yPos            = dword ptr  0Ch
004018FE 
004018FE                 push    esi
004018FF                 xor     esi, esi
00401901 
00401901 loc_401901:                             ; CODE XREF: sub_4018FE+2Cj
00401901                 movzx   eax, byte ptr unk_405088[esi]
00401908                 push    eax
00401909                 movzx   eax, byte ptr aCsQk[esi] ; "+qK"
00401910                 push    eax
00401911                 push    [esp+8+yPos]
00401915                 push    [esp+0Ch+xPos]
00401919                 call    sub_401935
0040191E                 add     esp, 10h
00401921                 cmp     eax, 40h
00401924                 jl      short loc_401931
00401926                 inc     esi
00401927                 cmp     esi, 5
0040192A                 jl      short loc_401901
0040192C                 or      eax, 0FFFFFFFFh
0040192F                 pop     esi
00401930                 retn
00401931 ; ---------------------------------------------------------------------------
00401931 
00401931 loc_401931:                             ; CODE XREF: sub_4018FE+26j
00401931                 mov     eax, esi
00401933                 pop     esi
00401934                 retn
00401934 sub_4018FE      endp

	so it pushes a byte from unk_405088, a byte from aCsQk and our mouse x and y positions,
and then it makes a call to sub_401935. then it checks the result, and if eax < 40h, we put esi
in eax and we return, else we check the other bytes of unk_405088 and aCsQk, and if we have
checked 5 bytes and we found nothing, we put -1 in eax and we return. we can feel something, we
are working with a pentagon, and we check 5 bytes. so we look at sub_401935. we see this :

00401935 sub_401935      proc near               ; CODE XREF: sub_4018FE+1Bp
00401935 
00401935 xPos            = dword ptr  4
00401935 yPos            = dword ptr  8
00401935 xCoord          = dword ptr  0Ch
00401935 yCoord          = dword ptr  10h
00401935 
00401935                 mov     ecx, [esp+yCoord]
00401939                 mov     eax, [esp+xCoord]
0040193D                 sub     ecx, [esp+yPos]
00401941                 sub     eax, [esp+xPos]
00401945                 mov     edx, ecx
00401947                 imul    eax, eax
0040194A                 imul    edx, ecx
0040194D                 add     eax, edx
0040194F                 retn
0040194F sub_401935      endp


	if we examinate the proc, we can guess that the byte pushed are the coords of a point of
the pentagon. this proc computes (xCoord-xPos)^2 + (yCoord-yPos)^2, so it computes the square of
the length between the center of a pentagon point to the mouse position. so we can rename the
procedure to computelength. so we see that if the value returned is lower than 040h (64d), that
is, if the length between the center of the circle of the pentagon we are checking and the mouse
position is lower than 8, we return the number of the circle in wich is the mouse. if we checked
all the circles, then we return -1. so we can rename sub_4018fe isptincircle. so we return to
processbuttondown. we see that we put the result in dword_405098, so we can rename it dtStartPos.
if we haven' t clicked in a circle, it puts 0 in dtProgState, so we can guess that it will
display the penta-crack text screen. we can rename the 2 strings of 5 bytes to yCoords for
unk_405088 and xCoords for aCsQk. so now we can check _lbuttonup. wee see 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+14h]
004013F5                 push    eax             ; xPos
004013F6                 call    processbuttonup
004013FB                 jmp     short loc_401432

	so it is similar to _lbuttondown. so we check processbuttonup. we see this :
00401975 processbuttonup proc near               ; CODE XREF: wndproc+55p
00401975 
00401975 xPos            = dword ptr  4
00401975 yPos            = dword ptr  8
00401975 
00401975                 cmp     dtProgState, 1
0040197C                 jnz     short locret_4019B4
0040197E                 cmp     dtStartPos, 0FFFFFFFFh
00401985                 jz      short loc_4019AD
00401987                 push    [esp+yPos]
0040198B                 push    [esp+4+xPos]
0040198F                 call    isptincircle
00401994                 pop     ecx
00401995                 cmp     eax, 0FFFFFFFFh
00401998                 pop     ecx
00401999                 mov     dword_40509C, eax
0040199E                 jz      short loc_4019AD
004019A0                 cmp     eax, dtStartPos
004019A6                 jz      short loc_4019AD
004019A8                 call    sub_4019B5
004019AD 
004019AD loc_4019AD:                             ; CODE XREF: processbuttonup+10j
004019AD                                         ; processbuttonup+29j ...
004019AD                 or      dtStartPos, 0FFFFFFFFh
004019B4 
004019B4 locret_4019B4:                          ; CODE XREF: processbuttonup+7j
004019B4                 retn
004019B4 processbuttonup endp

	we see that if dtProgState is not 1, or if dtStartPos=-1, that is we haven' t clicked in
a mouse circle, we do not check the user input. else we check if our mouse is in a circle. we put
the result in dword_40509c, so we can rename it to dtEndPos. if we haven' t released the mouse
button in a circle, or if we released it in the same circle as the one we clicked in, it exits.
else, it calls sub_4019b5. so we look at it. we see this :

004019B5 sub_4019B5      proc near               ; CODE XREF: processbuttonup+33p
004019B5                 mov     eax, dtStartPos
004019BA                 mov     edx, dtEndPos
004019C0                 cmp     eax, edx
004019C2                 jle     short loc_4019D5
004019C4                 mov     ecx, eax
004019C6                 mov     eax, edx
004019C8                 mov     edx, ecx
004019CA                 mov     dtStartPos, eax
004019CF                 mov     dtEndPos, edx
004019D5 
004019D5 loc_4019D5:                             ; CODE XREF: sub_4019B5+Dj
004019D5                 mov     ecx, dword_405070[eax*4]
004019DC                 push    1
004019DE                 add     ecx, edx
004019E0                 sub     ecx, eax
004019E2                 pop     eax
004019E3                 dec     ecx
004019E4                 shl     eax, cl
004019E6                 xor     dtSerial, eax
004019EC                 retn
004019EC sub_4019B5      endp

	so we see that it checks if dtStartPos < dtEndPos. if yes, it process the datas, if not,
it inverts dtStartPos and dtEndPos, and process the datas. we see that it puts a value in ecx
depending of dtStartPos. so we can rename dword_405070 to dtTable. we see that dtTable is
[0,4,7,9]. then it puts 1 << (dtEndPos - dtStartPos - 1 + dtTable[dtStartPos*4]) in eax, and xor
dtSerial with eax. so we now how to enter our serial. we can rename the procedure to
updateserial. so now we' ll make the things clearer.

	first, we' ll check xCoords and yCoords. we have this :

00405080 xCoords         db 96h                  ; DATA XREF: sub_4015DC+29r
00405080                                         ; sub_401633+5Eo ...
00405081                 db 0E1h ; 
00405082                 db 0BBh ; +
00405083                 db  71h ; q
00405084                 db  4Bh ; K

00405088 yCoords         db  4Bh ; K             ; DATA XREF: sub_4015DC+22r
00405088                                         ; sub_401633+50o ...
00405089                 db  96h ; 
0040508A                 db 0F0h ; 
0040508B                 db 0F0h ; 
0040508C                 db  96h ; 

	so we deduce this :

		(0)
	    (4)     (1)
	      (3) (2)

	now we can guess that the serial is 10 bits long, and it' s entered like this :

	a line (0)-(1) puts 1 in bit 1
	a line (0)-(2) puts 1 in bit 2
	a line (0)-(3) puts 1 in bit 3
	a line (0)-(4) puts 1 in bit 4
	a line (1)-(2) puts 1 in bit 5
	a line (1)-(3) puts 1 in bit 6
	a line (1)-(4) puts 1 in bit 7
	a line (2)-(3) puts 1 in bit 8
	a line (2)-(4) puts 1 in bit 9
	a line (3)-(4) puts 1 in bit 10

	so now we have to see where is the check if the serial is valid. we can return to
processmousemove to see if we see the things clearer now. we see this :

00401950 processmousemove proc near              ; CODE XREF: wndproc+8Cp
00401950 
00401950 xPos            = dword ptr  4
00401950 yPos            = dword ptr  8
00401950 
00401950                 cmp     dtStartPos, 0FFFFFFFFh
00401957                 jz      short locret_401974
00401959                 cmp     dtProgState, 1
00401960                 jnz     short locret_401974
00401962                 mov     eax, [esp+xPos]
00401966                 mov     dword_407768, eax
0040196B                 mov     eax, [esp+yPos]
0040196F                 mov     dword_40776C, eax
00401974 
00401974 locret_401974:                          ; CODE XREF: processmousemove+7j
00401974                                         ; processmousemove+10j
00401974                 retn
00401974 processmousemove endp


	so we can rename dword_407768 to xCurrent and dword_40776c to yCurrent. these dwords
holds the current positions of the mouse, to draw a line when we move the mouse. so now we can
check _paint. we see this :

0040145F _paint:                                 ; CODE XREF: wndproc+14j
0040145F                 lea     eax, [ebp+var_40]
00401462                 push    eax
00401463                 push    [ebp+hWnd]
00401466                 call    ds:BeginPaint
0040146C                 call    sub_401804
00401471                 xor     ecx, ecx
00401473                 push    0CC0020h
00401478                 push    ecx
00401479                 push    ecx
0040147A                 push    dword_407A7C
00401480                 mov     eax, 12Ch
00401485                 push    eax
00401486                 push    eax
00401487                 push    ecx
00401488                 push    ecx
00401489                 push    dword_407A80
0040148F                 call    ds:BitBlt
00401495                 lea     eax, [ebp+var_40]
00401498                 push    eax
00401499                 push    [ebp+hWnd]
0040149C                 call    ds:EndPaint
004014A2                 jmp     short loc_4014AC

	so we can examinate sub_401804. wee see this :

00401804 sub_401804      proc near               ; CODE XREF: wndproc+CBp
00401804                 push    dword_407A78
0040180A                 push    offset unk_407A60
0040180F                 push    dword_407A7C
00401815                 call    ds:FillRect
0040181B                 call    sub_40182C
00401820                 mov     eax, dtProgState
00401825                 jmp     off_4051B0[eax*4]
00401825 sub_401804      endp

	that is really interesting. the call to sub_40182c just draws some things. but then we
jump with a jump table at off_4051b0, according to dtProgState. so we can rename off_4051b0 to
dtJmpTable. we see this :

004051B0 dtJmpTable      dd offset sub_4014B2    ; DATA XREF: sub_401804+21r
004051B0                                         ; dtProgState=0
004051B4                 dd offset sub_40155B    ; dtProgState=1
004051B8                 dd offset sub_4017C7    ; dtProgState=2
004051BC                 dd offset sub_4017F5    ; dtProgState=3

	if we check sub_4014b2, we see that it displays the penta-crack text screen. if we check
sub_4017f5, we see that it displays the 'trying to bruteforce' text screen. if we check
sub_4017c7, we see that it displays the 'oh yes' string. so we have to get dtProgState=2. so now
we can examinate sub_40155b. we see this :

0040155B sub_40155B      proc near               ; CODE XREF: sub_401804+21j
0040155B                                         ; DATA XREF: .data:004051B4o
0040155B                 push    esi
0040155C                 push    dword_405090
00401562                 call    sub_401633
00401567                 pop     ecx
00401568                 mov     esi, eax
0040156A                 call    sub_4015DC
0040156F                 cmp     byte ptr [esi+1], 0
00401573                 jnz     short loc_401586
00401575                 mov     eax, dword_405094
0040157A                 mov     dtProgState, 2
00401584                 jmp     short loc_40158B
00401586 ; ---------------------------------------------------------------------------
00401586 
00401586 loc_401586:                             ; CODE XREF: sub_40155B+18j
00401586                 mov     eax, dword_405090
0040158B 
0040158B loc_40158B:                             ; CODE XREF: sub_40155B+29j
0040158B                 push    eax
0040158C                 call    sub_401594
00401591                 pop     ecx
00401592                 pop     esi
00401593                 retn
00401593 sub_40155B      endp

	so it is really interesting, we see a mov dtProgState, 2. so we can check sub_4015dc, but
we find nothing interesting, it only draws the line between the circle in wich we clicked and the
current position of the mouse. so we see, that for dtProgState to be set to 2, we have to get the
byte ptr [esi+1] to be 0. we see that esi gets the return value of sub_401633. before calling
this procedure, we push dword_405090 wich is a pointer to the 'Bad Pattern' message. so we can
rename it. so we can check sub_401633 and rename it checkserial. we see this :

00401633 checkserial     proc near               ; CODE XREF: sub_40155B+7p
00401633                                         ; sub_4017C7+6p
00401633 
00401633 var_C           = dword ptr -0Ch
00401633 var_8           = dword ptr -8
00401633 var_4           = dword ptr -4
00401633 arg_0           = dword ptr  4
00401633 
00401633                 mov     eax, dtSerial
00401638                 sub     esp, 0Ch
0040163B                 cmp     dword_407778, eax
00401641                 push    ebx
00401642                 push    ebp
00401643                 push    esi
00401644                 push    edi
00401645                 jz      short loc_40166C
00401647                 inc     dword_407774
0040164D                 cmp     dword_407774, 0Ch
00401654                 mov     dword_407778, eax
00401659                 jnz     short loc_40166C
0040165B                 and     dword_407774, 0
00401662                 mov     dtProgState, 3
0040166C 
0040166C loc_40166C:                             ; CODE XREF: checkserial+12j
0040166C                                         ; checkserial+26j
0040166C                 push    dword_407A70
00401672                 push    dword_407A7C
00401678                 call    ds:SelectObject
0040167E                 mov     eax, ptBadPattern
00401683                 mov     [esp+1Ch+var_C], offset yCoords
0040168B                 dec     [esp+1Ch+var_C]
0040168F                 push    1
00401691                 mov     [esp+20h+var_8], offset xCoords
00401699                 mov     [esp+20h+arg_0], eax
0040169D                 dec     [esp+20h+var_8]
004016A1                 pop     edi
004016A2                 mov     [esp+1Ch+var_4], offset dtTable
004016AA 
004016AA loc_4016AA:                             ; CODE XREF: checkserial+FEj
004016AA                 cmp     edi, 4
004016AD                 mov     ebp, edi
004016AF                 jg      short loc_401725
004016B1 
004016B1 loc_4016B1:                             ; CODE XREF: checkserial+F0j
004016B1                 mov     eax, [esp+1Ch+var_4]
004016B5                 mov     esi, ebp
004016B7                 push    1
004016B9                 add     esi, [eax]
004016BB                 pop     ebx
004016BC                 sub     esi, edi
004016BE                 mov     ecx, esi
004016C0                 shl     ebx, cl
004016C2                 and     ebx, dtSerial
004016C8                 jz      short loc_401706
004016CA                 mov     eax, [esp+1Ch+var_C]
004016CE                 push    0
004016D0                 movzx   eax, byte ptr [eax+edi]
004016D4                 push    eax
004016D5                 mov     eax, [esp+24h+var_8]
004016D9                 movzx   eax, byte ptr [eax+edi]
004016DD                 push    eax
004016DE                 push    dword_407A7C
004016E4                 call    ds:MoveToEx
004016EA                 movzx   eax, byte ptr ss:yCoords[ebp]
004016F1                 push    eax
004016F2                 movzx   eax, ss:xCoords[ebp]
004016F9                 push    eax
004016FA                 push    dword_407A7C
00401700                 call    ds:LineTo
00401706 
00401706 loc_401706:                             ; CODE XREF: checkserial+95j
00401706                 mov     eax, [esp+1Ch+arg_0]
0040170A                 mov     al, [eax]
0040170C                 push    eax
0040170D                 call    sub_4017AC
00401712                 pop     ecx
00401713                 mov     ecx, esi
00401715                 sar     ebx, cl
00401717                 cmp     eax, ebx
00401719                 jnz     short loc_40171F
0040171B                 inc     [esp+1Ch+arg_0]
0040171F 
0040171F loc_40171F:                             ; CODE XREF: checkserial+E6j
0040171F                 inc     ebp
00401720                 cmp     ebp, 4
00401723                 jle     short loc_4016B1
00401725 
00401725 loc_401725:                             ; CODE XREF: checkserial+7Cj
00401725                 add     [esp+1Ch+var_4], 4
0040172A                 inc     edi
0040172B                 lea     eax, [edi-1]
0040172E                 cmp     eax, 3
00401731                 jle     loc_4016AA
00401737                 push    dword_407A74
0040173D                 push    dword_407A7C
00401743                 call    ds:SelectObject
00401749                 xor     esi, esi
0040174B 
0040174B loc_40174B:                             ; CODE XREF: checkserial+16Bj
0040174B                 movzx   eax, byte ptr yCoords[esi]
00401752                 lea     edi, yCoords[esi]
00401758                 lea     ebx, xCoords[esi]
0040175E                 push    0
00401760                 push    eax
00401761                 movzx   eax, byte ptr [ebx]
00401764                 add     eax, 4
00401767                 push    eax
00401768                 push    dword_407A7C
0040176E                 call    ds:MoveToEx
00401774                 movzx   ecx, byte ptr [ebx]
00401777                 movzx   eax, byte ptr [edi]
0040177A                 lea     edx, [ecx+4]
0040177D                 push    eax
0040177E                 push    edx
0040177F                 push    eax
00401780                 lea     edi, [eax+4]
00401783                 push    edx
00401784                 push    edi
00401785                 add     eax, 0FFFFFFFCh
00401788                 push    edx
00401789                 add     ecx, 0FFFFFFFCh
0040178C                 push    eax
0040178D                 push    ecx
0040178E                 push    dword_407A7C
00401794                 call    ds:Arc          ; Draw an elliptical arc
0040179A                 inc     esi
0040179B                 cmp     esi, 5
0040179E                 jl      short loc_40174B
004017A0                 mov     eax, [esp+1Ch+arg_0]
004017A4                 pop     edi
004017A5                 pop     esi
004017A6                 pop     ebp
004017A7                 pop     ebx
004017A8                 add     esp, 0Ch
004017AB                 retn
004017AB checkserial     endp

	it' s a bit big, but lots of things aren' t used in the serial check. what it does it
that it looks if less than 11 lines have been drawn, if not, it reinitializes the serial and
displays the 'trying to bruteforce' message, then it checks if a certain bit of dtSerial is set,
if yes, it draws the line corresponding to it. then it checks the serial, and then it draws some
things. at the end we see this :

004017A0                 mov     eax, [esp+1Ch+arg_0]

	so the byte ptr [eax+1] must be 0 for us to be regged. so we look what is done with
arg_0. at the beginning, it is a pointer to the string 'Bad Pattern'. then we have this in the
loops :

00401706 loc_401706:                             ; CODE XREF: checkserial+95j
00401706                 mov     eax, [esp+1Ch+arg_0]
0040170A                 mov     al, [eax]
0040170C                 push    eax
0040170D                 call    sub_4017AC
00401712                 pop     ecx
00401713                 mov     ecx, esi
00401715                 sar     ebx, cl
00401717                 cmp     eax, ebx
00401719                 jnz     short loc_40171F
0040171B                 inc     [esp+1Ch+arg_0]

	so that seems interesting. to have the byte ptr [arg_0+1] to be 0, we have to inc it 10
times, and there is 10 checks that are done to the serial to check it' s bits. so we can
examinate sub_4017ac. what it does is that it counts the number of bits sets in eax, and returns
1 if this number is even, and 0 if it is odd. so the results corresponding to the string
'Bad Pattern' are :

	'Bad Pattern'
	 10001011110

	it incs arg_0 if the corresponding bit in our serial is set. so we can guess that our
serial has to be this. so bits 1, 5, 7,8, 9 and 10 are set. we can forget the bit corresponding
to 'n', as we have to inc arg_0 only 10 times. so we have to draw a line between :

	(0)-(1)
	(1)-(2)
	(1)-(4)
	(2)-(3)
	(2)-(4)
	(3)-(4)

		(0).
	            \
	    (4);----(1)
              \ ', /
	      (3)-(2)
_________________________________________________________________________________________________
  final words

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

