For Newbies Only

Introduction

La cryptographie est dans l'air, comme les packers l'ont été fut un temps. Peut être une question de mode (aujourd'hui si t'as pas un portable dont la taille est inversement proportionnelle à celle de
ta bi ton organe sexuel, et un shareware crypté en RSA, mérites tu d'exister ?).

Je n'ai pas l'intention, dans les lignes qui suivent, de réexpliquer le principe (disons de faire un copié/collé...) des différents algorithmes de cryptage, tout au plus un léger rappel des points les plus importants. De tout façon, si vous utilisez Google, il me semble qu'il n'y a qu'en Inuit que l'algorithme RSA n'a pas été expliqué, et encore je n'en mettrais pas ma main à couper... Ceci expliquant cela, le nombre de LIB pour C/C++/VC++ ou Delphi sont légions sur le NET, et les auteurs de sharewares ne s'en privent pas. Le seul avantage, c'est que beaucoup ne comprennent pas comment fonctionne exactement la LIB qu'ils incluent dans leurs programmes, ce qui pourra nous aider de temps en temps...

En fait, mon intention n'est même pas d'expliquer comment cracker tel ou tel algo, mais simplement d'essayer d'aider les tous débutants à reconnaître à quel mode de cryptage ils auront affaire. Ensuite à chacun de trouver à quoi est utilisé le résultat du cryptage obtenu ou l'origine du message à crypter...

Comme il est impossible de faire le tour de tous les algorithmes, je ne parlerai cette fois ci que de MD5 (très courant), SHA (courant) et RSA (très courant). Les deux premiers sont des fonctions de condensation (ou de hashage), le dernier est de type asymétrique.

Citons, pour mémoire, quelques autres algorithmes couramment utilisés: Twofish, Rijndael, Blowfish, Cast 128, Gost, IDEA, Misty1

Bonne lecture
christal

MD5

Le premier programme auquel nous allons nous intéresser est un crackme à serial unique écrit en Delphi et compressé par UPX.

Une fois décompressé (en utilisant l'option "Decompress" d'UpxGui), IDA va avoir des choses à dire (View -> Open subwiews -> Strings) :

"a5ba6896"
"MD5"
"serial valide"

Pas compliqué de deviner ici qu'il s'agit d'un hashage MD5....
Par contre, l'espèce de serial semble très prometteur :

:00441065  mov     edx, dword ptr [ebp-08]  > edx = caractères entrés
...
:00441087  mov     eax, dword ptr [ebp-04]  > eax = hash corespondant
...
:004410A1  mov     eax, dword ptr [ebp-04]  > eax = 8 derniers bytes du hash

* Possible StringData Ref from Code Obj ->"a5ba6896"
:004410A4  mov     edx, 004410FC            > edx = a5ba6896
:004410A9  call    00403C74                 > comparaison avec les 8 derniers bytes du hash_serial_entré
:004410AE  jne     004410C8                 > Pas Glop ! c'est la sortie
:004410B0  push    00000000                 > Glop Glop ! la MsgBox s'affiche.
:004410B2  mov     ecx, 00441108

* Possible StringData Ref from Code Obj ->"serial valide"
:004410B7  mov     edx, 0044110C            > serial valide

Et le tout l'un au-dessus de l'autre, il n'y a plus à hésiter !

Reste que dans ce cas précis, il sera nécessaire de bricoler un MD5 Brute Forcer testant des valeurs numériques puis alphanumériques. Heureusement, le serial sera de type décimal, composé de 4 caractères, et rapide à trouver. (mode d'emploi: vous entrez le DWORD recherché dans la quatrième case, vous indiquez que la recherche doit se faire entre 1 et 99999 par exemple dans les valeurs mini/maxi et vous cliquez sue "Search")

MD5 recoit, lors de son initialisation (c'est une de ses caractèristiques), une chaine de caractères typiques:

DATA:00442050 a0123456789abcdef_0 db '0123456789ABCDEF'

Suivant les programmeurs, elle est, ou non, en clair.
En soit même, une telle chaîne de caractères n'est pas spécifique aux fonctions de Hash MD5, mais lorqu'elle apparait codé ainsi:

30 31 32 33 34 35 36 37-38 39 61 62 63 64 65 66  0123456789abcdef
01 23 45 67 89 AB CD EF-FE DC BA 98 76 54 32 10  .#Eg........vT2. (le #Eg est significatif)

il va falloir commencer à regarder dans la fenêtre des Data si un hash n'apparait pas...

Mais cette string n'est pas toujours apparente dans les Strings Ref
Bien souvent, même, elle sera initialisée ainsi:

:00401800  mov     dword ptr [ecx],     067452301h   ; Possible Hash found can be SHA-1 or MD5a or Ripe-MD !!!
:00401806  mov     dword ptr [ecx+4],   0EFCDAB89h
:0040180D  mov     dword ptr [ecx+8],   098BADCFEh
:00401814  mov     dword ptr [ecx+0Ch], 010325476h

Vous vous doutez bien que la jolie petite phrase en bleu n'est pas apparue magiquement lors du déssasemblage.
Et bien SI!
Grace à un fichier IDC (écrit par Snacker & Defiler pour IDA), la routine d'implantation a été immédiatement repérée.
(touche F2 -> choix du fichier
hashfinder.idc que vous aurez judicieusement placé dans le répertoire ad'hoc).

MD5 est tout simple et ne pose pas de problème, par contre il est souvent utilisé combiné avec un autres algo, et bien souvent du RSA...

 Demonstration
Entrée:
Calcul:

Resultat:
 Demonstration

SHA

Et maintenant, un ch'tit coup de SHA-256 sur un autre crackme de JuLio eL NeGRo écrit en ASM

Le gros avantage de l'ASM, c'est que le code n'est pas "perverti" par les mois de l'année, ou Dieu sait quels autres cochoneries qui viennet se rajouter lors de la compilation de langages "évolués". Et donc, en dehors de la création de la dialog box, la totalité du reste du code est consacré à la routine de cryptage, ce qui la rendra facile à ripper pour en faire un copié/collé dans un Key Generator, mais ce ne sera pas toujours aussi simple...

Comme son copain MD5, SHA est initialisé:

:00401023   mov     dword_0_406804, 6A09E667h
:0040102D   mov     dword_0_406808, BB67AE85h
:00401037   mov     dword_0_40680C, 3C6EF372h
:00401041   mov     dword_0_406810, A54FF53Ah
:0040104B   mov     dword_0_406814, 510E527Fh
:00401055   mov     dword_0_406818, 9B05688Ch
:0040105F   mov     dword_0_40681C, 1F83D9ABh
:00401069   mov     dword_0_406820, 5BE0CD19h

Moins facile à identifier, j'ai juste fait une recherche sur le net en utilisant "6A09E667" comme clé, pour trouver immediatement ce site et la réponse à ma question:

Description of SHA-1 and SHA-256 http://home.ecn.ab.ca/~jsavard/crypto/mi060501.htm

The SHA-256 algorithm is very similar in structure to SHA-1, but not only does it use eight, rather than five, 32-bit subblocks, but there are other ways in which it is not analogous.

For SHA-256, the message is padded, and divided into 512-bit blocks, in the same way as for SHA-1.

From each block, considered as 16 32-bit words, 64 (rather than 80) 32-bit words are produced, the first 16 being the block itself, and the remaining words being the sum, modulo 2^32, of the following quantities:

the word 16 words ago;
the word 7 words ago;
the XOR of the following three quantities:

the word 2 words ago rotated right 17 places
that word rotated right 19 places
that word shifted right 10 places;

the XOR of the following three quantities:

the word 15 words ago rotated right 7 places
that word rotated right 18 places
that word shifted right 3 places.

Comme j'avais eu l'occasion de le dire un peu plus tôt, le calcul d'un hash n'est pas tout, sinon il suffirait d'utiliser un tool comme celui de DAMN pour solutionner le crackme:

La réponse du Hash Calculator de DAMN va donner:

Calculating hash of 8 bytes string `christal`...

SHA-256 : 0AE43A9D51ADD58D6F75E7529BE67970AD7D5BC68F7B97771F4F511A8007886F

Le crackme, lui, va dabord saisir le Name, et l'envoyer dans la routine de hashage:

:00404457  CALL      USER32!GetWindowTextA     ; get the name
:0040445C  OR        EAX,EAX                   ; si le champ n'est pas vide
:0040445E  JZ        004044A8
:00404460  PUSH      0040616C                  ; pousse le name
:00404465  PUSH      EAX                       ; pousse sa taille
:00404466  PUSH      0040656C                  ; pousse adresse de stockage du hash SHA-256
:0040446B  CALL      00401000                  ; hachage du name
:00404470  MOV       ESI,0040656C              ; récupère le hash
:0040656C 0A E4 3A 9D 51 AD D5 8D-6F 75 E7 52 9B E6 79 70  ..:.Q...ou.R..yp
:0040657C AD 7D 5B C6 8F 7B 97 77-1F 4F 51 1A 80 07 88 6F  .}[..{.w.OQ....o

:00404475  XOR       ECX,ECX                   ; pointeur caractère                        
:00404477  XOR       EAX,EAX                   ; stockage du résultat
:00404479  XOR       EBX,EBX
:0040447B  MOV       BL,[ESI+ECX]              ; récupère une valeur du hash
:0040447E  TEST      BL,BL                     ; vérifie que ce n'est pas la dernière
:00404480  JZ        00404490                  ; sinon -> out vers XORage
:00404482  IMUL      EBX,ECX                   ; bidouille 1
:00404485  IMUL      EBX,EBX                   ; bidouille 2
:00404488  ADD       EBX,50                    ; bidouille 3
:0040448B  ADD       EAX,EBX                   ; stock le résultat
:0040448D  INC       ECX                       ; incrémente pointeur caractère
:0040448E  JMP       00404479     
:00404490  XOR       EAX,12345678              ; et à la sortie, le résultat est XORé
:00404495  PUSH      EAX                       ; avant d'être transformé en string
:00404496  PUSH      00406078                  ; et d'être comparé avec le serial
:0040449B  PUSH      0040676C
:004044A0  CALL      USER32!wsprintfA
:004044A5  ADD       ESP,0C
:004044A8  RET

Bref, rien de compliqué quand on a les bons outils...

L'algorithme en bref:
- Prenez deux grands nombres premiers,
p et q.
- Calculez leur produit,
n = p.q, le modulo public.
- Choisissez
e, tel que e<n et e est premier avec n.
- Calculez
d tel que e.d = 1 [(p-1).(q-1)].

Cryptage,  Ciphertext c = m ^ e [n]
Décryptage, Plaintext m = c ^ d [n]

Une démo de RSA

Dans l'exemple ci contre, les valeurs que l'on trouve sont suffisament petites pour être calculées dans cette page. Vous pouvez bien sur changer les valeurs, mais sans oublier que ce n'est jamais que du javaScript...

p premier:

q premier:

Il nous faut maintenant donner un
e tel que e et phi(n)=(p-1)(q-1) soient premiers entre eux).

nombre
e :

Groupage: ce paramètre spécifie la taille des blocs à traiter

Maintenant on peut lancer le premier calcul:

On a n = p*q =         

Phi(n) = (p-1)(q-1) =  

Il ne reste qu'à calculer la clé privée d telle que:

e*d=1*mod((p-1)(q-1))

On trouve: d =          

Nous avons maintenant:
- Une clé privée, le couple (d,n)
- Une clé publique, le couple (e,n)

Il ne reste plus qu'à faire un 8483678 ^ 10961333 mod 12790891 pour trouver 7167622 et un 5666933 ^ 10961333 mod 12790891 pour obtenir 3196885 avec un calculator.
A aucun moment le nom n'est utilisé, le serial est 71676223196885.

 

RSA

Dans le crackme de TFC, les Strings Data pourraient induire en erreur (1279089184836785666933 étant factorisable sur 71 bits -> 258963172219 x 4939270607), mais TFC ayant précisé que son crackme était en RSA 24, la seule valeur qui convienne est 12790891. A quoi peuvent donc bien servir les 2 autres valeurs (8483678 et 5666933) ?

data:004200C0 a5666933        db '5666933',0 
data:004200C8 a8483678        db '8483678',0 
data:004200D0 a12790891       db '12790891',0 
data:004200DC a9901           db '9901',0      ; Public Exponent ?
En utilisant SoftIce, voici ce que l'on peut en déduire:
:004029CD push    offset 9901       ; Exponent        
:004029D2 lea     ecx, [esp+0E4h]
:004029D9 call    Lg_String         ; calcul longueur string
:004029DE push    offset 12790891   ; Modulus
:004029E3 lea     ecx, [esp+1Ch]
:004029E7 mov     [esp+664h], 0     ; Flag
:004029F2 call    Lg_String
:004029F7 push    offset 8483678    ; string 1
:004029FC lea     ecx, [esp+274h]
:00402A03 mov     [esp+664h], 1
:00402A0B call    Lg_String
:00402A10 push    offset 5666933    ; string 2
:00402A15 lea     ecx, [esp+1ACh]
:00402A1C mov     [esp+664h], 2
:00402A24 call    GetSerial         ; récupère le serial entré
:00402A29 mov     edx, [esp+668h]   ; offset serial sur la pile   
:00402A30 or      esi, 0FFFFFFFFh   ; mise à -1 de esi
:00402A33 mov     edi, edx          ; edi = offset serial
:00402A35 mov     ecx, esi          ; ecx = -1 (taille du scan)
:00402A37 xor     eax, eax          ; recherche Null Terminated String
:00402A39 mov     [esp+660h], 3     ; Flag
:00402A41 repne   scasb             ; calcul de la taille du serial
:00402A43 not     ecx               ; ecx = taille serial + "0"
:00402A45 dec     ecx               ; déduit le Null Terminated String
:00402A46 cmp     ecx, 0Eh          ; compare si serial = 14 digits
:00402A49 jnz     loc_0_402BB2      ; if not goto bad boy

Le format doit être de type numérique (vérification en 00402A51). Le serial RSA_crypted est divisé en 2 partie, les 7 premiers digits sont comparé avec 8483678, les 7 suivants avec 5666933:

:00401D78 mov     dl, [eax]         ; rsa result 1 (7 digits)
:00401D7A mov     bl, [esi]         ; string 1 8483678
:00401D7C mov     cl, dl           
:00401D7E cmp     dl, bl            ; comparaison caractère/caractère        
etc...

Grâce à RSA Tool2 de tE, entrez 12790891comme Modulus, et 26AD (9901 en base 16) comme Public Exponent, puis cliquez sur Factor N, vous aurez 1667 (Prime P) et 7673 (prime Q). Passez en Base 16, puis cliquez sur Calc.d pour obtenir d = A741B5h et repassez en base 10 pour d = 10961333. Tous les élements sont réunis pour résoudre le Crackme.

Bien souvent, une partie des informations qui nous mettrons sur le piste se trouvent dans les Datas.

Dans le cas de "Keygen Total Recorder v3.2" sur lequel LuTiN NoIR avait écrit un Tutor, l'identification de la Library utilisée lui a permis de considérablement se faciliter la tâche. Relisons ce qu'il avait écrit:

"Le plus simple serait de trouver la lib qu'il utilise. En faisant une petite recherche sur les strings sous google, j'ai découvert qu'il s'agissait de CryptoLib.

C'est ici que IDA va être d'un grand recourt, on va utiliser cette librarie et créer un fichier de reconnaissance de lib pour ida, comme cela il va reconnaitre les fonctions utilisées et ce sera plus simple de comprendre le code. On recupère d'abord cette lib (ici CryptoLib v1.1) sur le net. On a les sources en C, on les compile donc en librairie static avec Visual C++ 6.0 (ou 5.0) car le programme utilise VC++ (ida nous l'apprend au début du disasm). Ensuite on va utiliser FLAIR (un programme fournit avec la version complète d'ida, ou alors il faut se débrouiller pour le récupérer). On fait les manip suivantes :

PCF cryptolib.lib cryptolib.pat

sigmake cryptolib.pat cryptolib.sig

Et on a maintenant un fichier .sig qui va permettre à ida de reconnaitre les fonctions de cette librairie. On met les .sig dans le rep d'ida concu à cette effet, puis on le charge pour qu'ida reconnaisse les fonctions (File->Load File->Flirt Signature File)
"

Le challenger de CrytoLib est MIRACL dont on trouve parfois des traces fort peu discrètes dans les Data:

0040CAF0 aNoModulusDefined db 'No modulus defined',0Ah,0
0040CB04 aIllegalModulus db 'Illegal modulus',0Ah,0 
0040CB18 aMiraclNotInitialised db 'MIRACL not initialised - no call to mirsys()',0Ah,0
0040CB48 aIOBufferOverflow db 'I/O buffer overflow',0Ah,0
0040CD58 aMiraclErrorFromRoutine db 0Ah          
0040CD58 db 'MIRACL error from routine ',0

Si avec ca, vous avez encore des doutes sur la présence d'un algo de cryptage...
Et ce qui est vrai pour CryptoLib, l'est egalement pour
MIRACL concernant les fichiers de reconnaissance!

Dans les Strings Data, on reperera immédiatement la trace d'un Private Exponent (très certainement), et une très classique clé public: 10001 (toujours un nombre premier 3, 11, 17, 257d...)

A bien regarder D, son format est de type hexadécimal (bien que la clé "65537"" soit décimale...), et sa taille de 190 bits (dans RSA Tool, cliquez sur le rectangle [Exact Size])

data:0040B0A8 modulus     db '2F774486FD3B97FFA559687F7F9D5335CA3D16FBB60C0019',0
data:0040B0DC Public_key  db '65537',0

Mais aussi la trace de l'initialisation d'un MD5:

004012BC  mov     dword ptr [eax],     67452301h ; Possible Hash found can be SHA-1 or MD5a or Ripe-MD !!!
004012C2  mov     dword ptr [eax+4],   EFCDAB89h
004012C9  mov     dword ptr [eax+8],   98BADCFEh
004012D0  mov     dword ptr [eax+0Ch], 10325476h

De la à conclure que nous sommes face à un algo de type [Hash(Name)MD5] ^ D mod N, il n'y a qu'un pas que je vais allégrement essayer de franchir.

Comme le modulus est de type hexadécimal, la valeur du hash devra l'être aussi, et il faudra convertir la valeur de la clé publique pour que tout soit en base 16.

Commençons par chercher le private Exponent.
Une fois trouvé, il n'y a plus qu'à remplir les champs d'un calculator, et essayer si le résultat donné est le bon. Fine! Its works...

Une petite précision, un Hash MD5 n'aura pas la même valeur si votre nom est en minuscule ou en Majuscule, et de même pour un cryptage RSA (Case Sensitive).

Un Vrai/Faux RSA...

Même cas de figure pour le PGC RSA Crackme, dans les String Data on retrouve les trace d'un Modulus RSA :

data:00404275 Public_Key    db '10001',0            
data:0040427B Modulus       db '8e701a4c793eb8b739166bb23b49e421',0
data:0040429C Pgctrial2oo2  db '[PGCTRiAL/2oo2]',0

et l'initialisation d'un hash MD5 avec HashFinder.idc

text:00401054  mov     dword ptr [esi],     67452301h ; Possible Hash found can be MD5
text:0040105A  mov     dword ptr [esi+4],   EFCDAB89h
text:00401061  mov     dword ptr [esi+8],   98BADCFEh
text:00401068  mov     dword ptr [esi+0Ch], 10325476h

Le Modulus se factorise sans problème avec RSA TooL2, mais le Private Exponent ne sera pas nécessaire comme vous le verrez ensuite. La clé public est typique au cryptage RSA. Nous sommes bien, à priori, face à du RSA...

Prime p:
C2E0C6C46F34EEEB

Prime q:
BB1CC85B7A9D2E23

Modulus n:
8E701A4C793EB8B739166BB23B49E421

Private Exponent d:
8074D942DE95923F52DCB90FBC292981 (not used)

Le Crackme étant écrit en assembleur, il est très facile à suivre, le programme attrape le nom dans le premier champ, puis le serial:

text:00401A31  push    22h                      ; nombre de caractères que doit faire le serial           
text:00401A33  push    offset Serial_entered       
text:00401A38  push    hWndNewOwner             ; handle du second champ d'édition
text:00401A3E  call    GetWindowTextA
text:00401A43  cmp     eax, 1                   ; si la taille de la string retournée 
text:00401A46  jl      Serial_too_small         ; est égale ou inférieur à 1 -> message d'erreur

text:00401A4C  mov     Lg_name, eax             ; mémorise la taille de la string 'serial'
text:00401A51  push    0                        ; initailisation d'un espace mémoire
text:00401A53  call    BigCreate                ; réservé pour créer un bignum 

text:00401A58  mov     Big_Serial_entered, eax  ; stockage de l'adresse réservée
text:00401A5D  mov     eax, Lg_Serial_entered
text:00401A62  push    Big_Serial_entered
text:00401A68  push    offset Serial_entered
text:00401A6D  call    Fill_Big                 ; place le serial dans l'espace réservé

Concatène le nom et la string [PGC/TRIAL 2oo2], et récupère la taille de la chaîne créée

text:00401A72  push    offset Pgctrial2oo2 
text:00401A77  push    offset Name_entered  
text:00401A7C  call    lstrcatA
text:00401A81  push    offset Name_entered   
text:00401A86  call    lstrlenA

Hash MD5 de la chaîne créée:

text:00401A8B  push    offset @_Hash_Name_entered
text:00401A90  push    offset hash_return_value
text:00401A95  push    eax                       ; taille de la nouvelle string
text:00401A96  push    offset Name_entered
text:00401A9B  call    HashMD5_Function          ; hashage de la string

hash_return_value = 1A0D184AEA4E9B2EE50602C87BF9DE70 (pour 'christal').

Création des espaces mémoires pour les autres BIG Numbers (Modulus, Public Key et adresse de retour du calcul RSA)

text:00401AA0  push    0
text:00401AA2  call    BigCreate
text:00401AA7  mov     Big_Hash, eax
text:00401AAC  push    0
text:00401AAE  call    BigCreate
text:00401AB3  mov     Return_RSA, eax
text:00401AB8  push    0
text:00401ABA  call    BigCreate
text:00401ABF  mov     Big_Modulus, eax
text:00401AC4  push    0
text:00401AC6  call    BigCreate
text:00401ACB  mov     Big_Public_Key, eax

Le calcul RSA est lancé ici:

text:00401AD8  push    Big_Hash
text:00401ADE  push    offset @_Hash_Serial_entered 
text:00401AE3  call    Fill_Big                  ; transforme le hash en Big Number héxadécimal        
text:00401AE8  push    Big_Public_Key            ; push l'adresse de retour du calcul RSA
text:00401AEE  push    offset Public_Key         ; push 10001 
text:00401AF3  call    Fill_Big                  ; le transforme en Big Number héxadécimal
text:00401AF8  push    Big_Modulus               ; idem pour le modulus  
text:00401AFE  push    offset Modulus            ; 8e701a4c793eb8b739166bb23b49e421
text:00401B03  call    Fill_Big

En fait de RSA, il pourait s'agir de n'importe quoi d'autre, le calcul effectué est un simple cryptage de type C = M ^ E mod N
Aucun VRAI cryptage RSA n'est effectué...

text:00401B08  push    Return_RSA                
text:00401B0E  push    Big_Modulus
text:00401B14  push    Big_Public_Key
text:00401B1A  push    Big_Hash
text:00401B20  call    RSA_Function              ; PowerMod C = Hash ^ E mod N

Ce crackme n'exécute qu'un cryptage, à la différence des autres exemples qui font des décryptages, ce qui implique que le Private Exponent n'est pas nécessaire et que le programme ne contient pas, du coup, de lib RSA.

Pour finir, le résultat du PowerMod et du serial entré se fait quelques lignes plus bas:

text:00401B25  push    Big_Serial_entered
text:00401B2B  push    Return_RSA
text:00401B31  call    compare2Big_nbr
text:00401B36  test    eax, eax
text:00401B38  jz      short loc_0_401B6B        ; Well Done Good boy !
Rien de plus simple que de créer le KeyGenerateur, il n'y a qu'à ripper la presque totalité du Crackme en créant un fichier asm avec IDA...

Dans le KeygenMe #2 de TMG codé par tHE EGOiSTE, les String Data d'IDA ne donnent rien, et pour cause, la seule série des Data ressemblant à une valeur RSA est codée ainsi:

DATA:00402000 unk_0_402000    db  0Ah 
DATA:00402001                 db    0   
DATA:00402002                 db 0D2h ; Ê
DATA:00402003                 db 0E9h ; Ú
DATA:00402004                 db 0BFh ; +
DATA:00402005                 db  9Bh ; ø
DATA:00402006                 db  3Dh ; =
DATA:00402007                 db  25h ; %
DATA:00402008                 db  8Eh ; Ä
DATA:00402009                 db  47h ; G
DATA:0040200A                 db  9Dh ; Ø
DATA:0040200B                 db  8Ch ; î
DATA:0040200C                 db 0C2h ; -
DATA:0040200D                 db  3Ch ; <
DATA:0040200E                 db  7Ah ; z
DATA:0040200F                 db  33h ; 3
DATA:00402010                 db 0E1h ; ß
DATA:00402011                 db 0F8h ; °
DATA:00402012                 db 0EBh ; Ù
DATA:00402013                 db 0B3h ; ¦
DATA:00402014                 db 0ADh ; ¡
DATA:00402015                 db 0B1h ; ¦

Soit D2E9BF9B3D258E479D8CC23C7A33E1F8EBB3ADB1, ce qui pourrait bien être un Modulus...
Par contre, pas de trace d'une clé publique (10001, 65557... à ce sujet 10001h = 65557d !)
Comme la chaîne est déjà au format hexa, il y a fort à parier qu'il ne faudra pas s'attendre à trouver une chaîne alphanumérique contenant le bon serial, et qu'il faudra guetter les big numbers dans la fenêtre des Datas...

tHe EGOiSTE ayant écrit son crackme en assembleur, il est très facile de tracer le programme, et par la suite de ripper les fonctions qui seront intéressantes:

0040128E  MOV       EDI,00402230         ; load Magic adresse 
00401293  XOR       EAX,EAX              ; EAX = 0
00401295  PUSH      05
00401297  POP       ECX
00401298  REPZ STOSD                     ; efface son contenu
0040129A  DEC       EAX                  ; EAX = -1
0040129B  MOV       ESI,004020F0         ; esi = Name
004012A0  MOV       EDI,00402230         ; Magic adresse         
004012A5  MOV       ECX,[EBP-04]         ; ECX = taille du name
004012A8  XOR       EDX,EDX              ; edx est un pointeur
004012AA  LODSB                          ; charge une lettre du name
004012AB  XOR       AH,AL                ; Xor -> c'est la base du "cryptage" du name
004012AD  IMUL      EAX,EAX,89177313     ; bidouilles pour modifier la valeur de la lettre chargée
004012B3  AND       EAX,55AA55AA                |
004012B8  IMUL      EAX,EAX,12299381            |
004012BE  XOR       EAX,AA55AA11                |
004012C3  IMUL      EAX,EAX,61                  |
004012C6  XOR       AH,AL                       |
004012C8  OR        EAX,10030118                |
004012CD  IMUL      EAX,EAX,00988279            |
004012D3  RCL       EAX,CL                      V
004012D5  XOR       [EDX+EDI],EAX        ; xor le résultat avec le contenu de Magic Adresse (initialisé à 0) 
:00402230 E0 31 EE EF 7A AD CE 46-F2 80 BF E1 16 84 CC 23  
:00402240 1A AB C3 04 00 00 00 00-00 00 00 00 00 00 00 00  
004012D8  ADD       EDX,03                             
004012DB  AND       EDX,0F
004012DE  INC       EDX                  ; pointera sur le caractère suivant
004012DF  DEC       ECX                  ; ecx = taille de la string Name à traiter
004012E0  JG        004012AA             ; loop jusqu'à concurrence de 40 caractères traités
004012E2  MOV       ESI,00402170         ; charge le serial entré
004012E7  MOV       EDI,00402230         ; load la magic Adresse
004012EC  MOV       ECX,[EBP-08]         ; ECX = taille de la Compagny
004012EF  XOR       EDX,EDX              ; et on recommence la même chose
004012F1  LODSB                          ; avec le serial entré
004012F2  SUB       AH,AL                ; en continuant à modifier la
004012F4  IMUL      EAX,EAX,89157313     ; Magic Adresse
etc...
00401327  JG        004012F1
etc...

pour arriver ici:

00401329  SUB       EAX,[EDI+08]
0040132C  IMUL      EAX,EAX,34814815
00401332  ADD       [EDI+10],EAX
00401335  SHR       EAX,0B
00401338  AND       EAX,03
0040133B  MOV       [EDI],AL
0040133D  PUSH      00402270              ; adresse de destination du calcul RSA
00401342  PUSH      00402370              ; 0A00E031EE...  contenu de la Magic Adresse
00401347  PUSH      00402000              ; 0A00D2E9BF9... chaîne trouvée dans les Data
0040134C  CALL      004013CD              ; RSA decrypt 

Vous n'aurez pas été sans remarquer qu'il n'y a pas de Public Exponent de poussé en paramètre, le conclusion logique étant que nous sommes sur une phase de décryptage du Cipher Text (stocké dans la Magic Adresse), soit: M = C ^ D MOD N
Petite particularité du cryptage à la tHE EGOiSTE, le premier WORD contient le nombre de bits RSA dans laquelle la chaîne est décryptée. Ici nous sommes sur un cryptage 160 bits (160/16=0Ah)

00401351  PUSH      05
00401353  POP       ECX                   ; nombre de DWORDs de la chaîne à contrôler.
00401354  MOV       ESI,00402272          ; load le résultat du calcul RSA (sans le 0A00)
00401359  MOV       EDI,00402230          ; load l'adresse où est stocké le serial entré
0040135E  LODSD
0040135F  XOR       [EDI],EAX             ; xor les 2 chaînes entre elles, DWORD par DWORD. 
00401361  JNZ       00401382              ; Si elles sont identiques, le résultat sera 0 -> sinon Go Out
00401363  ADD       EDI,04                ; passe au DWORD suivant
00401366  DEC       ECX                   ; decremente le nb de dword (8x5=40)
00401367  JG        0040135E              ; loop. Si ECX = 0 -> GoTo Good Boy

Une chose assez surprenante, avec beaucoup de programme utilisant des algorithmes de cryptage, c'est que le bon serial apparaît souvent en clair, comme ici, dans la fenêtre des Data, "neutralisant" les effets de l'utilisation de RSA...

Il ne reste plus qu'à ripper tout ca, et faire un Key Generator RSA 160 bits.

Allez!
Un ch'tit dernier, pour la route...

Mais comme c'est un défi de l'UFDC, je ne vais quand même pas bazarder mon fond de commerce, n'est ce pas...

Voilà ce que l'on découvre dans les String Data:

:00446E70 Prime_P db '321531933146223116297714231272921230731',0
:00446EA0 Prime_Q db '328953248147600083343294590689304010411',0
:00446ED0 a65537  db '65537',0  

J'ai rebaptisé Prime P et Prime Q, tout simplement parce qu'il est douteux que le Modulus et le Private Exponent soient tout deux présents dans le programme, que ces deux valeurs sont pratiquement identiques, une des caractéristiques courantes des Prime Numbers RSA, et que finalement ces deux nombres sont premiers...
Le tout est au format décimal.

En utilisant un
calculator Big_Number (au passage je tiens à tirer mon chapeau à Roy http://www.effervescence.com pour sa remarquable "BigLib" dont la facilité d'utilisation n'a d'égale que sa fiabilité), une fois les deux Prime Numbers multipliés, il va être possible de remplir les champs de RSA Tool 2, pour obtenir le Private Exponent:

Le produit de 321531933146223116297714231272921230731 et 328953248147600083343294590689304010411 donne
105768973791627093168727987838085212294123493500168896927946603100184157140441 (256 bits)

Le Private Exponent est:
90913191504492689814620519872667595082410264501256857244959499776932082148273.

Il est à noter que la factorisation d'une clé RSA 256 bits (78 chiffres) a été réussie en 1985, qu'une clé RSA 512 a été cassée en 1999 (prévoir quand même 8000 Mips.An -> 1 Mips.An = 245 opérations élémentaires), et que le "cassage" d'une clé 1024 est seulement prévue pour... 2080. Reste heureusement, comme dans ce crackme, que d'autres alternatives à la factorisation peuvent être trouvées...

Maintenant, que va faire le programme?
Et bien après la saisie du name, il va transformer chaque lettre le composant en son équivalent binaire (soit 01100011 pour "c"), et accoler les series binaires les unes derrières les autres (C'est le propre de FGint, la lib utilisée...).

:00BB5348 30 31 31 30 31 31 30 31-30 30 31 30 30 31 31 31  0110110100100111
:00BB5358 30 30 30 31 30 31 30 30-30 30 30 30 30 31 30 31  0001010000000101

Vous devinez la suite, le résultat de ces bidouillages va être crypté par RSA...

Pour finir, le bon serial apparaît en clair:

:00BB53F8 01 00 00 00 4E 00 00 00-31 35 37 32 34 34 31 39  ....N...15724419
:00BB5408 38 32 32 37 39 34 36 35-36 35 33 32 34 35 31 33  8227946565324513
:00BB5418 39 38 32 34 32 31 34 37-31 35 36 31 36 31 31 34  9824214715616114
:00BB5428 36 32 32 33 37 39 31 38-37 37 31 34 32 33 31 32  6223791877142312
:00BB5438 33 32 35 30 38 30 31 39-34 39 31 35 35 37 33 31  3250801949155731
:00BB5448 39 37 31 31 32 33 00 00-50 54 BB 00 50 54 BB 00  971123..PT..PT..


Avec ce dernier Crackme, sans avoir fait le tour de la question, et loin de là !, vous avez une première approche des programmes utilisant des algorithmes de cryptages. Puissiez vous en faire bon usage....

Bonne journée
Christal

Les informations ci dessus ont été complétées grace au travail et aux scripts de WinTerMiNator, Roy (et sa fameuse BigLib), HCCC6, tHE EGOiSTE, cryptosec.lautre.net