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

				    	f   l	e   u	r   
_________________________________________________________________________________________________
  informations - thigo' s keygenme 1

	 difficulty level : 4
	 tools used : softice, rsa-tool
_________________________________________________________________________________________________
  tutorial

	 if you launch the keygenme, it tells you you should put a 'key.dat' file in the
directory. so create a 'key.dat' file and put some characters into. then bpx createfilea. it will
break in the shell. so press f5. it breaks in the keygenme. then you see this :

00401248                 mov     edi, eax
0040124A                 cmp     edi, 0FFFFFFFFh
0040124D                 jnz     short loc_401259
0040124F                 push    offset aYouShouldPutAF ; "You should put a file named key.dat in "...
00401254                 jmp     loc_401448
00401259 ; ---------------------------------------------------------------------------
00401259 
00401259 loc_401259:                             ; CODE XREF: sub_40115E+EFj
00401259                 lea     eax, [ebp-20h]
0040125C                 push    ebx
0040125D                 push    eax
0040125E                 lea     eax, [ebp-1B8h]
00401264                 push    esi				; 100h (256d)
00401265                 push    eax
00401266                 push    edi
00401267                 call    ds:ReadFile
0040126D                 push    edi
0040126E                 call    ds:CloseHandle
00401274                 cmp     dword ptr [ebp-20h], 1Eh
00401278                 jnz     loc_40148D

	so it reads 256 characters of the file. then it looks if the file is 1eh (30d) long. so
put 30 characters in your file. then you see this :

0040127E                 xor     ecx, ecx
00401280 
00401280 loc_401280:                             ; CODE XREF: sub_40115E+143j
00401280                 xor     byte ptr unk_40D290[ecx], 54h	; 'T'
00401287                 xor     byte ptr unk_40D291[ecx], 4Dh	; 'M'
0040128E                 xor     byte ptr unk_40D292[ecx], 47h	; 'G'
00401295                 lea     eax, unk_40D291[ecx]
0040129B                 add     ecx, 3
0040129E                 cmp     ecx, 3Ch
004012A1                 jb      short loc_401280

	so it xors the first byte of the buffer at 0040d290 with 'T', the second with 'M' and the
third with 'G' and do that to 3ch (60d) bytes. so it decrypts the buffer to
'9ZKwiaVmnTZvuQIBmKVTqRca3i6awsDrJoC4erkTD'. then we see this :

004012A3                 push    offset unk_40D290
004012A8                 push    dword ptr [ebp-10h]
004012AB                 call    sub_407130

	if you look what contains the buffer pointed to by the dword at [ebp-10h] after the call,
you see that we converted the number we decrypted in a bignum. we recognize the miracl library. a
bit before, we had this :

00401233                 mov     dword ptr [edi+230h], 3Ch

	so we can guess that the conversion base is 3ch (60d). then we have this :

004012B0                 lea     eax, [ebp-1B8h]
004012B6                 push    eax
004012B7                 lea     eax, [ebp-24h]
004012BA                 push    dword ptr [ebp-20h]
004012BD                 push    eax
004012BE                 call    sub_401000

	here, it converts the content of the 'key.dat' file in a bignum. the function used is
bytes_to_big, that is, it won' t convert '01234' to 000000001h 000001234h, but to 000000002h
031323334h 000000030h. then we have this :

004012C3                 push    dword ptr [ebp-14h]
004012C6                 push    dword ptr [eax]
004012C8                 call    sub_403FF0

	it simply copies the bignum from the file content to a new bignum. then we have this :

004012CD                 push    dword ptr [ebp-24h]
004012D0                 call    sub_403C10
004012D5                 push    dword ptr [ebp-1Ch]
004012D8                 push    38CB201h
004012DD                 call    sub_4035B0

	the first call deletes the bignum at [ebp-24h], and the second creates a bignum that is
000000001h 0038cb201h. then we have this :

004012E2                 lea     eax, [ebp-10h]		; '9ZKwiaVmnTZvuQIBmKVTqRca3i6awsDrJoC4erkTD' bignum
004012E5                 push    eax			; (B9B9BCDA766CC754AF5A3AA6A4302E0C62B455B6977488F9CDAD8F2F9479h)
004012E6                 lea     eax, [ebp-1Ch]		; 38CB201h bignum
004012E9                 push    eax
004012EA                 lea     eax, [ebp-14h]		; file content bignum
004012ED                 push    eax
004012EE                 lea     eax, [ebp-24h]		; clear bignum
004012F1                 push    eax
004012F2                 call    sub_401057

	if we look at the miracl.h file, and we search function accepting 4 bignums as
parameters, we find this :

extern void  powmod(_MIPT_ big,big,big,big);
extern void  nres_lucas(_MIPT_ big,big,big,big);

	we can guess that the function used here is powmod. that is :

	[ebp-24h] = file content^38cb201h mod (9ZKwiaVmnTZvuQIBmKVTqRca3i6awsDrJoC4erkTD)

	so this is rsa-240 decryption of the file content. so we have to factorize
n=B9B9BCDA766CC754AF5A3AA6A4302E0C62B455B6977488F9CDAD8F2F9479h into two prime numbers p and q.
we find p=CDD0DEA72F2AF6DCBFB08ADFF44E43h and q=E702D159FB761B66A1E85D3FDE8C93h, since the
decryption key is d=38CB201h, we compute the encryption key
e=78076BDC2928F59C2ABB141DE14F6F73B43D1EEADBAEC09D09E3F1A69E11h

	then we have this :

004012F7                 push    dword ptr [ebp-18h]
004012FA                 push    dword ptr [eax]
004012FC                 call    sub_403FF0
00401301                 add     esp, 40h
00401304                 push    dword ptr [ebp-24h]
00401307                 call    sub_403C10
0040130C                 push    esi
0040130D                 lea     eax, [ebp-1B8h]
00401313                 push    ebx
00401314                 push    eax
00401315                 call    _memset
0040131A                 lea     eax, [ebp-1B8h]
00401320                 push    eax
00401321                 lea     eax, [ebp-18h]
00401324                 push    0FFh
00401329                 push    eax
0040132A                 call    sub_401040

	so the first call copies the decrypted file content into a new bignum.
the second clears the bignum at [ebp-24h], and the third fills the buffer that contained the read
file with 00h bytes, the fourth copies the decrypted file content into the cleared buffer as
bytes, that is, without the first bignum dword that indicates the number of dwords in the number.
then we have this :

0040132F                 mov     cl, [ebp-1B8h]
00401335                 add     esp, 1Ch
00401338                 xor     eax, eax
0040133A 
0040133A loc_40133A:                             ; CODE XREF: sub_40115E+1EBj
0040133A                 mov     [ebp+eax-68h], cl
0040133E                 mov     cl, [ebp+eax-1B7h]
00401345                 inc     eax
00401346                 cmp     cl, 20h
00401349                 jnz     short loc_40133A

	so it copies the characters from the decrypted buffer until it reaches a 020h byte (' ').
then we have this :

0040134B                 mov     cl, [ebp+eax-1B7h]
00401352                 mov     [ebp+eax-68h], bl
00401356                 inc     eax
00401357                 xor     esi, esi
00401359 
00401359 loc_401359:                             ; CODE XREF: sub_40115E+20Ej
00401359                 inc     eax
0040135A                 mov     [ebp+esi-90h], cl
00401361                 inc     esi
00401362                 mov     cl, [ebp+eax-1B8h]
00401369                 cmp     cl, 20h
0040136C                 jnz     short loc_401359

	so it puts a 00h byte after the buffer that we wrote, and copies the other decrypted
characters to a new buffer until it reaches a 020h byte. then we have this :

0040136E                 inc     eax
0040136F                 mov     [ebp+esi-90h], bl
00401376                 xor     edx, edx
00401378                 lea     ecx, [ebp+eax-1B8h]
0040137F                 mov     al, [ebp+eax-1B8h]
00401386 
00401386 loc_401386:                             ; CODE XREF: sub_40115E+235j
00401386                 inc     ecx
00401387                 mov     [ebp+edx-0B8h], al
0040138E                 inc     edx
0040138F                 mov     al, [ecx]
00401391                 cmp     al, bl
00401393                 jnz     short loc_401386

	so it puts a 00h byte after the buffer that we wrote, and copies the last decrypted
characters, until it reaches a 00h byte, but since our decrypted buffer has been copied on a
buffer that was initialized with 00h bytes, we won' t have to include the last 00h byte in the
string we' ll have to encrypt. so the string we' ll have to encrypt looks like this :

buffer1,' ',buffer2,' ',buffer3

	then we have this :

00401395                 lea     eax, [ebp-68h]
00401398                 push    offset aThigo   ; "Thigo"
0040139D                 push    eax
0040139E                 mov     [ebp+edx-0B8h], bl
004013A5                 call    ds:lstrcmpA
004013AB                 test    eax, eax
004013AD                 jnz     loc_40148D

	so it puts a 00h character after the buffer that we wrote, and compares buffer1 with
'Thigo'. so buffer1 must be 'Thigo'. change it so we can continue. then we have this :

004013B3 loc_4013B3:                             ; CODE XREF: sub_40115E+272j
004013B3                 mov     cl, [ebp+eax-90h]
004013BA                 cmp     cl, 61h
004013BD                 jl      loc_40148D
004013C3                 cmp     cl, 7Ah
004013C6                 jg      loc_40148D
004013CC                 inc     eax
004013CD                 cmp     eax, 6
004013D0                 jb      short loc_4013B3

	so it looks if the 6 first chars of buffer2 are greater or equal to 'a' and less or equal
to 'z'. so we can guess that buffer2 will be 6 characters, that are [a..z]. change them so we can
continue. we can guess that buffer3 is our name. so our string to encrypt looks like this :

'Thigo',' ',6 chars([a..z]),' ',name

	then we have this :

004013D2                 lea     eax, [ebp-214h]
004013D8                 push    eax
004013D9                 call    sub_402F70
004013DE                 lea     eax, [ebp-90h]
004013E4                 push    6
004013E6                 push    eax
004013E7                 lea     eax, [ebp-214h]
004013ED                 push    eax
004013EE                 call    sub_402F9F
004013F3                 lea     eax, [ebp-214h]
004013F9                 push    eax
004013FA                 lea     eax, [ebp-40h]
004013FD                 push    eax
004013FE                 call    sub_403042

	if you look at the first call, you see that it initializes some chaining variables, that
are the sha-1 chaining variables. then the second call initializes the hash, and the third call
performs the actual sha-1 hashing to the 6 first characters of buffer2 and writes the hash in the
buffer at [ebp-40h]. then we have this :

00401403                 mov     esi, offset unk_40D040
00401408                 add     esp, 18h
0040140B                 xor     edi, edi
0040140D                 mov     eax, esi
0040140F 
0040140F loc_40140F:                             ; CODE XREF: sub_40115E+2C3j
0040140F                 mov     cl, [ebp+edi-40h]
00401413                 xor     [eax], cl
00401415                 inc     eax
00401416                 inc     edi
00401417                 cmp     edi, 14h
0040141A                 jnz     short loc_40141E
0040141C                 xor     edi, edi
0040141E 
0040141E loc_40141E:                             ; CODE XREF: sub_40115E+2BCj
0040141E                 cmp     byte ptr [eax], 0FEh
00401421                 jnz     short loc_40140F

	so it uses the hash to decrypt a buffer at 0040d040. it xors the 14h (20d) first bytes of
the buffer with the 14h characters of the hash, then do the same with the next 14h bytes of the
buffer until it reaches a 0feh byte. then we see this :

00401423                 lea     eax, [ebp-2Ch]
00401426                 push    eax
00401427                 push    40h
00401429                 push    17Fh
0040142E                 push    esi
0040142F                 call    ds:VirtualProtect
00401435                 lea     eax, [ebp-68h]
00401438                 push    eax
00401439                 lea     eax, [ebp-0B8h]
0040143F                 push    eax
00401440                 call    esi ; unk_40D040
00401442                 pop     ecx
00401443                 lea     eax, [ebp-68h]
00401446                 pop     ecx
00401447                 push    eax
00401448 
00401448 loc_401448:                             ; CODE XREF: sub_40115E+F6j
00401448                                         ; sub_40115E+334j
00401448                 push    3ECh
0040144D                 push    dword ptr [ebp+8]
00401450                 call    ds:SetDlgItemTextA

	so it call the buffer that we decrypted with 'Thigo' and our name as parameters. then it
sets a text in the edit control, so we can guess that the call to the decrypted buffer will
generate a registered message. so the first 3 bytes of the encrypted buffer are 0b8h, 04ch and
065h. the first 3 bytes of the hash must be so that when they are xored with the first 3 bytes of
the encrypted buffer, they are the first 3 byte of a regular proc, that is the byte corresponding
to push ebp, mov ebp,esp, that is 055h, 08bh, 0ech. so we have this :

0b8h xor BYTE1 = 055h
04ch xor BYTE2 = 08bh
065h xor BYTE3 = 0ech

	so :

BYTE1 = 055h xor 0b8h = 0edh
BYTE2 = 08bh xor 04ch = 0c7h
BYTE3 = 0ech xor 065h = 089h

	so we have to bruteforce these 6 characters to find the corresponding hash. we can guess
that it is a verb, since it' s between 'Thigo' and your name. after some time i' ve found this :
'agphab'. if we write it, it doesn' t work because the rest of the procedure has no meaning.
'bwzrcn' 'cqnnzu' 'fcszuw' 'fzwwjy'
'gszjcd' 'hdyfur' 'hlzezb' 'hstndx'
'hwyzui' 'jisffh' 'lbpqze' 'lgqabi'
'nmbblj' 'oqmbkx' 'qnippw' 'rcqntw'
'rmrgyt' 'ufound'

	so we can try 'ufound'. it works. so now we have to do the following :

	get the user name
	cat the user name to the string 'Thigo ufound '
	encrypt it
	padd it at left to 30 characters with 00h bytes
	write the data in a 'key.dat' file
_________________________________________________________________________________________________
  final words

	 it was a nice keygen with some cryptography. the problem is that the computer might
crash if the buffer that we decrypt is not the right one.
_________________________________________________________________________________________________
  roy|fleur

