[CrackMe 9.0 by WiteG ]
by Amenesia
First we can see that the CrackMe is packed with FSG (using PEiD):

We can easily find OEP with the OllyDbg option: "Trace real entry blockwise"

seg001:00413831 loc_0_413831: 
seg001:00413831                 dec     byte ptr [esi]
seg001:00413833                 jz      near ptr dword_0_402D71    ; OEP
seg001:00413839                 push    esi
seg001:0041383A 
seg001:0041383A loc_0_41383A: 
seg001:0041383A                 push    ebp
seg001:0041383B                 call    dword ptr [ebx+4]
seg001:0041383E                 stosd
seg001:0041383F                 jmp     short loc_0_413821
seg001:0041383F start           endp

Then dump and rebuild the IAT...


1-Input

It doesn't use  GetDlgItemText  ,neither GetWindowTextA... so I seek for the string "Invalid user data."

seg000:00403991                 mov     ebx, offset aInvalidUserData
seg000:00403996                 mov     esi, offset Serial
seg000:0040399B                 push    esi             ; lParam
seg000:0040399C                 push    41h             ; wParam
seg000:0040399E                 push    0Dh             ; Msg
seg000:004039A0                 push    3EAh            ; nIDDlgItem
seg000:004039A5                 push    [ebp+hDlg]      ; hDlg
seg000:004039A8                 call    SendDlgItemMessageA
seg000:004039AD                 cmp     eax, 40h
seg000:004039B0                 jnz     short End

seg000:004039B2                 mov     edi, offset Name
seg000:004039B7                 push    edi             ; lParam
seg000:004039B8                 push    41h             ; wParam
seg000:004039BA                 push    0Dh             ; Msg
seg000:004039BC                 push    3E9h            ; nIDDlgItem
seg000:004039C1                 push    [ebp+hDlg]      ; hDlg
seg000:004039C4                 call    SendDlgItemMessageA
seg000:004039C9                 cmp     eax, 5
seg000:004039CC                 jl      short End

So, Serial length = 40h and Name length > 4



Then the Name is used to creat a 256 bits key (NameKey)...

seg000:004039CE                 push    edi
seg000:004039CF                 push    eax              ; Name length
seg000:004039D0                 push    edi              ; Name
seg000:004039D1                 call    GenSubKey



... and the serial string is converted:  '0' -> 0, '1' ->1, ..., 'F' -> F

seg000:004039D6                 push    esi
seg000:004039D7                 push    esi             ; serial
seg000:004039D8                 call    AsciiToHex
seg000:004039DD                 jb      End



2- Serial

Then NameKey and a constant  ( MagicKey ) are used to modify the Serial (ModifiedSerial):

seg000:004039E2 Loop: 
seg000:004039E2                 push    esi             ; NameKey
seg000:004039E3                 push    offset MagicKey ; a constant
seg000:004039E8                 push    edi             ; Serial
seg000:004039E9                 call    GenereKey
seg000:004039EE                 add     esi, 10h
seg000:004039F1                 add     edi, 10h
seg000:004039F4                 dec     ecx
seg000:004039F5                 jnz     short Loop 

seg000:00403A45 GenereKey       proc near 
seg000:00403A45 
seg000:00403A45 Name            = dword ptr  8
seg000:00403A45 MagicKey        = dword ptr  0Ch
seg000:00403A45 Serial          = dword ptr  10h
seg000:00403A45 
seg000:00403A45                 push    ebp
seg000:00403A46                 mov     ebp, esp
seg000:00403A48                 pusha
seg000:00403A49                 mov     esi, [ebp+Serial]
seg000:00403A4C                 mov     edi, [ebp+Name]
seg000:00403A4F                 xor     eax, eax
seg000:00403A51                 mov     ecx, 80h
seg000:00403A56 
seg000:00403A56 LoopGenKey: 
seg000:00403A56                 shl     dword ptr [edi+0Ch], 1
seg000:00403A59                 rcl     dword ptr [edi+8], 1
seg000:00403A5C                 rcl     dword ptr [edi+4], 1
seg000:00403A5F                 rcl     dword ptr [edi], 1
seg000:00403A61                 setb    al
seg000:00403A64                 or      [edi+0Ch], eax
seg000:00403A67                 push    esi
seg000:00403A68                 push    [ebp+MagicKey]
seg000:00403A6B                 call    [off_0_403A79 + eax*4]
seg000:00403A72                 loop    LoopGenKey
seg000:00403A74                 popa
seg000:00403A75                 leave
seg000:00403A76                 retn    0Ch
seg000:00403A76 GenereKey       endp

seg000:00403A79 off_0_403A79    dd offset Cas1 
seg000:00403A7D                 dd offset Cas2

So if the current bit  is 0 GenereKey call Cas1 and if the current bit is 1 it calls Cas2...



 

seg000:00403B87 Cas1            proc near 
seg000:00403B87 
seg000:00403B87 MagicKey        = dword ptr  8
seg000:00403B87 Serial          = dword ptr  0Ch
seg000:00403B87 
seg000:00403B87                 push    ebp
seg000:00403B88                 mov     ebp, esp
seg000:00403B8A                 pusha
seg000:00403B8B                 xor     ecx, ecx
seg000:00403B8D                 push    ecx
seg000:00403B8E                 push    ecx
seg000:00403B8F                 push    ecx
seg000:00403B90                 push    ecx
seg000:00403B91                 mov     esi, [ebp+MagicKey]
seg000:00403B94                 mov     edi, [ebp+Serial]
seg000:00403B97                 mov     edx, 80h
seg000:00403B9C 
seg000:00403B9C LoopCase1: 
seg000:00403B9C                 shr     dword ptr [edi], 1
seg000:00403B9E                 rcr     dword ptr [edi+4], 1
seg000:00403BA1                 rcr     dword ptr [edi+8], 1
seg000:00403BA4                 rcr     dword ptr [edi+0Ch], 1
seg000:00403BA7                 jnb     short loc_0_403BB7
seg000:00403BA9 
seg000:00403BA9 Loop64_C1: 
seg000:00403BA9                 mov     eax, [ecx+esi]
seg000:00403BAC                 xor     [esp+ecx], eax
seg000:00403BAF                 add     ecx, 4
seg000:00403BB2                 and     ecx, 0Fh
seg000:00403BB5                 jnz     short Loop64_C1
seg000:00403BB7 
seg000:00403BB7 loc_0_403BB7: 
seg000:00403BB7                 add     esi, 10h
seg000:00403BBA                 dec     edx
seg000:00403BBB                 jnz     short LoopCase1
seg000:00403BBD                 cld
seg000:00403BBE                 pop     eax
seg000:00403BBF                 stosd
seg000:00403BC0                 pop     eax
seg000:00403BC1                 stosd
seg000:00403BC2                 pop     eax
seg000:00403BC3                 stosd
seg000:00403BC4                 pop     eax
seg000:00403BC5                 stosd
seg000:00403BC6                 popa
seg000:00403BC7                 leave
seg000:00403BC8                 retn    8
seg000:00403BC8 Cas1            endp
seg000:00403BC8 

How determine Serial with Cas1(Serial) ?

If  "Y1 = Cas1(Serial1)"  and "Y2 = Cas1(Serial2)" then "Y2 xor Y1 = Cas1(Serial2 xor Serial1)"
Moreover a Serial can be consider as:

BnBn-1...B1B0 =000...001*B0 xor  000...010*B1 xor  ... xor 010...000*B(n-1) xor 100...000*Bn

      so Cas1(BnBn-1...B1B0 ) = Cas1(000...001)*B0 xor  Cas1(000...010)*B1 xor  ... xor Cas1(010...000)*B(n-1) xor Cas1(100...000)*Bn

So  AnAn-1...A1A0 = Cas1(BnBn-1...B1B0 )  = BnBn-1...B1B0 *M with M a matrix: 
 

B0 B1 ... Bn-1 Bn
\/ \/ \/ \/ \/
( Cas1(B0 )n Cas1(B1 )n ... Cas1(Bn-1 )n Cas1(Bn )n ) >  An
( Cas1(B0 )n-1 Cas1(B1 )n-1 ... Cas1(Bn-1 )n-1 Cas1(Bn )n-1 ) >  An-1
( ... ... ... ... ... ) > ...
( Cas1(B0 )1 Cas1(B1 )1 ... Cas1(Bn-1 )1 Cas1(Bn )1 ) > A1
( Cas1(B0 )0 Cas1(B1 )0 ... Cas1(Bn-1 )0 Cas1(Bn )0 ) > A0

Performing xor on the differentes col we can transform M  in :
 

B? xor ... xor B? B? xor ... xor B? ... B? xor ... xor B? B? xor ... xor B?
\/ \/ \/ \/ \/
( 1 Cas1(B1 )n ... Cas1(Bn-1 )n Cas1(Bn )n ) >  An
( 0 1 ... Cas1(Bn-1 )n-1 Cas1(Bn )n-1 ) >  An-1
( ... ... ... ... ... ) > ...
( 0 0 ... 1 Cas1(Bn )1 ) > A1
( 0 0 ... 0 1 ) > A0

Now it is easy to dermine which col have to be xored to:

AnAn-1...A1A0 = ModifiedSerial...
... B? xor ... xor B?
\/ \/ \/ \/ \/
( 1 Cas1(B1 )n ... Cas1(Bn-1 )n (ModifiedSerial)n ) >  An
( 0 1 ... Cas1(Bn-1 )n-1 (ModifiedSerial)n-1 ) >  An-1
( ... ... ... ... ... ) > ...
( 0 0 ... 1 (ModifiedSerial)1 ) > A1
( 0 0 ... 0 (ModifiedSerial)0 ) > A0

So Cas1(B? xor ... xor B?) = ModifiedSerial... in others words B? xor ... xor B? = Serial 
 
 


seg000:00403BCB Cas2            proc near 
seg000:00403BCB 
seg000:00403BCB var_2C          = dword ptr -2Ch
seg000:00403BCB var_28          = dword ptr -28h
seg000:00403BCB var_24          = dword ptr -24h
seg000:00403BCB MagicKey        = dword ptr  8
seg000:00403BCB Serial          = dword ptr  0Ch
seg000:00403BCB 
seg000:00403BCB                 push    ebp
seg000:00403BCC                 mov     ebp, esp
seg000:00403BCE                 pusha
seg000:00403BCF                 xor     ecx, ecx
seg000:00403BD1                 push    ecx
seg000:00403BD2                 push    ecx
seg000:00403BD3                 push    ecx
seg000:00403BD4                 push    ecx
seg000:00403BD5                 mov     esi, [ebp+MagicKey]
seg000:00403BD8                 mov     edi, [ebp+Serial]
seg000:00403BDB                 cld
seg000:00403BDC                 mov     edx, 80h
seg000:00403BE1 
seg000:00403BE1 LoopCase2: 
seg000:00403BE1                 xor     ebx, ebx
seg000:00403BE3 
seg000:00403BE3 Loop64_C2: 
seg000:00403BE3                 lodsd 
seg000:00403BE4                 and     eax, [ecx+edi]
seg000:00403BE7                 call    NumEax
seg000:00403BEC                 add     ecx, 4
seg000:00403BEF                 and     ecx, 0Fh
seg000:00403BF2                 jnz     short Loop64_C2
seg000:00403BF4                 shr     ebx, 1
seg000:00403BF6                 rcl     [esp+30h+var_24], 1
seg000:00403BFA                 rcl     [esp+30h+var_28], 1
seg000:00403BFE                 rcl     [esp+30h+var_2C], 1
seg000:00403C02                 rcl     dword ptr [esp], 1
seg000:00403C05                 dec     edx
seg000:00403C06                 jnz     short LoopCase2
seg000:00403C08                 pop     eax
seg000:00403C09                 stosd
seg000:00403C0A                 pop     eax
seg000:00403C0B                 stosd
seg000:00403C0C                 pop     eax
seg000:00403C0D                 stosd
seg000:00403C0E                 pop     eax
seg000:00403C0F                 stosd
seg000:00403C10                 popa
seg000:00403C11                 leave
seg000:00403C12                 retn    8
seg000:00403C12 Cas2            endp
 

We can use the matrix N:

B0 B1 ... Bn-1 Bn
\/ \/ \/ \/ \/
( Cas2(B0 )n Cas2(B1 )n ... Cas2(Bn-1 )n Cas2(Bn )n ) >  An
( Cas2(B0 )n-1 Cas2(B1 )n-1 ... Cas2(Bn-1 )n-1 Cas2(Bn )n-1 ) >  An-1
( ... ... ... ... ... ) > ...
( Cas2(B0 )1 Cas2(B1 )1 ... Cas2(Bn-1 )1 Cas2(Bn )1 ) > A1
( Cas2(B0 )0 Cas2(B1 )0 ... Cas2(Bn-1 )0 Cas2(Bn )0 ) > A0

... to determine the Serial value  thanks to ModifiedSerial value...



So to obtain the Serial thanks to the ModifiedSerial we have to make rotate the name in the reverse order and use the differents matrices ( M if the current bit is 0, N if it is 1 )
 
 
 

3 - Check

Then the first part of the serial is checked:

seg000:004039FD                 push    esi             ; ModifiedSerial
seg000:004039FE                 push    edi             ; NameKey
seg000:004039FF                 call    vTEA 
seg000:00403A04                 jb      short Fin


seg000:00403A81 vTEA             proc near 
seg000:00403A81 
seg000:00403A81 TEA1_A          = dword ptr -28h
seg000:00403A81 TEA1_B          = dword ptr -24h
seg000:00403A81 TEA2_A          = dword ptr -20h
seg000:00403A81 TEA2_B          = dword ptr -1Ch
seg000:00403A81 var_18          = byte ptr -18h
seg000:00403A81 arg_0           = dword ptr  8
seg000:00403A81 arg_4           = dword ptr  0Ch
seg000:00403A81 
seg000:00403A81                 push    ebp
seg000:00403A82                 mov     ebp, esp
seg000:00403A84                 pusha
seg000:00403A85                 mov     esi, [ebp+arg_4]
seg000:00403A88                 mov     edi, [ebp+arg_0]
seg000:00403A8B                 mov     ecx, 2
seg000:00403A90 
seg000:00403A90 LoopTEA_Encode: 
seg000:00403A90                 sub     esp, 8
seg000:00403A93                 push    esp             ; Buffer
seg000:00403A94                 push    edi             ; Key
seg000:00403A95                 push    esi             ; Data
seg000:00403A96                 call    vTEA_Encode
seg000:00403A9B                 xchg    esi, edi
seg000:00403A9D                 loop    LoopTEA_Encode
seg000:00403A9F                 mov     eax, [esp+28h+TEA1_A]
seg000:00403AA2                 xor     eax, [esp+28h+TEA2_A]
seg000:00403AA6                 jnz     short Invalid
seg000:00403AA8                 mov     eax, [esp+28h+TEA1_B]
seg000:00403AAC                 sub     eax, [esp+28h+TEA2_B]
seg000:00403AB0                 jnz     short Invalid
seg000:00403AB2                 mov     ecx, 4
seg000:00403AB7                 repe cmpsd
seg000:00403AB9                 jecxz   short Invalid
seg000:00403ABB                 clc
seg000:00403ABC 
seg000:00403ABC loc_0_403ABC: 
seg000:00403ABC                 lea     esp, [esp+10h]
seg000:00403AC0                 popa
seg000:00403AC1                 leave
seg000:00403AC2                 retn    8

So to be good vTEA_Encode(ModifiedSerial,NameKey) has to be equal to vTEA_Encode(NameKey,ModifiedSerial)  and ModifiedSerial != NameKey


seg000:00403B17 vTEA_Encode     proc near
seg000:00403B17 
seg000:00403B17 InternalKey4    = dword ptr -34h
seg000:00403B17 InternalKey2    = dword ptr -30h
seg000:00403B17 InternalKey1    = dword ptr -2Ch
seg000:00403B17 InternalKey0    = dword ptr -28h
seg000:00403B17 ptrData         = dword ptr  8
seg000:00403B17 ptrKey          = dword ptr  0Ch
seg000:00403B17 Buffer          = dword ptr  10h
seg000:00403B17 
seg000:00403B17                 push    ebp
seg000:00403B18                 mov     ebp, esp
seg000:00403B1A                 pusha
seg000:00403B1B                 cld
seg000:00403B1C                 mov     esi, [ebp+ptrKey]
seg000:00403B1F                 mov     ebx, [ebp+ptrData]
seg000:00403B22                 push    [ebp+Buffer]
seg000:00403B25                 lodsd
seg000:00403B26                 push    eax
seg000:00403B27                 lodsd
seg000:00403B28                 push    eax
seg000:00403B29                 lodsd
seg000:00403B2A                 push    eax
seg000:00403B2B                 lodsd
seg000:00403B2C                 push    eax
seg000:00403B2D                 xor     edx, edx
seg000:00403B2F                 mov     esi, [ebx]
seg000:00403B31                 mov     edi, [ebx+4]
seg000:00403B34                 mov     ebp, 20h
seg000:00403B39 
seg000:00403B39 LoopTEA: 
seg000:00403B39                 add     edx, 9E3779B9h
seg000:00403B3F                 mov     eax, edi
seg000:00403B41                 mov     ecx, eax
seg000:00403B43                 mov     ebx, edi
seg000:00403B45                 rol     eax, 4
seg000:00403B48                 ror     ebx, 5
seg000:00403B4B                 add     eax, [esp+34h+InternalKey0]
seg000:00403B4F                 add     ebx, [esp+34h+InternalKey1]
seg000:00403B53                 add     ecx, edx
seg000:00403B55                 xor     ecx, eax
seg000:00403B57                 xor     ecx, ebx
seg000:00403B59                 add     esi, ecx
seg000:00403B5B                 mov     eax, esi
seg000:00403B5D                 mov     ebx, esi
seg000:00403B5F                 mov     ecx, esi
seg000:00403B61                 shl     eax, 4
seg000:00403B64                 shr     ebx, 5
seg000:00403B67                 add     eax, [esp+34h+InternalKey2]
seg000:00403B6B                 add     ebx, [esp+34h+InternalKey4]
seg000:00403B6E                 add     ecx, edx
seg000:00403B70                 xor     ecx, eax
seg000:00403B72                 xor     ecx, ebx
seg000:00403B74                 add     edi, ecx
seg000:00403B76                 dec     ebp
seg000:00403B77                 jnz     short LoopTEA
seg000:00403B79                 add     esp, 10h
seg000:00403B7C                 pop     ebx
seg000:00403B7D                 mov     [ebx], esi
seg000:00403B7F                 mov     [ebx+4], edi
seg000:00403B82                 popa
seg000:00403B83                 leave
seg000:00403B84                 retn    0Ch
seg000:00403B84 vTEA_Encode     endp

So vTEA_Encode performs:
 

void code(long* v, long* k)  { 
unsigned long y=v[0],z=v[1], sum=0,   /* set up */
 delta=0x9e3779b9, n=32 ;             /* a key schedule constant */
while (n-->0) {                       /* basic cycle start */
  sum += delta ;
    y += (ROL4(z)+k[0])  xor  ( y+sum)  xor ( ROL5(z)+k[1]) ; 
    z += (SHL4(y)+k[2])  xor  ( y+sum)  xor ( SHR5(y)+k[3]) ; 
              } 
v[0]=y ; v[1]=z ; }

So if we remplace k[2] and k[3] by ( k[2] xor 2^31 ) and ( k[3] xor 2^31 ) the result will be the same but the keys will be different...

The fact that each TEA (this routine is very close to TEA ) key has 3 other equivalent keys is described in the paper  "Key-Schedule Cryptanalysis of IDEA, G-DES, GOST, SAFER, and Triple-DES" 


So [ModifiedSerial ] = [ NameKey ],
      [ModifiedSerial +4 ] = [ NameKey + 4 ],
      [ModifiedSerial +8 ] = [ NameKey  + 8]    xor 2^31,
      [ModifiedSerial + 12 ] = [ NameKey +12] xor 2^31
 



Then the second part of the serial is checked:

seg000:00403A0C                 push    esi             ; Serial p2
seg000:00403A0D                 push    edi             ; Name
seg000:00403A0E                 push    esi             ; Serial p2
seg000:00403A0F                 call    CheckSerialP2
seg000:00403A14                 dec     dword ptr [esi+0Ch]
seg000:00403A17                 xor     ecx, ecx
seg000:00403A19 
seg000:00403A19 CheckSerial: 
seg000:00403A19                 mov     eax, [ecx+esi]
seg000:00403A1C                 test    eax, eax
seg000:00403A1E                 jnz     short Fin
seg000:00403A20                 add     ecx, 4
seg000:00403A23                 and     ecx, 0Fh
seg000:00403A26                 jnz     short CheckSerial

So the result of CheckSerialP2 has to be equal to 1


seg000:00403CAC CheckSerialP2   proc near 
seg000:00403CAC 
seg000:00403CAC Serial_         = dword ptr  8
seg000:00403CAC Name_P2         = dword ptr  0Ch
seg000:00403CAC Serial          = dword ptr  10h
seg000:00403CAC 
seg000:00403CAC                 push    ebp
seg000:00403CAD                 mov     ebp, esp
seg000:00403CAF                 pusha
seg000:00403CB0                 sub     esp, 20h
seg000:00403CB3                 mov     ecx, 4
seg000:00403CB8                 mov     edi, esp
seg000:00403CBA                 mov     esi, [ebp+Serial_]
seg000:00403CBD                 cld
seg000:00403CBE                 repe movsd
seg000:00403CC0                 mov     ecx, 4
seg000:00403CC5                 mov     ebx, edi
seg000:00403CC7                 mov     esi, [ebp+Name_P2]
seg000:00403CCA                 repe movsd
seg000:00403CCC                 xor     eax, eax
seg000:00403CCE                 mov     ecx, 4
seg000:00403CD3                 mov     edi, [ebp+Serial]
seg000:00403CD6                 repe stosd 
seg000:00403CD8                 sub     edi, 10h
seg000:00403CDB                 mov     ecx, 80h
seg000:00403CE0                 clc
seg000:00403CE1 
seg000:00403CE1 Loop: 
seg000:00403CE1                 mov     eax, 3
seg000:00403CE6 
seg000:00403CE6 _Loop1: 
seg000:00403CE6                 rcl     dword ptr [edi+eax*4], 1 
seg000:00403CE9                 dec     eax
seg000:00403CEA                 jns     short _Loop1 
seg000:00403CEC                 mov     eax, 3
seg000:00403CF1                 jnb     short _Loop2 
seg000:00403CF3                 xor     dword ptr [edi+0Ch], 87h 
seg000:00403CFA 
seg000:00403CFA _Loop2: 
seg000:00403CFA 
seg000:00403CFA                 rcl     dword ptr [esp+eax*4], 1 
seg000:00403CFD                 dec     eax
seg000:00403CFE                 jns     short _Loop2 
seg000:00403D00                 jnb     short Next
seg000:00403D02                 mov     eax, 3
seg000:00403D07 
seg000:00403D07 _Loop3: 
seg000:00403D07                 mov     edx, [ebx+eax*4] 
seg000:00403D0A                 xor     [edi+eax*4], edx
seg000:00403D0D                 dec     eax
seg000:00403D0E                 jns     short _Loop3 
seg000:00403D10 
seg000:00403D10 Next: 
seg000:00403D10                 loop    Loop
seg000:00403D12                 add     esp, 20h
seg000:00403D15                 popa
seg000:00403D16                 leave
seg000:00403D17                 retn    0Ch
seg000:00403D17 CheckSerialP2   endp

Here again we can use a matrix: L
 
 

B0 B1 ... Bn-1 Bn
\/ \/ \/ \/ \/
( CheckSerialP2(B0 )n CheckSerialP2(B1 )n ... CheckSerialP2(Bn-1 )n CheckSerialP2(Bn )n ) >  An
( CheckSerialP2(B0 )n-1 CheckSerialP2B1 )n-1 ... CheckSerialP2(Bn-1 )n-1 CheckSerialP2(Bn )n-1 ) >  An-1
( ... ... ... ... ... ) > ...
( CheckSerialP2(B0 )1 CheckSerialP2(B1 )1 ... CheckSerialP2(Bn-1 )1 CheckSerialP2(Bn )1 ) > A1
( CheckSerialP2(B0 )0 CheckSerialP2(B1 )0 ... CheckSerialP2(Bn-1 )0 CheckSerialP2(Bn )0 ) > A0

... to determine whose ModifiedSerial_P2 verifies: CheckSerialP2(ModifiedSerial_P2) == 1


So now we are able to compute ModifiedSerial_P1 and ModifiedSerial_P2 (that is to say ModifiedSerial) and we know how obtain Serial value using ModifiedSerialValue...  so we can compute a valid Serial ;)
 

Name   Amenesia
Serial 93180C843E7004FA4F749AB6E82A9E883A4C2C6FBBDF8921927E9ACBC6C885E1

I know that my english is very bad so if you find an error or if you think that this tut is un-understandable feel free to contact me : tchernozium@yahoo.fr