How To Find HCCC6 MD5 CrackMe's Serial


A la sortie du nouvel HCCC, le 6, Kahel qui avait codé l'interface du wiever avait aussi inclu un petit exercice sympa basé sur l'algorithme de hashage MD5.
Dans les explications que Kahel donnait, il y avait beaucoup à prendre :

" Le but du crackme est tout d'abord de trouver quel est le hash prédéfini ".
" ... ensuite il faudra écrire un bruteforcer pour trouver le serial ".
" ... Maximum 5 minutes de calculs :) ".
" ... Le crackme peut etre keygennable , en effet il ne compare que les 8 premiers bytes du Hash ".
" Le serial auquel je pensais en codant ce crackme n'est composé que de chiffres... ".


Il y a donc :

- un hash prédéfini à trouver
- le texte correspondant à ce hash est forcement court, sinon les 5 minutes de recherche seront largement dépassées (comptez plusieurs heures, suivant les cas…), même pour une recherche ne portant que sur les 8 premiers bytes.
- le texte n'est composé que de chiffres

et pour nous aider, Kahel avait de plus inclu dans un zip toute la doc nécessaire, dont en voici un extrait :

"
Notion de fonction de hachage

Une fonction de hachage est une fonction mathématique qui a partir d'un message (d'une donnée) génère une autre chaîne (généralement plus courte).

Terminologie: fonction de contraction, digest, empreinte digitale, ...
Exemples:
Calcul de parité verticale :
On fait le OU exclusif de tous les octets d'une chaîne de caractères.

Calcul de code polynomial :

Notion de fonction de hachage à sens unique sans clé :
C'est une fonction de hachage à sens unique qui peut être calculée par n'importe qui (MD5).

Notion de fonction de hachage à sens unique avec clé :
C'est une fonction de hachage à sens unique qui ne peut être calculée que par
une seule entité détentrice de la clé.

Signatures numériques :

Une signature manuscrite idéale est réputée posséder les propriétés suivantes:

- La signature ne peut-être imitée. Elle prouve que le signataire a délibérément signé le document.

- La signature authentifie le signataire. Seul le signataire peut avoir signé.

- La signature appartient à un seul document (elle n'est pas réutilisable).

- Le document signé ne peut être partiellement ou totalement modifié.

- La signature ne peut-être reniée.

Base de la signature numérique:

L'existence d'une fonction de hachage à sens unique avec clé :

Une solution possible: une fonctions de hachage à sens unique et une technique
classique de cryptographie (exemple le RSA)

MD5 Message Digest version 5 :

Une fonction de hachage à sens unique :

On génère une signature sur 128 bits. Le message est décomposé en blocs de 512 bits soient 16 sous-blocs Mj de 32 bits. Pour chaque bloc de 512 bits on réalise 4 séries de 16 applications successives des fonctions de base FF, GG , HH, II qui dépendent des sous-blocs Mj et de constantes a, b, c, d, ti:

FF(a,b,c,d,Mj,s,ti)   -> a = b + ((a = F(b, c,d) + Mj+ ti) <s)
GG(a, b,c,d,Mj,s, ti) -> a = b + ((a = G(b,c,d) + Mj+ ti) <s)
HH(a,b, c,d,Mj,s,ti)  -> a = b + ((a = H(b,c,d) + Mj + ti) <s)
II(a,b, c,d,Mj,s,ti)  -> a = b + ((a = I(b,c, d) + Mj + ti) <s)

Dans les formules précédentes <s désigne un décalage à gauche de <s positions les fonctions F,G, H,I sont données par:

F(X,Y,Z)  = (X AND Y) OR (NOT X AND Z)
G(X,Y, Z) = (X AND Z) OR (Y AND NOT Z)
H(X,Y,Z)  = (X XOR Y XOR Z)
I(X,Y,Z)  =  Y XOR (X OR  NOT Z) ".

(Il est à noter que Kahel a aussi signé dans HCCC6 un article sur le cryptage El Gamal qui mérite vraiment d'être lu !)

Après cette introduction un peu longue, voyons ce qu'il en est du crackme de Kahel.

On peut y accéder via le viewer.
Serait ce à dire que le crackme est une dialogbox incorporé à ce wiever ?
Non !
En fermant HCCC6, la box est toujours présente, donc elle a été crée pour être indépendante du wiever.
Le plus simple est de faire une recherche sur le HDD en prenant le caption comme clé. Et effectivement, on trouve rapidement que le crackme a été copié dans C:\WINDOWS\TEMP\.

Pour faire plus compliqué, il y avait moyen d'utiliser FileMon pour l'apprendre :

Ezine	Open	C:\WINDOWS\TEMP\CRACKME.EXE	0x50	CREATENEW READWRITE

Ou encore d'utiliser SoftIce pour breaker sur les APIs ShellExecute ou ShellExecuteEx, histoire de jeter un coup d'œil dans lpDirectory :

La fonction ShellExecute ouvre ou imprime un fichier spécifié. Ce fichier peut être un exécutable ou un document.

HINSTANCE ShellExecute(

    HWND hwnd,               // handle de la fenêtre propriétaire
    LPCTSTR lpOperation,    // pointe vers une string spécifiant l'opération à exécuter
    LPCTSTR lpFile,        // pointe vers le fichier ou le répertoire à atteindre
    LPCTSTR lpParameters, // pointe vers une string spécifiant les paramètres d'exécution 
    LPCTSTR lpDirectory, // pointe vers une string spécifiant le répertoire par défaut
    INT nShowCmd        // indique le statut du fichier lors de son ouverture

Finalement, Wdasm donne les strings data qui vont bien (un fois HCCC6 Un-UPXé -> sensationnelle cette fonction décompress !) :

" Hccc Crackme"
"c:\windows\temp\crackme.exe"
"CRACKME"
"open"

et un chtit double clic de mulot nous envoie ici :

:004015B1 6A01                    push 00000001
:004015B3 6A00                    push 00000000
:004015B5 6A00                    push 00000000
:004015B7 68C2B14400              push 0044B1C2  ->"c:\windows\temp\crackme.exe"
:004015BC 6861B14400              push 0044B161  ->"open"
:004015C1 6A00                    push 00000000
:004015C3 E8B40C0000              Call SHELL32.ShellExecuteA

Bene, maintenant que l'on sait ou se trouve le crackme de kahel, voyons ce qu'il a dans le ventre :

__________________________________________________________
sections :
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
name     vSize     vAddress  rawSize   rOffset   Caract
UPX0     00034000h 00001000h 00000000h 00000400h E0000080h
UPX1     00021000h 00035000h 00020400h 00000400h E0000040h
.rsrc    00001000h 00056000h 00000C00h 00020800h C0000040h
__________________________________________________________

PARFAIT !
Lui aussi est compressé avec UPX, histoire de le rendre plus petit.
Kahel a vraiment été cool !

Une fois décompressé, Wdasm va encore avoir des choses à dire :

"a5ba6896"
"MD5"
"serial valide"

Si kahel n'avait pas précisé qu'il s'agissait d'un hashage MD5, la seconde string que j'ai retenue ne m'aurait peut être pas sauté au yeux.
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
: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 !
Kahel a cependant conservé un peu de mystère…
Il avait parlé des 8 premiers bytes du hash comparés avec une clé prédéfinie, mais sans préciser qu'il en faisait la lecture de la droite vers la gauche : en fait c'est le dernier Dword du hash qui est comparé avec la clé !

Il ne reste plus qu'à trouver un texte de quelques caractères numériques (disons 5) dont le hash donnerait une série se finissant par a5ba6896.

Je ne sais pas s'il existe un Un_hasher, capable de reverser MD5 pour en donner le serial (je crois que DAMN et TMG en ont réalisé), mais j'ai découvert, pour l'avoir testé, qu'il faut environ deux heures pour calculer une série allant de 1 à 99999999h. En incluant des caractères alphabétiques, le temps augmente considérablement…

Voici le source que je propose comme
solution à l'exercice de Kahel , basé sur un source de roy|crisiscrackers pour le calcul du Hash MD5:

 .386
      .model flat, stdcall
      option casemap :none   ; case sensitive

      ; déclaration des procédures

      DlgProc       proto    :dword,:dword,:dword,:dword
      FF            proto    :dword,:dword,:dword,:dword,:dword,:byte,:dword
      GG            proto    :dword,:dword,:dword,:dword,:dword,:byte,:dword
      HH            proto    :dword,:dword,:dword,:dword,:dword,:byte,:dword
      II            proto    :dword,:dword,:dword,:dword,:dword,:byte,:dword
      procMD5hash   proto    :dword,:dword,:dword
      StaticImage   PROTO    :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
      Str2Hex       PROTO    :DWORD, :DWORD
      OpenDialog    PROTO    :DWORD

      ; récupération des Dll et des fonctions

      include \masm32\include\windows.inc
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc
      include \masm32\include\gdi32.inc
      include \masm32\include\comdlg32.inc 
      include \masm32\include\comctl32.inc
      include \masm32\include\masm32.inc
      include \masm32\include\shell32.inc 

      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
      includelib \masm32\lib\gdi32.lib
      includelib \masm32\lib\comdlg32.lib 
      includelib \masm32\lib\comctl32.lib        
      includelib \masm32\lib\masm32.lib
      includelib \MASM32\LIB\shell32.lib 

      ; déclaration de la structure MD5

      MD5RESULT        STRUCT
                dtA        dd    ?
                dtB        dd    ?
                dtC        dd    ?
                dtD        dd    ?
      MD5RESULT        ENDS
      
.const
      
      IDC_ABOUT        equ    101
      IDC_EDITTEXT     equ    102
      IDC_EDITHASH     equ    103
      IDD_DIALOG       equ    100
      IDI_ICON         equ    200
      IDC_progress     equ    130
      ID_Fond          equ    500
      IDC_STATIC2      equ   1004
      IDC_Search       equ    106
      IDC_Exit         equ    108
      IDC_Result       equ    123
      IDC_Open         equ    107
      IDC_mini         equ    113
      IDC_maxi         equ    114
      IDC_h1           equ    118
      IDC_h2           equ    120
      IDC_h3           equ    121
      IDC_h4           equ    122 
      
      MAXSIZE          equ 260
      
.data
      
      bfBuffer         db    MAXSIZE dup (0)
      buffer1          db    MAXSIZE dup (0)
      buffer2          db    MAXSIZE dup (0)
      buffer3          db    10      dup (0)
      buffer4          db    10      dup (0)
      buffer5          db    10      dup (0)
      buffer6          db    10      dup (0)
      brut             dd    20      dup (0)
     
      szAboutCaption   db    'about HCCC6 md5 hasher',0
      szAboutText      db    'md5hasher',13,10,'basé sur un source de'
                       db    13,10,'roy|crisiscrackers.',13,10
                       db    13,10,"La recherche ne porte que"
                       db    13,10,"sur un seul Dword du hash"
                       db    13,10,"dans le cadre mini/maxi,"
                       db    13,10,"que vous aurez indiqué."
                       db    13,10,13,10,"Coded by Christal",0
      szMD5Format      db    '%.8x%.8x%.8x%.8x',0
      serialformat     db    "%d",0
      format2          db    "8x%",0
      dlgname          db    "dialogbox",0
      good             db    "Serial trouvé",0
      nogood           db    "Serial non trouvé",0
      error_1          db    "Erreur entre valeurs mini et maxi",0
      error_2          db    "valeur de hash non valide",0
      open             db    "open",0
      crackme          db    "crackme.exe",0
      slash            db    "C:\WINDOWS\TEMP\CRACKME.EXE",0
      cible_ok         db    "Crackme trouvé",0

      TimerID          dd 0
      hBmp             dd 0
      lg_mini          dd 0
      lg_maxi          dd 0
      rang             dd 0
      
      StaticClass      db "static",0 
      FilterString     db "HCCC6 Crackme",0,"crackme.exe",0
                       db "Tous les Fichiers",0,"*.*",0,0
      
      ofn   OPENFILENAME <>
      
.data?
      
      hInstance        HINSTANCE ?
      stMD5Result      MD5RESULT <?>
      
      hwndProgress     dd ?
      hwndResult       dd ?
      hwndStatus       dd ?
      hStatImage       dd ?
      CurrentStep      dd ?
      Directory        db 512 dup (?)

.code

start:      invoke  GetModuleHandle,0
            mov      hInstance,eax

; appel de la dialgBox crée dans les ressources

            invoke  DialogBoxParam,hInstance,ADDR dlgname,0,ADDR DlgProc,0
            invoke  ExitProcess,eax

DlgProc proc    uses ebx edi esi,hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

            cmp   uMsg,WM_INITDIALOG
            jz    initdialog

            cmp   uMsg,WM_CLOSE
            jz    close

            cmp   uMsg,WM_COMMAND
            jz    command

            ret

bruteforcer:

; saisie du 1er dword du hash. Si absent passe au suivant, etc...

            invoke    GetDlgItemText,hWnd,IDC_h1,addr buffer3,9    
            mov       dword ptr [rang],0
            cmp       eax,8
            je        @F
            invoke    GetDlgItemText,hWnd,IDC_h2,addr buffer3,
            mov       dword ptr [rang],8
            cmp       eax,8
            je        @F
            invoke    GetDlgItemText,hWnd,IDC_h3,addr buffer3,9
            mov       dword ptr [rang],16 
            cmp       eax,8
            je        @F           
            invoke    GetDlgItemText,hWnd,IDC_h4,addr buffer3,9
            mov       dword ptr [rang],24
            cmp       eax,8
            je        @F
            invoke    SetWindowTextA,hwndProgress, addr error_2 
            ret

; saisie de la plus petite et de la plus grande valeur qui serviront 
; de fourchette de recherche

@@:
            invoke    GetDlgItemText,hWnd,IDC_mini,addr buffer5,9
            cmp       eax,0
            jle       error1             
            mov       dword ptr [lg_mini],eax
            invoke    GetDlgItemText,hWnd,IDC_maxi,addr buffer6,9
            cmp       eax,0
            jle       error1             
            mov       dword ptr [lg_maxi],eax

; les valeurs mini et maxi sont transformées d'une string en une valeur hexadécimale

            invoke    Str2Hex, addr buffer5,dword ptr [lg_mini]
            mov       dword ptr [buffer5],eax
            invoke    Str2Hex, addr buffer6,dword ptr [lg_maxi]
            mov       dword ptr [buffer6],eax
            sub       eax, dword ptr [buffer5]
            jle       error1 
            invoke    SetWindowTextA,hwndProgress, NULL 

            mov       eax, dword ptr [buffer5]
            mov       dword ptr [brut],eax
loop1:
            invoke    wsprintfA,addr buffer1,addr serialformat, dword ptr [brut] 
            invoke    wsprintfA,addr buffer2,addr serialformat, dword ptr [brut] 
            invoke    lstrlen,addr buffer1
            invoke    procMD5hash,addr buffer1,eax,addr stMD5Result
            mov       eax, dword ptr [buffer3]
            mov       esi, dword ptr [rang]
            cmp       dword ptr [buffer1+esi], eax
            je        trouve1
            inc       dword ptr [brut]
            mov       eax, dword ptr [buffer6]
            cmp       dword ptr [brut], eax
            jle       loop1
Pas_Glop:  
            invoke    SetWindowTextA,hwndResult, NULL
            invoke    SetWindowTextA,hwndProgress, addr nogood 
            ret
trouve1:
            mov       eax, dword ptr [buffer3+4]
            mov       esi, dword ptr [rang]
            add       esi,4
            cmp       dword ptr [buffer1+esi], eax
            je        trouve2
            inc       dword ptr [brut]
            mov       eax, dword ptr [buffer5]
            cmp       dword ptr [brut], eax
            jle       loop1
            jmp       Pas_Glop
trouve2:    
            invoke    SetWindowTextA,hwndResult, addr buffer2
            invoke    SetWindowTextA,hwndProgress, addr good              
            ret
error1:            
            invoke    SetWindowTextA,hwndProgress, addr error_1 
            ret  
endcheck:   
            mov     eax,1
            ret
command:    
            mov     eax,wParam
        mov     edx,wParam

            .if    ax == IDC_Search
                   invoke SetWindowTextA,hwndProgress, NULL 
                   jmp    bruteforcer
            .endif

            .if    ax == IDC_Exit
                   invoke ExitProcess,0
            .endif
            
            .if     ax == IDC_Open
                    invoke ShellExecuteA,hWnd,addr open,addr crackme,NULL,NULL,01
                    cmp    eax,32
                    jnle   @F
                    invoke ShellExecuteA,hWnd,addr open,addr slash,NULL,NULL,01
                    cmp    eax,32
                    jnle   @F
                    invoke OpenDialog, hWnd

  @@:
            .endif

              shr     edx,16

        cmp     edx,BN_CLICKED
        jnz     @f

        cmp     ax,IDC_ABOUT
        jnz     endcheck
        invoke MessageBoxA,hWnd,addr szAboutText,addr szAboutCaption,MB_OK or MB_ICONASTERISK

        ret 
            
@@:         cmp    edx,EN_CHANGE
            jnz    endcheck

            cmp    ax,IDC_EDITTEXT
            jnz    endcheck

            invoke    GetDlgItemText,hWnd,IDC_EDITTEXT,addr bfBuffer,MAXSIZE
            invoke    procMD5hash,addr bfBuffer,eax,addr stMD5Result
            invoke    SendDlgItemMessageA,hWnd,IDC_EDITHASH,WM_SETTEXT,0,addr bfBuffer

            ret
initdialog: 

        invoke      LoadIconA,hInstance,IDI_ICON
        invoke      SendMessageA,hWnd,WM_SETICON,1,eax
        invoke      SendDlgItemMessageA,hWnd,IDC_EDITTEXT,WM_SETTEXT,0,0

; load bitmap 
        invoke      StaticImage,NULL,hWnd,10,10,121,44,IDC_STATIC2
        mov         hStatImage, eax
        invoke      LoadBitmap,hInstance,ID_Fond   
        mov         hBmp, eax  
        
; place l'image dans static control
  
        invoke      SendMessage,hStatImage,STM_SETIMAGE,IMAGE_BITMAP,hBmp
        invoke      GetDlgItem, hWnd, IDC_progress
        mov         hwndProgress, eax

        invoke      GetDlgItem, hWnd, IDC_Result
        mov         hwndResult, eax
        ret

close:  invoke      EndDialog,hWnd,0
        ret

DlgProc    endp

procMD5hash proc    ptBuffer:dword,dtBufferLength:dword,ptMD5Result:dword
            local   dta:dword,dtb:dword,dtc:dword,dtd:dword

; phase I · padding
            mov    edi,ptBuffer
            mov    eax,dtBufferLength
            inc    eax
            add    edi,eax
            mov    byte ptr [edi-1],080h
            xor    edx,edx
            mov    ebx,64
            div    ebx
            neg    edx
            add    edx,64
            cmp    edx,8
            jae    @f
            add    edx,64

@@:         mov    ecx,edx
            xor    al,al
            rep    stosb
            mov    eax,dtBufferLength
            inc    edx
            add    dtBufferLength,edx
            xor    edx,edx
            mov    ebx,8
            mul    ebx
            mov    dword ptr [edi-8],eax
            mov    dword ptr [edi-4],edx
            mov    edx,dtBufferLength
            mov    edi,ptBuffer

; phase II · chaining variables initialization

            mov     esi,ptMD5Result
            assume esi:ptr MD5RESULT
            mov     [esi].dtA,067452301h
            mov     [esi].dtB,0efcdab89h
            mov     [esi].dtC,098badcfeh
            mov     [esi].dtD,010325476h

; phase III · hashing

hashloop:   mov    eax,[esi].dtA
            mov    dta,eax
            mov    eax,[esi].dtB
            mov    dtb,eax
            mov    eax,[esi].dtC
            mov    dtc,eax
            mov    eax,[esi].dtD
            mov    dtd,eax

; round 1
            invoke    FF,dta,dtb,dtc,dtd,dword ptr [edi+00*4],07,0d76aa478h
            mov    dta,eax
            invoke    FF,dtd,dta,dtb,dtc,dword ptr [edi+01*4],12,0e8c7b756h
            mov    dtd,eax
            invoke    FF,dtc,dtd,dta,dtb,dword ptr [edi+02*4],17,0242070dbh
            mov    dtc,eax
            invoke    FF,dtb,dtc,dtd,dta,dword ptr [edi+03*4],22,0c1bdceeeh
            mov    dtb,eax
            invoke    FF,dta,dtb,dtc,dtd,dword ptr [edi+04*4],07,0f57c0fafh
            mov    dta,eax
            invoke    FF,dtd,dta,dtb,dtc,dword ptr [edi+05*4],12,04787c62ah
            mov    dtd,eax
            invoke    FF,dtc,dtd,dta,dtb,dword ptr [edi+06*4],17,0a8304613h
            mov    dtc,eax
            invoke    FF,dtb,dtc,dtd,dta,dword ptr [edi+07*4],22,0fd469501h
            mov    dtb,eax
            invoke    FF,dta,dtb,dtc,dtd,dword ptr [edi+08*4],07,0698098d8h
            mov    dta,eax
            invoke    FF,dtd,dta,dtb,dtc,dword ptr [edi+09*4],12,08b44f7afh
            mov    dtd,eax
            invoke    FF,dtc,dtd,dta,dtb,dword ptr [edi+10*4],17,0ffff5bb1h
            mov    dtc,eax
            invoke    FF,dtb,dtc,dtd,dta,dword ptr [edi+11*4],22,0895cd7beh
            mov    dtb,eax
            invoke    FF,dta,dtb,dtc,dtd,dword ptr [edi+12*4],07,06b901122h
            mov    dta,eax
            invoke    FF,dtd,dta,dtb,dtc,dword ptr [edi+13*4],12,0fd987193h
            mov    dtd,eax
            invoke    FF,dtc,dtd,dta,dtb,dword ptr [edi+14*4],17,0a679438eh
            mov    dtc,eax
            invoke    FF,dtb,dtc,dtd,dta,dword ptr [edi+15*4],22,049b40821h
            mov    dtb,eax

; round 2
            invoke    GG,dta,dtb,dtc,dtd,dword ptr [edi+01*4],05,0f61e2562h
            mov    dta,eax
            invoke    GG,dtd,dta,dtb,dtc,dword ptr [edi+06*4],09,0c040b340h
            mov    dtd,eax
            invoke    GG,dtc,dtd,dta,dtb,dword ptr [edi+11*4],14,0265e5a51h
            mov    dtc,eax
            invoke    GG,dtb,dtc,dtd,dta,dword ptr [edi+00*4],20,0e9b6c7aah
            mov    dtb,eax
            invoke    GG,dta,dtb,dtc,dtd,dword ptr [edi+05*4],05,0d62f105dh
            mov    dta,eax
            invoke    GG,dtd,dta,dtb,dtc,dword ptr [edi+10*4],09,002441453h
            mov    dtd,eax
            invoke    GG,dtc,dtd,dta,dtb,dword ptr [edi+15*4],14,0d8a1e681h
            mov    dtc,eax
            invoke    GG,dtb,dtc,dtd,dta,dword ptr [edi+04*4],20,0e7d3fbc8h
            mov    dtb,eax
            invoke    GG,dta,dtb,dtc,dtd,dword ptr [edi+09*4],05,021e1cde6h
            mov    dta,eax
            invoke    GG,dtd,dta,dtb,dtc,dword ptr [edi+14*4],09,0c33707d6h
            mov    dtd,eax
            invoke    GG,dtc,dtd,dta,dtb,dword ptr [edi+03*4],14,0f4d50d87h
            mov    dtc,eax
            invoke    GG,dtb,dtc,dtd,dta,dword ptr [edi+08*4],20,0455a14edh
            mov    dtb,eax
            invoke    GG,dta,dtb,dtc,dtd,dword ptr [edi+13*4],05,0a9e3e905h
            mov    dta,eax
            invoke    GG,dtd,dta,dtb,dtc,dword ptr [edi+02*4],09,0fcefa3f8h
            mov    dtd,eax
            invoke    GG,dtc,dtd,dta,dtb,dword ptr [edi+07*4],14,0676f02d9h
            mov    dtc,eax
            invoke    GG,dtb,dtc,dtd,dta,dword ptr [edi+12*4],20,08d2a4c8ah
            mov    dtb,eax

; round 3
            invoke    HH,dta,dtb,dtc,dtd,dword ptr [edi+05*4],04,0fffa3942h
            mov    dta,eax
            invoke    HH,dtd,dta,dtb,dtc,dword ptr [edi+08*4],11,08771f681h
            mov    dtd,eax
            invoke    HH,dtc,dtd,dta,dtb,dword ptr [edi+11*4],16,06d9d6122h
            mov    dtc,eax
            invoke    HH,dtb,dtc,dtd,dta,dword ptr [edi+14*4],23,0fde5380ch
            mov    dtb,eax
            invoke    HH,dta,dtb,dtc,dtd,dword ptr [edi+01*4],04,0a4beea44h
            mov    dta,eax
            invoke    HH,dtd,dta,dtb,dtc,dword ptr [edi+04*4],11,04bdecfa9h
            mov    dtd,eax
            invoke    HH,dtc,dtd,dta,dtb,dword ptr [edi+07*4],16,0f6bb4b60h
            mov    dtc,eax
            invoke    HH,dtb,dtc,dtd,dta,dword ptr [edi+10*4],23,0bebfbc70h
            mov    dtb,eax
            invoke    HH,dta,dtb,dtc,dtd,dword ptr [edi+13*4],04,0289b7ec6h
            mov    dta,eax
            invoke    HH,dtd,dta,dtb,dtc,dword ptr [edi+00*4],11,0eaa127fah
            mov    dtd,eax
            invoke    HH,dtc,dtd,dta,dtb,dword ptr [edi+03*4],16,0d4ef3085h
            mov    dtc,eax
            invoke    HH,dtb,dtc,dtd,dta,dword ptr [edi+06*4],23,004881d05h
            mov    dtb,eax
            invoke    HH,dta,dtb,dtc,dtd,dword ptr [edi+09*4],04,0d9d4d039h
            mov    dta,eax
            invoke    HH,dtd,dta,dtb,dtc,dword ptr [edi+12*4],11,0e6db99e5h
            mov    dtd,eax
            invoke    HH,dtc,dtd,dta,dtb,dword ptr [edi+15*4],16,01fa27cf8h
            mov    dtc,eax
            invoke    HH,dtb,dtc,dtd,dta,dword ptr [edi+02*4],23,0c4ac5665h
            mov    dtb,eax

; round 4
            invoke    II,dta,dtb,dtc,dtd,dword ptr [edi+00*4],06,0f4292244h
            mov    dta,eax
            invoke    II,dtd,dta,dtb,dtc,dword ptr [edi+07*4],10,0432aff97h
            mov    dtd,eax
            invoke    II,dtc,dtd,dta,dtb,dword ptr [edi+14*4],15,0ab9423a7h
            mov    dtc,eax
            invoke    II,dtb,dtc,dtd,dta,dword ptr [edi+05*4],21,0fc93a039h
            mov    dtb,eax
            invoke    II,dta,dtb,dtc,dtd,dword ptr [edi+12*4],06,0655b59c3h
            mov    dta,eax
            invoke    II,dtd,dta,dtb,dtc,dword ptr [edi+03*4],10,08f0ccc92h
            mov    dtd,eax
            invoke    II,dtc,dtd,dta,dtb,dword ptr [edi+10*4],15,0ffeff47dh
            mov    dtc,eax
            invoke    II,dtb,dtc,dtd,dta,dword ptr [edi+01*4],21,085845dd1h
            mov    dtb,eax
            invoke    II,dta,dtb,dtc,dtd,dword ptr [edi+08*4],06,06fa87e4fh
            mov    dta,eax
            invoke    II,dtd,dta,dtb,dtc,dword ptr [edi+15*4],10,0fe2ce6e0h
            mov    dtd,eax
            invoke    II,dtc,dtd,dta,dtb,dword ptr [edi+06*4],15,0a3014314h
            mov    dtc,eax
            invoke    II,dtb,dtc,dtd,dta,dword ptr [edi+13*4],21,04e0811a1h
            mov    dtb,eax
            invoke    II,dta,dtb,dtc,dtd,dword ptr [edi+04*4],06,0f7537e82h
            mov    dta,eax
            invoke    II,dtd,dta,dtb,dtc,dword ptr [edi+11*4],10,0bd3af235h
            mov    dtd,eax
            invoke    II,dtc,dtd,dta,dtb,dword ptr [edi+02*4],15,02ad7d2bbh
            mov    dtc,eax
            invoke    II,dtb,dtc,dtd,dta,dword ptr [edi+09*4],21,0eb86d391h
            mov    dtb,eax
            mov    eax,dta
            add    [esi].dtA,eax
            mov    eax,dtb
            add    [esi].dtB,eax
            mov    eax,dtc
            add    [esi].dtC,eax
            mov    eax,dtd
            add    [esi].dtD,eax
            add    edi,64
            sub    edx,64
            jnz    hashloop

; phase IV · results

            mov    ecx,4

@@:         mov    eax,dword ptr [esi]
            xchg   al,ah
            rol    eax,16
            xchg   al,ah
            mov    dword ptr [esi],eax
            add    esi,4
            loop   @b
            mov    esi,ptMD5Result
            invoke wsprintfA,ptBuffer,addr szMD5Format,[esi].dtA,[esi].dtB,[esi].dtC,[esi].dtD
            ret

procMD5hash        endp

FF    proc   dta,dtb,dtc,dtd,x,s:byte,t   ; a = b + ((a + F(b,c,d) + x + t) << s )

            mov    eax,dtb
            mov    ebx,dtc
            mov    ecx,dtd

; F(x,y,z) = (x and y) or ((not x) and z)
            and    ebx,eax
            not    eax
            and    eax,ecx
            or    eax,ebx
            add    eax,dta
            add    eax,x
            add    eax,t
            mov    cl,s
            rol    eax,cl
            add    eax,dtb
            ret

FF            endp

GG   proc  dta,dtb,dtc,dtd,x,s:byte,t    ; a = b + ((a + G(b,c,d) + x + t) << s)

            mov    eax,dtb
            mov    ebx,dtc
            mov    ecx,dtd

; G(x,y,z) = (x and z) or (y and (not z))
            and    eax,ecx
            not    ecx
            and    ecx,ebx
            or    eax,ecx
            add    eax,dta
            add    eax,x
            add    eax,t
            mov    cl,s
            rol    eax,cl
            add    eax,dtb
            ret

GG            endp

HH    proc   dta,dtb,dtc,dtd,x,s:byte,t        ; a = b + ((a + H(b,c,d) + x + t) << s)

            mov    eax,dtb
            mov    ebx,dtc
            mov    ecx,dtd

; H(x,y,z) = x xor y xor z
            xor    eax,ebx
            xor    eax,ecx
            add    eax,dta
            add    eax,x
            add    eax,t
            mov    cl,s
            rol    eax,cl
            add    eax,dtb
            ret

HH            endp

II   proc   dta,dtb,dtc,dtd,x,s:byte,t        ; a = b + ((a + I(b,c,d) + x + t) << s)

            mov    eax,dtb
            mov    ebx,dtc
            mov    ecx,dtd

; I(x,y,z) = y xor (x or (not z))
            not    ecx
            or    eax,ecx
            xor    eax,ebx
            add    eax,dta
            add    eax,x
            add    eax,t
            mov    cl,s
            rol    eax,cl
            add    eax,dtb
            ret

II            endp

;=========================================================================
;                           affichage BitMap
;=========================================================================

StaticImage proc lpText:DWORD,hParent:DWORD,
                 a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,ID:DWORD

    invoke CreateWindowEx,WS_EX_STATICEDGE,\
    ADDR StaticClass ,lpText,\
    WS_CHILD or WS_VISIBLE or SS_BITMAP,\
    a,b,wd,ht,hParent,ID,\
    hInstance,NULL
    ret
StaticImage endp


;=========================================================================
;                           conversion string en val hex
;=========================================================================

Str2Hex PROC uses ebx ecx edx Buff:DWORD, Lenght:DWORD

        mov ebx,Buff        
        mov ecx,Lenght
        xor eax,eax
        xor edx,edx
CHC_pour1:
        mov dl,byte ptr[ebx+ecx-1]
        cmp dl,'A'
        jge CHC_sinon1
        sub dl,'0'
        jmp CHC_fsi1

CHC_sinon1:
        sub dl,'A'-10

CHC_fsi1:
        or al,dl        
        ror eax,04
        loop CHC_pour1
       
CHC_fpour1:
        mov ecx, Lenght
        neg ecx
        add ecx, 8
        shl ecx, 2        
        ror eax, cl
ret
Str2Hex endp

;========================================================================= 
;                                Brownse  
;=========================================================================
OpenDialog    PROC hWin:DWORD

        mov [Directory],00

        mov  ofn.lStructSize,SIZEOF ofn
        mov  ofn.lpstrFilter, OFFSET FilterString
        mov  ofn.lpstrFile, OFFSET Directory
        mov  ofn.nMaxFile,512
        mov  ofn.Flags, OFN_FILEMUSTEXIST or \
                        OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                        OFN_EXPLORER or OFN_HIDEREADONLY
        invoke    GetOpenFileName, offset ofn
        cmp       eax, FALSE
        jz        EndOD
        invoke    SetWindowTextA,hwndProgress, ADDR cible_ok
        invoke    ShellExecuteA,hWin,addr open,addr Directory,NULL,NULL,01
EndOD:
    ret

OpenDialog    ENDP

end    start

Bonne Journée

Christal