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

				    	f   l	e   u	r   
_________________________________________________________________________________________________
  informations - thigo keygenme 2

	 difficulty level : 4
	 tools used : softice, procdump, resourcestudio, ida
_________________________________________________________________________________________________
  tutorial

	 we don' t see a way to check if our datas are valid. thigo hides this in every
keygenme. so, since the keygenme is packed, dump it, and edit it with a resource editor. you see
that all labels have an id that is -1 except the 'Thigo' one. so launch the crackme and click on
'Thigo'. you see a messagebox, so that' s the way to check our name and serial.

	 so enter a name and a serial, bpx getdlgitemtexta and click on 'Thigo'. it takes the
name. look if a name has been entered. if yes, it takes the serial, and looks if it is at least
14h (20d) characters long. so enter a serial that is at least 20 characters long. then you see
this :

0040A295                 lea     eax, [esp+3B4h]
0040A29C                 push    ebx
0040A29D                 push    eax
0040A29E                 lea     ecx, [esp+108h]
0040A2A5                 call    sub_40A870
0040A2AA                 lea     ecx, [esp+18h]
0040A2AE                 push    ecx
0040A2AF                 lea     ecx, [esp+104h]
0040A2B6                 call    sub_40A920

	if you look at the parameter passed to the first call, you notice 4 chaining variables.
we can guess that the name will be hashed. the chaining variables are reminiscent of md5 since
it' s on 128 bits, but they do not correspond to the real md5 chaining variables. here they are :

	01324ad68h 098765478h 0fda85ec9h 09645687ah

	the first call initializes some buffers. the real hashing is performed in the second
call, in the call to 0040a990 at 0040a8ca. if you examinate the hash, you see that it looks a
great deal like md5, but some changes have been made to the algorithm. the chaining variables
have been changed, some constants have been changed, and there are some changes in the functions.
so the easiest way to do the hash for us will be to ripp the algorithm and to apply some changes
to make it work. so we have to ripp this proc. we know that the 2 parameters that have to be
pushed are the pointer regular md5 buffer containing the name (name followed by a 080h byte,
padded with 0 to 64 bytes, and the last 8 bytes of the buffer are the size in bits) and the
pointer to the chaining variables. so we' ll have to initialize the buffer and the chaining
variables, and then do the hashing.

	 then we have this :

0040A2BB                 lea     edx, [esp+2B4h]
0040A2C2                 push    11h
0040A2C4                 lea     eax, [esp+1B8h]
0040A2CB                 push    edx
0040A2CC                 push    eax
0040A2CD                 call    [KERNEL32!lstrcpyn]

	it copies the first 10h (16d) characters of the serial to a buffer. then we have this :

0040A2D3                 lea     ecx, [esp+1B4h]
0040A2DA                 mov     dword ptr [ebp+238h], 10h
0040A2E4                 push    ecx
0040A2E5                 push    esi
0040A2E6                 call    sub_40DFE0

	the first 16 characters of the serial i entered were A1B1C1D1A2B2C2D2. if we look at what
the buffer in esi contains after the call, we can see this :

	000000002h 0A2B2C2D2h 0A1B1C1D1h

	so it converted these characters in hexadecimal. in fact, it is a bignum routine. that is
a library that has been made to treat big numbers. here we can recognize the miracl library. so
you better download it. the format of bignum is this : first dwords contains the number of dwords
in the number, and the following dwords are the number, last bytes first (that is, if our number
is 0123456789ABCDEF, we' ll have this : 000000002h 089ABCDEFh 001234567h). the problem with the
bignum routines is that they are often long and complex. here, since it is the miracl library
that has been used, we can use the documentation that has been given with it to guess what
function does what. the :

	mov     dword ptr [ebp+238h], 10h

	means that the conversions are made in base 10h (16d)

	then we have this :

0040A2EB                 lea     edx, [esp+1BCh]
0040A2F2                 mov     dword ptr [ebp+238h], 100h
0040A2FC                 push    edx
0040A2FD                 push    esi
0040A2FE                 call    sub_40E270

	so we are in base 100h (256d). if we look at what contains the buffer pointed to by edx
after the call, we see that it has simply copied the number that we converted to the buffer,
without the first dword that was the number of dwords in the number. then we have this :

0040A303                 add     esp, 10h
0040A306                 lea     eax, [esp+18h]
0040A30A                 lea     ecx, [esp+5DCh]
0040A311                 push    eax
0040A312                 push    10h
0040A314                 call    sub_406C40

	if we look at what is pushed, we see the hash of the name and a buffer that is
reminiscent of a blowfish buffer. if you examinate the call, you see that it initializes a
blowfish buffer with the hash of the name as a key. then you have this :

0040A319                 push    0
0040A31B                 push    40344Ch
0040A320                 lea     ecx, [esp+40h]
0040A324                 push    8
0040A326                 lea     edx, [esp+1C0h]
0040A32D                 push    ecx
0040A32E                 push    edx
0040A32F                 lea     ecx, [esp+5F0h]
0040A336                 call    sub_4075C0

	that call performs the actual blowfish decryption, on the 2 dwords corresponding to the
16 first characters of the serial. then it looks if the first character is a 'T', of if the
second character is a 'h', a 'i' or a 'g', if yes, it looks if the fourth character is a 'h'. so
we see that more than one serial is possible. since we' ll see that the 4 first characters won' t
have any other action in the registration, we' ll choose them as 'Thig' and the 5th character
must be 'h'. now we should write a program that will encrypt these characters with the hash of
the name as key so we can go further in the program. but we' ll first examinate what comes just
next. so each time it checks the characters, change the zero flag, so we can continue in the
keygenme. then we see this :

0040A382                 lea     edx, [esp+3Ch]
0040A386                 push    4
0040A388                 push    edx
0040A389                 lea     ecx, [esp+160h]
0040A390                 call    sub_40D2B0
0040A395                 mov     ecx, 32h
0040A39A                 xor     eax, eax
0040A39C                 lea     edi, [esp+38h]
0040A3A0                 repe stosd
0040A3A2                 lea     eax, [esp+38h]
0040A3A6                 lea     ecx, [esp+158h]
0040A3AD                 push    eax
0040A3AE                 call    sub_40D370
0040A3B3                 lea     ecx, [esp+38h]
0040A3B7                 push    ecx
0040A3B8                 push    esi
0040A3B9                 call    sub_40DFE0
0040A3BE                 lea     edx, [esp+40h]
0040A3C2                 mov     dword ptr [ebp+238h], 3Ch
0040A3CC                 push    edx
0040A3CD                 push    esi
0040A3CE                 call    sub_40E270
0040A3D3                 add     esp, 10h
0040A3D6                 lea     eax, [esp+38h]
0040A3DA                 push    eax
0040A3DB                 push    403424h
0040A3E0                 call    [KERNEL32!lstrcmp]

	if we look at the parameter pushed in the first call, we see the chaining variables
corresponding to sha-1. it initializes some buffers. then it hashes the 2nd dword that has been
decrypted in the second call. then the 3rd call converts the 5 dwords of the hash in a bignum,
and the :

	mov     dword ptr [ebp+238h], 3Ch

	means that we are now in base 3ch (60d). so it converts the bignum in a ascii string in
base 60, and then compares it with the string 'pxE0vwiw135JHPxQ0C7DiAUgo5B'. so we have to
bruteforce 3 bytes to know what we should enter for the 3 last bytes of the 2 dwords to encrypt.
we have to hash these 3 bytes with a 'h' before (so we have to hash a string in the format hxxx),
then we have to convert this hash in base 60 and then compare with the string. in fact, i
bruteforced it in 15 mins on my computer by testing every possibilities, and i realized that it
was only low case letters. so you can reduce the bruteforcing time to only 26*26*26
possibilities, that is 17576 possibilities (really few). in fact, the string is 'heya', so the
possibilities to test are 4*26*26 + 25*26 = 3356, wich is really few. so the 2 dwords we have
to encrypt are 'Thig' and 'heya'. so now we can write a program that hashes our name and encrypt
the dwords, so it will be easier to continue.

	if we enter the serial, it won' t work. if we examinate the blowfish decryption call, we
see that after it has decrypted the dwords, it xors them with 'Good' and ' luc', so that' s how
we should encrypt our dwords :

	md5modifiedhash(&name);
	blowfishinit(&blowfishcontext,&md5modifiedhash);
	dt1='Thig' xor 'Good';
	dt2='heya' xor ' luc';
	blowfishencrypt(&blowfishcontext,&dt1,&dt2);
	wsprintf(&szSerial,"%08X%08X", dt1, dt2);

	for 'roy' it gave me 'C1AA4DB62B1088E4'. so now we are here :

0040A3EE                 push    offset aD84e28b5c2075f ; "D84E28B5C2075FE923D9B1780878F84EDB86F1B"...
0040A3F3                 push    esi
0040A3F4                 mov     dword ptr [ebp+238h], 10h
0040A3FE                 call    sub_40DFE0

	so we are in base 10h (16d), and it converts the string
'D84E28B5C2075FE923D9B1780878F84EDB86F1B746BDECE01A58D86F88DF1413' to a bignum. then we have :

0040A403                 mov     ecx, 8
0040A408                 xor     eax, eax
0040A40A                 lea     edi, [esp+20h]
0040A40E                 lea     edx, [esp+4BCh]
0040A415                 repe stosd
0040A417                 push    edx
0040A418                 call    sub_407A20
0040A41D                 lea     eax, [esp+3C0h]
0040A424                 push    ebx
0040A425                 lea     ecx, [esp+4C4h]
0040A42C                 push    eax
0040A42D                 push    ecx
0040A42E                 call    sub_407A70
0040A433                 lea     edx, [esp+30h]
0040A437                 lea     eax, [esp+4CCh]
0040A43E                 push    edx
0040A43F                 push    eax
0040A440                 call    sub_407BF0

	in the first call, we see that it initializes some chaining variables. we see that the
variables correspond to haval-256. then it initializes the hash in the second call and performs
the hash in the third call. so it hashes the name with haval-256. then it converts the hash to
a bignum. and then it converts the string 'TMGRoxx' to a bignum in base 60. then we have this :

0040A479                 push    esi			; 'D84E28B5C2075FE923D9B1780878F84EDB86F1B'...
0040A47A                 push    esi			; 'D84E28B5C2075FE923D9B1780878F84EDB86F1B'...
0040A47B                 push    ebx			; 'TMGRoxx'
0040A47C                 push    edi			; the haval-256 hash
0040A47D                 call    sub_40D7E0
0040A482                 add     esp, 44h
0040A485                 lea     edx, [esp+38h]
0040A489                 push    edx
0040A48A                 push    esi
0040A48B                 call    sub_40E270
0040A490                 add     esp, 8
0040A493                 lea     eax, [esp+2C4h]
0040A49A                 lea     ecx, [esp+1B4h]
0040A4A1                 push    eax
0040A4A2                 push    ecx
0040A4A3                 call    [KERNEL32!lstrcpy]
0040A4A9                 lea     edx, [esp+38h]
0040A4AD                 lea     eax, [esp+1B4h]
0040A4B4                 push    edx
0040A4B5                 push    eax
0040A4B6                 call    [KERNEL32!lstrcmp]

	so it makes a computation with the number corresponding to
'D84E28B5C2075FE923D9B1780878F84EDB86F1B'...,  the number corresponding to 'TMGRoxx' and the
haval-256 hash, then it writes the corresponding number in base 60 and copies the last
characters of the serial to a buffer, and compare this buffer with the number in base 60. if they
are the same, we are regged. so now we have to determine wich function is sub_40d7e0. so we take
a look at miracl.h, and we search function that accept 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 here is powmod. so we have to perform the haval-256 hash,
then a powmod, and then convert the resulting number to base 60.
_________________________________________________________________________________________________
  final words

	 it was a nice keygenme with lot of cryptography
_________________________________________________________________________________________________
  roy|fleur

