Analyse du code:
Un breakpoint sur GetDlgItemTextA...
_text:004013A1
push 100h
; nMaxCount
_text:004013A6
push offset Nom ; lpString
_text:004013AB
push 65h
; nIDDlgItem
_text:004013AD
push edi
; hDlg
_text:004013AE
call GetDlgItemTextA
_text:004013B3
mov ds:NameSize, eax
_text:004013B8
push 100h
; nMaxCount
_text:004013BD
push offset Serial ; lpString
_text:004013C2
push 67h
; nIDDlgItem
_text:004013C4
push edi
; hDlg
_text:004013C5
call GetDlgItemTextA
_text:004013CA
mov ds:SizeSerial, eax
_text:004013CF
mov eax, ds:NameSize
_text:004013D4
or eax, eax
_text:004013D6
jz ErreurSerial
_text:004013DC
cmp eax, 40h
_text:004013DF
jnb ErreurSerial
_text:004013E5
cmp ds:SizeSerial, 0
_text:004013EC
jz ErreurSerial
Le serial fait donc moins de 64 caracteres...
... et il n'est composé que des caracteres [ 0 - 9 ] [ A - F
] ( hexadecimal ) :
_text:004013FB A_F:
_text:004013FB
mov eax, ds:Flag
_text:00401400
movzx eax, ds:Serial[eax]
_text:00401408
mov ds:lettres, eax
_text:0040140D
cmp eax, 41h
_text:00401410
jb short Chiffres
_text:00401412
cmp eax, 46h
_text:00401415
jbe short Suite
_text:00401417
_text:00401417 Chiffres:
_text:00401417
mov eax, ds:lettres
_text:0040141C
cmp eax, 30h
_text:0040141F
jb short ErreurLettre
_text:00401421
cmp eax, 39h
_text:00401424
jbe short Suite
_text:00401426
_text:00401426 ErreurLettre:
_text:00401426
push offset aInvalidKey ; lpString
_text:0040142B
push 67h
; nIDDlgItem
_text:0040142D
push edi
; hDlg
_text:0040142E
call SetDlgItemTextA
_text:00401433
jmp loc_0_401593
_text:00401438
_text:00401438 Suite:
_text:00401438
inc ds:Flag
_text:0040143E
_text:0040143E loc_0_40143E:
_text:0040143E
mov eax, ds:SizeSerial
_text:00401443
cmp ds:Flag, eax
_text:00401449
jb short A_F
Puis le programme initialise des bignums (cf la doc de Miracl )
_text:00401461
push 0
_text:00401463
call mirvar
_text:00401468
mov ds:Big1, eax
_text:0040146D
push 0
_text:0040146F
call mirvar
_text:00401474
mov ds:Big2, eax
_text:00401479
push 0
_text:0040147B
call mirvar
_text:00401480
mov ds:Big3, eax
_text:00401485
push 0
_text:00401487
call mirvar
_text:0040148C
mov ds:Big4, eax
_text:00401491
push 0
_text:00401493
call mirvar
et leur affectent la valeur du serial, du nom ( valeur ascii des lettres
) et de la Magic Key...
_text:004014A0
mov dword ptr [eax+238h], 10h ; base 16
_text:004014AA
push ds:Big5
_text:004014B0
push offset Nom
_text:004014B5
push ds:NameSize
_text:004014BB
call bytes_to_big
_text:004014C0
push offset Serial
_text:004014C5
push ds:Big4
_text:004014CB
call sub_0_4065BC
_text:004014D0
push offset MagicKey
_text:004014D5
push ds:Big2
_text:004014DB
call sub_0_4065BC
Le Big3 recoit la valeur 10001h.. il ya donc de forte chance que le
programme utilise RSA...
_text:004014E0
push ds:Big3
_text:004014E6
push 10001h
_text:004014EB
call cinstr
Et effectivement on reconnait, quelques lignes plus bas, la signature
de la fonction powmod (cf la doc de la librarie Miracl )
_text:004014F0
push ds:Big1
_text:004014F6
push ds:Big2 ; Magic Key
_text:004014FC
push ds:Big3 ; 10001h
_text:00401502
push ds:Big4 ; Serial
_text:00401508
call powmod
Le resultat est ensuite comparé au Nom...
_text:0040150D
push ds:Big1
_text:00401513
push ds:Big5
_text:00401519
call compare
Donc pour trouver un serial valide il "suffit" de calculer le RSA du
nom... ;)
Le petit probleme est qu'ici la longueur du modulo ( la Magic Key)
depasse les 500 bits... ;p
D'ou vient la Magic Key ? En posant un "bpx SetDlgItemTextA" on
tombe ici, or quelques lignes plus haut le programme semble utiliser des
Bignums....
_text:0040134E
push offset MagicKey
_text:00401353
push ds:Big2
_text:00401359
call BigToString
_text:0040135E
push offset MagicKey ; lpString
_text:00401363
push 66h
; nIDDlgItem
_text:00401365
push [ebp+hDlg] ; hDlg
_text:00401368
call SetDlgItemTextA
Donc tout semble indiquer que la valeur de la Magic Key soit crée
au cours de l'execution de ces quelques lignes:
_text:004012E7
mov dword ptr [edi+238h], 10h ; base
_text:004012F1
push 0
_text:004012F3
call mirvar
_text:004012F8
mov ds:Big1g, eax
_text:004012FD
push 0
_text:004012FF
call mirvar
_text:00401304
mov ds:Big2g, eax
_text:00401309
push 0
_text:0040130B
call mirvar
_text:00401310
mov ds:Big2, eax
_text:00401315
push [ebp+arg_4]
_text:00401318
call IniSeed
_text:0040131D
push ds:Big1g
_text:00401323
push 20h
_text:00401325
call Rand
_text:0040132A
push ds:Big2g
_text:00401330
push 20h
_text:00401332
call Rand
_text:00401337
push ds:Big2
_text:0040133D
push ds:Big2g
_text:00401343
push ds:Big1g
_text:00401349
call multiply
Deux bignums recoivent une valeur aleatoire puis sont multipliés.
Le resultat de la multiplication est la Magic Key...
Comment deviner que le call ligne 00401349 est une multiplication
en observant les parametres d'entrées / sorties et en etant un peu
logique: le modulo intervenant dans le cryptage RSA est le produit de 2
grands nombres premiers...
Effectivment si on se penche un peu sur Rand : que la valeur de Seed
est utilisée pour generer une suite pseudo aleatoire qui est par
la suite affecté a un des 2 bignums servant a generer la Magic Key...
Or comme les 2 bignums doivent etre premiers, il y a de forts chances que
le call de la ligne 004012C8 soit en fait un appel à la
fonction nxPrime...
_text:00401297 Rand
proc near
_text:00401297
_text:00401297 Size
= dword ptr 8
_text:00401297 Big
= dword ptr 0Ch
_text:00401297
_text:00401297
push ebp
_text:00401298
mov ebp, esp
_text:0040129A
push ebx
_text:0040129B
push esi
_text:0040129C
push edi
_text:0040129D
mov esi, [ebp+Size]
_text:004012A0
mov ebx, [ebp+Big]
_text:004012A3
xor edi, edi
_text:004012A5
jmp short RandGen
_text:004012A7 LoopGenRand:
_text:004012A7
call sub_0_40126A
_text:004012AC
mov edx, eax
_text:004012AE
mov ds:RandNumber[edi], dl
_text:004012B5
inc edi
_text:004012B6
_text:004012B6 RandGen:
_text:004012B6
cmp edi, esi
_text:004012B8
jb short LoopGenRand
_text:004012BA
push ebx
_text:004012BB
push offset RandNumber
_text:004012C0
push esi
_text:004012C1
call bytes_to_big
_text:004012C6
push ebx
_text:004012C7
push ebx
_text:004012C8
call sub_0_4091B8
_text:004012CD
add esp, 14h
_text:004012D0
pop edi
_text:004012D1
pop esi
_text:004012D2
pop ebx
_text:004012D3
pop ebp
_text:004012D4
retn
_text:004012D4 Rand
endp
_text:0040126A sub_0_40126A proc near
_text:0040126A
_text:0040126A var_4
= dword ptr -4
_text:0040126A
_text:0040126A
push ebp
_text:0040126B
mov ebp, esp
_text:0040126D
push ecx
_text:0040126E
mov eax, 14EF2A01h
_text:00401273
mul ds:Seed
_text:00401279
mov [ebp+var_4], eax
_text:0040127C
mov ds:Seed, eax
_text:00401281
add ds:Seed, 3F5743FAh
_text:0040128B
mov eax, ds:Seed
_text:00401290
xor eax, 42398544h
_text:00401295
leave
_text:00401296
retn
_text:00401296 sub_0_40126A endp
Apres verification il s'agit bien de la fonction nxPrime, on est sur
la bonne voie ;)
Comment fait le programme pour créer des nombres (pseudo-)aleatoires
?
En observant la fonction IniSeed on se rend compte qu'a chaque
execution Seed recoit une nouvelle valeur ( qui est à l'origine
de la generation des bignums aleatoires )
_text:00401250 IniSeed
proc near
_text:00401250
_text:00401250
mov ecx, [esp+arg_0]
; <= GetTickCount
_text:00401254
or ecx, ecx
_text:00401256
jnz short loc_0_40125D
_text:00401258
mov ecx, 0FADEh
_text:0040125D
_text:0040125D loc_0_40125D:
_text:0040125D
mov eax, ecx
_text:0040125F
and eax, 0FFFFh
; <== La faille !!! ;p
_text:00401264
mov ds:Seed, eax
_text:00401269
retn
_text:00401269 IniSeed
endp
_text:00401269
Autrement dit tout depend de cette valeur puisque pour une valeur donnés
qu'une seule suite aleatoire existe... or cette valeur est comprise
entre 0 et FFFFh. Autrement dit rien ne nous empeche de generer les 65536
couples de Bignums possibles et de verifier si ce sont eux qui ont servit
a creer la Magic Key... Certes ca peut etre un peu long ( moins de
deux heures dans le pire des cas ) mais c'est quand meme beaucoup plus
raisonnable que de tenter de factoriser directement la Magic Key... ;)
KeyGen:
Une fois le couple trouvé on n'a plus qu'a calculer la clef privee
correspondante et calculer le serial...
J'espere n'avoir embrouillé personne... ;)
Bonne continuation ;)
|