[ - Intro - Explications - L'outil expliqué - Liens - Notes de fin - ]
 
[ - Tutoriaux : Bases ~ Jnz / Jz ~ Jmp ~ La fonction d'enregistrement ~ Crack GifMovieGear 3.0 - ]

Comme logiciel d'application, nous allons prendre GifMovieGear 3.0 version francophone.
Ce programme présente l'avantage d'avoir une protection très simple et surtout cela fait plus d'un an qu'il n'y a pas eu d'update de la version Shareware.
Vous pouvez également vous attaquer à la version 3.0.1 anglophone.

Emplacement : http://www.gamani.com
Outils : W32Dasm8.93 et Hexworkshop 2.54
 

L'étude du logiciel

On lance le programme et on tombe sur un Nag-Screen puis un autre.

D'accord, passons à la suite... Regardons dans le menu "Aide".

Si l'on clique sur "A propos de GMG...", on tombe sur une fenêtre "non standard".

On nous rappelle le Trial de 30 jours.
Si l'on clique sur "S'enregistrer maintenant", on tombe sur une boîte.

On rentre un nom et un numéro bidon et on tombe sur le truc suivant.

Bien, bien. Fermons le programme. Hum, on retombe sur la fenêtre du "A propos de GMG..." sauf que le bouton Ok n'apparait qu'au bout de quelques secondes, histoire de bien nous faire comprendre le message.
 

Le Crack

On désassemble MOVGEAR.EXE 

Recherchons le texte de notre boîte qui nous est renvoyé quand on rentre un serial bidon dans les SDR.
Et on tombe sur :

:00431CEE C21000                  ret 0010

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00431C3E(C)
|
:00431CF1 6A30                    push 00000030

* Possible Reference to String Resource ID=40213: "Renseignements d'enregistrement invalides"
                                  |
:00431CF3 68159D0000              push 00009D15

* Possible Reference to String Resource ID=40212: "Les renseignements que vous venez d'entrer sont erronés. Vér"
                                  |
:00431CF8 68149D0000              push 00009D14

Donc on repère que c'est un saut conditionnel en 431C3E qui nous fait atterir ici.
Cliquons sur  et entrons 431C3E pour revenir au saut.
 

:00431C32 50                      push eax
:00431C33 51                      push ecx
:00431C34 E8E7FAFFFF              call 00431720 
:00431C39 83C408                  add esp, 00000008
:00431C3C 85C0                    test eax, eax
:00431C3E 0F84AD000000            je 00431CF1 <=== on revient ici
:00431C44 8D542410                lea edx, dword ptr [esp+10]
:00431C48 8D44240C                lea eax, dword ptr [esp+0C]
:00431C4C 52                      push edx
:00431C4D 50                      push eax
:00431C4E 6A00                    push 00000000
:00431C50 683F000F00              push 000F003F
:00431C55 6A00                    push 00000000
:00431C57 6894FE4400              push 0044FE94
:00431C5C 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"Software\gamani\GIFMovieGear\2.0" <=== un chemin
                                  |
:00431C5E 68D0C44400              push 0044C4D0
:00431C63 6801000080              push 80000001

* Reference To: ADVAPI32.RegCreateKeyExA, Ord:015Fh <=== oh ! on crée une clé dans la base de registre
                                  |
:00431C68 FF1510904400            Call dword ptr [00449010]
:00431C6E 8D7C2460                lea edi, dword ptr [esp+60]
:00431C72 83C9FF                  or ecx, FFFFFFFF
:00431C75 33C0                    xor eax, eax
:00431C77 8B54240C                mov edx, dword ptr [esp+0C]
:00431C7B F2                      repnz
:00431C7C AE                      scasb
:00431C7D F7D1                    not ecx

* Reference To: ADVAPI32.RegSetValueExA, Ord:0186h <=== on demande à fixer des infos dedans
                                  |
:00431C7F 8B1D18904400            mov ebx, dword ptr [00449018]
:00431C85 51                      push ecx
:00431C86 8D4C2464                lea ecx, dword ptr [esp+64]
:00431C8A 51                      push ecx
:00431C8B 6A01                    push 00000001
:00431C8D 50                      push eax

* Possible StringData Ref from Data Obj ->"RegName3" <=== ce type d'info portant le nom RegName3
                                  |
:00431C8E 68FCE54400              push 0044E5FC
:00431C93 52                      push edx
:00431C94 FFD3                    call ebx
:00431C96 8DBC24C4000000          lea edi, dword ptr [esp+000000C4]
:00431C9D 83C9FF                  or ecx, FFFFFFFF
:00431CA0 33C0                    xor eax, eax
:00431CA2 F2                      repnz
:00431CA3 AE                      scasb
:00431CA4 F7D1                    not ecx
:00431CA6 8D8424C4000000          lea eax, dword ptr [esp+000000C4]
:00431CAD 51                      push ecx
:00431CAE 8B4C2410                mov ecx, dword ptr [esp+10]
:00431CB2 50                      push eax
:00431CB3 6A01                    push 00000001
:00431CB5 6A00                    push 00000000

* Possible StringData Ref from Data Obj ->"RegCode3" <=== et un autre avec le nom RegCode3
                                  |
:00431CB7 6808E64400              push 0044E608

Ok, ok, combien vous pariez que ces informations ( RegName3 et RegCode3 ) sont notre nom et serial que l'on a rentré ?
Le plus intéressant vient d'en haut :

:00431C32 50                      push eax
:00431C33 51                      push ecx
:00431C34 E8E7FAFFFF              call 00431720 <=== un call ?
:00431C39 83C408                  add esp, 00000008
:00431C3C 85C0                    test eax, eax <=== eax = 0 ?
:00431C3E 0F84AD000000            je 00431CF1 <=== notre saut

Donc la valeur d'eax semble conditionnée notre enregistrement. Ici si eax = 0 : c'est pas bon.

Rentrons dans notre call.

* Referenced by a CALL at Addresses:
|:00431979   , :00431C34 
|
:00431720 8B442408                mov eax, dword ptr [esp+08]
:00431724 8B4C2404                mov ecx, dword ptr [esp+04]
:00431728 50                      push eax
:00431729 51                      push ecx
:0043172A E811000000              call 00431740 <=== un autre call ?
:0043172F 83C408                  add esp, 00000008
:00431732 C3                      ret

Ah ah, déjà, on a un autre appel se référant à la même fonction. Donc il n'y a pas qu'ici qu'on teste notre nom + serial.
Suivons notre code et entrons dans le call 00431740.

* Referenced by a CALL at Address:
|:0043172A 
|
:00431740 81ECD8000000            sub esp, 000000D8
:00431746 83C9FF                  or ecx, FFFFFFFF
:00431749 33C0                    xor eax, eax
:0043174B 8D542410                lea edx, dword ptr [esp+10]
..................                ..........................
..................                ..........................
..................                ..........................
:00431787 8D7C2420                lea edi, dword ptr [esp+20]
:0043178B 7422                    je 004317AF

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004317AD(C)
|
:0043178D 0FBE16                  movsx edx, byte ptr [esi]
:00431790 52                      push edx

* Possible StringData Ref from Data Obj ->"KSDF234897544URTFBBMNZXCSDKA"
                                  |
:00431791 682CE64400              push 0044E62C
:00431796 E885DC0000              call 0043F420
:0043179B 83C408                  add esp, 00000008
..................                ..........................
..................                ..........................
:004318C1 83D8FF                  sbb eax, FFFFFFFF

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004318BD(U)
|
:004318C4 5F                      pop edi
:004318C5 5E                      pop esi
:004318C6 5D                      pop ebp
:004318C7 5B                      pop ebx
:004318C8 85C0                    test eax, eax
:004318CA 750C                    jne 004318D8
:004318CC B801000000              mov eax, 00000001
:004318D1 81C4D8000000            add esp, 000000D8
:004318D7 C3                      ret

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004318CA(C)
|
:004318D8 33C0                    xor eax, eax
:004318DA 81C4D8000000            add esp, 000000D8
:004318E0 C3                      ret

Ok, nous y voici !
Donc en traçant un peu dans le code on voit beaucoup d'instructions dont certaines seront revues dans le cas d'une keygennisation, mais ce n'est pas notre cas ici.
Nous sommes dans un call et donc le premier "ret" que nous rencontrons sera celui qui nous fera sortir de la fonction, donc la valeur d'eax devrait déjà être fixée et c'est le cas car si vous voyez les instructions avant le ret, c'est un mov eax,00000001 ( eax =1 ) et un xor eax, eax ( remet la valeur d'eax à 0 ) si le saut en 4318CA est fait.
Nous voulons que eax = 1.

Voici deux solutions équivalentes.

Première solution
**********************
:004318C5 5E                      pop esi
:004318C6 5D                      pop ebp
:004318C7 5B                      pop ebx
:004318C8 85C0                    test eax, eax
:004318CA 750C                    jne 004318D8 <=== on remplace par NOP ( 2 x )
:004318CC B801000000              mov eax, 00000001
:004318D1 81C4D8000000            add esp, 000000D8
:004318D7 C3                      ret

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004318CA(C)
|
:004318D8 33C0                    xor eax, eax
:004318DA 81C4D8000000            add esp, 000000D8
:004318E0 C3                      ret

Le saut ne sera jamais car il n'existe plus, remplaçé par 2 NOP.
Donc on remplace 750C par 9090.
 

Deuxième solution
**********************
:004318C5 5E                      pop esi
:004318C6 5D                      pop ebp
:004318C7 5B                      pop ebx
:004318C8 85C0                    test eax, eax
:004318CA 750C                    jne 004318D8
:004318CC B801000000              mov eax, 00000001
:004318D1 81C4D8000000            add esp, 000000D8
:004318D7 C3                      ret

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004318CA(C)
|
:004318D8 33C0                    xor eax, eax <=== on remplace par mov eax,01
:004318DA 81C4D8000000            add esp, 000000D8
:004318E0 C3                      ret

Que le saut soit fait ou non, on aura une valeur d'eax différente de "0".
On remplace 33C0 par B001.
 

Mais il y a encore une AUTRE solution !
***********************************************
On vient de voir que le call dans lequel nous sommes n'est appellé qu'une fois dans le programme.
Donc si on revient en arrière, au premier call fait.

* Referenced by a CALL at Addresses:
|:00431979   , :00431C34 
|
:00431720 8B442408                mov eax, dword ptr [esp+08]
:00431724 8B4C2404                mov ecx, dword ptr [esp+04]
:00431728 50                      push eax
:00431729 51                      push ecx
:0043172A E811000000              call 00431740 
:0043172F 83C408                  add esp, 00000008
:00431732 C3                      ret

Pourquoi ne pas fixer la valeur d'eax ici ? 

* Referenced by a CALL at Addresses:
|:00431979   , :00431C34 
|
:00431720 8B442408                mov eax, dword ptr [esp+08] <== on remplace par mov eax, 01 et ret
:00431724 8B4C2404                mov ecx, dword ptr [esp+04]
:00431728 50                      push eax
:00431729 51                      push ecx
:0043172A E811000000              call 00431740 
:0043172F 83C408                  add esp, 00000008
:00431732 C3                      ret

Donc on remplace 8B442408 par B001C3 + le byte restant de l'instruction patché ( ici 08 )
Si on désassemble le programme cracké de cette façon, on la chose suivante :

* Referenced by a CALL at Addresses:
|:00431979   , :00431C34 
|
:00431720 B001                    mov al, 01
:00431722 C3                      ret
 

:00431723 088B4C240450            or byte ptr [ebx+5004244C], cl
:00431729 51                      push ecx
:0043172A E811000000              call 00431740
:0043172F 83C408                  add esp, 00000008
:00431732 C3                      ret

Parfait ! 
Pour le reste du code suivant notre nouveau ret, il ne sera jamais exécuté... donc pas besoin de faire des NOP de 431723 à 431733.

On relance le programme, plus de problèmes ! On avance son horloge Windows d'un an pour voir si le trial de 30 jours est aussi mort... C'est le cas. On vient "d'émuler" le mode enregistré.

Chose importante
*********************
La chose à ne pas oublier est que le logiciel met des clés dans la base de registre avec notre nom + serial !
Lancez Regedit et allez voir en :
HKEY_CURRENT_USER\Software\gamani\GIFMovieGear\2.0
Vous retrouvez le chemin ( Software\gamani\GIFMovieGear\2.0 ) donné dans W32Dasm et les noms de clé ( RegCode3 et RegName3 ) que nous avons vu dans le code précédemment. Et celles-ci contiennent évidemment nos informations.

Si vous effacez la clé HKEY_CURRENT_USER\Software\gamani\GIFMovieGear\2.0 et que vous relancez le logiciel, vous retomberez en version non enregistrée. Evidemment, il vous suffira de rentrer de nouveau un nom+serial pour que ça marche, mais la chose importante n'est pas là.
Quand le logiciel vient d'être installé, il n'y a pas d'informations d'enregistrement ( RegCode3 et RegName3 ) et donc cracker le logiciel implique qu'un nom et un serial soient entrés obligatoirement une fois pour toute.
 

Voilà, voilà, un logiciel commercial dont la protection se cracke très facilement... Vous avez donc un exemple quand la protection n'a pas été traitée avec sérieux. ; )
 

Lise Grim 2002 / WiA