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

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

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

	 disassemble the keygenme in ida. we find the serial checking routine quite easily.
it' s at 00401000. we see this :

_text:00401046                 call    _MD5Init
_text:0040104B                 push    offset aKeygenme3BisByThigo ; "Keygenme 3 bis by Thigo\n"
_text:00401050                 call    _printf
_text:00401055                 push    offset aGimmeYourKeyBaby ; "Gimme your key baby :\n"
_text:0040105A                 call    _printf
_text:0040105F                 push    offset bfKey
_text:00401064                 call    _gets

	the first call initializes the md5 chaining variables. then it gets the key in bfKey.
then we see this :

_text:00401069                 mov     eax, dword ptr bfKey
_text:0040106E                 xor     ecx, ecx
_text:00401070                 mov     cl, bfKey+1
_text:00401076                 and     eax, 0FFh
_text:0040107B                 xor     edx, edx
_text:0040107D                 add     esp, 0Ch
_text:00401080                 mov     bl, byte ptr ds:MultiByteToWideChar[eax]
_text:00401086                 mov     al, byte ptr ds:MultiByteToWideChar[ecx]

	so it puts the second character of the key in cl and the first in al. then it puts in bl
the byte that is at ds:MultiByteToWideChar + eax. if we consider that the serial can be hex
digits, that is [0..9][A..F], and that we look at what is at address
ds:MultiByteToWideChar + 030h (030h is '0'), we see this :

_rdata:004070C0                 db    0 ;  
_rdata:004070C1                 db    1 ;  
_rdata:004070C2                 db    2 ;  
_rdata:004070C3                 db    3 ;  
_rdata:004070C4 unk_0_4070C4    db    4 ;               ; DATA XREF: unknown_libname_1+4Ar
_rdata:004070C5                 db    5 ;  
_rdata:004070C6                 db    6 ;  
_rdata:004070C7                 db    7 ;  
_rdata:004070C8                 db    8 ;  
_rdata:004070C9                 db    9 ;  
_rdata:004070CA                 db    0 ;  
_rdata:004070CB                 db    0 ;  
_rdata:004070CC                 db    0 ;  
_rdata:004070CD                 db    0 ;  
_rdata:004070CE                 db    0 ;  
_rdata:004070CF                 db    0 ;  
_rdata:004070D0                 db    0 ;  
_rdata:004070D1                 db  0Ah ;  
_rdata:004070D2                 db  0Bh ;  
_rdata:004070D3                 db  0Ch ;  
_rdata:004070D4                 db  0Dh ;  
_rdata:004070D5                 db  0Eh ;  
_rdata:004070D6                 db  0Fh ;  

	wich is quite interesting. this is a table that converts a byte to it' s hexadecimal
value. that is '0' to 0, '1' to 1, ...., 'A' to 0ah, 'B' to 0bh, .... so bl is the hex value of
the first key byte, and al is the value of the second one. then we see this :

_text:0040108C                 mov     dl, bfKey+2
_text:00401092                 xor     ecx, ecx
_text:00401094                 mov     cl, bfKey+3
_text:0040109A                 mov     edi, ds:CreateFileA
_text:004010A0                 shl     bl, 4
_text:004010A3                 add     bl, al
_text:004010A5                 mov     al, byte ptr ds:MultiByteToWideChar[edx]
_text:004010AB                 mov     dl, byte ptr ds:MultiByteToWideChar[ecx]

	so dl is the third key byte and cl is the fourth. then bl is the hex value of the 2
first bytes of the key, that is if the key starts with '12', bl=012h, if the key starts with
'AB', bl=0abh. then it converts the third and fourth characters to their hex value. then we see
this :

_text:004010B1                 push    0               ; hTemplateFile
_text:004010B3                 push    80h             ; dwFlagsAndAttributes
_text:004010B8                 push    3               ; dwCreationDisposition
_text:004010BA                 shl     al, 4
_text:004010BD                 push    0               ; lpSecurityAttributes
_text:004010BF                 push    1               ; dwShareMode
_text:004010C1                 add     al, dl
_text:004010C3                 push    80000000h       ; dwDesiredAccess
_text:004010C8                 push    offset aData_bin ; lpFileName
_text:004010CD                 mov     byte ptr [ebp+dtKeyA], bl
_text:004010D0                 mov     byte ptr [ebp+dtKeyB], al
_text:004010D3                 call    edi ; CreateFileA

	so it converts the third and fourth characters to their hex value in al, then it puts
the hex value of the 2 first characters in dtKeyA, and the one of the 2 next characters in
dtKeyB, and opens data.bin file. then we see this :

_text:004010F3 loc_0_4010F3:                           ; CODE XREF: _CheckSerial+DDj
_text:004010F3                 lea     edx, [ebp+nNumberOfBytesToWrite]
_text:004010F6                 push    0               ; lpOverlapped
_text:004010F8                 push    edx             ; lpNumberOfBytesRead
_text:004010F9                 push    1000h           ; nNumberOfBytesToRead
_text:004010FE                 push    offset bfBuffer ; lpBuffer
_text:00401103                 push    eax             ; hFile
_text:00401104                 call    ds:ReadFile
_text:0040110A                 cmp     [ebp+nNumberOfBytesToWrite], 0F03h
_text:00401111                 jz      short loc_0_401127

	so it reads the file in bfBuffer, and check if it has read 0f03h bytes. then we see
this :

_text:00401127 loc_0_401127:                           ; CODE XREF: _CheckSerial+111j
_text:00401127                 mov     eax, hFile
_text:0040112C                 push    eax             ; hObject
_text:0040112D                 call    ds:CloseHandle
_text:00401133                 mov     ecx, [ebp+nNumberOfBytesToWrite]
_text:00401136                 lea     eax, [ecx-1]
_text:00401139                 cmp     eax, 0FFFFFFFFh
_text:0040113C                 mov     [ebp+NumberOfBytesWritten], eax
_text:0040113F                 jz      short loc_0_4011B3
_text:00401141                 mov     ecx, [ebp+dtKeyA]
_text:00401144                 and     ecx, 0FFh
_text:0040114A                 mov     [ebp+dtKeyA], ecx
_text:0040114D                 mov     ecx, [ebp+dtKeyB]
_text:00401150                 and     ecx, 0FFh
_text:00401156                 mov     [ebp+dtKeyB2], ecx

	so it closes the file, puts the size of the file - 1 in eax, then clean dtKeyA and
dtKeyB, that is, ensure that dtKeyA and dtKeyB are only bytes, and put dtKeyB in dtKeyB2. then
we see this :

_text:00401159 __decryptfile_:                         ; CODE XREF: _CheckSerial+1AEj
_text:00401159                 test    eax, eax
_text:0040115B                 jz      short loc_0_401168
_text:0040115D                 mov     dl, [eax+408AC3h]
_text:00401163                 mov     byte ptr [ebp+NumberOfBytesWritten], dl
_text:00401166                 jmp     short loc_0_40116C
_text:00401168 ; ---------------------------------------------------------------------------
_text:00401168 
_text:00401168 loc_0_401168:                           ; CODE XREF: _CheckSerial+15Bj
_text:00401168                 mov     byte ptr [ebp+NumberOfBytesWritten], 88h
_text:0040116C 
_text:0040116C loc_0_40116C:                           ; CODE XREF: _CheckSerial+166j
_text:0040116C                 mov     edx, [ebp+NumberOfBytesWritten]
_text:0040116F                 mov     cl, al
_text:00401171                 not     cl
_text:00401173                 and     ecx, 0FFh
_text:00401179                 and     edx, 0FFh
_text:0040117F                 xor     ecx, edx
_text:00401181                 xor     edx, edx
_text:00401183                 mov     dl, bfBuffer[eax]
_text:00401189                 xor     ecx, edx
_text:0040118B                 mov     edx, [ebp+dtKeyB2]
_text:0040118E                 imul    ecx, [ebp+dtKeyA]
_text:00401192                 add     ecx, edx
_text:00401194                 and     ecx, 800000FFh
_text:0040119A                 jns     short loc_0_4011A4
_text:0040119C                 dec     ecx
_text:0040119D                 or      ecx, 0FFFFFF00h
_text:004011A3                 inc     ecx
_text:004011A4 
_text:004011A4 loc_0_4011A4:                           ; CODE XREF: _CheckSerial+19Aj
_text:004011A4                 mov     bfBuffer[eax], cl
_text:004011AA                 dec     eax
_text:004011AB                 cmp     eax, 0FFFFFFFFh
_text:004011AE                 jnz     short __decryptfile_

	so it decrypts the file with the 2 byte that we entered as serial as key. 00408ac3h is
bfBuffer-1. then it stores the decrypted text in data.txt. so the algorithm can be rewritten as
this :

i=SIZEOF file-1

while (i<=0) {
	if (i=0) { A=88h}
	else { A=File[i-1] }
	A^=i
	A^=File[i]
	File[i]=A * keyA + keyB
}

	so we have :

	File[i]=File[i-1]^i^File[i] * keyA + keyB

	so we need to find the key to decrypt this text. there are two possible methods. it will
be easy to do, since the key is quite small (there are only 010000h possible values, that is,
65536). for both methods, we need a clean text, that is, first, we need to get a text without
the File[i-1]^i^File[i], so we' ll only work with keyA and keyB. to do this, we can simply run
the keygenme with the serial '0100', so we' ll have File[i]=File[i-1]^i^File[i] * 1 + 0. so then
we get a data.txt file, on wich we have to apply File[i] = File[i] * keyA + keyB to decipher it.

::::::::::::::::::::::: f i r s t   m e t h o d :   b r u t e f o r c e ::::::::::::::::::::::::
	thigo prefers that we don' t use this method, but it can be used here, and will work
quite well, since the keys are small. if data.txt is a text file, it' s very likely that the 4
characters 'the ' will be stored in it. so we can use this algorithm to find a possible key that
will decipher the word 'the ' :

	i=0
	while (i<filesize-4) { // we search 4 characters
		keyA=1
		while (keyA<256) {
			keyB = 't' - File[i] * keyA
			if (File[i+1] * keyA + keyB) = 'h' {
				if (File[i+2] * keyA + keyB) = 'e' {
					if (File[i+3] * keyA + keyB) = ' ' {
						// found possible keyA and keyB
						break
					}
				}
			}
			keyA++
		}
		i++
	}

	in fact, we run through all possible keyA, for each, we make the hypothesis that it' s
the good one, so we compute keyB so that File[i] * keyA + keyB = 't'. then we check if it will
decipher the next bytes as 'h', 'e' and ' '. if not, we check another keyA until we did them
all, then we start from the next character. a fast bruteforce gives 'AD9E' as a possible key. if
you try it, it will decipher correctly both text files. so it looks like the second file has
been encrypted with the same key, so we can skip the decryption of the second file.

::::::::::: s e c o n d   m e t h o d   :   s t a t i s t i c a l   a n a l y s i s ::::::::::::
	a better way will be to count the characters in the file, then to try to guess wich
character they could be, and use this to find the key. since 2 bytes are used for the key,
we' ll only need to identify 2 characters of the file. the most frequent characters are :

	0c3h: 320 times
	0cah: 557 times

	so 0c3h could be 'e' and 0cah could be ' '. so we have :

	0cah * keyA + keyB = 020h mod (0ffh)
	0c3h * keyA + keyB = 065h mod (0ffh)

	(0cah - 0c3h) * keyA = 020h - 065h mod (0ffh)
	0c3h * keyA + keyB = 065h mod (0ffh)

	7 * keyA = 0bbh mod (0ffh)
	keyB = 020h - 0cah * a mod (0ffh)

	keyA = 0adh
	keyB = 09eh

	so the 4 first characters of the serial are 'AD9E'.

	so data.txt was only here to provide enough material to permitt a statistical analysis.
data2.txt is more interesting. so we have this :

_moduli_________________________________________________________________________________________
Tony: 92s3A2StudSiAS5qFYIuORUotmooDQCkrGcFuAGOgwxDQb5lutOVCaGdAigCb63k54jnKlYchnTwGaRTkmcLvtD=n1
Paul: 76XiOfSGqrbAr92Ast8u5F3qOBcgg0FJ4CM74XreU9s36HNn3sdC77lXKcEnb6MBewiu15O9iP2IWBxZHSNDtQ1=n2
Thomas: 5aO3rKMUcVKcpKDxp0Zf62NHkZiAI8YJYCZfghXpr7UnTLsObBHolRPaZbRApbrH638m7xZUdCjO6sWcCdOGXtb=n3

_messages_______________________________________________________________________________________
Tony: 7moeqBnWbuQiU2FNedG7ocREZifpEOOs0YTQNMlECITiBhLCg75afFmBFA4VHweIdoXWGpAqKkr6VQjM2MGL9m4=c1
Paul: 71phDS43RJY3Utqix3aF0JMCxpGPGM5g1qcCgfoFJmL2rDdqsv1fKma7rAmClLt8gfXLaeEBgMeYbqr45YoAQ6d=c2
Thomas: 3oYZJGhswUWAoXb3xPOFjaEaAiK7R38WOEn5KZ9Ron9GFiSDB3UU09h4ghwg4euAQWvAXMOkobgScGpubqIh8YJ=c3

	c1 = M^3 mod (n1)
	c2 = M^3 mod (n2)
	c3 = M^3 mod (n3)

	n1, n2 and n3 are pairwise relatively prime, so we can apply the chinese remainder
theorem on the moduli n1, n2 and n3 and the remainders c1, c2 and c3, and we' ll get M^3. we
find :

M^3=9Co41vOq1d839MA9XcLNr8AfqlAgOFvduUSqYdwJhmVgH2RgXNkTVaDseaNvXLOIIBtjFCVBAi3iJKipqVWQJYwpOfK5
K3TwHxlXxx24fwa9Mw27OQY0FDcPXVS92qXucpmfPmUJLisrqtJZoauJcvJOq1gGkMLnW6Wa9AsL6RlN3HP6mG9128Q6oLAh
voAG1fXjoDRVScJTQHPP9YsBtV0gAXcdKlx

	in base 60, then we have to compute it' s cube root. we find :

M=25l9oCo0TKH7ZVSviJomLDZETW5tbpKFRPWiPtncwFdd5EIJwFfPi8BWuveex6m4WoZKpwSUgtx

	in base 60, that is :

M=Hello boy, I got a party on Satursday evening, u come ?

	in base 256. the md5 hash of evening in base 60 is EPUtdBUrqF8ZTC1Jd8HUt6, so the serial
is :

AD9E-EPUtdBUrqF8ZTC1Jd8HUt6
________________________________________________________________________________________________
:::::::::::::::::::::::::::::::::::: f i n a l   w o r d s :::::::::::::::::::::::::::::::::::::

	 it was a nice keygenme, quite unusual and interesting
________________________________________________________________________________________________
										      roy|fleur

