Keygenerator de Winzip
Par Papow

 

Winzip32 v6.x & v7.0  (générateur de Reg Codes)
- écrit par Papaow -


Outils utilisés :

   Débuggeur : Softice 3.25
   Désassembleur : W32Dasm V8.9 

Introduction

Ce tutoriel à pour but de comprendre ce qu'il y a derrière les routines que l'on shunt pour cracker un programme, avec l'aboutissement évident de réaliser un générateur de Reg Codes.
J'ai donc choisi un programme très répandu (qui n'a pas Winzip ?) et assez démonstratif : le patch est quasi immédiat et la routine de vérification du Reg Code assez facile à identifier (elle n'est pas dispersée en cinq ou six fois).  

La première des choses à faire est d'essayer notre programme pour avoir une idée des fonctions qu'il propose, connaître son principe d'enregistrement et repérer des informations qui pourraient nous être utiles ultérieurement:

On lance Winzip ... quel superbe "Unregistered" écran (pas pour longtemps, je l'espère) ... et nous voila dans l'application principale.
On y apprend rien de particulier, tout à l'air de fonctionner correctement.
On va dans le menu [Help] >> [About Winzip], et on découvre enfin qu'on peut enregistrer (légalement) notre magnifique version de Winzip. Essayons donc !
Nous devons remplir deux TextBox, la première pour notre nom (j'utiliserai papaow), et la deuxième pour notre reg code (12345).
Evidemment le Reg # n'est pas bon et nous obtenons un message très interressant : "Incomplete or incorrect information ...", qui poura peut être nous servir ultérieurement.
Le fichier d'aide lui par contre ne nous aide pas beaucoup, la seul information que j'y ai trouvée concerne le prix d'une copie de Winzip ($29).  

Travail initial 

On va commencer à partir de la seul indication valable que nous avons sur Winzip: le message d'erreur en cas d'enregistrement invalide. On part d'abord sur l'hypothèse qu'ils sont un peu couillons chez Winzip (et ça va marcher ...)
_  Faites un dead-listing de Winzip32.exe à l'aide de W32Dasm.
_  Ouvrez le menu [Search] de W32Dasm et essayez de retrouver la chaîne "Incomplete or incorrect
    information".

Normalement vous devriez obtenir

* Reference To: USER32.GetDlgItemTextA, Ord:00F5h
                                  |
:00409D6D FF15C86A4700            Call dword ptr [00476AC8]
:00409D73 0FB60558124700          movzx eax, byte ptr [00471258]
:00409D7A 85C0                    test eax, eax
:00409D7C 7414                    je 00409D92
:00409D7E 0FB60578F54600          movzx eax, byte ptr [0046F578]
:00409D85 85C0                    test eax, eax
:00409D87 7409                    je 00409D92
:00409D89 E85CF9FFFF              call 004096EA
:00409D8E 85C0                    test eax, eax
:00409D90 7541                   jne 00409DD3   ; renvoie plus loing dans le programme
                                                   (saute la routine "mauvaise clef...").

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:00409D7C(C), :00409D87(C)
|
:00409D92 E805020000              call 00409F9C

* Possible Reference to String Resource ID=00654: "Incomplete or incorrect information"
                                  |
:00409D97 688E020000              push 0000028E
:00409D9C E82EB10100              call 00424ECF
:00409DA1 59                      pop ecx

Si on regarde juste au-dessus de notre chaîne de référence on peut observer qu'il y a trois possibilités pour le programme d'afficher ce message : la réalisation des deux premiers sauts (c-à-d eax=0), et la non réalisation du dernier (eax non nul).

Nous allons donc travailler sur cette piste afin de savoir si la modification de ces conditions de saut ne nous permettrait pas d'éviter la routine destinée à celui qui s'est trompé de numéro.

Dans ce but je vous propose un rappel de toutes les instructions d'assembleur que nous allons utiliser dans ce tutotiel. (Vous pouvez evidemment sauter le chapitre suivant si vous n'en avez pas besoin).  

Opcodes

 J'ai fait des copier-coller pour ce passage et je n'ai absolument pas envie de m'ammuser à le traduire. (j'ai déja mis en avant les points importants pour chaque instruction, ce qui évidemment dépend beaucoup de votre niveau).

MOV - Move Byte or Word
        Usage:  MOV     dest, src
        Modifies flags: None
          Copies byte or word from the source operand to the destination  operand.  If the destination is SS
            interrupts are disabled except  on early buggy 808x CPUs.  Some CPUs disable interrupts if the
            destination is any of the segment registers

MOVZX - Move with Zero Extend (386+)
                 Usage:  MOVZX   dest, src
                 Modifies flags: None
                 Copies the value of the source operand to the destination register with the zeroes extended.

SUB - Subtract
          Usage: SUB     dest, src
       Modifies flags: AF CF OF PF SF ZF
            The source is subtracted from the destination and the result is stored in the destination.

ADD - Arithmetic Addition
       Usage:  ADD     dest, src
       Modifies flags: AF CF OF PF SF ZF
           Adds "src" to "dest" and replacing the original contents of "dest". Both operands are binary.

INC - Increment
         Usage:  INC     dest
     Modifies flags: AF OF PF SF ZF
       Adds one to destination unsigned binary operand.

IMUL - Signed Multiply
        Usage:  IMUL    dest, src
           Modifies flags: CF OF (AF,PF,SF,ZF undefined)
            Variations of this instruction allow specification of source and destination registers as well as a third immediate factor.

CMP - Compare
     Usage:  CMP     dest, src
     Modifies flags: AF CF OF PF SF ZF
         Subtracts source from destination and updates the flags but does not save result.
     Flags can subsequently be checked for conditions.

TEST - Test For Bit Pattern
            Usage:  TEST    dest, src
       Modifies flags: CF OF PF SF ZF (AF undefined)
            Performs a logical AND of the two operands updating the flags register without saving the result.

JE -Jump if Equal
    Jump condition :  ZF=1   (Zero Flag, the n° 6)

JNE - Jump if Not Equal
    Jump condition :  ZF=0   (Zero Flag, the n° 6)

JGE - Jump if Greater or Equal (signed)
           Jump condition :  SF=OF  (Sign Flag, the n° 7)

LEA - Load Effective Address
         Usage:  LEA     dest, src
         Modifies flags: None
        Transfers offset address of "src" to the destination register.

PUSH - Push Word onto Stack
            Usage:  PUSH    src
        Modifies flags: None
           Decrements SP by the size of the operand (two or four, byte values are sign extended) and transfers
               one word from source to the stack top (SS:SP).

SHL - Shift Logical Left
         Usage:  SHL     dest, count
          Modifies flags: CF OF PF SF ZF (AF undefined)
        Shifts the destination left by "count" bits with zeroes shifted in on right.  The Carry Flag contains the last bit shifted out.

AND - Logical And
    Usage: AND     dest, src
          Modifies flags: CF OF PF SF ZF (AF undefined)
        Performs a logical AND of the two operands replacing the destination with the result.

XOR - Exclusive OR
          Usage:  XOR     dest, src
     Modifies flags: CF OF PF SF ZF (AF undefined)
          Performs a bitwise exclusive OR of the operands and returns the result in the destination.

LEAVE - Restore Stack for Procedure Exit (80188+)
          Usage:  LEAVE
             Modifies flags: None
              Releases the local variables created by the previous ENTER instruction by restoring SP and BP to their
                 condition before the procedure stack frame was initialized. (Before exit procedure).

RET - Return From Procedure
    Usage:RET     nBytes
          Modifies flags: None
     Transfers control from a procedure back to the instruction address saved on the stack.
            "n bytes" is an optional number of bytes to release.  Far returns pop the IP followed by
            the CS, while near returns pop only the IP register.

Le crack

On va donc tester notre première intuition à propos des trois instructions de saut avec un débuggeur.
Retournez sous l'écran d'enregistrement de Winzip et remplissez les deux TextBox :

Name:         Papaow
Registration  #:   7777777

Ensuite pressez  Ctrl - D ... nous somme dans Softice.
Nous allons mettre un point d'arrêt qui stoppera l'exécution du programme juste après la validation de notre reg code, donc tapez bpx GetDlgitemTexta pour mettre en place le point d'arrêt et Ctrl - D pour quitter Softice.

Pressez le bouton 'OK'.

Softice interromp Winzip et nous nous retrouvons dans la fonction GetDlgItemTextA.
Tapez 'BD 00' pour désactiver le point d'arrêt et ' F12' pour retourner dans la section de code de Winzip (pour être sûr vérifiez en bas de l'écran correspondant au segment de code, vous devez voir "Winzip32!.text" et non pas celui de modules ou diverses dll de Windobe).

Vous verrez alors le segment de code suivant :

:00409D58 FF15C86A4700            Call dword ptr [00476AC8]
:00409D5E 6A0A                    push 0000000A
:00409D60 6878F54600              push 0046F578                      Oh que c'est joli
:00409D65 68810C0000              push 00000C81                     tout ce code !
:00409D6D FF15C86A4700            Call dword ptr [00476AC8]
:00409D73 0FB60558124700          movzx eax, byte ptr [00471258]
:00409D7A 85C0                    test eax, eax
:00409D7C 7414                    je 00409D92
:00409D7E 0FB60578F54600          movzx eax, byte ptr [0046F578]
:00409D85 85C0                    test eax, eax
:00409D87 7409                    je 00409D92
:00409D89 E85CF9FFFF              call 004096EA               Ne vous inquiétez pas
:00409D8E 85C0                    test eax, eax                On va essayer de l'ellucider.
:00409D90 7541                    jne 00409DD3
:00409D92 E805020000              call 00409F9C
:00409D97 688E020000              push 0000028E
:00409D9C E82EB10100              call 00424ECF
:00409DA1 59                      pop ecx

Maintenant essayons de comprendre tout cela.

Quelques instructions de Softice :
   wd  ##   pour voir ## lignes du segment de données.
   watch eax  pour voir le registre eax.
   d ####   pour voir ce qu'il y a à l'adresse #### .
   ed eax   pour éditer la donnée pointé par eax (avec la traduction ascii !).
   r eax      pour modifier eax.
   F10        pour parcourir le code (en l'exécutant).
   F8          pour parcourir les calls.

A chaque étape nous observerons le code, les registres et le segment de données.

:00409D58 FF15C86A4700            Call dword ptr [00476AC8]   ; GetDlgItemTexta (User 32).
:00409D5E 6A0A                    push 0000000A               ; RAS dans le segment de données.
:00409D60 6878F54600              push 0046F578              ; 7777777 dans le segment
                                                                de données !!!
:00409D65 68810C0000              push 00000C81              ; RAS dans le segment de données.
:00409D6D FF15C86A4700            Call dword ptr [00476AC8]   ; GetDlgItemTexta (User 32).
:00409D73 0FB60558124700          movzx eax, byte ptr [00471258] ; Papaow dans le segment de
                                                                   données!
                                                                   eax=50 : le P de "Papaow".
:00409D7A 85C0                    test eax, eax               ; eax & eax <>0 ?
                                                                (y a-t-il une lettre dans
                                                                 Name ?)
:00409D7C 7414                    je 00409D92                 ; s'il y en une, on continu.
:00409D7E 0FB60578F54600          movzx eax, byte ptr [0046F578] ; eax=37 : le 7 de "7777777".
:00409D85 85C0                    test eax, eax              ; eax & eax <>0 ?
                                                                (y a-t-il une lettre dans
                                                                 Reg# ?)
:00409D87 7409                    je 00409D92                 ; s'il y en une, on continu.
:00409D89 E85CF9FFFF              call 004096EA               ; Ce saut modifie eax:
                                                                maintenant eax=0 !!
:00409D8E 85C0                    test eax, eax      ; évidemment eax & eax =0 ... pas de saut!
:00409D90 7541                    jne 00409DD3       ;               |
:00409D92 E805020000              call 00409F9C      ;               | On
:00409D97 688E020000              push 0000028E      ;               | a
:00409D9C E82EB10100              call 00424ECF      ;               | perdu.
:00409DA1 59                      pop ecx            ;              |

Mais si vous stoppez l'exécution juste avant l'instruction jne (n'appuyez plus sur F10) vous voyez :
eax = 0 dans la fenêtre des registres (dans le cas contraire tapez watch eax).
 

Nous allons modifier la valeur de eax pour obtenir un saut vers la bonne routine d'enregistrement : nous devons donc modifier eax avec une valeur non nulle, 1 par exemple.

Tapez r eax 1 , maintenant eax=1 et nous pouvons exécuter le saut.
On appui sur F10 .... et voila!

On se trouve en face d'un magnifique écran nous demandant confirmation quant à la validité de notre numéro d'enregistrement et si nous l'avons obtenu de la part de revendeurs autorisés ... ils sont vraiment stupides ... on appuira donc sur le bouton Cancel

Maintenat on va s'intéresser à ce call qui modifie eax et à la façon dont notre numéro d'enregistrement est contrôlé.

Le générateur de Reg Code

Nous allons maintenant parcourir la fonction qui met eax à zéro en regardant les manipulations suspectes faites avec notre nom (00471258), notre Reg Code (0046F578), ou le registre eax.

... nous avons là beaucoup de travail ... il faut penser aux écritures en mémoire ... aux arguments des calll ... et au reste !

Une sous fonctin de ce call est tout particulièrement intéressante :

:004097DE 8D85F8FDFFFF            lea eax, dword ptr [ebp+FFFFFDF8]
:004097E4 50                      push eax
:004097E5 6858124700             push 00471258   ; notre nom.
:004097EA E8D4000000              call 004098C3  

Si vous observez ce qu'il y a en mémoire à l'adresse pointé par eax juste avant le call vous trouverez à [EBP+FFFFFDF8], un segment de huit zéros.
Quel peut bien être l'intéret de passer ce segment en argument à une fonction ?

Tapez F10 et regardez à la même adresse juste après le call !
Nous avons un nouveau segment de huits chiffres un peu bizards qui ne ressenblent certainement pas à un compteur ou à une adresse en mémoire ...
Avez vous deviné ?
Oui, [38B60673] est mon numéro personnel d'enregistrement !

Mais notre travail n'est pas uniquement de trouver notre code personnel (on aurrait tout aussi bien pu patcher le programme pour arriver au même résultat, ce qui n'aurrait nécessité que quelques minutes).

Nous voulons trouver une solution pour pouvoir enregistrer Winzip, à tous les coups, sans même toucher à l'exécutable

Nous allons donc être obligés d'étudier cette routine et de la comprendre.

:004098C3 55                       push ebp
:004098C4 8BEC                    mov ebp, esp
:004098C6 83EC10                  sub esp, 00000010
:004098C9 668365F400              and word ptr [ebp-0C], 0000
:004098CE 668365F800              and word ptr [ebp-08], 0000
:004098D3 8B4508                  mov eax, dword ptr [ebp+08]  ; Récupère Name.
:004098D6 8945FC                  mov dword ptr [ebp-04], eax  ; le sauve localement à
                                                                 [ebp-04].
:004098D9 668365F000              and word ptr [ebp-10], 0000  ; initialisation d'un compteur
                                                                 à l'adresse [ebp-10].
:004098DE EB13                    jmp 004098F3 @2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409915(U)
|@1
:004098E0 668B45F0                mov ax, word ptr [ebp-10]     ; récupère le compteur.
:004098E4 66050100                add ax, 0001                  ; l'incrémente et
:004098E8 668945F0                mov word ptr [ebp-10], ax     ; le sauve.
:004098EC 8B45FC                  mov eax, dword ptr [ebp-04]   ; récupère Name.
:004098EF 40                      inc eax                       ; décallage d'une lettre
:004098F0 8945FC                  mov dword ptr [ebp-04], eax   ; dans le nom et sauvegarde.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004098DE(U)
|@2
:004098F3 8B45FC                  mov eax, dword ptr [ebp-04]  ; notre nom est dans eax.
:004098F6 0FB600                  movzx eax, byte ptr [eax]    ; récupère la première lettre
                                                                 du nom.
:004098F9 85C0                    test eax, eax                ; y en a-t-il une ?
:004098FB 741A                    je 00409917 @#               ; oui : on continu, non : jump .
:004098FD 8B45FC                  mov eax, dword ptr [ebp-04]  ; récupère de nouveau la première
:00409900 0FB600                  movzx eax, byte ptr [eax]    ; lettre de notre nom.
:00409903 0FB74DF0                movzx ecx, word ptr [ebp-10] ; ecx = compteur.
:00409907 0FAFC1                  imul eax, ecx                ; la lettre est multipliée
                                                                 par le compteur.
:0040990A 668B4DF4                mov cx, word ptr [ebp-0C]    ; charge le buffer1 dans cx.
:0040990E 6603C8                  add cx, ax                  ; ajoute le résultat de la
                                                                 multiplication à buffer1.
:00409911 66894DF4                mov word ptr [ebp-0C], cx    ; sauvegarde de buffer1.
:00409915 EBC9                    jmp 004098E0 @1  
 

Les 5 premières lettre de Papaow ont donc été utilisées (y a-t-il une lettre?,oui ... non)
A ce niveau du code nous avons 4 des 8 chiffres de notre reg Code, ils sont situés à [ebp-0C].
 * Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004098FB(C)
|
:00409917 C7055C1C470001000000    mov dword ptr [00471C5C], 00000001
:00409921 8B4508                  mov eax, dword ptr [ebp+08]        ; récupère Name.
:00409924 8945FC                  mov dword ptr [ebp-04], eax        ; le sauvegarde localement
                                                                       à [ebp-04].
:00409927 EB07                    jmp 00409930 @2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409956(U)
|@1
:00409929 8B45FC                  mov eax, dword ptr [ebp-04]    ; récupère Name.
:0040992C 40                      inc eax                        ; décallage d'une lettre, sauvegarde
:0040992D 8945FC                  mov dword ptr [ebp-04], eax    ; de la nouvelle position.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409927(U)
|@2
:00409930 8B45FC                  mov eax, dword ptr [ebp-04]   ; place Name dans eax.
:00409933 0FB600                  movzx eax, byte ptr [eax]     ; récupère une lettre.
:00409936 85C0                    test eax, eax                 ; y a-t-il quelque chose?
:00409938 741E                    je 00409958 @3                ; oui : continu, non : jump .
:0040993A 6821100000              push 00001021                 ; push une constante.
:0040993F 8B45FC                  mov eax, dword ptr [ebp-04]   ; notre nom se trouve dans eax.
:00409942 660FB600                movzx ax, byte ptr [eax]      ; une lettre est placée dans ax.
:00409946 50                      push eax                      ; push eax.
:00409947 FF75F8                  push [ebp-08]                ; push buffer2.
:0040994A E831000000              call 00409980                ; un call !
:0040994F 83C40C                  add esp, 0000000C             ; pas d'utilité.
:00409952 668945F8                mov word ptr [ebp-08], ax     ; sauvegarde du résultat dans buffer2.
:00409956 EBD1                   jmp 00409929 @1

Une fois de plus on a utilisé toute les lettres de notre nom, et nous obtenons (pas exactement) les 4 autres chiffre de notre Reg Code (à [EBP-08]), mais il reste une sous-routine que nous n'avons toujours pas étudiée (on va le faire juste après la fin de celle là).  

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409938(C)
|@3
:00409958 668B45F8                mov ax, word ptr [ebp-08] ; place les quatres autres chiffres dans ax.
:0040995C 66056300                add ax, 0063                  ; ax = ax+63. Exactement
                                                                              maintenant !
:00409960 668945F8                mov word ptr [ebp-08], ax     ; sauvegarde du résultat.
:00409964 0FB745F4                movzx eax, word ptr [ebp-0C]  ; eax = 0000 ####
                                                                  (où ####= buffer2 + 63).
:00409968 50                      push eax                      ; push eax.
:00409969 0FB745F8                movzx eax, word ptr [ebp-08]  ; eax = 0000 ####
                                                                  (où ####= buffer1).
:0040996D 50                      push eax                      ; push eax.

* Possible StringData Ref from Data Obj ->"%04X%04X"
                                  |
:0040996E 6854394600              push 00463954                 ; pas d'importance.
:00409973 FF750C                  push [ebp+0C]                 ; pas d'importance.
:00409976 E865B90300              call 004452E0                 ; Est ce que notre Reg Code est
                                                                  bon ?
                                                                ; bien sûr que non ...
                                                                  => eax=0!
:0040997B 83C410                  add esp, 00000010
:0040997E C9                      leave
:0040997F C3                      ret                   ; retour au point de départ.  

Maintenant nous avons une bonne connaissance de la routine de test, mais nous ne pouvons toujours pas fabriquer de générateurs de Reg Code, car il nous reste encore une sous-routine à étudier, la dernière! (mais la plus dure).

:00409980 55                      push ebp                           ; on place à [EBP+8]
                                                                       la valeur qui
:00409981 8BEC                    mov ebp, esp                       ; se trouve à [EBP-08].
:00409983 51                      push ecx                           ; buffer3=buffer2
:00409984 668B450C                mov ax, word ptr [ebp+0C]          ; on récupère la lettre.
:00409988 66C1E008                shl ax, 08                        ; ax = lettre * 256 .
:0040998C 6689450C                mov word ptr [ebp+0C], ax          ; sauvegarde du résultat à
                                                                       l'adresse [EBP+0C] (L2).
:00409990 8365FC00                and dword ptr [ebp-04], 00000000   ; compteur=0.
:00409994 EB07                    jmp 0040999D @2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004099DE(U)
|@1
:00409996 8B45FC                  mov eax, dword ptr [ebp-04]         ; incrémente
:00409999 40                      inc eax                             ; le compteur et
:0040999A 8945FC                  mov dword ptr [ebp-04], eax         ; le sauvegarde.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409994(U)
|@2
:0040999D 837DFC08                cmp dword ptr [ebp-04], 00000008    ; est ce que
                                                                        compteur <= 8 ?
:004099A1 7D3D                    jge 004099E0 @5                     ; oui : continu.
:004099A3 0FB74508                movzx eax, word ptr [ebp+08]        ; récupère buffer3.
:004099A7 0FB74D0C                movzx ecx, word ptr [ebp+0C]        ; récupère L2.
:004099AB 33C1                    xor eax, ecx                        ; eax XOR L2.
:004099AD 2500800000              and eax, 00008000                   ; if eax >= 8000
:004099B2 85C0                    test eax, eax                       ; continu, else
:004099B4 7412                    je 004099C8 @3                      ; jump to @3
:004099B6 0FB74508                movzx eax, word ptr [ebp+08]        ; récupère buffer3.
:004099BA D1E0                    shl eax, 1                          ; eax= buffer3 * 2.
:004099BC 0FB74D10                movzx ecx, word ptr [ebp+10]        ; 1021.
:004099C0 33C1                    xor eax, ecx                        ; eax= eax XOR 1021.
:004099C2 66894508                mov word ptr [ebp+08], ax           ; sauvegarde de eax
                                                                        dans buffer3.
:004099C6 EB0B                    jmp 004099D3 @4

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004099B4(C)
|@3
:004099C8 668B4508                mov ax, word ptr [ebp+08]             ; récupère buffer3.
:004099CC 66D1E0                  shl ax, 1                             ; ax= buffer3 * 2.
:004099CF 66894508                mov word ptr [ebp+08], ax             ; sauvegarde de buffer3.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004099C6(U)
|@4
:004099D3 668B450C                mov ax, word ptr [ebp+0C]             ; récupère L2.
:004099D7 66D1E0                  shl ax, 1                             ; L2= L2 * 2 .
:004099DA 6689450C                mov word ptr [ebp+0C], ax             ; sauvegarde de L2.
:004099DE EBB6                    jmp 00409996 @1                       ; on repare au début.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004099A1(C)
|@5
:004099E0 668B4508                mov ax, word ptr [ebp+08]             ; ax = buffer3.
:004099E4 C9                      leave                                 ; fin du
:004099E5 C3                      ret                                   ; call.
 

La valeur de buffer3 est replacée dans buffer2 à la fin de chaque exécution de la sous-routine, en fait buffer3 est buffer2, mais il y a un décallage de ebp à chaque appel de la sous-routine :

mov ebp, esp

Cette instruction à pour résultat que [ebp+8] n'a pas la même valeur à l'intérieur et à l'extérieur de la sous-routine, et c'est la raison de "buffer3".

Rq : le nom de L2 signifie "nouvelle lettre" car on part d'une lettre que l'on modifie à chaque passage... évidemment!  
 

Conclusion

 

Nous avons maintenant tout en main pour créer un générateur de Reg Code, qui fait la différence entre celui qui comprend vraiment ce qu'il fait et celui qui fille directement à la fin dans les tutoriels (cf Le Patch).

Létape de la création du générateur doit être considérée comme un aboutissement et non comme une fin (il n'y à cas aller dans la rubrique "Crack" et vous y trouverez le programme compilé), ausi je ne ferai que vous conseiller pour sa réalisation, mais je ne vous donnerai pas le code source (ou pas tout de suite ...)

for (int k=1;k<=Name.Length();k++)
{
c=Name[k];
buf += (c * (k-1));
}

J'espère que ce tutoriel n'est pas trop flou et qu'il vous a permis, pour ce qui en avait besoin, de comprendre ce qu'il y avait derrière un call de vérification de Reg Code. Pour ceux qui savent programmer en assembeur j'attend vos commentaires, vos remarques (et aussi vos sugestions).
 


Pour tout complément d'information : Boite01@hotmail.com