XNVIEW v1.12 Fr

Avant Propos :

Bon je me suis décidé à regardé le défi de la main rouge, qui consiste à faire passer en shareware le prog xnview qui est freeware. Tout d’abord il ne faut pas vous attendre ici à des merveilles de reverse engineering et autres truc... je ne suis qu’un newbie . Pour cela faudra aller voir les autres contributions.

Enfin, pour ma part j’ai décidé de rendre se programme en version de démonstration et de brider quelques fonctions.

 
downloader le prog :   xnview


Outils

W32dasm v8.93
Softice v4.01
HexWorkshop v2.5
Borland ressource Workshop v4.5
Procdump v1.6


HowTo


 

Le premier objectif que je me suis fixé c’est de mettre un nagscreen au démarage du prog. Je me suis contenté d’une simple messagebox, car les dialogbox ou les fenêtres sont plus longues à faire (on utilise Masm ou autre, et je suis pas au top sur la création de fenêtre).

Pour ce faire il faut de la place dans le prog. A la fin il y en a, mais j’ai préféré rajouter une section au prog. Pour cela on prend procdump, on va sur Pe-editor, on ouvre xnview, on clique sur sections, on se place sur la dernière, et on fait add section (ajouter une section). La mienne à les caractéristiques suivantes :

Name .LuTiN
VirtualSize 00001000
VirtualOffset 00110000
RawSize 00001000
RawOffset 00109800
Characteristics E0000020 code exécutable, readable, writable

Maintenant que la section est crée il faut changer la taille de l’image base toujours sous procdump de 110000 par 111000 (j’ai rajouté 1000 bytes ce qui est amplement suffisant, même de trop).

Maintenant que notre section est crée il faut lui donné c’est 1000 bytes. Pour cela on prend Hex Workshop, on va à la fin du fichier, on fait insérer, on met 1000 bytes en hexa et ok. Maintenant que l’on a notre espace de travail on peut s’attaquer à la MessageBox.
Pour cela j’ai decidé quelle apparaitra avant la création du prog. Il faut donc rechercher où le prog est créer. On va sous softice et on met un point d’arrêt sur la création d’une fenêtre :
BPX CreateWindowExA. On lance le soft, et là softice se déclenche. On appuie sur F12 pour remonter dans le prog et chercher quelle fonction affiche le prog (et le créé). En remontant les fonctions et en regardant dans W32dasm j’arrive là :

:00478954 6A0A             push 0000000A
:00478956 8B1574924D00     mov edx, dword ptr [004D9274]
:0047895C 52               push edx
:0047895D 6A00             push 00000000
:0047895F 6A00             push 00000000

* Reference To: KERNEL32.GetModuleHandleA, Ord:002Fh
|
:00478961 2EFF15D0F84B00   Call dword ptr cs:[004BF8D0]
:00478968 50 push eax
:00478969 E82AA8FAFF       call 00423198 <-- affiche le prog
:0047896E E850F8FBFF       call 004381C3
:00478973 89EC             mov esp, ebp
:00478975 5D               pop ebp
:00478976 5A               pop edx
:00478977 59               pop ecx
:00478978 5B               pop ebx
:00478979 C3               ret

Donc en 478969 on trouve la fonction qui affiche le prog : c’est donc là que l’on va détourner notre prog vers le début de notre section qui se trouve à l’adresse 00510780 (c’est Hiew qui l’dit J ).
Mais avant de faire cela il faut savoir ce que l’on va ecrire dans cette section. Donc en gros voilà comment se présente l’appel d’une MessageBox (voir tut de Morgate pour de plus ample informations) :
 

PUSH 00                        ß forme de la MessageBox
PUSH XXXXXXX         ß adresse du titre
PUSH XXXXXXX         ß adresse du texte
PUSH 00                        ß n° de la fenêtre
CALL USER32 !MessageBoxA            ß appel de la message box (c’est pas exactement comme cela, mais c’est comme ça qu’on va le mettre sous softice)

Donc il y a besoin d’une place pour le titre, et d’une pour le texte. J’ai décidé de mettre le texte, et le titre au début de la section, ce qui donne :

On trouve que le début du titre est à l’adresse 510780 et le début du texte à l’adresse 51078B.
On va mettre l’appel du nag un peu après en 5107FB (par exemple).
Donc on modifie d’abor le call. On lance le prog avec symbol loader, on met un point d’arrêt en 478969, on appuie sur F5 et la on tape a 478969 pour remplacer le call par notre saut :

:00478961 2EFF15D0F84B00     Call dword ptr cs:[004BF8D0]
:00478968 50                 push eax
:00478969 E98D7E0900         jmp 005107FB ßsaut vers nag
:0047896E E850F8FBFF         call 004381C3
:00478973 89EC               mov esp, ebp
:00478975 5D                 pop ebp
:00478976 5A                 pop edx
:00478977 59                 pop ecx
:00478978 5B                 pop ebx
:00478979 C3                                                       ret

On appuie sur f10 pour aller à l’endroit où l’on va mettre le nag. On rappuit sur F10 car la zone est invalide sous softice, il break et l’adresse redevient valide. On peut mettre notre nag avec a 5107FB :

5107FB 60                         pushad                          ß sauvegarde les registres
5107FC 6A00                    push 00           ß forme nag
5107FE 6880075100         push 00510780            ß titre nag
5107F3 688B075100         push 0051078B            ß texte nag
5107F8 6A00                     push 00                ß n° MessageBox
5107FA E81F39A4BF       call USER32!MessageBoxA            ß appel nag
51080F 61                          popad                         ß restaure les registres
510810 E88329F1FF         call 00423198            ß création du prog
510815 E95481F6FF         jmp 0047896E            ß on retourne dans le prog
51081A 0000                     add [eax], al                ß suite de notre section

  On effectue les changements avec un éditeur hexa. On test si toute fonctionne. OK le nag s’affiche, on peut passer au reste.

Maintenant on va désactiver les fonctions de sauvegarde. Pour cela on désassemble le prog avec W32dasm, on va dans import fonction et on trouve GetSaveFileName qui sert à sauver les fichiers. On on trouve plusieurs dans le prog. Pour savoir si elle corresponde ou pas au fonction save ou save as j’ai mis un point d’arrêt vers l’endroit où elle sont appelées et j’ai testé save et save as. Voici la fonction save as :

:00418EC9 B906080000             mov ecx, 00000806
:00418ECE 89842430170000         mov dword ptr [esp+00001730], eax
:00418ED5 B8DC8C4100             mov eax, 00418CDC
:00418EDA 8B1D7C934E00           mov ebx, dword ptr [004E937C]
:00418EE0 89842444170000         mov dword ptr [esp+00001744], eax
:00418EE7 A178934E00             mov eax, dword ptr [004E9378]
:00418EEC 89942448170000         mov dword ptr [esp+00001748], edx
:00418EF3 89842408170000         mov dword ptr [esp+00001708], eax
:00418EFA 8D842400100000         lea eax, dword ptr [esp+00001000]
:00418F01 898C2434170000         mov dword ptr [esp+00001734], ecx
:00418F08 89842440170000         mov dword ptr [esp+00001740], eax
:00418F0F 85DB                   test ebx, ebx
:00418F11 740B                   je 00418F1E ßon va dériver le prog ici
:00418F13 C784243417000066080800 mov dword ptr [esp+00001734], 00080866

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00418F11(C)
|
:00418F1E 8D842400170000         lea eax, dword ptr [esp+00001700]
:00418F25 50                     push eax

* Reference To: comdlg32.GetSaveFileNameA, Ord:0002h
|
:00418F26 E8295D0A00             Call 004BEC54 ßboite de dialog save
:00418F2B 85C0                   test eax, eax
:00418F2D 745E                   je 00418F8D ßsaut important
:00418F2F 8B842418170000         mov eax, dword ptr [esp+00001718]
:00418F36 A3ACE74C00             mov dword ptr [004CE7AC], eax
:00418F3B 668B8484FC0F0000       mov ax, word ptr [esp+4*eax+00000FFC]
:00418F43 8D942400140000         lea edx, dword ptr [esp+00001400]
:00418F4A 668906                 mov word ptr [esi], ax
:00418F4D 89F8                   mov eax, edi
:00418F4F E8C5F80000             call 00428819
:00418F54 31C0                   xor eax, eax
:00418F56 668B842438170000       mov ax, word ptr [esp+00001738]
:00418F5E 31D2                   xor edx, edx
:00418F60 C6040700               mov byte ptr [edi+eax], 00
:00418F64 668B942438170000       mov dx, word ptr [esp+00001738]
:00418F6C 8D842400140000         lea eax, dword ptr [esp+00001400]
:00418F73 01C2                   add edx, eax
:00418F75 89E8                   mov eax, ebp
:00418F77 E89DF80000             call 00428819
:00418F7C B883944E00             mov eax, 004E9483
:00418F81 89FA                   mov edx, edi
:00418F83 E891F80000             call 00428819

* Possible Ref to Menu: BROWSERMENU, Item: "Ouvrir..."
|
:00418F88 B801000000             mov eax, 00000001

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00418F2D(C)
|
:00418F8D 81C454170000           add esp, 00001754 ßsaut arrive là
:00418F93 5D                     pop ebp
:00418F94 5F                     pop edi
:00418F95 5E                     pop esi
:00418F96 C3                     ret ßretour de la fonction
 

En 418F26 la boite de sauvegarde est appelé. Pour voir comment éviter cela j’ai d’abord mis ret à la place du suat avant la fonction en 418F11 mais le programme plantait. Ensuite j’ai remarqué le saut en 418F2D qui nous ammenait vers la fin de la fonction. Je l’ai donc forcé, après que la boite de dialogue soit apparu et la le prog plantait plus.

Donc j’ai d’abord détourné le saut en 418F11 vers une partie de la section .LuTiN où j’ai mis un autre nag, puis il revenait en 418F8D où le programme continuait sa route.
Voilà comment forcer le saut :

:00418F0F 85DB           test ebx, ebx
:00418F11 E904790F00     jmp 0051081A
:00418F13 90             nop ßon rééquilibre le code
:00418F13 90             nop
:00418F13 90             nop
:00418F13 90             nop
:00418F13 90             nop
:00418F13 90             nop
:00418F13 90             nop
:00418F13 90             nop
:00418F1E 8D842400170000 lea eax, dword ptr [esp+00001700]
:00418F25 50             push eax

L’adresse 51081A de la section .LuTiN est juste après le nag précédent . Donc maintenant , on peut aller à cette adresse et y faire notre nag. Ici comme mon but n’est pas de détruire la fonction de sauvegarde, mais de la bloquer (en gros quelques changement la réactive) j’ai volontairement réécrit la partie que l’on a détruit par le saut :

51081A 60                                              pushad            ß sauvegarde les registres
51081B 6A00                                         push 00                    ß forme de la MessageBox
51081D 6880075100                              push 00510780            ß Titre
510822 688B075100                              push 0051078B                ß Texte
510827 6A00                                          push 00                        ß
510829 E80039A4BF                             call USER32!MessageBoxA            ß MessageBox
51082E 61                                              popad                            ß on restaure les registres
51082F E95987F0FF                             jmp 00418F8D            ß on retourne à la fin de la fonction
510834 0F84E486F0FF                         jz 00418F1E                    ß ce que l’on a détruit par le saut
51083A C784243417000066080800     mov dword ptr [esp+00001734], 00080866
510845 E9D486F0FF                             jmp 00418F1E                    ß retourne dans la fonction
 
 

Donc cette partie du code affiche la MessageBox de tout à l’heure et retourne à la fin de la fonction pour éviter l’enregistrement. Il peut être réactiver en noppant le call en 51082F car j’ai remis ce qui suivait normalement dans le prog. (le je devient jz c’est un saut long)

Si on s’arrête là, on a plus la boite de sauvegarde mais pourtant une sauvegarde s’effectue. C’est parce qu’en retour de la fonction il y a un test sur eax :

:004127D9 E8DE650000         call 00418DBC
:004127DE 85C0               test eax, eax ß test eax
:004127E0 7445               je 00412827 ßsaute si = 0 et pas sauvegarde
:004127E2 8D942400030000     lea edx, dword ptr [esp+00000300]
:004127E9 89E0               mov eax, esp
:004127EB E829600100         call 00428819
:004127F0 8D942400020000     lea edx, dword ptr [esp+00000200]
:004127F7 89E0               mov eax, esp
:004127F9 E89D630100         call 00428B9B

Donc pour que l’enregistrement ne s’effectue pas, il faut que eax soit égale à 0. Donc on modifie légérement notre appel de nag :

51081A 60                                             pushad            ß sauvegarde les registres
51081B 6A00                                         push 00            ß forme de la MessageBox
51081D 6880075100                             push 00510780         ß Titre
510822 688B075100                             push 0051078B         ß Texte
510827 6A00                                         push 00            ß
510829 E80039A4BF                             call USER32!MessageBoxA                ß MessageBox
51082E 61                                              popad                            ß on restaure les registres
51082F B800000000                              mov eax, 00000000
510834 E95487F0FF                             jmp 00418F8D                    ß on retourne à la fin de la fonction
510839 0F84DF86F0FF                        jz 00418F1E                    ß ce que l’on a détruit par le saut
51083F C784243417000066080800     mov dword ptr [esp+00001734], 00080866
510849 E9CF86F0FF                            jmp 00418F1E                        ß retourne dans la fonction

Et là le nag s’affiche et l’enregistrement ne s’effectue pas J . Attention aux valeurs hexa qui ont changées. On peut maintenant effectuer les modif avec un éditeur hexa.

Bon maintenant on peut s’attaquer à la fonction sauver. Pour cela j’ai ouvert un fichier, j’ai fait sauver, et là une boite de dialogue nous dit que le fichier existe déjà et nous demande si on veut l’écraser. Là j’ai fait surgir softice, j’ai taper task pour obtenir les noms des progs en mémoire. Le notre c’est xnviewfr. On fait hwnd xnviewfr pour voir tous les évènements du prog. J’obtiens ça (attention surement différent chez vous) :
 
Window handle
hQueue
SZ
QOwner
ClassName
Window Procedure
0494 (1) 31FF 32 XNVIEWER #32770 (Dialog) 17AF :000050B1
049C (2) 31FF 32 XNVIEWER Button 17AF :00001040
04A0 (2) 31FF 32 XNVIEWER Button 17AF :00001040
04A4 (2) 31FF 32 XNVIEWER Static 17AF :00005C20

Il y en a encore d’autre mais celle là suffise.

Bon je veux mettre un Breakpoint sur l’activité de la souris donc il Faut prendre une ClassName avec bouton, or la première c’est la boite de dialog et après il y a deux bouton (ceux de la boite). Bon on met le point d’arrêt sur un des deux et si ça marche pas on prend l’autre. Donc on met le point d’arrêt : BMSG 49C 0202 . 49C c’est le window handle du bouton et 0202 c’est l’api WM_LbuttonUp.

On appuie sur F5 et softice se déclenche, on remonte avec F12, on regarde où on est (on peut s’aider du désassembleur) et on arrive là :
 

* Reference To: USER32.GetWindowLongA, Ord:0037h
|
:004126C1 2EFF152CF74B00           Call dword ptr cs:[004BF72C]
:004126C8 89C6                     mov esi, eax
:004126CA 8B8002020000             mov eax, dword ptr [eax+00000202]
:004126D0 C1F810                   sar eax, 10
:004126D3 83F8FF                   cmp eax, FFFFFFFF
:004126D6 7521                     jne 004126F9 ßsaute vers nag fichier existe
:004126D8 89D9                     mov ecx, ebx
:004126DA 31C0                     xor eax, eax
:004126DC 31D2                     xor edx, edx
:004126DE 668B842404040000         mov ax, word ptr [esp+00000404]
:004126E6 668B942400040000         mov dx, word ptr [esp+00000400]
:004126EE 89C3                     mov ebx, eax
:004126F0 89F8                     mov eax, edi
:004126F2 E885000000               call 0041277C
:004126F7 EB75                     jmp 0041276E

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004126D6(C)
|
:004126F9 6800010000               push 00000100 ßnag fichier existe
:004126FE 8D442404                 lea eax, dword ptr [esp+04]
:00412702 50                       push eax

* Possible Reference to String Resource ID=04017: "Ce fichier existe !Voulez-vous l'écrasez ?"
|
:00412703 68B10F0000               push 00000FB1
:00412708 8B1578934E00             mov edx, dword ptr [004E9378]
:0041270E 52                       push edx

* Reference To: USER32.LoadStringA, Ord:004Bh
|
:0041270F 2EFF157CF74B00           Call dword ptr cs:[004BF77C]
:00412716 6A21                     push 00000021

* Possible StringData Ref from Data Obj ->"Save As"
|
:00412718 68181A4C00               push 004C1A18
:0041271D 8D442408                 lea eax, dword ptr [esp+08]
:00412721 50                       push eax
:00412722 57                       push edi
 

Donc en 4126D6 il saute vers le nag le fichier existe voulez vous l’écraser. J’ai dans un premier temps penser à détourner ce saut comme tout à l’heure vers une partie de la section .LuTiN et faire afficher le nag. Mais en y regardant de plus près, c’est inutile. Et oui si le saut ne s’effectue pas on arrive en 4126F2 à un appel de fonction, or cet fonction c’est le save as. Donc si le saut ne s’effectue pas en 4126D6 le prog va vers enregistrez sous or on a désactivé cette fonction et notre nag apparait J . Il suffit donc de virer ce saut avec un éditeur hexa.

Bon maintenant on va rajouter dans le menu about, un item register. Pour cela on prend Borland Resource Workshop et on édite les menus et on rajoute l’item register dans about . Je lui ai donné l’id 194. Bon en fait on aurait du faire cela au début parce que quand on fait cela il détruit ce que l’on a mis dans notre section .LuTiN. Il y a plus qu’à tout recommencer.

Une fois qu’on à tout refait, on lance le prog et on vérifie que l’item est dans le menu about. Maintenant on va afficher une MessageBox quand on cliquera sur register. Pour ce faire il faut trouver l’endroit où le prog traite le fait qu’on est appuyé sur register. Pour ce faire j’ai recherché 00000111 dans W32dasm (Pour comprendre à quoi correspond ce 00000111 il faut lire le tut de christal et de +Spath sur les menus). J’ai d’abord mis des points d’arrêts sur chaque comparaison avec 00000111 et j’ai cliqué sur register mais aucun n’a marché. J’en est mis ensuite sur les autres références à 00000111 (11 en tout) et un seul à marché en cliquant sur register, celui en 40DE71. On obtient cela :
 

:0040DE6E 40             inc eax
:0040DE6F EBCB           jmp 0040DE3C

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040DE3E(C)
|
:0040DE71 8B0C24         mov ecx, dword ptr [esp]
:0040DE74 BB11010000     mov ebx, 00000111 ßon arrive là
:0040DE79 55             push ebp
:0040DE7A 8B4605         mov eax, dword ptr [esi+05]
:0040DE7D 89FA           mov edx, edi
:0040DE7F C1F818         sar eax, 18
:0040DE82 E8DDFEFFFF     call 0040DD64

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040DE6C(U)
|
:0040DE87 83C408         add esp, 00000008
:0040DE8A 5D             pop ebp
:0040DE8B 5F             pop edi
:0040DE8C 5E             pop esi
:0040DE8D C20400         ret 0004

Donc on va détourner le prog en 40DE74 vers la section .LuTiN, à la suite de ce que l’on a écrit. Mais là il faut encore vérifier si c’est bien avec register, et oui A propos fait aussi breaker softice. Donc pour cela il faut vérifier que l’id de register est bien dans ecx. L’id est 194 ce qui correspond à C2h. Voilà on peut détourner le prog :

:0040DE71 8B0C24         mov ecx, dword ptr [esp]
:0040DE74 E9D6291000     jmp 0051084F ßon détourne le prog
:0040DE79 55             push ebp
:0040DE7A 8B4605         mov eax, dword ptr [esi+05]
:0040DE7D 89FA           mov edx, edi

Et en 51084F (suite des autres nag que l’on a fait dans .LuTiN) on met l’appel du nag :

51084F BB11010000         mov ebx, 00000111 ß on restaure ce qu’on a détruit
510854 81F9C2000000     cmp ecx, 000000C2 ß register ?
51085A 7515                     jnz 00510871 ß Non, on saute
51085C 60                         pushad
51085D 6A00                     push 00 ß oui on appel le nag
51085F 6880075100          push 00510780
510864 688B075100          push 0051078B
510869 6A00                      push 00
51086B E8BE38A4BF       call USER32 !MessageBoxA
510870 61                          popad
510871 E903D6EFFF        jmp 0040DE79 ß et on retourne dans prog

Voilà . J’ai fait le saut à la fin en 0040DE79 pour éviter d’avoir des erreurs dans le prog. Bon là on a le nag, mais c’est pas les bon messages. On peut les mettre juste après :

Donc le titre de la MessageBox est en 510876 et le texte en 510882. On fait les modif :
 

51084F BB11010000         mov ebx, 00000111 ß on restaure ce qu’on a détruit
510854 81F9C2000000     cmp ecx, 000000C2 ß register ?
51085A 7515                     jnz 00510871 ß Non, on saute
51085C 60                         pushad
51085D 6A00                     push 00 ß oui on appel le nag
51085F 6876085100         push 00510876
510864 6882085100         push 00510882
510869 6A00                     push 00
51086B E8BE38A4BF      call USER32 !MessageBoxA
510870 61                         popad
510871 E903D6EFFF       jmp 0040DE79 ß et on retourne dans prog

On fait les modifs avec un éditeur hexa. On lance le prog, on teste notre item register : ça marche impec. J .

Voilà. Maintenant je m’attaque à la dernière protection que je veux mettre : un anti-softice. Bon là je met juste un meltice, même pas un pour NT. Pour ce faire on met \\.\SICE à la suite de notre section :

Bon là pour appeler la routine on va redétourner le prog en 00478969 où l’on arrivait vers le nag de départ, mais ici on va tomber sur l’anti-si en 51089A :

:00478961 2EFF15D0F84B00     Call dword ptr cs:[004BF8D0]
:00478968 50                 push eax
:00478969 E92C7F0900         jmp 0051089A ßsaut vers anti SI
:0047896E E850F8FBFF         call 004381C3
:00478973 89EC               mov esp, ebp
:00478975 5D                 pop ebp
:00478976 5A                 pop edx
:00478977 59                 pop ecx
:00478978 5B                 pop ebx
:00478979 C3                 ret

Bon maintenant on peut écrire la routine de détection :

51089A 90                             nop            ß sinon le prog aime pas
51089B 50                             push eax                ß on sauve les registres
51089C 52                             push edx
51089D 51                             push ecx
51089E 53                             push ebx
51089F B891085100             mov eax, 00510891                ß \\.\SICE
5108A4 50                             push eax
5108A5 E83572A6BF           call KERNEL !32CreateFileA            ß debuger ?
5108AA 3DFFFFFFFF         cmp eax, FFFFFFFF                    ß eax et –1 égal ?
5108AF 7418                         jz 005108C9                        ß saute si pas softice
5108B1 6A00                         push 00                        ß sinon message softice trouvé
5108B3 68EB085100             push 005108EB
5108B8 68D8085100             push 005108D8
5108BD 6A00                         push 00
5108BF E86A38A4BF           call USER32 !MessageBoxA        ß message
5108C4 E801CCA7BF          call KERNEL32 !ExitProcess            ß et on quite le prog
5108C9 BC10FD6500           mov esp, 0065FD10         ß sinon on ce replace
5108CE 5B                             pop ebx            ß au bon endroit sur
5108CF 5C                             pop ecx         ß la pile et on restaure
5108D0 5A                             pop edx         ß les registres
5108D1 58                              pop eax
5108D2 E924FFFFFF            jmp 005107FB            ß et on va vers nag début

Pour mieux comprendre le pourquoi du comment de cette routine il faut lire la doc fournit avec frogice (merci au meilleur cracker français J ). Voilà en gros on test la présence de softice, s’il y est on le dit et on quitte le prog, sinon on continue le prog.

On fait les modifs avec un éditeur hexa, on lance le prog et pof softice est détecté et on quitte le prog. On relance mais avec FPloader en mémoire , on contourne la protection et le prog marche impec. J .

Voilà j’ai fini avec la protection du prog. A si j’ai aussi rajouté une petite compression (Aspack), histoire de dire.
 

Voilà c’est fini pour mon travail sur le défi proposé par la main rouge. Ce défi m’aura permis de découvrir pas mal de truc. J’espère que j’ai été assez clair dans la rédaction, sinon un petit mail J (city_of_bitch@caramail.com).

Amicalement,

LuTiN NoIR

PS : Merci tout particulièrement à Christal (tut sur menu), Morgate (tut sur messagebox) et TeeJi (cours sur reverse engineering).