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

				    	f   l	e   u	r   
________________________________________________________________________________________________
::::::::::::::::::::::::::::::::::: i n f o r m a t i o n s ::::::::::::::::::::::::::::::::::::

	 difficulty level : 4
	 tools used : softice, ida
________________________________________________________________________________________________
::::::::::::::::::::::::::::::::::::::: t u t o r i a l ::::::::::::::::::::::::::::::::::::::::

	 disassemble the program, we quickly find the dialog procedure at 00401350, the
generate button command is handled at 0040143f

0040143f __OnGenerate:
00401453	SendMessageA(hWnd, WM_GETTEXT, 101, lpszName);
00401466	SendMessageA(hWnd, WM_GETTEXT, 101, lpszSerial);
00401475	if (CheckSerial(lpszName, lpszSerial))
0040148e		MessageBoxA(hWnd, "Good job, you did it :o) !", "Your serial is correct", MB_ICONINFORMATION);
004014b0	else
004014b0		MessageBoxA(hWnd, "Try again", "Sorry, wrong serial.", MB_ICONERROR);

	so the serial checking routine is at 00401000

	 we see have this :

00401000	BOOL CheckSerial(LPCTSTR lpszName, LPCTSTR lpszSerial)
00401000	{
00401000	int nNameLen
00401000	long lSerial[4];
00401000	ModRMD160_CTX ctxModRMD160;
00401000	ModBLOWFISH_CTX ctxModBlowfish;
00401000	DWORD ModRIPEMD160Digest[5];
00401000	SquareMatrix matSerial, matResult, matCompute;
00401000
00401045	nNameLen = strlen(lpszName);
0040104b	if (nNameLen < 1 || nNameLen > 100)
0040104b	    return FALSE;
00401067	if (!CheckFormat(lpszSerial))
00401071	    return FALSE;
00401071
0040107e	matSerial.SetSize(2)
0040108a	matResult.SetSize(2)
00401096	matCompute.SetSize(2)
00401096
004010a1	AsciiToHex(&lpszSerial, &lSerial);
004010a1
004010ae	ModRMD160Init(&ctxModRMD160);
004010bd	ModRMD160Update(&ctxModRMD160, lpszName, nNameLen);
004010cf	ModRMD160Final(&ModRMD160Digest, &ctxModRMD160);
004010cf
004010e1	ModBlowfishInit(&ModRMD160Digest, &ctxModBlowfish);
004010f6	ModBlowfishEncrypt(&Serial[0], &ctxModBlowfish);
00401108	ModBlowfishEncrypt(&Serial[1], &ctxModBlowfish);
0040111a	ModBlowfishEncrypt(&Serial[2], &ctxModBlowfish);
0040111a
0040114d	matSerial.Coeff[0][0] = Serial[0];
0040115d	matSerial.Coeff[0][1] = Serial[1];
00401173	matSerial.Coeff[1][0] = Serial[2];
0040117c	matSerial.Coeff[1][1] = Serial[3];
00401186	matResult.Coeff[0][0] =  1219698867;
00401190	matResult.Coeff[0][1] = -1639862078;
00401198	matResult.Coeff[1][0] = -1936863006;
0040119c	matResult.Coeff[1][1] = -1251512586;
004011fa	matCompute = (matSerial*matSerial) * 2 + (matSerial*5) + matResult;
004011ff	if (matCompute != 0)
004011ff	    return FALSE
00401225	return TRUE
00401281	}

	the name must be between 1 and 100 characters long
	the CheckFormat call returns TRUE if and only if the serial is 32 characters long, and
the characters are [0-9A-F]
	then the program set the matrices, the code permits to set the matrix size as
paramenter, but the functions have only been designed for 2x2 matrices, so any other value would
make the program bug
	AsciiToHex converts the serial to hex bytes
	then a modified RIPEMD-160 is applied to the name (in the RIPEMD-160 transform function,
the order of parallel rounds has been set to I, F, H, G, J, and at then end, the final sums are
modified (digest[1] = digest[2] + ee + eee, and digest[2] = digest[3] + dd + bbb))
	then a modified blowfish is initialized with the hash (the number of rounds has been set
to 30, the P table has been completed consequently with new elements, the S table has been
altered, and the F function has been modified (it returns (S[2][d]-S[1][b])^(S[0][c]+S[3][a]))
	then the serial is encrypted, by first encrypting Serial[0] and Serial[1], then
Serial[1] and Serial[2], then Serial[2] and Serial[3]
	then the matrices are loaded with the serial and some hardcoded values, and it checks
that 2*matSerial^2 + 5*matSerial + matResult = 0, so we have to solve the following matrix
equation in M2(Z/(2^32)Z) :
  _   _       _   _      _   _
 |S0 S1|2    |S0 S1|    |R0 R1|
2|     |  + 5|     | = -|     |
 |S2 S3|     |S2 S3|    |R2 R3|
                        
knowing R0, R1, R2 and R3
	we find :
 _                   _
|1685024583 1970239794|
|                     |
|1684628530  779381042|
                    
is a solution

	then we have to do this :
	 > get user name
	 > hash it with modified RIPEMD-160
	 > use the hash to initialize the modified blowfish
	 > encrypt the solution matrix by first encrypting S2 and S3, then S1 and S2, then S0
	   and S1
	 > swap the resulting dwords, to get the correct byte ordering for AsciiToHex, and
	   output the result as uppercase hex digit, of width 8
________________________________________________________________________________________________
:::::::::::::::::::::::::::::::::::: f i n a l   w o r d s :::::::::::::::::::::::::::::::::::::

	 it was a nice keygenme, very interesting
________________________________________________________________________________________________
										      roy|fleur

