pDriLl's Crypto Keygenme 4

Type de protection : name / serial
Outils utilisés :

Références : Fichiers joints :

Ce keygenme est basé sur le DSA (Digital Signature Algorithm). Il a été codé avec la librairie MIRACL, ce qui le rend plus facile à comprendre, étant donné qu'elle est très documentée.

Le programme est packé, avec un packer pas très puissant.
Avant d'ouvrir le keygenme, dans Olly il faut aller dans Options --> Debugging Options --> SFX, et cocher
'Trace real entry blockwise'. OllyDbg va ainsi tracer le prog jusqu'à l'OEP.

On ouvre ensuite le keygenme avec Olly, et on regarde rapidement le listing.
En regardant les imports je n'ai pas trouvé de fonctions intéressantes: GetDlgItemTextA, GetWindowTextA, etc...
Le breakpoint sur SendMessage ne fonctionne pas. Je ne sais pas du tout me servir de Olly, je ne sais pas poser de breakpoint sur WM_GETTEXT par exemple.

Alors j'ai lancé le programme (F9), et j'ai regardé les SDR intéressantes.

Ici par exemple :

004013CF   . 68 94D14000    PUSH pdr-keyg.0040D194                   ;  ASCII "Bn6EN1dDFrupNxw1Wk4WO5=="
004013D4   . 8B8D 04FFFFFF  MOV ECX,DWORD PTR SS:[EBP-FC]
004013DA   . 51             PUSH ECX
004013DB   . E8 A04A0000    CALL pdr-keyg.00405E80

Ca ressemble à l'initialisation d'un bignum à partir d'une chaîne en base64.
Alors j'ai posé un breakpoint plus haut, en .4012DE

On entre un nom (jB), un serial bidon (11223344556677889900AABB).
Et on clique sur 'Check'. Le breakpoint a bien fonctionné.
On se retrouve ici :

004012DE   > 8D85 D4FDFFFF  LEA EAX,DWORD PTR SS:[EBP-22C]
004012E4   . 50             PUSH EAX
004012E5   . E8 16060000    CALL pdr-keyg.00401900
004012EA   . 83C4 04        ADD ESP,4

On rentre dans le call en .401900 :

00401900  /$ 8B4424 04      MOV EAX,DWORD PTR SS:[ESP+4]
00401904  |. 33C9           XOR ECX,ECX
00401906  |. 8948 14        MOV DWORD PTR DS:[EAX+14],ECX
00401909  |. 8948 10        MOV DWORD PTR DS:[EAX+10],ECX
0040190C  |. C700 01234567  MOV DWORD PTR DS:[EAX],67452301
00401912  |. C740 04 89ABCD>MOV DWORD PTR DS:[EAX+4],EFCDAB89
00401919  |. C740 08 FEDCBA>MOV DWORD PTR DS:[EAX+8],98BADCFE
00401920  |. C740 0C 765432>MOV DWORD PTR DS:[EAX+C],10325476
00401927  \. C3             RETN

On reconnaît une initialisation typique d'un hash (MD, RipeMD ou SHA).
Retour à la routine précédente :

004012ED   . 8A0D C6E94000  MOV CL,BYTE PTR DS:[40E9C6]
004012F3   . 880D 40E94000  MOV BYTE PTR DS:[40E940],CL
004012F9   . 8A15 CDE94000  MOV DL,BYTE PTR DS:[40E9CD]
004012FF   . 8815 41E94000  MOV BYTE PTR DS:[40E941],DL
00401305   . A0 D4E94000    MOV AL,BYTE PTR DS:[40E9D4]
0040130A   . A2 42E94000    MOV BYTE PTR DS:[40E942],AL

Le serial entré est stocké à l'offset .40E6C0
Cette routine va donc copier le 7e, le 14e et le 21e char du serial en .40e940, .40e941 et .401942

0040130F   . C745 B8 43E940>MOV DWORD PTR SS:[EBP-48],pdr-keyg.0040E943
00401316   . 8B8D FCFEFFFF  MOV ECX,DWORD PTR SS:[EBP-104]
0040131C   . 51             PUSH ECX                                            ;  longueur du serial
0040131D   . 68 C0D14000    PUSH pdr-keyg.0040D1C0                              ;  ASCII "%d"
00401322   . 8B55 B8        MOV EDX,DWORD PTR SS:[EBP-48]
00401325   . 52             PUSH EDX
00401326   . E8 D5650000    CALL pdr-keyg.00407900                              ;  wsprintfA
0040132B   . 83C4 0C        ADD ESP,0C

La longueur du serial est ensuite convertie en string, et stockée à l'adresse pointée par edx (.401943).
Ici la longueur du serial est 24.

Puis on a :

0040132E   . C745 B8 45E940>MOV DWORD PTR SS:[EBP-48],pdr-keyg.0040E945
00401335   . 68 B4D14000    PUSH pdr-keyg.0040D1B4                              ;  ASCII "EGBE-YEAH!!"
0040133A   . 68 B0D14000    PUSH pdr-keyg.0040D1B0                              ;  ASCII "%s"
0040133F   . 8B45 B8        MOV EAX,DWORD PTR SS:[EBP-48]
00401342   . 50             PUSH EAX
00401343   . E8 B8650000    CALL pdr-keyg.00407900                              ;  wsprintfA
00401348   . 83C4 0C        ADD ESP,0C

Encore un autre appel à wsprintfA. "EGBE-YEAH!!" est copié à l'adresse pointée par eax, ie .40E945
On arrive ensuite ici:

0040134B   . 8A0D 45E94000  MOV CL,BYTE PTR DS:[40E945]
00401351   . 80C1 01        ADD CL,1
00401354   . 880D 45E94000  MOV BYTE PTR DS:[40E945],CL
0040135A   . 8A15 46E94000  MOV DL,BYTE PTR DS:[40E946]
00401360   . 80C2 01        ADD DL,1
00401363   . 8815 46E94000  MOV BYTE PTR DS:[40E946],DL
00401369   . A0 47E94000    MOV AL,BYTE PTR DS:[40E947]
0040136E   . 04 01          ADD AL,1
00401370   . A2 47E94000    MOV BYTE PTR DS:[40E947],AL
00401375   . 8A0D 48E94000  MOV CL,BYTE PTR DS:[40E948]
0040137B   . 80C1 01        ADD CL,1
0040137E   . 880D 48E94000  MOV BYTE PTR DS:[40E948],CL
00401384   . C605 50E94000 >MOV BYTE PTR DS:[40E950],0

Cette routine incrémente les chars situés aux adresses .40e945, .40e946, .40e947 et .40e948.
"EGBE" devient donc "FHCF".
On obtient finalement une chaîne de 16 caractères :

0040E940  34 37 41 32 34 46 48 43 46 2D 59 45 41 48 21 21  47A24FHCF-YEAH!!

Où 4,7,A sont respectivement les 7e, 14e et 21e caractères du serial, et 24 la taille du serial.
Ensuite on arrive ici :

0040138B   . 6A 10          PUSH 10                                             ;  longueur de la chaîne de caractères
0040138D   . 68 40E94000    PUSH pdr-keyg.0040E940                              ;  ASCII "47A24FHCF-YEAH!!"
00401392   . 8D95 D4FDFFFF  LEA EDX,DWORD PTR SS:[EBP-22C]
00401398   . 52             PUSH EDX
00401399   . E8 92050000    CALL pdr-keyg.00401930
0040139E   . 83C4 0C        ADD ESP,0C
004013A1   . 8D85 D4FDFFFF  LEA EAX,DWORD PTR SS:[EBP-22C]
004013A7   . 50             PUSH EAX
004013A8   . 8D8D 10FFFFFF  LEA ECX,DWORD PTR SS:[EBP-F0]
004013AE   . 51             PUSH ECX
004013AF   . E8 2C060000    CALL pdr-keyg.004019E0
004013B4   . 83C4 08        ADD ESP,8

On a en sortie un hash MD5 du buffer entré (47A24FHCF-YEAH!!), à l'offset pointé par ecx (ebp-f0).
On obtient:

0012FA6C  10 8B 9B E7 C6 34 E0 9A C7 BE 47 E8 50 1C A9 87  .....4....G.P...

Puis on arrive ici :

004013B7   . 8B95 34FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1CC]
004013BD   . 52             PUSH EDX                                             ;
004013BE   . 8D85 10FFFFFF  LEA EAX,DWORD PTR SS:[EBP-F0]                        ; hash MD5
004013C4   . 50             PUSH EAX
004013C5   . 6A 10          PUSH 10
004013C7   . E8 F4510000    CALL pdr-keyg.004065C0
004013CC   . 83C4 0C        ADD ESP,0C

En sortie on a, à l'offset pointé par *eax :

00912090  04 00 00 00 9C 20 91 00 00 00 00 00 87 A9 1C 50  ..... .........P
009120A0  E8 47 BE C7 9A E0 34 C6 E7 9B 8B 10 00 00 00 00  .G....4.........

On reconnaît dont la procédure bytes_to_big de MIRACL : le hash MD5 est converti en bignum.
Puis on arrive ici :

004013CF   . 68 94D14000    PUSH pdr-keyg.0040D194                   ;  ASCII "Bn6EN1dDFrupNxw1Wk4WO5=="
004013D4   . 8B8D 04FFFFFF  MOV ECX,DWORD PTR SS:[EBP-FC]
004013DA   . 51             PUSH ECX
004013DB   . E8 A04A0000    CALL <pdr-keyg.instr>
004013E0   . 83C4 08        ADD ESP,8
004013E3   . 8B95 34FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1CC]
004013E9   . 52             PUSH EDX
004013EA   . 8B85 04FFFFFF  MOV EAX,DWORD PTR SS:[EBP-FC]
004013F0   . 50             PUSH EAX
004013F1   . E8 CA250000    CALL <pdr-keyg.compare>
004013F6   . 83C4 08        ADD ESP,8
004013F9   . 85C0           TEST EAX,EAX
004013FB   . 74 26          JE SHORT pdr-keyg.00401423

Une chaîne en base 64 est convertie en bignum, puis est comparée avec le hash converti précédemment en bignum.
La chaîne convertie en hexadécimal donne :

00913170  04 00 00 00 7C 31 91 00 00 00 00 00 B9 63 E1 A4  ....|1.......c..
00913180  55 C3 71 93 BA 6B 31 74 75 43 E8 67 00 00 00 00  U.q..k1tuC.g....

Le hash MD5 doit donc être égal à : 67e8437574316bba9371c355a4e163b9
On fait donc un brute force sur ce hash.
Pour le charset j'ai utilisé les majuscules, les minuscules, les chiffres, plus le tiret étant donné l'emplacement des caractères utilisés pour le hash (on peut s'attendre à un serial du type: xxxxxx-xxxxxx-xxxxxx-xxxxxx).
On va donc brute forcer les 5 premiers caractères du buffer à hasher, les autres étant fixes. J'ai utilisé MDCrack pour cela.

----------------------------------------------------------
mdcrack -e FHCF-YEAH!! -s ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-0123456789 67e8437574316bba9371c355a4e163b9

<<System>> MDcrack v1.2 is starting.
<<System>> Sorting custom charset ... done
<<System>> Using custom charset : ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst
uvwxyz-0123456789
<<System>> Max pass size = 28 >> Entering MD5 Core 2.

Password size: 12

Password size: 13

Password size: 14

Password size: 15

Password size: 16


----------------------------------------
Collision found ! => ---27FHCF-YEAH!!


Collision(s) tested : 990625526 in 181 second(s), 922 millisec, 0 microsec.
Average of 5445331.2 hashes/sec.
----------------------------------------------------------

Le brute force donne donc le format du serial : 27 caractères, avec l'emplacement des tirets dans le serial.
Le serial est de la forme: xxxxxx-xxxxxx-xxxxxx-xxxxxx

Le format du serial que l'on a entré n'est donc pas bon. On relance le prog en entrant comme nom 'jB' et comme serial: '11233-445566-778899-00AABB'.

On trace comme précédemment, les bignums comparés sont égaux et on arrive là :

00401439   > 8B8D 00FFFFFF  MOV ECX,DWORD PTR SS:[EBP-100]
0040143F   . 83C1 01        ADD ECX,1
00401442   . 898D 00FFFFFF  MOV DWORD PTR SS:[EBP-100],ECX
00401448   > BF C0E94000    MOV EDI,pdr-keyg.0040E9C0                ;  ASCII "112233-445566-778899-00AABB"
0040144D   . 83C9 FF        OR ECX,FFFFFFFF
00401450   . 33C0           XOR EAX,EAX
00401452   . F2:AE          REPNE SCAS BYTE PTR ES:[EDI]
00401454   . F7D1           NOT ECX
00401456   . 83C1 FF        ADD ECX,-1
00401459   . 398D 00FFFFFF  CMP DWORD PTR SS:[EBP-100],ECX
0040145F   . 7D 74          JGE SHORT pdr-keyg.004014D5
00401461   . 83BD 00FFFFFF >CMP DWORD PTR SS:[EBP-100],6             ;  1er tiret
00401468   . 75 0F          JNZ SHORT pdr-keyg.00401479
0040146A   . 8B95 00FFFFFF  MOV EDX,DWORD PTR SS:[EBP-100]
00401470   . 83C2 01        ADD EDX,1
00401473   . 8995 00FFFFFF  MOV DWORD PTR SS:[EBP-100],EDX
00401479   > 83BD 00FFFFFF >CMP DWORD PTR SS:[EBP-100],0D            ;  2e tiret
00401480   . 75 0F          JNZ SHORT pdr-keyg.00401491
00401482   . 8B85 00FFFFFF  MOV EAX,DWORD PTR SS:[EBP-100]
00401488   . 83C0 01        ADD EAX,1
0040148B   . 8985 00FFFFFF  MOV DWORD PTR SS:[EBP-100],EAX
00401491   > 83BD 00FFFFFF >CMP DWORD PTR SS:[EBP-100],14
00401498   . 75 0F          JNZ SHORT pdr-keyg.004014A9              ;  3e tiret
0040149A   . 8B8D 00FFFFFF  MOV ECX,DWORD PTR SS:[EBP-100]
004014A0   . 83C1 01        ADD ECX,1
004014A3   . 898D 00FFFFFF  MOV DWORD PTR SS:[EBP-100],ECX
004014A9   > 8B95 F8FEFFFF  MOV EDX,DWORD PTR SS:[EBP-108]
004014AF   . 8B85 00FFFFFF  MOV EAX,DWORD PTR SS:[EBP-100]
004014B5   . 8A88 C0E94000  MOV CL,BYTE PTR DS:[EAX+40E9C0]
004014BB   . 888A 40E94000  MOV BYTE PTR DS:[EDX+40E940],CL
004014C1   . 8B95 F8FEFFFF  MOV EDX,DWORD PTR SS:[EBP-108]
004014C7   . 83C2 01        ADD EDX,1
004014CA   . 8995 F8FEFFFF  MOV DWORD PTR SS:[EBP-108],EDX
004014D0   .^E9 64FFFFFF    JMP pdr-keyg.00401439

Cette routine va tout simplement copier le serial entré en enlevant les tirets. On obtient:

0040E940  31 31 32 32 33 33 34 34 35 35 36 36 37 37 38 38  1122334455667788
0040E950  39 39 30 30 41 41 42 42 00 00 00 00 00 00 00 00  9900AABB........

La routine suivante vérifie ensuite les caractères du serial. Seuls les chiffres et les lettres entre 'A' et 'F' sont autorisés.
Si on entre un caractère autre que ceux là, une message box apparaît.
Puis on est ici :

0040157C   > 8B85 2CFEFFFF  MOV EAX,DWORD PTR SS:[EBP-1D4]
00401582   . C780 20020000 >MOV DWORD PTR DS:[EAX+220],10            ;  mip->IOBASE=16
0040158C   . C745 B8 4CE940>MOV DWORD PTR SS:[EBP-48],pdr-keyg.0040E>;  ASCII "77889900AABB"
00401593   . 8B4D B8        MOV ECX,DWORD PTR SS:[EBP-48]
00401596   . 51             PUSH ECX
00401597   . 8B95 20FFFFFF  MOV EDX,DWORD PTR SS:[EBP-E0]
0040159D   . 52             PUSH EDX
0040159E   . E8 DD480000    CALL <pdr-keyg.instr>
004015A3   . 83C4 08        ADD ESP,8
004015A6   . C605 4CE94000 >MOV BYTE PTR DS:[40E94C],0               ;  serial[12]=0
004015AD   . 68 40E94000    PUSH pdr-keyg.0040E940                   ;  ASCII "11223344556677889900AABB"
004015B2   . 8B85 24FFFFFF  MOV EAX,DWORD PTR SS:[EBP-DC]
004015B8   . 50             PUSH EAX
004015B9   . E8 C2480000    CALL <pdr-keyg.instr>
004015BE   . 83C4 08        ADD ESP,8

On passe en base hexadécimale.
La deuxième partie du serial est convertie en bignum, et stockée à l'offset pointé par ebp-48
Ensuite le 12 caractère du serial est mis à zéro, et 112233445566 est converti en bignum, puis stocké à l'offset pointé par ebp-0dc.

Puis on a :

004015C1   . 8D8D 5CFFFFFF  LEA ECX,DWORD PTR SS:[EBP-A4]
004015C7   . 51             PUSH ECX
004015C8   . E8 C30E0000    CALL pdr-keyg.00402490
004015CD   . 83C4 04        ADD ESP,4

On rentre à l'intérieur du call, et on voit l'initialisation d'un nouveau hash: MD, RipeMD ou SHA :

00402490  /$ 8B4424 04      MOV EAX,DWORD PTR SS:[ESP+4]
00402494  |. 33C9           XOR ECX,ECX
00402496  |. C700 01234567  MOV DWORD PTR DS:[EAX],67452301
0040249C  |. C740 04 89ABCD>MOV DWORD PTR DS:[EAX+4],EFCDAB89
004024A3  |. C740 08 FEDCBA>MOV DWORD PTR DS:[EAX+8],98BADCFE
004024AA  |. C740 0C 765432>MOV DWORD PTR DS:[EAX+C],10325476
004024B1  |. C740 10 F0E1D2>MOV DWORD PTR DS:[EAX+10],C3D2E1F0
004024B8  |. 8948 14        MOV DWORD PTR DS:[EAX+14],ECX
004024BB  |. 8948 18        MOV DWORD PTR DS:[EAX+18],ECX
004024BE  \. C3             RETN

Puis on arrive ici :

004015D0   . 8B95 30FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1D0]
004015D6   . 52             PUSH EDX                                 ;  longueur du nom
004015D7   . 68 C0E84000    PUSH pdr-keyg.0040E8C0                   ;  ASCII "jB"
004015DC   . 8D85 5CFFFFFF  LEA EAX,DWORD PTR SS:[EBP-A4]
004015E2   . 50             PUSH EAX
004015E3   . E8 D80E0000    CALL pdr-keyg.004024C0
004015E8   . 83C4 0C        ADD ESP,0C
004015EB   . 8D8D 5CFFFFFF  LEA ECX,DWORD PTR SS:[EBP-A4]
004015F1   . 51             PUSH ECX
004015F2   . 8D95 E0FEFFFF  LEA EDX,DWORD PTR SS:[EBP-120]
004015F8   . 52             PUSH EDX
004015F9   . E8 62110000    CALL pdr-keyg.00402760
004015FE   . 83C4 08        ADD ESP,8

On rentre dans chacun des deux calls, et on analyse ce qui se passe.
On reconnaît facilement un hash SHA (voir l'emploi des constantes 5A827999, 6ED9EBA1, 8F1BBCDC et CA62C1D6, en .402550, typiques d'un SHA).
Puis on débroussaille un peu, et on s'aperçoit que c'est un SHA-0 qui est utilisé (regardez une routine comme celle de MIRACL par exemple pour saisir les différences).
Enfin on s'aperçoit qu'en sortie de la procédure de process, au lieu d'avoir 0,0x80,"Bj" on obtient: "jB",0x80,0.
Il faut donc réaliser une conversion Little Endian / Big Endian.

On obtient en sortie pour le hash du nom: 9795ABFEC6051F456196F441F6C8D11A1B40E345

Puis on arrive ici:

00401601   . 8B85 2CFEFFFF  MOV EAX,DWORD PTR SS:[EBP-1D4]
00401607   . C780 20020000 >MOV DWORD PTR DS:[EAX+220],40            ;  mip->IOBASE=64
00401611   . 68 70D14000    PUSH pdr-keyg.0040D170                   ;  ASCII "rizMjllW3niYFDZJlEEI7vyix++QkBK7="
00401616   . 8B4D C0        MOV ECX,DWORD PTR SS:[EBP-40]
00401619   . 51             PUSH ECX
0040161A   . E8 61480000    CALL <pdr-keyg.instr>
0040161F   . 83C4 08        ADD ESP,8
00401622   . 68 64D14000    PUSH pdr-keyg.0040D164                   ;  ASCII "p911BFFR="
00401627   . 8B55 BC        MOV EDX,DWORD PTR SS:[EBP-44]
0040162A   . 52             PUSH EDX
0040162B   . E8 50480000    CALL <pdr-keyg.instr>
00401630   . 83C4 08        ADD ESP,8
00401633   . 68 40D14000    PUSH pdr-keyg.0040D140                   ;  ASCII "jfwz34Lt7/VqvRrhYb4X+8H0A9XfEzEG="
00401638   . 8B85 08FFFFFF  MOV EAX,DWORD PTR SS:[EBP-F8]
0040163E   . 50             PUSH EAX
0040163F   . E8 3C480000    CALL <pdr-keyg.instr>
00401644   . 83C4 08        ADD ESP,8
00401647   . 68 1CD14000    PUSH pdr-keyg.0040D11C                   ;  ASCII "qg1kJK2T1pVDWjoJ+q/VNYYg03Ij7q85="
0040164C   . 8B8D 04FFFFFF  MOV ECX,DWORD PTR SS:[EBP-FC]
00401652   . 51             PUSH ECX
00401653   . E8 28480000    CALL <pdr-keyg.instr>
00401658   . 83C4 08        ADD ESP,8

Quatre chaînes de caractères sont converties en bignums (la conversion se fait base 64).
Voici la correspondance base64 / hexa :

rizMjllW3niYFDZJlEEI7vyix++QkBK7 = AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BB
p911BFFR                         = A7DD75045151
jfwz34Lt7/VqvRrhYb4X+8H0A9XfEzEG = 8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106
qg1kJK2T1pVDWjoJ+q/VNYYg03Ij7q85 = AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39

Puis on arrive ici :

0040165B   . 8B95 34FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1CC]
00401661   . 52             PUSH EDX
00401662   . 8D85 E0FEFFFF  LEA EAX,DWORD PTR SS:[EBP-120]           ;  hash SHA-0 du nom
00401668   . 50             PUSH EAX
00401669   . 6A 14          PUSH 14
0040166B   . E8 504F0000    CALL <pdr-keyg.bytes_to_big>
00401670   . 83C4 0C        ADD ESP,0C

Le hash SHA-0 est converti en bignum.
Puis on a :

00401673   . 8B8D 20FFFFFF  MOV ECX,DWORD PTR SS:[EBP-E0]
00401679   . 51             PUSH ECX                                 ;  77889900AABB
0040167A   . 8B95 20FFFFFF  MOV EDX,DWORD PTR SS:[EBP-E0]
00401680   . 52             PUSH EDX                                 ;  77889900AABB
00401681   . 8B85 20FFFFFF  MOV EAX,DWORD PTR SS:[EBP-E0]
00401687   . 50             PUSH EAX                                 ;  77889900AABB
00401688   . 8B4D BC        MOV ECX,DWORD PTR SS:[EBP-44]
0040168B   . 51             PUSH ECX                                 ;  A7DD75045151
0040168C   . 8B95 20FFFFFF  MOV EDX,DWORD PTR SS:[EBP-E0]
00401692 > . 52             PUSH EDX                                 ;  77889900AABB
00401693   . E8 983E0000    CALL pdr-keyg.00405530
00401698   . 83C4 14        ADD ESP,14

On reconnaît la procédure xgcd qui, avec ces arguments, va calculer l'inverse de 77889900AABB modulo A7DD75045151
On a: 77889900AABB^(-1) mod A7DD75045151 = 4204ABAF3E18

0040169B   . 8B85 DCFEFFFF  MOV EAX,DWORD PTR SS:[EBP-124]
004016A1   . 50             PUSH EAX                                 ;  0
004016A2   . 8B4D BC        MOV ECX,DWORD PTR SS:[EBP-44]
004016A5   . 51             PUSH ECX                                 ;  A7DD75045151
004016A6   . 8B55 BC        MOV EDX,DWORD PTR SS:[EBP-44]
004016A9   . 52             PUSH EDX                                 ;  A7DD75045151
004016AA   . 8B85 20FFFFFF  MOV EAX,DWORD PTR SS:[EBP-E0]
004016B0   . 50             PUSH EAX                                 ;  4204ABAF3E18 = 1/77889900AABB
004016B1   . 8B8D 20FFFFFF  MOV ECX,DWORD PTR SS:[EBP-E0]
004016B7   . 51             PUSH ECX                                 ;  4204ABAF3E18 = 1/77889900AABB
004016B8   . 8B95 34FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1CC]
004016BE   . 52             PUSH EDX
004016BF   . E8 8C370000    CALL pdr-keyg.00404E50
004016C4   . 83C4 18        ADD ESP,18

La procédure prend 6 bigs en arguments. C'est donc soit power2, soit mad.
Ici c'est mad, et la procédure calcule donc: hash(nom) * 4204ABAF3E18 mod A7DD75045151
Ce qui donne: 3F3C5C0D52D0.

Puis mad est utilisé une autre fois :

004016C7   . 8B85 38FEFFFF  MOV EAX,DWORD PTR SS:[EBP-1C8]
004016CD   . 50             PUSH EAX                                 ;  0
004016CE   . 8B4D BC        MOV ECX,DWORD PTR SS:[EBP-44]
004016D1   . 51             PUSH ECX                                 ;  A7DD75045151
004016D2   . 8B55 BC        MOV EDX,DWORD PTR SS:[EBP-44]
004016D5   . 52             PUSH EDX                                 ;  A7DD75045151
004016D6   . 8B85 20FFFFFF  MOV EAX,DWORD PTR SS:[EBP-E0]
004016DC   . 50             PUSH EAX                                 ;  4204ABAF3E18 = 1/77889900AABB
004016DD   . 8B8D 20FFFFFF  MOV ECX,DWORD PTR SS:[EBP-E0]
004016E3   . 51             PUSH ECX                                 ;  4204ABAF3E18 = 1/77889900AABB
004016E4   . 8B95 24FFFFFF  MOV EDX,DWORD PTR SS:[EBP-DC]
004016EA   . 52             PUSH EDX                                 ;  112233445566
004016EB   . E8 60370000    CALL pdr-keyg.00404E50
004016F0   . 83C4 18        ADD ESP,18

Calcul de 112233445566 * 4204ABAF3E18 mod A7DD75045151,
ce qui donne : 5E1E8CFFDB97

On a ensuite :

004016F3   . 8B85 0CFFFFFF  MOV EAX,DWORD PTR SS:[EBP-F4]
004016F9   . 50             PUSH EAX                                 ;  0
004016FA   . 8B4D C0        MOV ECX,DWORD PTR SS:[EBP-40]
004016FD   . 51             PUSH ECX                                 ;  AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BB
004016FE   . 8B95 38FEFFFF  MOV EDX,DWORD PTR SS:[EBP-1C8]
00401704   . 52             PUSH EDX                                 ;  5E1E8CFFDB97
00401705   . 8B85 04FFFFFF  MOV EAX,DWORD PTR SS:[EBP-FC]
0040170B   . 50             PUSH EAX                                 ;  AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39
0040170C   . 8B8D DCFEFFFF  MOV ECX,DWORD PTR SS:[EBP-124]
00401712   . 51             PUSH ECX                                 ;  3F3C5C0D52D0
00401713   . 8B95 08FFFFFF  MOV EDX,DWORD PTR SS:[EBP-F8]
00401719   . 52             PUSH EDX                                 ;  8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106
0040171A   . E8 713D0000    CALL pdr-keyg.00405490                   ;  calcule a^b * c^d mod n
0040171F   . 83C4 18        ADD ESP,18                               ;  ce qui donne: 12C20BFCCDE062BFC59ABD97D9D3CAD11A781ECC86E5EB2D

Encore une procédure qui prend 6 bigs en entrée. Mais ce n'est pas mad. C'est donc power2.
La procédure renvoie donc :
Power(8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106, 3F3C5C0D52D0) * Power(AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39, 5E1E8CFFDB97) mod AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BB
ce qui donne: 12C20BFCCDE062BFC59ABD97D9D3CAD11A781ECC86E5EB2D

Puis :

00401722   . 8B45 BC        MOV EAX,DWORD PTR SS:[EBP-44]
00401725   . 50             PUSH EAX                                 ; /A7DD75045151
00401726   . 8B4D BC        MOV ECX,DWORD PTR SS:[EBP-44]            ; |
00401729   . 51             PUSH ECX                                 ; |A7DD75045151
0040172A   . 8B95 0CFFFFFF  MOV EDX,DWORD PTR SS:[EBP-F4]            ; |
00401730   . 52             PUSH EDX                                 ; |12C20BFCCDE062BFC59ABD97D9D3CAD11A781ECC86E5EB2D
00401731   . E8 7A2D0000    CALL pdr-keyg.004044B0                   ; \
00401736   . 83C4 0C        ADD ESP,0C

La procédure retourne 12C20BFCCDE062BFC59ABD97D9D3CAD11A781ECC86E5EB2D % A7DD75045151.
C'est donc divide, qui ne retourne que le reste de la division euclidienne entre ces deux nombres puisque le 2e et le 3e argument sont égaux.
On obtient : 617344B1104B

Puis finalement :

00401739   . 8B85 24FFFFFF  MOV EAX,DWORD PTR SS:[EBP-DC]
0040173F   . 50             PUSH EAX                                 ;  112233445566
00401740   . 8B8D 0CFFFFFF  MOV ECX,DWORD PTR SS:[EBP-F4]
00401746   . 51             PUSH ECX                                 ;  617344B1104B
00401747   . E8 74220000    CALL <pdr-keyg.compare>                  ;  on compare tout ca
0040174C   . 83C4 08        ADD ESP,8
0040174F   . 85C0           TEST EAX,EAX
00401751   . 74 28          JE SHORT pdr-keyg.0040177B

Procédure qui compare la première partie du serial entré avec le résultat du calcul précédent.

Récapitulons :
On note :
q = A7DD75045151
alpha = 8DFC33DF82EDEFF56ABD1AE161BE17FBC1F403D5DF133106
y = AA0D6424AD93D695435A3A09FAAFD5358620D37223EEAF39
p = AE2CCC8E5956DE7898143649944108EEFCA2C7EF909012BB

m le nom entré
h(m) = hash_sha1(m)
r la première partie du serial
s la deuxième partie du serial

Le programme calcule :
w = s^(-1) mod q
u1 = w*h(m) mod q
u2 = r*w mod q
v = (alpha^u1 * y^u2 mod p) mod q
Et on doit avoir: v=r

On reconnaît donc la routine de vérification du DSA.
On doit alors résoudre le logarithme discret, ie trouver a tel que :
y = alpha^a mod p

Pour cela j'ai utilisé Discrete logarithm calculator
Au bout de quelques secondes on obtient :
a = 40A6C8A2464A891E99DDBFCFC967BAFD4BAFA67B3ECEDC43

On calcule donc :
r = (alpha^k mod p) mod q
Pour simplifier on prend ici k=1.
Alors
r = (alpha mod p) mod q
  = 4A2B8273F9AF

k^(-1) mod q= 1
Et
s = k^(-1)(h(m)+a*r) mod q
  = h(m)+a*r mod q
  = 4B3E0430F8DB

1ere partie du serial: 4A2B8273F9AF
2eme partie du serial: 4B3E0430F8DB

Le serial est donc: 4A2B82-73F9AF-4B3E04-30F8DB

Le keygen est codé en C avec la librairie MIRACL
Le hash SHA-0 est celui de MIRACL avec quelques petites modifications.

Et c'est terminé