Avertissement: Cette page n'est pas une page officielle de "Fravia's Reverser's page", mais en constitue un hommage !

Sharepad
Transformation du Notepad de Windows en Shareware

Avancé
Novembre 2002
par Anubis
Un hommage à "Fravia's Reverser's page of reverse engineering"
fra_00xx
021122
Anubis
0001
AD
PC
Cher Fravia,
Your wonderful work has influenced an army of Reversers all around the world. None of us has not spend hours and nights reading all the essays published in your fortress to enter this magic world of the Reverse Engineering. The reverse engineering has now become the Reverse Engineering, an Art! I would like to personally thank you as well as all the "first hour" Reversers (too much of them to give names, I would miss some ;) who have open and shown the way to light.
We miss you Fravia.
As I have seen by great Reversers, there is sometimes a moment where one thinks "I have no longer fun or energy for it..." and so did I think and do too. But I am always coming back, and it would be really great
if by a cold winter day the Legend were back ;)
There is a crack, a crack in everything That's how the light gets in
Niveau
( )Débutant (x)Intermédiaire (x)Avancé ( )Expert

Un "petit" exemple de Reverse Engineering: Transformer le Notepad en shareware.

Je dédie cet essai aux deux Reversers qui m'ont le plus influencé (sans ordre particulier): LaZaRuS (pour son essai sur LaZ-Calc ou "LaZ-CalC, Adding functionality to the Windows Calculator") et NeuRaL_NoiSE (pour son essai nnhnpad.htm ou "Reversing, functions addition, modifications in the existing code and classic cracking of a typical M$-target: notepad.exe").
Il y a longtemps, je ne savais même pas encore ce que pouvait être le cracking que je suis tombé sur leurs essais. Je ne trouve pas les mots pour décrire les impressions qui m'ont traversé à ce moment là. Combien de portes se sont ouvertes en moi! Pouvoir transformer, créer suivant notre imagination là où il n'y avait rien avant, là où on ne (théoriquement) pouvait plus créer! C'était presque un miracle... Mais c'était il y a longtemps. Bref, leur travail est tout simplement merveilleux! Et afin de contribuer à cette connaissance et pour les en remercier, j'ai écris ce petit papier ^_~

Encore une chose! Je n'ai rien à voir avec Anub|s du nnhnpad.htm ou un autre Anubis qui pourrait exister (je n'en ai jamais rencontré, mais ça pourrait être un pseudo répandu!). Je fais partie de la Shmeitcorp (voir à la fin du tutorial pour plus d'informations).


Sharepad
Transformation du Notepad de Windows en Shareware
Ecris par Anubis
anubis@iname.com


Introduction
J'ai entendu parlé dans le passé de ce défi qui consistait à transformer le notepad de windows en shareware. Je n'ai aucune idée si cela a déjà été fait, et comme j'ai toujours été enivré par le Reverse Engineering, j'ai toujours voulu écrire un essai sur ce sujet. J'espère également que vous aurez autant de plaisir à le lire que j'en ai eu à l'écrire :o) Cet essai est rédigé en 2 parties. La première partie traite d'une transformation qui n'utilise pas de GUI (pour l'interface), uniquement du codage pur sous un éditeur hexa. La deuxième partie utilisera le GUI et présentera la typique boite d'enregistrement avec nom et calcul du sérial.

Boite à outils
Pour la première partie:

Hex-Workshop (pour transformer le fichier)
HIEW (pour ne pas être emmer.. par les calculs des sauts. Encore que... :)
Une référence Win-API (Win32.hlp pour les apis)
W32Dasm (pour vérifier les imported functions, c'est plus facile!)
Un éditeur de ressources (pour localiser quelques chaînes et IDs)

Pour la deuxième partie:

En fait, la même chose qu'en haut mais utilisé plus en profondeur.
On a aussi besoin de Softice (quand on construit la boite d'enregistrement)
BRW - Borland Ressource Workshop (pour construire la boite d'enregistrement et ajouter les nouveaux menus).

Nous n'en aurons pas besoin, mais je me permets de joindre à ce tutorial ceux de LaZaRuS et NeuRaL_NoiSE que j'ai mentionné plus haut à titre d'information (ici et ).


URL/FTP de la cible
Ceci n'est pas un tutorial de cracking (en fait c'est justement l'opposé ^_^). J'ai utilisé le notepad de windows qui est fourni avec Win 98. Vous trouverez la version modifié sharepad1 de la partie 1 ici et celle modifiée de la partie 2 ici.

Histoire du programme
Rien de spécial à dire ici.

Essai

Avant de commencer: remarques générales sur le Notepad...

Il est conseillé d'avoir des notions de structure de fichiers PE pour aborder ce tutorial. Certaines notions (PEP, IAT, RVA,...) ne seront pas expliquées lors de leur emploi. De même il faut savoir manipuler les APIs (ordre de passage des paramètres,...) et calculer des sauts (jne,jmp,...). Enfin, il faut avoir déjà utilisé un éditeur de ressources.

Un petit coup de Procdump nous montre que le RawOffset et le VirtualOffset sont pareils. Ceci simplifie grandement les calculs car le RVA est égal à l'offset de l'instruction sous un éditeur hexa (à l'ImageBase près qui est de 400000).

Le PEP est en 10CC.

D'une manière générale, quand on crack, on utilise souvent le bouton StringDataRefs sous Wdasm. Quand on reverse, on utilisera plutôt le bouton Imported Functions pour jongler avec les APIs ;o).

Compatibilité
Le sharepad1 a été testé avec succès sous win 9x, win 2000 et win XP. Il ne marche pas sous win 3.1 et win NT.
Le sharepad2 a été testé pareillement et affiche les même résultats à l'exception de win 2000 et win XP qui font planter le sharepad au démarrage lors de la routine qui utilise l'API RegQueryValueExA quand les clés Name et Code ne sont pas encore dans le registre. En effet, je n'utilise pas directement cette API, mais je passe par un call que je branche directement dans le programme et qui contient du code compilé (optimisé pour win 9x) qui lui utilise cette API. Cette partie de code-là ne semble pas fonctionner sous win 2000/XP. Pour remédier au problème, il suffit d'initialiser les clés Name et Code dans la base de registre. Pour cela, utiliser le fichier init s2 win2k-xp.reg fournit avec ce tutorial. De même, la REGBOX n'est pas affichée complètement, mais fonctionne toutefois. N'utilisant ni ne programmant sous win 2000 et XP, je n'ai pas approfondi la question.
Le keygen fourni pour le sharepad2 est un programme DOS.

La compatibilité avec win ME n'a pas été testé.


Partie I : version sans GUI



But:

On veut créer un shareware du notepad avec les restrictions suivantes:
- affichage d'une msgbox au lancement du prog
- affichage d'une msgbox à la sortie du prog
- affichage du mot "SHAREWARE" dans la barre de titre du prog
- menus "ENREGISTRER" et "ENREGISTRER SOUS..." désactivés

Ce shareware doit devenir une version complète sans les restrictions ci-dessus lorsqu'on aura fourni la clé d'activation. Cette clé d'activation se présente sous la simple présence du fichier "sharepad.key" dans le répertoire C:/. Sa présence ou son absence fera que le notepad sera en version complète ou en shareware.

Affichage du mot "SHAREWARE" dans la barre de titre du prog
------------------------------------------------------------------

On fait simplement une recherche sur la chaîne "Bloc-Notes" sous un éditeur hexa, et on modifie cette chaîne d'une lettre jusqu'à tomber sur la bonne chaîne (on enlève évidement les modifications si on n'est pas sur la bonne chaîne!). Alors, on peut changer "Bloc-Notes" en "SHAREWARE ". L'espace à la fin cache en fait le "s". Pour repasser en "Bloc-Notes" dans la version enregistrée, on verra cela plus tard.

Désactivation des menus "ENREGISTRER" et "ENREGISTRER SOUS..."
----------------------------------------------------------------------------

On peut évidement faire cela très facilement avec un éditeur de ressources. Mais comme on doit inverser ce changement lors de la version enregistrée du sharepad, il faut savoir comment on le fait. Pour cela, on fait une copie du fichier du notepad (que j'appelle 1.exe). On fait une deuxième copie (2.exe) que l'on va modifier sous l'éditeur de ressources. Sous cet éditeur, on 1/ désactive les menus "ENREGISTRER" et "ENREGISTRER SOUS..." et 2/ on les grise.

Ensuite pour connaître la différence entre les deux fichiers, on tape sous DOS la commande suivante...:
fc 1.exe 2.exe > ici.txt
...et on a le résultat dans le fichier ici.txt, automatiquement créé:

Comparaison des fichiers 1.exe et 2.exe
0000A000: 00 03
0000A01E: 00 03
On voit donc que pour griser et désactiver un menu, on doit passer 00 en 03 à l'endroit qui convient (résultat à regarder en parallèle sous l'éditeur hexa).


Avant d'aborder la partie coding, voici la logique de fonctionnement du sharepad:



Test de la présence de la clé "sharepad.key" : TESTKEY@PEP
-----------------------------------------------------------------

Au commencement, on doit d'abord vérifier la présence de la clé d'enregistrement pour déterminer l'attitude du sharepad (i.e. version shareware ou version enregistrée). Pour cela, on détourne le programme au PEP par un jump qui pointe tout à la fin du notepad dans le padding après la section .rsrc. Pourquoi à cet endroit-là? Car c'est très souvent l'endroit dans un programme où il y a le plus de place dans le padding. Et si cette place s'avérait trop juste, il faudrait alors créer une nouvelle section dans laquelle on pourrait travailler tranquillement.

//******************** Program Entry Point ********      
:004010CC 55                      push ebp
:004010CD 8BEC                    mov ebp, esp
:004010CF 83EC44                  sub esp, 00000044
:004010D2 56                      push esi
modifié en :
//******************** Program Entry Point ********
:004010CC E97FC90000              jmp 0040DA50
:004010D1 90                      nop
:004010D2 56                      push esi
A la fin du programme, on copie les instructions que l'on a écrasé en mettant le jump au PEP, puis on code directement l'API pour tester la présence du fichier "sharepad.key". L'API choisie est "_lopen". Elle se trouve dans la DLL kernel32.dll et ne possède que deux paramètres à passer. Bien que maintenant obsolète, elle rend encore de fiers services et est très courte à coder. Ceci simplifie beaucoup la tache comparé à "CreateFileA" par exemple (regardez cette API dans le win32hlp).

Voici l'aperçu de l'API _lopen :
   HFILE _lopen(
    LPCSTR lpPathName,	// pointer to name of file to open  
    int iReadWrite 	// file access mode 
   );
avec pour file access mode :

Value	        Meaning					  Code
OF_READ	        Opens the file for reading only		  01
OF_READWRITE	Opens the file for reading and writing	  02
OF_WRITE	Opens the file for writing only		  03
Ici, on va choisir le PathName "C:\sharepad.key" car tout le monde a ce répertoire sur son disque dur, et on va prendre un file access mode en READWRITE, soit une valeur de 2. On peut bien sûr mettre le fichier sharepad.key dans le même répertoire que l'exe. A ce moment là, il faudra changer la chaîne "C:\sharepad.key" ci-dessous en ".\sharepad.key". Je n'ai pas mis la clé dans le même répertoire que l'exe, juste pour montrer que l'on pouvait mettre la clé n'importe où et notamment dans un répertoire système.

La chaîne "C:\sharepad.key" est écrite sans les guillemets en D9F0 directement dans un éditeur hexa. Ainsi, l'API se présente comme suit :
0000D9F0 433A 5C73 6861 7265 7061 642E 6B65 7900 C:\sharepad.key.
0000DA00 0000 0000 0000 0000 0000 0000 0000 0000 ................

.0040DA56: 6A02                         push        002		<- 1er paramètre de l'API
.0040DA58: 68F0D94000                   push        00040D9F0	<- 2eme paramètre de l'API
.0040DA5D: FF1560634000                 call        _lopen	<- Appel de l'API
Comment faire pour trouver le code hexa d'une API? Comment appeler une API? La méthode que j'utilise est de faire une recherche de l'API sous Wdasm dans les Imported Functions. Si vous double-cliquez sur le nom de l'API dont vous avez besoin, vous tomberez toujours sur le même code hexa (sauf pour la dernière occurrence, tout en bas du listing, mais c'est une autre histoire). Donc si on double-clique sur _lopen (et pas lopen qui n'y est pas), on tombera toujours sur le même code hexa (le FF1560634000). Bon en fait, il n'y a qu'une seule occurrence de _lopen, mais ça ne change rien à ce que je viens de dire. Cette valeur hexadécimale contient un paramètre dword qui est propre à l'API et qui correspond à son adresse. Ainsi, à n'importe quel endroit du programme on pourra appeler cette API en faisant "call < dword >". C'est à dire en utilisant la séquence FF1560634000 pour l'API _lopen.

Une fois l'API codée, on va utiliser une deuxième API pour connaître la présence ou non du fichier "sharepad.key" (i.e. la réponse de l'API _lopen). Cette seconde API est GetLastError. Elle n'a aucun paramètre à passer, et retourne une valeur spécifique en eax suivant la présence ou non du fichier "sharepad.key" passé en paramètre dans _lopen.

Voici l'aperçu de l'API GetLastError :
   DWORD GetLastError(VOID)
Ensuite, on teste la valeur de eax (test eax, eax), puis on saute sur la MSGBOX1 (jne MSGBOX1) si eax n'est pas nulle, ou bien on saute sur la partie PATCH (jmp PATCH) pour repasser le sharepad en notepad si eax est nulle. On obtient au final pour la partie TESTKEY@PEP ceci:
.0040DA50: 55                           push        ebp			|Instructions écrasées 
.0040DA51: 8BEC                         mov         ebp,esp		|par le jump au PEP
.0040DA53: 83EC44                       sub         esp,044 		|
.0040DA56: 6A02                         push        002			<- 1er paramètre de l'API
.0040DA58: 68F0D94000                   push        00040D9F0   	<- 2eme paramètre de l'API
.0040DA5D: FF1560634000                 call        _lopen 		<- Appel de l'API
.0040DA63: FF15C8634000                 call        GetLastError 	<- Traitement du message renvoyé
.0040DA69: 85C0                         test        eax,eax		<- "sharepad.key" présent?
.0040DA6B: 7543                         jne        .00040DAB0   	<- non, on va à MSGBOX1@TEST
.0040DA6D: E9BE000000                   jmp        .00040DB30		<- oui, on va à PATCH@TEST
Comment sélectionner une API convenable pour ce que l'on veut faire? C'est très simple, il y a deux critères à respecter. Le premier est que l'API puisse nous dire si le fichier "sharepad.key" se trouve bien en C:\ (j'ai choisi ce répertoire par défaut car tout le monde a ce répertoire sur son disque dur!). Donc on aura intérêt à choisir des APIs du style CreateFileA, _lopen, FindFirstFile, GetFileAttribute... c'est à dire en rapport avec des fichiers. Le deuxième critère est que l'API choisie se trouve bien dans la IAT du notepad, sans quoi on doit coder son appel et cela rend la tache plus complexe (Note: on fera cela dans la deuxième partie de ce tutorial, mais pas ici, car on veut du codage simple, rapide et efficace). Pour savoir cela, il suffit de regarder dans les Imported Functions sous Wdasm et de choisir les APIs qui vont bien.

Finalement, on obtient cela sous un éditeur hexa:
0000D9F0 433A 5C73 6861 7265 7061 642E 6B65 7900 C:\sharepad.key.
0000DA00 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA10 0000 0000 0000 0000 0000 0000 0000 0000 ................  
0000DA20 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA30 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA40 5445 5354 4B45 5940 5045 5000 0000 0000 TESTKEY@PEP.....  <-- Titre de la partie. N'intervient pas dans le code.
0000DA50 558B EC83 EC44 6A02 68F0 D940 00FF 1560 U....Dj.h..@...`
0000DA60 6340 00FF 15C8 6340 0085 C075 43E9 BE00 c@....c@...uC...
0000DA70 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA80 0000 0000 0000 0000 0000 0000 0000 0000 ................
Note : On va rentrer plusieurs chaînes dans l'éditeur hexa (pour les MSGBOXs). Il est fortement conseillé de laisser une ligne vide entre chaque chaîne de caractères pour des raisons de lisibilité et de buffer dans la gestion des APIs (bien que ce ne soit pas une obligation, seul le byte 00 en fin de chaîne est important pour la terminer).

Affichage d'une msgbox au lancement du prog : MSGBOX1@TEST
---------------------------------------------------------------------

En fait, cette messagebox vient après TESTKEY@PEP, mais quand on lance le programme, on ne voit que la messagebox MSGBOX1 qui apparaît. Cette messagebox a pour titre "SHAREWARE!!!" et message "Veuillez vous enregistrez.". On la code de la manière suivante:
0000D990 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9A0 5348 4152 4557 4152 4521 2121 0000 0000 SHAREWARE!!!....  <-- Titre
0000D9B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9C0 5665 7569 6C6C 657A 2076 6F75 7320 656E Veuillez vous en  <-- Message
0000D9D0 7265 6769 7374 7265 722E 0000 0000 0000 registrer.......
0000D9E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
[...]
0000DA90 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DAA0 4D53 4742 4F58 3140 5445 5354 0000 0000 MSGBOX1@TEST....  <-- Titre de la partie. N'intervient pas dans le code. 
0000DAB0 6A00 68A0 D940 0068 C0D9 4000 6A00 FF15 j.h..@.h..@.j...
0000DAC0 A864 4000 E909 36FF FF00 0000 0000 0000 .d@...6.........
0000DAD0 0000 0000 0000 0000 0000 0000 0000 0000 ................
Ce qui donne en asm:
.0040DAB0: 6A00                         push        000
.0040DAB2: 68A0D94000                   push        00040D9A0     <-- Titre
.0040DAB7: 68C0D94000                   push        00040D9C0     <-- Message
.0040DABC: 6A00                         push        000
.0040DABE: FF15A8644000                 call        MessageBoxA 
.0040DAC4: E90936FFFF                   jmp        .0004010D2     <-- Retour au PEP après le(s) 90. 


Transformation en version enregistrée : PATCH@TEST (1ere partie)
----------------------------------------------------------------------

Pour l'instant on va seulement se contenter d'afficher une messagebox dont le titre et le message sont les même (par exemple "SHAREWARE!!!" en D9A0). On rebranche ensuite cette messagebox au même endroit que là où se branche MSGBOX1@TEST, à savoir juste après le(s) 90 au PEP.

0000DB20 5041 5443 4840 5445 5354 0000 0000 0000 PATCH@TEST......
0000DB30 6A00 68A0 D940 0068 A0D9 4000 6A00 FF15 j.h..@.h..@.j...
0000DB40 A864 4000 E989 35FF FF00 0000 0000 0000 .d@...5.........
0000DB50 0000 0000 0000 0000 0000 0000 0000 0000 ................
Soit en asm:
.0040DB30: 6A00                         push        000
.0040DB32: 68A0D94000                   push        00040D9A0     <-- Titre
.0040DB37: 68A0D94000                   push        00040D9A0     <-- Message (=Titre)
.0040DB3C: 6A00                         push        000
.0040DB3E: FF15A8644000                 call        MessageBoxA 
.0040DB44: E98935FFFF                   jmp        .0004010D2     <-- Retour au PEP après le(s) 90.
Quel est l'intérêt? Et bien dès maintenant, on peut déjà tester notre système de shareware!!!

Sans le fichier "sharepad.key" dans C:\, on a:

	
Avec le fichier "sharepad.key" dans C:\, on a:

	


Cela marche parfaitement ^_^. Et bien évidement, si on efface le fichier "sharepad.key", on repasse automatiquement en version shareware. Le changement est réversible à volonté. Quant au fichier clé "sharepad.key", il n'y a rien dedans. Son contenu n'est même pas testé. C'est sa PRESENCE dans le répertoire C:\ qui fait que l'utilisateur s'est enregistré ou non:
- Il sait qu'il faut un fichier clé pour être enregistré
- Il connaît le nom de ce fichier
- Il sait OU mettre se fichier
D'ailleurs, le but de ce tutorial est d'introduire un mécanisme de shareware sur un freeware, et non pas de mettre au point une sécurité du shareware. Au niveau sécurité, ce mécanisme est nul et je rappelle que ce n'est pas le but de ce tut (Je vais d'ailleurs cracker cette sécurité en fin de partie I pour le montrer).

Affichage d'une msgbox à la sortie du prog : MSGBOX2
---------------------------------------------------------

Cette messagebox se branche en sortie de programme quand on clique sur "Quitter" ou sur la croix en haut à droite de la fenêtre. Ces deux commandes appellent l'API ExitProcess. On regarde sous Wdasm dans les ImportedFunctions, et on ne trouve (bien sur) qu'une seule occurrence dans le listing...:

 * Reference To : KERNEL32.ExitProcess, Ord: 007Fh
 |
 :00401143 FF1598634000            Call dword ptr [00406398] 
 :00401149 8BC6                    mov eax, esi
 :0040114B 5E                      pop esi
 :0040114C 8BE5                    mov esp, ebp
 :0040114E 5D                      pop ebp
 :0040114F C3                      ret
...que l'on transforme en:
 :00401143 E9A8C90000              jmp 0040DAF0
 :00401148 90                      nop
 :00401149 8BC6                    mov eax, esi
 :0040114B 5E                      pop esi
 :0040114C 8BE5                    mov esp, ebp
 :0040114E 5D                      pop ebp
 :0040114F C3                      ret
Et en DAF0, on code la MSGBOX2:
0000D940 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D950 4E27 6F75 626C 6965 7A20 7061 7320 6465 N'oubliez pas de  <-- Message
0000D960 2076 6F75 7320 656E 7265 6769 7374 7265  vous enregistre
0000D970 722E 2043 6F6E 7375 6C74 657A 206C 6520 r. Consultez le 
0000D980 6669 6368 6965 7220 7265 672E 7478 742E fichier reg.txt.
0000D990 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9A0 5348 4152 4557 4152 4521 2121 0000 0000 SHAREWARE!!!....  <-- Titre 
0000D9B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
[...]
0000DAD0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DAE0 4D53 4742 4F58 3240 4558 4954 0000 0000 MSGBOX2@EXIT....  <-- Titre de la partie. N'intervient pas dans le code. 
0000DAF0 6A00 68A0 D940 0068 50D9 4000 6A00 FF15 j.h..@.hP.@.j...
0000DB00 A864 4000 FF15 9863 4000 8BC6 E938 36FF .d@....c@....86.
0000DB10 FF00 0000 0000 0000 0000 0000 0000 0000 ................
Soit en asm:
.0040DAF0: 6A00                         push        000			|Paramètres de la messagebox
.0040DAF2: 68A0D94000                   push        00040D9A0		|
.0040DAF7: 6850D94000                   push        00040D950  		|
.0040DAFC: 6A00                         push        000			|
.0040DAFE: FF15A8644000                 call        MessageBoxA 	<-- API
.0040DB04: FF1598634000                 call        ExitProcess 	|Instructions écrasées par le jump au 
.0040DB0A: 8BC6                         mov         eax,esi		|ExitProcess original
.0040DB0C: E93836FFFF                   jmp        .000401149   	<-- Retour au EXITPROC après le(s) 90.


Résumé jusqu'ici
-----------------

On a implémenté les fonctions suivantes:

- affichage d'une msgbox au lancement du prog
- affichage d'une msgbox à la sortie du prog
- affichage du mot "SHAREWARE" dans la barre de titre du prog
- menus "ENREGISTRER" et "ENREGISTRER SOUS..." désactivés

Et le sharepad réagit à la présence d'un fichier clé de désactivation dans le répertoire C:\. Le code rajouté ou modifié au fichier d'origine notepad.exe est le suivant:

Au PEP:
000010C0 2532 2E32 6400 0000 0D0A 0000 E97F C900 %2.2d...........
000010D0 0090 56FF 15E0 6340 008B F08A 003C 2275 ..V...c@.....<"u

[...]
A l'EXITPROCESS:
00001140 508B F0E9 A8C9 0000 908B C65E 8BE5 5DC3 P..........^..].

[...]
Après la fin de la section .reloc:
0000D940 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D950 4E27 6F75 626C 6965 7A20 7061 7320 6465 N'oubliez pas de
0000D960 2076 6F75 7320 656E 7265 6769 7374 7265  vous enregistre
0000D970 722E 2043 6F6E 7375 6C74 657A 206C 6520 r. Consultez le 
0000D980 6669 6368 6965 7220 7265 672E 7478 742E fichier reg.txt.
0000D990 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9A0 5348 4152 4557 4152 4521 2121 0000 0000 SHAREWARE!!!....
0000D9B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9C0 5665 7569 6C6C 657A 2076 6F75 7320 656E Veuillez vous en
0000D9D0 7265 6769 7374 7265 722E 0000 0000 0000 registrer.......
0000D9E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D9F0 433A 5C73 6861 7265 7061 642E 6B65 7900 C:\sharepad.key.
0000DA00 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA10 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA20 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA30 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA40 5445 5354 4B45 5940 5045 5000 0000 0000 TESTKEY@PEP.....
0000DA50 558B EC83 EC44 6A02 9090 9068 F0D9 4000 U....Dj....h..@.
0000DA60 FF15 6063 4000 FF15 C863 4000 85C0 0F85 ..`c@....c@.....
0000DA70 3C00 0000 E9B7 0000 0000 0000 0000 0000 <...............
0000DA80 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DA90 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DAA0 4D53 4742 4F58 3140 5445 5354 0000 0000 MSGBOX1@TEST....
0000DAB0 6A00 68A0 D940 0068 C0D9 4000 6A00 FF15 j.h..@.h..@.j...
0000DAC0 A864 4000 E909 36FF FF00 0000 0000 0000 .d@...6.........
0000DAD0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DAE0 4D53 4742 4F58 3240 4558 4954 0000 0000 MSGBOX2@EXIT....
0000DAF0 6A00 68A0 D940 0068 50D9 4000 6A00 FF15 j.h..@.hP.@.j...
0000DB00 A864 4000 FF15 9863 4000 8BC6 E938 36FF .d@....c@....86.
0000DB10 FF00 0000 0000 0000 0000 0000 0000 0000 ................
0000DB20 5041 5443 4840 5445 5354 0000 0000 0000 PATCH@TEST......
0000DB30 6A00 68A0 D940 0068 A0D9 4000 6A00 FF15 j.h..@.h..@.j...
0000DB40 A864 4000 E989 35FF FF00 0000 0000 0000 .d@...5.........
0000DB50 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000DB60 0000 0000 0000 0000 0000 0000 0000 0000 ................
Maintenant, on va mettre au point la neutralisation des éléments shareware lorsque le fichier "sharepad.key" est dans C:\.

Transformation en version enregistrée : PATCH@TEST (2eme partie)
-----------------------------------------------------------------------

Dans cette partie, il faut trouver un moyen pour que:
- les 2 msgboxes n'apparaissent plus
- les 2 menus soient activés
- "SHAREWARE" soit remplacé par le mot "Bloc-Notes" d'origine

Regardons tout cela en détail...

* Désactivation des msgboxes MSGBOX1 et MSGBOX2:
Rien de plus facile. MSGBOX1 n'apparaît absolument pas car on passe par PATCH@TEST et que l'on retourne directement après le PEP. Quant à MSGBOX2, un simple patch de l'instruction "call messageboxA" va la désamorcer:

 FF15A8644000    call  MessageBoxA 
...devient...:
 9015A8644000    call  MessageBoxA 
...et plus de msgbox! En asm, cela s'écrit:
.0040DB30: B890000000                   mov         eax,000000090   <-- met 00000090 dans eax
.0040DB35: A2FEDA4000                   mov         [00040DAFE],al  <-- change le byte à l'adresse DAFE en 90
* Activation des 2 menus:
On pourrait utiliser des APIS pour réactiver les modifications du départ faites en dur dans le fichier. En fait, on va utiliser le truc de patcher le programme en mémoire seulement. Le fichier restera toujours en shareware sur le disque dur, mais le patch se fait en mémoire. Pour cela, il nous faut comme tout patch:

- l'adresse du byte à patcher
- la valeur à patcher

Et pour ça on reprend les informations de la commande fc utilisée plus haut...:
Comparaison des fichiers 1.exe et 2.exe
0000A000: 00 03
0000A01E: 00 03
... mais en faisant nous l'inverse, on met 00 à la place de 03 (et on efface ici le code de la msgbox qui affichait le même titre et message):
.0040DB3A: B800000000                   mov         eax,000000000   <-- met 00000000 dans eax
.0040DB3F: A200A04000                   mov         [00040A000],al  <-- change le byte à l'adresse A000 en 00
.0040DB44: A21EA04000                   mov         [00040A01E],al  <-- change le byte à l'adresse A01E en 00
* Remplacement du mot "SHAREWARE":
Même technique que les deux cas précédents. Bloc-notes en 32-bits s'écrit: 42006C006F0063002D006E006F00740065007300. On va remplacer "SHAREWARE" DWORD par DWORD. Cela donne...:
.0040DB49: B842006C00                   mov         eax,0006C0042 ;" l B"
.0040DB4E: A35CAB4000                   mov         [00040AB5C],eax
.0040DB53: B86F006300                   mov         eax,00063006F ;" c o"
.0040DB58: A360AB4000                   mov         [00040AB60],eax
.0040DB5D: B82D006E00                   mov         eax,0006E002D ;" n -"
.0040DB62: A364AB4000                   mov         [00040AB64],eax
.0040DB67: B86F007400                   mov         eax,00074006F ;" t o"
.0040DB6C: A368AB4000                   mov         [00040AB68],eax
.0040DB71: B865007300                   mov         eax,000730065 ;" s e"
.0040DB76: A36CAB4000                   mov         [00040AB6C],eax
.0040DB7B: E95235FFFF                   jmp        .0004010D2   -------- (1)
...suivi du dernier jump qui se rebranche sur le PEP après le(s) 90. On obtient au final pour PATCH@TEST:
0000DB20 5041 5443 4840 5445 5354 0000 0000 0000 PATCH@TEST......
0000DB30 B890 0000 00A2 FEDA 4000 B800 0000 00A2 ........@.......
0000DB40 00A0 4000 A21E A040 00B8 4200 6C00 A35C ..@....@..B.l..\
0000DB50 AB40 00B8 6F00 6300 A360 AB40 00B8 2D00 .@..o.c..`.@..-.
0000DB60 6E00 A364 AB40 00B8 6F00 7400 A368 AB40 n..d.@..o.t..h.@
0000DB70 00B8 6500 7300 A36C AB40 00E9 5235 FFFF ..e.s..l.@..R5..
0000DB80 0000 0000 0000 0000 0000 0000 0000 0000 ................
Mais ce n'est pas tout!!!

Le sharepad va crasher si on le lance comme cela. N'oublions pas que l'on patche la MSGBOX2 qui se trouve dans la section .reloc, ainsi que les 2 menus et le mot "SHAREWARE" qui se trouvent eux dans la section .rsrc. Par conséquent, comme on va écrire en mémoire dans ces sections, il faut vérifier leurs caractéristiques pour que l'opération d'écriture puisse se faire sans problème. Un petit coup d'oeil dans Procdump nous donne les données suivantes originales :
Name        Virtual Size    Virtual Offset  Raw Size        Raw Offset      Characteristics
 .text       00003E9C        00001000        00004000        00001000        60000020
 .data       0000084C        00005000        00001000        00005000        C0000040
 .idata      00000DE8        00006000        00001000        00006000        40000040
 .rsrc       00006000        00007000        00006000        00007000        40000040
 .reloc      00000A9C        0000D000        00001000        0000D000        42000040
On voit que les sections .rsrc et .reloc sont en lecture seulement (0x40000000). On va les mettre en lecture + écriture :
 .rsrc       00006000        00007000        00006000        00007000        C0000040
 .reloc      00000A9C        0000D000        00001000        0000D000        C2000040
Voilà!!! Le notepad est maintenant un shareware et s'appelle un sharepad! La clé d'activation est le fichier "sharepad.key" qu'il faut mettre dans le répertoire C:\. On aura bien sûr reçu cette clé en consultant le fichier "reg.txt" fourni avec le sharepad et donnant toutes les modalités pour recevoir la clé d'activation (à savoir, envoyer des $$$$$$$ et des ££££££££ mais aussi des €€€€€€€€€€€).

Et maintenant pour le fun!

Crack du sharepad
--------------------

On a ici bien sûr le sharepad, mais on ne sait pas comment le rendre en version complète. Et on n'a pas la clé "sharepad.key". Comme je l'ai dis plu haut, la solidité de la sécurité du sharepad est NULLE. En regardant dans un éditeur hexa, le code se voit comme un nez en pleine figure. Pour désactiver le mécanisme du sharepad, il suffit simplement d'inverser le saut inconditionnel de la partie TESTKEY@PEP:
.0040DA5B: 68F0D94000                   push        00040D9F0   	
.0040DA60: FF1560634000                 call        _lopen 	
.0040DA66: FF15C8634000                 call        GetLastError 	
.0040DA6C: 85C0                         test        eax,eax			
.0040DA6E: 0F853C000000                 jne        .00040DAB0   	<- inversion ici en 0F843C000000
.0040DA74: E9B7000000                   jmp        .00040DB30   	
Un petit conseil, ne laissez pas la clé dans C:\, sinon vous vous retrouvez avec une version crackée qui est ... du shareware :o) ou alors, noppez carrément tout le saut avec 909090909090.






Partie II : version avec GUI



But:

Construire une boite d'enregistrement en GUI avec nom + sérial, et coder la routine de calcul du sérial. Les limitations de la version shareware seront celles de la partie I.

On va d'abord s'attacher à dessiner la boite d'enregistrement, puis on élaborera la structure du mécanisme du shareware, et on la codera (toujours dans le padding à la fin de la section .reloc).

Quelques conseils avant de commencer cette partie:

J'ai eu beaucoup de problèmes qui n'en étaient pas, par des réactions illogiques de la part des softs (SI, Hiew,...), ou bien de partie de code JUSTE mais qui ne marchait pas. Si vous voyez que vous vous cassez la tête sur un truc pendant un moment sans voir de solution, redémarrez l'ordi pour purger la RAM et les softs. Souvent SI, Hiew ou autres disjonctent et font n'importe quoi...

Par exemple, quand on pose un breakpoint sous SI, il faut savoir que le byte de l'adresse du bpx est remplacé par le byte "CC" qui correspond à "int 03". C'est comme ça que SI se rend compte des breaks et peut surgir. Bien sûr dans la fenêtre du code de SI, on verra les données normales. Mais en dansant entre SI, Wdasm et HIEW, j'ai souvent retrouvé ce "CC" à la place de mes instructions dans le notepad... La solution est de patcher la valeur d'origine sous un éditeur hexa, et ça repart! Conclusion: FAITES TOUJOURS UNE SAUVEGARDE DU FICHIER QUE VOUS ETES EN TRAIN DE MODIFIER.

Quant à HIEW, quand on écrit un saut en mode asm et qu'on valide par F9, il y a très souvent des "40" (cela provient de l'ImageBase qui fait 0x400000 et qui est rajoutée intempestivement) qui apparaissent et transforment un "je 00405656" en "je 00805656" quand on est en train de tracer sous SI. C'est très agréable :o/

Je commence ce tut en n'ayant AUCUNE connaissance pour l'utilisation (écriture/lecture) de la base de registre, et une faible connaissance de l'utilisation des APIs (celle de la partie I de ce tutorial). On se fera la main en cours de route! ;o)

Pour choisir les IDs, on peut en théorie prendre n'importe quel nombre du moment qu'il n'est pas déjà utilisé dans le programme. En pratique, lors de la comparaison des IDs dans le soft, certains sauts qui suivent sont "idiots" et font qu'il vaut mieux en pratique prendre des IDs plus grandes que les plus grandes IDs utilisées par le soft. Exemple ici avec le notepad:

On choisit une ID de 0x250 pour un nouveau menu. Malheureusement, on va sauter en 40128D (et 401294). Si on met notre branchement en 40129A, le code "marchera" (sera exempt de bug) mais du fait des saut avec "jl/jle", on n'atteindra jamais notre branchement (ce qui peut quand même être un bug :o/ !!!).
* Possible Ref to Menu: MenuID_0001, Item : "Couper Ctrl+X"
|
:00401288 3D00030000              cmp eax, 00000300
:0040128D 7C21                    jl 004012B0			; on saute ici

* Possible Ref to Menu: MenuID_0001, Item : "Copier Ctrl+C"
|
:0040128F 3D01030000              cmp eax, 00000301
:00401294 0F8E3E040000            jle 004016D8			; on saute ici

* Possible Ref to Menu: MenuID_0001, Item : "Coller Ctrl+V"
|
:0040129A 3D02030000              cmp eax, 00000302		; branchement pour notre menu
:0040129F 0F8456040000            je 004016FB                    
Donc on choisira une ID au dessus de 310. On prendra par exemple à partir de 350 (848 en décimal). En général, un rapide coup d'oeil sous un éditeur de ressources donne une idée d'où s'arrêtent les IDs.

Dernier conseil: ON MODIFIE TOUJOURS LES RESSOURCES EN PREMIER PUIS ON N'Y TOUCHE PLUS, ET ON RAJOUTE LE CODE ENSUITE!!! Si vous deviez remodifier les ressources (même infime!) après avoir mis du code hors sections, vous pouvez en général tout recoder à zéro (en particulier si vous avez codé dans la section ressources, car elles seront écrasées par les nouvelles lors de la recompilation... et votre code aussi par la même occasion). Pour éviter ce problème et pouvoir retoucher les ressource en cours de route, il faut créer une nouvelle section et coder dedans.

Dans cette deuxième partie du sharepad, je vais prendre les composants/IDs suivants:

Boite d'enregistrement : ID=1664 (tout lien avec une boisson... n'est que pure hasard ;o) Je préfère la Mort-Subite :oD )
Edittext (nom) : ID=900
Edittext (code) : ID=901
Text (nom) : ID=902
Text (code) : ID=903
Bouton (valider) : ID=904
Bouton (annuler) : ID=905

Sous-menu "Enregistrement..." : ID=910 (Ctrl+T)
Sous-menu "A propos du Sharepad" : ID=911

Raccourci Ctrl+T : ID=950

Script de la boite d'enregistrement sous BRW:
1664 DIALOG 6, 15, 180, 75
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Enregistrement"
FONT 8, "MS Sans Serif"
{
 EDITTEXT, 900, 44,10,119,14,WS_BORDER
 EDITTEXT, 901, 44,30,119,14,WS_BORDER
 LTEXT "Nom:",902,18,12,16,14
 LTEXT "Code:",903,18,32,18,14
 DEFPUSHBUTTON "Valider", 904, 44, 56, 50, 14
 PUSHBUTTON "Annuler", 905, 113, 56, 50, 14
}
Et du menu:
 POPUP "E&nregistrement"
 {
  MENUITEM "Enregis&trement...\tCtrl+T", 910
  MENUITEM SEPARATOR
  MENUITEM "À &propos du Sharepad", 911
 }
Et du raccourci clavier (Ctrl+T):
1 ACCELERATORS 
{
 VK_INSERT, 769, VIRTKEY, CONTROL
 VK_F1, 5, VIRTKEY
 VK_F3, 8, VIRTKEY
 VK_F5, 12, VIRTKEY
 VK_BACK, 25, VIRTKEY, ALT
 "^Z", 25, ASCII
 "^T", 950, ASCII
 "^X", 768, ASCII
 "^C", 769, ASCII
 "^V", 770, ASCII
}
--------------------------------
2 ACCELERATORS 
{
 VK_INSERT, 769, VIRTKEY, CONTROL
 VK_F1, 5, VIRTKEY
 VK_F3, 8, VIRTKEY
 VK_F5, 12, VIRTKEY
 VK_BACK, 25, VIRTKEY, ALT
 "^Z", 25, ASCII
 "^T", 950, ASCII
 "^X", 768, ASCII
 "^C", 769, ASCII
 "^V", 770, ASCII
 VK_ESCAPE, 28, VIRTKEY
 "C", 28, VIRTKEY, CONTROL
 "D", 28, VIRTKEY, CONTROL
 "Z", 28, VIRTKEY, CONTROL
}
On ajoute donc un boite d'enregistrement avec deux champs EDIT ("Nom:" et "Code:", resp. IDs 900 et 901), ainsi que deux boutons ("Valider" et "Annuler", resp. IDs 904 et 905). Quant au menu, on insère entre "&Recherche" et "&?" un menu "E&nregistrement" qui contient deux sous-menus ("Enregis&trement...\tCtrl+T" et "À &propos du Sharepad", resp. IDs 910 et 911). Tout ceci se fait entièrement sous Borland Ressources Workshop. Aucun autre programme n'est utilisé pour traiter et insérer ces ressources.

Par curiosité on regarde vite fait la différence avec Procdump:

Avant la compilation des ressources:
  Name        Virtual Size    Virtual Offset  Raw Size        Raw Offset      Characteristics
 .text        00003E9C        00001000        00004000        00001000        60000020
 .data        0000084C        00005000        00001000        00005000        C0000040
 .idata       00000DE8        00006000        00001000        00006000        40000040
 .rsrc        00006000        00007000        00006000        00007000        40000040
 .reloc       00000A9C        0000D000        00001000        0000D000        42000040
Après la compilation des ressources:
  Name        Virtual Size    Virtual Offset  Raw Size        Raw Offset      Characteristics
 .text        00003E9C        00001000        00004000        00001000        60000020
 .data        0000084C        00005000        00001000        00005000        C0000040
 .idata       00000DE8        00006000        00001000        00006000        40000040
 .reloc       00000A9C        00007000        00001000        00007000        42000040
 .rsrc        00006000        00008000        00006000        00008000        40000040
La taille des sections n'a pas bougé, .rsrc et .reloc ont été inversé lors de la recompilation. C'est l'éditeur de ressources qui a fait ça... Ca ne nous pose aucun problème.

Bien, maintenant, il faut brancher la boite d'enregistrement (ID 1664) sur le menu "Enregis&trement...\tCtrl+T" (ID 910) et la MSGBOX5 sur "A propos du Sharepad" (ID 911).

Pour savoir comment s'y prendre, il faut avoir quelques notions de la gestion des événements dans un programme sous windows. La gestion d'un événement, c'est : "Que se passe-t-il quand on clique sur un menu, un bouton,... (une ressource) ou bien que l'on fait une action dans le programme?". Le programme est comme un piano. Il reste muet tant que l'on ne fait pas d'action, mais dès que c'est le cas, il analyse l'action faite et répond en conséquence (en se servant de l'ID de l'action exécutée). Pour les physiciens, cela correspond au principe de l'inertie de Galilée : "Tout corps (aka programme) persévère dans l'état de repos ou de mouvement uniforme dans lequel il se trouve, à moins que quelque force (aka action de l'utilisateur) n'agisse sur lui et ne le contraigne à changer d'état". Donc, quand on clique sur une ressource, on envoie son ID à Windows. Celui-ci, via l'API User32!SendMessageA, va gérer la transmission de cette information et renvoyer l'ID activée dans eax (au programme). Une boucle dans le programme va comparer ensuite chaque ID à celle stockée en eax, et exécutera le code correspondant lors de la bonne comparaison.

Par exemple:
* Possible Ref to Menu: MenuID_0001, Item : "Couper Ctrl+X"
|
:00401288 3D00030000              cmp eax, 00000300
:0040128D 7C21                    jl 004012B0

* Possible Ref to Menu: MenuID_0001, Item : "Copier Ctrl+C"
|
:0040128F 3D01030000              cmp eax, 00000301
:00401294 0F8E3E040000            jle 004016D8

* Possible Ref to Menu: MenuID_0001, Item : "Coller Ctrl+V"
|
:0040129A 3D02030000              cmp eax, 00000302
:0040129F 0F8456040000            je 004016FB             
On va donc utiliser ici un saut long (0F8X...) pour se brancher sur notre code qui se trouvera après la dernière section comme pour la partie I de ce tutorial. Au passage, on va mettre avant les chaînes de caractères dont on a besoin pour cette fois:

Limitations shareware:
- Une MSGBOX1 au PEP du programme (comme dans le partie I)
titre="SHAREWARE!!!" message="Veuillez vous enregistrer."
- Une MSGBOX2 au EXITPROCESS du programme (comme dans le partie I)
titre="SHAREWARE!!!" message="N'oubliez pas de vous enregistrer. Consultez le fichier reg.txt."

Menu "Enregistrement":
- Une MSGBOX3 (ou Goodboy) en cas de succès de l'enregistrement
titre="Bravo!" message="Merci de votre soutien."
- Une MSGBOX4 (ou Badboy) en cas d'échec de l'enregistrement
titre="Erreur!" message="Mauvais Code"
- Une MSGBOX5 pour la partie "À propos du Sharepad"
titre="Sharepad" message="Réversé par Anubis (Shmeitcorp)!"

Cela fait donc 9 chaines à mettre (MSGBOX1 et MSGBOX2 ont le même titre). Cela donne:
0000D720 5348 4152 4557 4152 4521 2121 0000 0000 SHAREWARE!!!....
0000D730 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D740 5665 7569 6C6C 657A 2076 6F75 7320 656E Veuillez vous en
0000D750 7265 6769 7374 7265 722E 0000 0000 0000 registrer.......
0000D760 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D770 4E27 6F75 626C 6965 7A20 7061 7320 6465 N'oubliez pas de
0000D780 2076 6F75 7320 656E 7265 6769 7374 7265  vous enregistre
0000D790 722E 2043 6F6E 7375 6C74 657A 206C 6520 r. Consultez le 
0000D7A0 6669 6368 6965 7220 7265 672E 7478 742E fichier reg.txt.
0000D7B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D7C0 4272 6176 6F21 0000 0000 0000 0000 0000 Bravo!..........
0000D7D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D7E0 4D65 7263 6920 6465 2076 6F74 7265 2073 Merci de votre s
0000D7F0 6F75 7469 656E 2E00 0000 0000 0000 0000 outien..........
0000D700 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D810 4572 7265 7572 2100 0000 0000 0000 0000 Erreur!.........
0000D820 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D830 4D61 7576 6169 7320 436F 6465 0000 0000 Mauvais Code....
0000D840 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D850 5368 6172 6570 6164 0000 0000 0000 0000 Sharepad........
0000D860 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D870 5265 7665 7273 E920 7061 7220 416E 7562 Revers. par Anub
0000D880 6973 2028 5368 6D65 6974 636F 7270 2921 is (Shmeitcorp)!
0000D890 0000 0000 0000 0000 0000 0000 0000 0000 ................
J'ai laissé une ligne d'espace par clarté et pour bien distinguer les différentes phrases.

Ensuite on code la gestion de notre boite d'enregistrement puis de la MSGBOX5 pour "À propos du Sharepad". On utilise ici la technique ultra classique de brancher un jump sur une instruction qui n'est de préférence pas un saut (ça peut éviter certains problèmes...). Ce branchement "sauvage" saute à notre code que l'on va injecter, et qui se trouve en général à la fin d'une section dans du padding, voir dans une section nouvellement créée pour l'occasion. On aura ainsi de très fortes chances de se retrouver tout à la fin du soft après les .reloc et .rsrc. Puis de ce code, on recopie les instructions écrasées par notre branchement, et on se rebranche sur l'instruction juste après notre jump sauvage.

Ici on a pas mal de choix. On va faire le branchement au niveau de "Ctrl+C" par exemple...:
 * Possible Ref to Menu : MenuID_0001, Item: "Couper Ctrl+X"
 |
 :00401288 3D00030000              cmp eax, 00000300
 :0040128D 7C21                    jl 004012B0

 * Possible Ref to Menu : MenuID_0001, Item: "Copier Ctrl+C"
 |
 :0040128F 3D01030000              cmp eax, 00000301
 :00401294 0F8E3E040000            jle 004016D8

 * Possible Ref to Menu : MenuID_0001, Item: "Coller Ctrl+V"
 |
 :0040129A 3D02030000              cmp eax, 00000302
 :0040129F 0F8456040000            je 004016FB
...qui devient:
 * Possible Ref to Menu : MenuID_0001, Item: "Couper Ctrl+X"
 |
 :00401288 3D00030000              cmp eax, 00000300
 :0040128D 7C21                    jl 004012B0
 :0040128F E92CC60000              jmp 0040D8C0		<<== on se branche ici, saut en D8C0
 :00401294 0F8E3E040000            jle 004016D8

 * Possible Ref to Menu : MenuID_0001, Item: "Coller Ctrl+V"
 |
 :0040129A 3D02030000              cmp eax, 00000302
 :0040129F 0F8456040000            je 004016FB
La chaîne " * Possible Ref to Menu : MenuID_0001, Item: "Copier Ctrl+C" " disparaît, car il n'y a plus son ID (301) dans le code réécrit.

En D8C0, on rajoute le code de comparaison des IDs de notre menu (ID-COMPARAISON). Voilà ce que cela donne en asm pour l'affichage de la MSGBOX5...:
(ID-COMPARAISON)
.0040D8C0: 60                  pushad                                <-- sauvegarde de tous les registres
.0040D8C1: 3D8E030000          cmp         eax,00000038E             <-- on a choisi la boite d'enregistrement ?
.0040D8C6: 0F8484000000        je         .00040D950                 <-- oui, alors on exécute son code
.0040D8CC: 3D8F030000          cmp         eax,00000038F             <-- on a choisi la MSGBOX5 de "À propos du Sharepad" ?
.0040D8D1: 0F8439000000        je         .00040D910                 <-- oui, alors on exécute son code
.0040D8D7: 61                  popad                                 <-- restauration de tous les registres
.0040D8D8: 3D01030000          cmp         eax,000000301             <-- instruction écrasée par notre jump en 40128F
.0040D8DD: E9B239FFFF          jmp        .000401294                 <-- retour au code juste après notre jump sauvage

(MSGBOX5)
.0040D910: 6A00                push        000
.0040D912: 6850D84000          push        00040D850                 <-- Titre
.0040D917: 6870D84000          push        00040D870                 <-- Message
.0040D91C: 6A00                push        000
.0040D91E: FF15A8644000        call        MessageBoxA               <-- Affichage de la MSGBOX5
.0040D924: 61                  popad                                 <-- Restauration de tous les registres
.0040D925: E9833FFFFF          jmp        .0004018AD                 <-- Retour à la boucle de l'API SendMessage
...et sous l'éditeur hexa:
0000D8B0 4944 2D43 4F4D 5041 5241 4953 4F4E 0000 ID-COMPARAISON..    <-- Titre de la partie. N'intervient pas dans le code.
0000D8C0 603D 8E03 0000 0F84 8400 0000 3D8F 0300 `=..........=...    |Code
0000D8D0 000F 8439 0000 0061 3D01 0300 00E9 B239 ...9...a=......9    |Code
0000D8E0 FFFF 0000 0000 0000 0000 0000 0000 0000 ................    |Code
0000D8F0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D900 4D53 4742 4F58 3500 0000 0000 0000 0000 MSGBOX5.........    <-- Titre de la partie. N'intervient pas dans le code.
0000D910 6A00 6850 D840 0068 70D8 4000 6A00 FF15 j.hP.@.hp.@.j...    |Code
0000D920 A864 4000 61E9 833F FFFF 0000 0000 0000 .d@.a..?........    |Code
0000D930 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000D940 5245 4742 4F58 0000 0000 0000 0000 0000 REGBOX..........    <-- Titre de la partie. N'intervient pas dans le code.
0000D950 0000 0000 0000 0000 0000 0000 0000 0000 ................
Les titres des parties n'interviennent pas car les différentes parties de code sont connectées entre elles par des sauts ou des calls qui passent au dessus des titres. De même, aucune autre instruction en assembleur ne va appeler ces chaînes par leur adresse (offset).

On peut déjà faire un petit test en live pour l'affichage de la Msgbox5 qui marche bien. En résumé jusqu'ici au cas où vous auriez un problème:
- on modifie les ressources (ajout des menus, IDs...)
- on se branche sur Ctrl+C avec un "jump D8C0" qui écrase le "cmp eax, 301"
- en D8C0:
  • sauvegarde de tous les registres (sinon plantage assuré!)
  • ajout des comparaisons des IDs rajoutées par reverse
  • restauration des registres sauvegardés (sinon ça plante aussi!)
  • ajout de l'instruction écrasée par "jump D8C0"
  • retour juste après le "jump D8C0"
  • - on écrit le code de la MSGBOX5 qui renvoie sur la boucle des messages du soft en 4018AD.

    Quelques commentaires s'imposent sur la construction du code ci-dessus. Peut-être vous dites vous "Comment on sait qu'il faut s'occuper des registres?" ou bien "On met l'instruction écrasée par notre jump AVANT ou APRES le code qu'on rajoute?"...

    Pour les registres, quand on affiche une MSGBOX en "débutant" dans le RE, on ne s'en occupe jamais. En effet, l'API MessageBoxA ne modifie pas les registres, donc pas la peine de les traiter. Par contre, dans le code rajouté ici, on fait intervenir des tests (sous la forme "cmp"). La réponse de ces tests est enregistrée dans les registres, et si on écrit par dessus sans sauver les données, alors les données sont perdues et le processeur ne va pas apprécier (=planter) à un moment donné. Donc la logique est:

    - sauvegarde des registres
    - [...]
    - MON CODE RAJOUTÉ
    - [...]
    - restauration des registres

    ... et là, le rajout est "propre" ET marche. Cette logique est à appliquer pour tout rajout de code un peu "élaboré".

    Pour la place de l'instruction écrasée (parfois, il y en a plusieurs!), cela dépend en fait du code. Il faut faire au cas par cas. Pour illustrer, prenons par exemple les 2 Msgboxes de la partie I de ce tut. Une se trouve au PEP, et l'autre en sortie de programme. Pour la première on veut qu'elle s'affiche avant du code, donc les instructions écrasées seront rajoutées APRES. Pour la deuxième, on veut qu'elle s'affiche après du code, donc ce sera le cas inverse. Vu? ;)

    Au niveau de la MSGBOX5, le popad/61 (en D924) n'est en faite absolument pas indispensable. Je l'ai mis par analogie avec ce que je viens de dire, mais il ne sert en fait pas à grand chose... S'il vous dérange, vous pouvez toujours le remplacer par un nop/90. Quant au 4018AD, comment sait-on que c'est cette valeur? Il suffit de tracer un peu sous Wdasm dans les jumps du code qui correspond aux commandes Ctrl+C,V,X. On tombe toujours sur cette valeur à la fin des procédures. Et quand on a un peu l'habitude de reverser, on remarque très vite ce genre de valeur finale pour la boucle SendMessage!


    Maintenant, on va coder l'appel de la boite d'enregistrement (REGBOX) en D950. Mais avant, il faut réfléchir 2 secondes sur le "comment on fait?".

    En cliquant sur le menu "Enregistrement...", windows va renvoyer l'ID 911 (38Fh) au notepad qui va jumper au niveau du code ci-dessus. Jusque là, rien de très nouveau. Ensuite il faut faire afficher notre REGBOX. Pour cela, on a grosso-modo 2 solutions!

    Pour afficher une boite de dialogue, on a le choix entre 2 manières (i.e. 2 APIs) bien connues: CreateDialogParam et DialogBoxParam. Chacune de ces 2 méthodes a ses inconvénients et ses avantages.

    CreateDialogParam est une boite de dialogue de type "sans mode" (modeless). Ce type de boites permet de faire des modifications sur d'autres fenêtres du programme ou d'un autre programme. Un exemple est la boite "Rechercher" d'un éditeur de texte. Quand cette boite est ouverte, il est toujours possible de lancer d'autres fonctions dans le menu de l'éditeur de texte ou d'utiliser d'autres programmes.

    DialogBoxParam est une boite de dialogue de type "avec mode" (modal). Lors de l'utilisation de cette boite de dialogue, le focus est bloqué. Par exemple, la boite de dialogue "Imprimer...". Ce focus peut être bloqué de deux manières différentes: il bloque seulement l'application propriétaire de la boite de dialogue ouverte (on parle de mode application ou "application modal") ou bien le focus bloque tout tant que l'on ne sort pas de la boite de dialogue (on parle de mode système ou "system modal").

    D'autres différences importantes ont également lieu:

    - Affichage:
  • CreateDialogParam CREE la boite de dialogue en mémoire sans l'afficher forcément. Il faut alors utiliser l'API ShowWindow pour cela.

  • DialogBoxParam affiche la boite de dialogue automatiquement.


  • - Destruction/fermeture:
  • CreateDialogParam: la boite est fermée en utilisant l'API DestroyWindow. Si à la place on utilisait l'API EndDialog, on ne verrait plus la boite à l'écran, mais elle serait toujours en mémoire.
  • DialogBoxParam: la boite de dialogue est fermée en utilisant l'API EndDialog.

  • - Gestion des messages (WM_COMMAND,...):
  • CreateDialogParam doit être suivie de sa propre structure de gestion des messages qu'il faut coder. Au final, le code est plus long que pour DialogBoxParam.
  • DialogBoxParam génère sa propre boucle de gestion des messages. On n'a pas à le coder nous. Le codage de cette API est simple et court.

  • - Passage des paramètres de l'API:
  • Le passage des paramètres est strictement le même pour les deux APIs.

  • Toutes ces données nous donne déjà un aperçu du choix à faire. Il est plus judicieux de choisir DialogBoxParam qui est plus simple à coder, bien qu'il faille utiliser une (courte) API de plus pour gérer son affichage. Mais le facteur dominant dans le choix est la disponibilité de ces deux APIs dans l'import table. En effet, on fait du Reverse ici et non pas de la programmation où on peut disposer de tous les éléments que l'on souhaite. Ici notre choix est dicté par les APIs présentes dans les Imported Functions (i.e. APIs déjà utilisées dans le programme). Et si on regarde un programme comme le notepad, il n'y a QUE l'API CreateDialogParam de disponible. On n'a donc pas le choix!

    En fait si on a le choix... :o)

    En effet il est possible d'appeler une API qui ne se trouve pas dans l'import table. Si on ne veut pas défaire l'import table et devoir la recompiler, il n'y a en gros qu'une méthode qui est un grand classique. Mais pour cela il faut disposer de deux autres API qui sont GetModuleHandle et GetProcAddress. La première récupère le handle des DLLs système (kernel32, user32,...) qui sont DEJA chargées en mémoire. La seconde récupère le handle de l'API que l'on veut et qui se trouve dans la DLL dont on vient de récupérer le handle. Avec ces handles, on peut appeler ensuite toutes les APIs que l'on veut!

    Pour illustrer ce qui vient juste d'être écrit, je me permet de citer un cours extrait approprié du fabuleux tutorial de LaZaRuS:
    The code for "Start Notepad":
    :00000204 3D9C020000              cmp eax, 0000029C ;; is "Start Notepad" chosen?
    :00000209 7525                    jne 00000230 ;; if not, then jump
    :0000020B 68ACE64000              push 0040E6AC ;; push "KERNEL32.DLL"
    :00000210 FF1590E24000            call dword ptr [0040E290] ;; "GetModuleHandle"
    :00000216 68071B4100              push 00411B07 ;; "WinExec"
    :0000021B 50                      push eax ;; handle of Kernel32.dll
    :0000021C FF15DCE24000            call dword ptr [0040E2DC] ;; GetProcAddress
    :00000222 6A01                    push 00000001 ;; SW_SHOW
    :00000224 68EA174100              push 004117EA ;; "Notepad.exe"
    :00000229 FFD0                    call eax ;; call WinExec
    :0000022B E9B616FFFF              jmp FFFF18E6 ;; back to MessageLoop
    
    Si vous ne comprenez pas le code, je vous renvoie à son tutorial. Je ne lui ferai pas l'affront de l'expliquer. Et si vous voulez plus de détails sur la méthode, allez à la source voir le tutorial de NeuRaL_NoiSE (dans sa Phase 5). Il y a d'excellentes explications!

    On a le choix alors ?! Encore que pas tout a fait...

    Comme je viens de le dire, on doit avoir impérativement GetModuleHandle et GetProcAddress dans l'import table, sinon c'est vraiment foutu. Et malheureusement, GetProcAddress ne se trouve pas dans l'import table du notepad. Il ne nous reste donc qu'à définitivement utiliser CreateDialogParam. On devra donc coder la gestion de la boucle des messages, et terminer la boite de dialogue par DestroyWindow.

    Ca sera plus long et moins facile que pour DialogBoxParam :( Mais au moins on apprendra des choses en plus! ;o)

    Voyons maintenant la structure de l'API CreateDialogParam:
    HWND CreateDialogParam(
        HINSTANCE hInstance,	// handle to application instance
        LPCTSTR lpTemplateName,	// identifies dialog box template
        HWND hWndParent,	      // handle to owner window
        DLGPROC lpDialogFunc,	// pointer to dialog box procedure  
        LPARAM dwInitParam 	      // initialization value
       );	
    
    Et on fermera cette API avec DestroyWindow. Sa structure ne possède qu'un seul paramètre à passer:
    BOOL DestroyWindow(
        HWND hWnd 	// handle to window to destroy  
       );	
    
    Comme cela ne nous avance pas trop malgré tout, on va regarder l'API CreateDialogParam qui est présente dans le notepad sous Wdasm/SI. On ne trouve qu'une seule occurrence de cette API dans le programme (affichage de la petite DialogBox de l'imprimante "impression en cours"), qui donne les renseignements suivants pour les 5 paramètres à passer:
     :00404085 56                      push esi                        ; init. value = 0
     :00404086 A100504000              mov eax, dword ptr [00405000]
     :0040408B 68E13B4000              push 00403BE1                   ; pointer to procedure = 8B 44 24 08 
     :00404090 50                      push eax                        ; handle to owner window = 30C
    
     * Possible Ref to Menu : MenuID_0001, Item: "Heure/Date F5"       |
     |                                                                 |
     * Possible Reference to Dialog: DialogID_000C                     | Wdasm s'emmêle les pinceaux ;)
     |                                                                 |
     * Possible Reference to StringResource ID=00012: "- Bloc-notes"   |
     |
     :00404091 6A0C                    push 0000000C                   ; dialog box template = 0x0C (soit 12 sous BRW)
     :00404093 FF3540554000            push dword ptr [00405540]       ; handle to appli. inst. = 00 00 40 00 (400000)
    
     * Reference To : USER32.CreateDialogParamA, Ord: 0050h
     |
     :00404099 FF155C644000            Call dword ptr [0040645C]       ; API CreateDialogParamA
    
    Explications avec les valeurs que j'ai choisi pour mon code :
    initialization value   = 0		; on ne s'en occupe pas. On met zéro.
    pointer to procedure   = 40D980	; procédure du code à exécuter dans la fenêtre (REGBOX) affichée. 
    handle to owner window = 8C		; comment trouver cette valeur?? voir plus bas... ;)
    dialog box template    = 680		; 0x680 = 1664d. Vu?
    handle to appli. inst. = 400000	; il s'agit en général de l'ImageBase (ici = 400000).
    
    Pour le "pointer to procedure", c'est comme un jump qui va exécuter le code de la fenêtre REGBOX (gestion des messages, calcul du sérial,...). J'ai fixé cette valeur aprés avoir codé l'appel de la REGBOX. Pour le "handle to owner window", il y a un moyen très simple d'avoir cette valeur embêtante à trouver: on lance le soft dont on veut l'handle. Sous SI, on fait "task" et on voit beaucoup de données, dont les noms des applications lancées. On repère dans la liste le nom du soft dont on veut l'handle (ce nom n'est pas toujours le même que celui du programme qu'on lance, c'est pour ça que l'on fait un "task" d'abord!). Puis on fait "hwnd nom_du_soft", et on regarde la 1ère colonne qui contient les handles du soft. La 1ère valeur est celle recherchée (0x8C pour notre cas). Elle est en retrait du reste de la colonne.

    Les autres valeurs ne doivent pas vous poser de problème.

    Passons à la phase pratique , c'est à dire coder la boite de dialogue. On va commencer par coder l'API CreateDialogParam avec ses 5 paramètres, et définir une instruction bidon (pour le moment) pour sa procédure.

    On reprend le codage à l'endroit suivant:
    (ID-COMPARAISON)
    .0040D8C0: 60                  pushad                                <-- sauvegarde de tous les registres
    .0040D8C1: 3D8E030000          cmp         eax,00000038E             <-- on a choisi la boite d'enregistrement ?
    .0040D8C6: 0F8484000000        je         .00040D950                 <-- oui, alors on exécute son code
    .0040D8CC: 3D8F030000          cmp         eax,00000038F             <-- on a choisi la MSGBOX5 de "À propos du Sharepad" ?
    .0040D8D1: 0F8439000000        je         .00040D910                 <-- oui, alors on exécute son code
    .0040D8D7: 61                  popad                                 <-- restauration de tous les registres
    .0040D8D8: 3D01030000          cmp         eax,000000301             <-- instruction écrasée par notre jump en 40128F
    .0040D8DD: E9B239FFFF          jmp        .000401294                 <-- retour au code juste après notre jump sauvage
    
    Comme on appelle maintenant la REGBOX, on va avoir l'ID 38E et sauter en D950. On place directement l'API CreateDialogParam à cette adresse, suivie d'une instruction qui sauvegarde le handle de la dialog box crée (ce handle est retourné dans eax lors de la création de la dialog box). L'offest [405390] pour sauvegarder eax a été choisi au hasard dans le padding de la section .data, c'était le 1er grand padding que j'ai rencontré en descendant, lisant le code sous un éditeur hexa. De plus cette section est C0000040 (le C signifie read et write dans la section), donc on a tout ce qu'il nous faut!

    Voilà le code de REGBOX:
    .0040D950: 6A00                push        0000			|
    .0040D952: 6880D94000          push        00040D980            |
    .0040D957: 688C000000          push        00000008C            | Nos 5 paramètres de l'API CreateDialogParam
    .0040D95C: 6880060000          push        000000680            |
    .0040D961: 6800004000          push        000400000            |
    .0040D966: FF155C644000        call        CreateDialogParamA   <-- API CreateDialogParam appelant la REGBOX
    .0040D96C: A390534000          mov         [000405390],eax      <-- sauvegarde du handle de la REGBOX
    .0040D971: E9373FFFFF          jmp        .0004018AD            <-- on sort/saute à notre boucle bien connue!
    [...]
    .0040D980: 33C0                xor         eax,eax
    .0040D982: C21000              retn        00010 
    
    Dans l'API CreateDialogParam, j'ai dit qu'on avait la procédure du code à exécuter dans la fenêtre (REGBOX) affichée. Elle doit se trouver en 40D980 telle définie en 40D952 par le push 40D980. Cette procédure correspond aux 2 instructions ci-dessus en 40D980 qui sont pour l'instant des instructions bidons, histoire que le programme puisse tourner. On mettra ici plus tard le code de calcul du sérial.

    Sous un éditeur hexa, on obtient:
    0000D940 5245 4742 4F58 0000 0000 0000 0000 0000 REGBOX..........  <-- Titre de la partie. N'intervient pas dans le code.
    0000D950 6A00 6880 D940 0068 8C00 0000 6880 0600 j.h..@.h....h...  |Code1
    0000D960 0068 0000 4000 FF15 5C64 4000 A390 5340 .h..@...\d@...S@  |Code1
    0000D970 00E9 373F FFFF 0000 0000 0000 0000 0000 ..7?............  |Code1 + padding 
    0000D980 33C0 C210 0000 0000 0000 0000 0000 0000 3...............  |Code2
    
    On peut maintenant tester le soft et cliquer sur le menu pour s'enregistrer. Ô joie! Voilà la REGBOX qui s'affiche :o)

    Et voilà!



    Bon ce n'est pas si rose, car on ne peut pas fermer la REGBOX. Mais la plus belle des choses ne peut donner que ce qu'elle a, n'est-ce pas?

    Maintenant, on doit s'occuper de fermer la REGBOX en cliquant sur le bouton "Annuler" (ID=0x389 ou 905d) ou sur la croix X de la fenêtre. De plus, il faut aussi activer le bouton "Valider". Mais pour l'instant, pour fermer le programme utilisez la croix de la fenêtre principale du notepad.

    Si on raisonne par analogie avec les insertions de menus que l'on a faites au début, on se retrouve ici dans le même cas. On a deux boutons (Valider et Annuler) auxquels il faut rattacher du code (une action). On a une fenêtre propriétaire de ces deux boutons, qui est la REGBOX (ID=1664, Handle=? Le Handle change tout le temps, on le retrouve quelque part dans la pile). Il ne nous reste donc qu'à reproduire une boucle de "cmp eax, ID" pour savoir quelle action est effectuée. Cette boucle commence directement en D980 à la place du XOR (l'instruction bidon) que l'on avait mis. Ensuite, on dirigera la REGBOX sur une sortie (Annuler) ou sur le calcul du serial (Valider).

    Au boulot!

    Comme je l'ai dis plus haut dans l'analyse des deux APIs pour afficher une boite de dialogue (CreateDialogParam et DialogBoxParam), avant de pouvoir gérer les IDs des boutons, il faut gérer les messages que la REGBOX envoie à windows (qui les renvoie au notepad, c'est à dire à notre code).

    Voici le code que je propose (en D980 donc):

    * Sous un éditeur hexa
    0000D980 558B EC81 7D0C 1000 0000 750E FF75 08FF U...}.....u..u..
    0000D990 15A0 6440 00E9 2F00 0000 817D 0C11 0100 ..d@../....}....
    0000D9A0 0075 268B 4510 7521 3D89 0300 0075 0EFF .u&.E.u!=....u..
    0000D9B0 7508 FF15 A064 4000 E90C 0000 003D 8803 u....d@......=..
    0000D9C0 0000 7505 E827 0000 00C9 C300 0000 0000 ..u..'..........
    0000D9D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
    0000D9E0 5345 5249 414C 2D43 414C 4390 0000 0000 SERIAL-CALC.....
    0000D9F0 6A00 68C0 D740 0068 C0D7 4000 6A00 FF15 j.h..@.h..@.j...
    0000DA00 A864 4000 C9C3 0000 0000 0000 0000 0000 .d@.............
    0000DA10 0000 0000 0000 0000 0000 0000 0000 0000 ................
    
    * Et en listing asm (suite de REGBOX)
    .0040D980: 55                 push        ebp
    .0040D981: 8BEC               mov         ebp,esp
    .0040D983: 817D0C10000000     cmp         [ebp+0C],000000010 
    .0040D98A: 750E               jne        .00040D99A   
    .0040D98C: FF7508             push        [ebp+08]
    .0040D98F: FF15A0644000       call        DestroyWindow 
    .0040D995: E92D000000         jmp        .00040D9C7   
    .0040D99A: 817D0C11010000     cmp         [ebp+0C],000000111 
    .0040D9A1: 7524               jne        .00040D9C7   
    .0040D9A3: 8B4510             mov         eax,[ebp+10]
    .0040D9A6: 3D89030000         cmp         eax,000000389 
    .0040D9AB: 750E               jne        .00040D9BB   
    .0040D9AD: FF7508             push        [ebp+08]
    .0040D9B0: FF15A0644000       call        DestroyWindow 
    .0040D9B6: E90C000000         jmp        .00040D9C7   
    .0040D9BB: 3D88030000         cmp         eax,000000388 
    .0040D9C0: 7505               jne        .00040D9C7   
    .0040D9C2: E829000000         call       .00040D9F0   
    .0040D9C7: C9                 leave
    .0040D9C8: C3                 retn
    
    [...]
    
    .0040D9F0: 6A00               push        000
    .0040D9F2: 68C0D74000         push        00040D7C0   
    .0040D9F7: 68C0D74000         push        00040D7C0   
    .0040D9FC: 6A00               push        000
    .0040D9FE: FF15A8644000       call        MessageBoxA 
    .0040DA04: C9                 leave
    .0040DA05: C3                 retn
    
    Analyse du code:

    On va utiliser le registre ebp pour travailler. Donc on le sauvegarde, puis on lui assigne (copie) la valeur de esp (de la pile, pour traiter les messages de windows). Ceci se fait en D980.

    On a deux types de messages à gérer. Le premier est de regarder si la valeur ebp+C correspond à 10h (gestion des événements de la fenêtre: curseur de souris sur la REGBOX?, utilisation de la croix X pour fermer la fenêtre...). Le second est de regarder si ça correspond à 111h (gestion des boutons "Valider" et "Annuler").

    En D98A, si le message ne correspond pas à 10h, on saute en D99A et on regarde si ça correspond à 111h. Si ce n'est pas le cas, on saute à la fin de la routine et on boucle. Il y a une énorme quantité de messages qui sont envoyés et reçus sous windows. Même quand on ne fait rien à l'ordi. Donc, dans cette masse d'information, on met un filtre (le "cmp ebp+C,valeur") pour chopper ce qui nous intéresse.

    En D98C, la REGBOX va être fermée si on a appuyé sur la croix X. On passe par l'API DestroyWindow et on saute à la fin du code sur la boucle des messages.

    Jusqu'ici on a traité la gestion des messages qui n'était pas intégrée à l'API CreateDialogParam comme dit plus haut dans l'analyse/comparaison des 2 APIs d'affichage de boites de dialogues.

    Maintenant, on va traiter les messages des boutons de la REGBOX.

    En D9A3, on isole le word de ebp+10 dans eax. Cette opération revient à choisir le lParam du dword envoyé par windows. On a ainsi directement l'ID du bouton cliqué dans eax. Simple, propre et efficace! Pour les explications sur lParam et tout le reste, allez sur le site de Iczelion (win32asm.cjb.net - tutoriaux 10 et 11), là pareil, je ne vais pas re-expliquer ce qu'il a déjà fait magistralement.

    On compare maintenant l'ID envoyée avec les actions à faire.

    En D9A6, on regarde si l'ID envoyée par windows correspond à notre bouton "Annuler" (ID=389h). Si ce n'est pas le cas, on saute à la prochaine ID. Si c'est le cas, on ferme la REGBOX par le même code que pour la croix X de fermeture, puis on saute à la fin du code.

    En D9BB, on compare l'ID envoyée avec notre bouton "Valider" (ID=388h). Si ce n'est pas le cas, on saute à la fin du code, sinon on exécute le call en D9C2. Ce call va en D9F0 et affiche pour l'instant une msgbox (bidon) mais qui nous sert à voir que tout marche bien. Cette msgbox va être remplacée ensuite par le calcul du sérial. Un petit commentaire sur le jne en D9C0: bien qu'il ne soit pas utile car il n'y a que 2 contrôles dans la REGBOX, je l'ai quand même mis par rigueur. Ainsi seul le bouton "Valider" aura accès au call du calcul de sérial!

    A partir de maintenant donc, la REGBOX est terminé... enfin dans la gestion de ses éléments. Le bouton "Valider" renvoie une messgebox avec la même chaîne en titre et en phrase. Cette portion de code (en D9F0) sera remplacée par le calcul du sérial par la suite. Le bouton "Annuler" ferme la REGBOX par l'API DestroyWindow, de même que lorsqu'on appuie sur la croix X de la REGBOX.

    Il faut maintenant coder le calcul du sérial, puis gérer l'attitude du notepad en fonction de enregistré/pas enregistré.

    Je fais appel ici à l'expérience que chacun de vous a, lors du traçage de sérial sous Softice. On va "copier" la structure de création de sérial des schémas les plus basiques et faciles lorsqu'on débute en cracking. Je ferai ici la même remarque que pour la partie I de ce tutorial. Ce qui est important ici, c'est COMMENT construire une boite de dialogue qui va calculer un sérial. Ce n'est pas d'avoir une SECURITE pointue dans la protection du sérial lors de son calcul!

    Revenons-en à nos mouton. Et commençons par le début:

    Question: quelles sont les 2 APIs sur lesquelles on pose un break quand on rentre un nom+sérial bidon sous Softice??
    Réponse: GetDlgItemText et GetWindowText! Hmemcpy est ici hors sujet, on atterri dans les DLLs systèmes.

    On en choisi donc une, et on regarde (sous Wdasm) si elle est disponible dans l'import table du notepad. Comme les deux APIs sont présentes, on choisi celle que l'on veut. Personnellement, j'ai une petite préférence pour GetDlgItemText. Voilà leur tête, à titre d'information:
    int GetWindowText(
        HWND hWnd,	// handle of window or control with text
        LPTSTR lpString,	// address of buffer for text
        int nMaxCount 	// maximum number of characters to copy
       );	
     
    UINT GetDlgItemText(
        HWND hDlg,	// handle of dialog box
        int nIDDlgItem,	// identifier of control
        LPTSTR lpString,	// address of buffer for text
        int nMaxCount 	// maximum size of string
       );
    
    A noter que ces 2 APIs renvoient la longueur de la chaîne saisie dans eax.

    Bien la liste des paramètres est claire. On va coder GetDlgItemText à la place de la msgbox qui nous affichait le même titre et la même phrase. En fait on procède de même manière que pour le codage de CreateDialogParam.

    Quelques mots sur ce qui va suivre... On va saisir les 2 champs EDIT de notre REGBOX par l'API GetDlgItemText, puis on va fabriquer le sérial qui va être comparé avec le sérial entré par l'utilisateur. Ensuite par un test, on regarde si cela correspond. Si ce n'est pas le cas, on affiche une msgbox "Mauvais code!" (on a déjà mis la chaîne de caractère qui y correspond au début de ce tutorial). Sinon on va créer une entrée dans la base de registre et mettre le nom + le sérial, et enlever les restrictions du shareware (qui ne sont pas encore mises jusqu'ici. On fera cela après!).

    Une fois cette partie codée, on mettra les restrictions shareware (les même que celle de la partie I), et on testera au démarrage du notepad si les entrées de la base de registre sont 1/présentes et 2/justes. Si c'est le cas, on sautera au code qui vire les restrictions shareware, sinon on laisse lancer le notepad sans rien faire avec les restrictions shareware.

    Pour la gestion des buffers, on les mettra dans la même zone/section que là ou on a sauvegardé le handle de la REGBOX (voir plus haut), soit 53A0, 53B0,... De plus on va utiliser les zones suivantes:

    Les variables/offsets utilisés pour stocker des données temporaires:
    4053A0 : [nom entré par l'utilisateur/la bdr] (sur 0x20 bytes)
    4053C0 : longueur du [nom] (sur 1 byte)
    4053D0 : [code entré par l'utilisateur/la bdr] (sur 0x10 bytes)
    4053E0 : booléen/flag (sur 1 byte)
    4053F0 : [sérial calculé par le sharepad]
    Je rappelle que les deux champs EDIT ont comme ID 900d/0x384 (pour le nom) et 901d/0x385 (pour le sérial). On commence donc en D9F0 à coder la saisie des 2 champs EDIT avec GetDlgItemText, et on rajoute une petite astuce:
    (SERIAL-CALC)
    .0040D9F0: 6A20               push        020              <-- longueur max. du buffer (32d)
    .0040D9F2: 68A0534000         push        0004053A0        <-- offset en mémoire du nom entré
    .0040D9F7: 6884030000         push        000000384        <-- ID du champs EDIT_nom
    .0040D9FC: FF7508             push        [ebp+08]         <-- handle de la REGBOX (dans la pile)
    .0040D9FF: FF157C644000       call        GetDlgItemTextA  <-- on va chercher le nom entré...
    .0040DA05: A3C0534000         mov         [0004053C0],eax  <-- ... on sauve sa longueur ici
    .0040DA0A: 6A10               push        010              <-- longueur max. du buffer (16d)
    .0040DA0C: 68D0534000         push        0004053D0        <-- offset en mémoire du sérial entré
    .0040DA11: 6885030000         push        000000385        <-- ID du champs EDIT_sérial
    .0040DA16: FF7508             push        [ebp+08]         <-- handle de la REGBOX (dans la pile)
    .0040DA19: FF157C644000       call        GetDlgItemTextA  <-- on va chercher le sérial entré...
    .0040DA1F: C3                 retn
    
    ... et on obtient le nom rentré en 4053A0, et le sérial entré en 4053D0. Rien de très compliqué jusque là! Le C3 est juste là pour que le soft ne plante pas et pour pouvoir vérifier les offsets sous Softice (par "d 4053A0" et "d 4053D0" en posant un bpx en 40D9F0). Le "mov [offset],eax" en DA05 stocke en fait la longueur du nom saisi dans l'[offset].

    Quand on code cette partie, il faut bien faire attention à deux points particuliers. La première instruction empilée (en D9F0) est la longueur du buffer. Quand vous mettez l'adresse du buffer dans la deuxième instruction (en D9F2), il faut tenir compte de cette longueur (en D9F0). Sinon on risque d'écraser des instructions/valeurs qui sont plus bas. Pareil quand on code la saisie du sérial. On ne peut pas commencer n'importe ou à la suite du buffer du nom. Il faut tenir compte de la taille du buffer du nom, sinon cela donne n'importe quoi dans le traitement des informations...

    Ensuite vient la partie la plus amusante du tutorial: la création du sérial. Alors là, c'est carte blanche pour toutes les fantaisies! De mon coté, j'ai choisi de faire la somme du double des valeurs ascii des caractères du nom, de multiplier cette somme par une contante et de xorer cette valeur par une autre constante. Rien que ça! Bon en fait ce n'est pas très important comment on calcule le vrai sérial (le notre ;) ), c'est comment on va le traiter après qui est important.

    Bien! On va d'abord coder la création de notre sérial officiel du notepad (yeah! :D ), puis on va convertir la valeur hexadécimale du sérial en décimal par l'API wsprintf (qui est dans l'IAT du notepad). Enfin on va comparer cette valeur obtenue avec le sérial entré par l'utilisateur dans la REGBOX avec l'API lstrcmp (qui est aussi dans l'IAT du notepad). Un cours test pour connaître le résultat de cette comparaison nous emmènera sur un bad boy ou un good boy avec affichage de la msgbox correspondante dont les phrases se trouvent dans les chaînes que l'on a marqué tout au début de cette 2ème partie. On terminera les procédures comme toujours avec les instructions leave/retn (0xC9/0xC3).

    On commence en DA1F en virant le C3 qu'on avait mis, et on code SERIAL-CALC:
    .0040DA1F: C605E053400000     mov         [0004053E0],000         <-- explication plus tard...
    .0040DA26: 33C0               xor         eax,eax                 |Mise à zéro des registres 
    .0040DA28: 33D2               xor         edx,edx                 |que l'on va utiliser
    .0040DA2A: 33DB               xor         ebx,ebx                 |
    .0040DA2C: 8B0DC0534000       mov         ecx,[0004053C0]         <-- longueur du nom dans ecx
    .0040DA32: 8A82A0534000       mov         al,[edx+0004053A0]      <-- on met les lettres du nom dans eax
    .0040DA38: 8D1C43             lea         ebx,[ebx+eax*2]         <-- formule de calcul du sérial
    .0040DA3B: 42                 inc         edx                     <-- on passe au caractère suivant
    .0040DA3C: 3BCA               cmp         ecx,edx                 <-- on regarde si on a fait tous les caractères
    .0040DA3E: 75F2               jne        .00040DA32               <-- si pas fini, on continue le calcul
    .0040DA40: 81C321430000       add         ebx,000004321           <-- sinon on ajoute notre constante...
    .0040DA46: 81F334120000       xor         ebx,000001234           <-- ...et on xor avec une autre constante
    .0040DA4C: 53                 push        ebx                     <-- on met le résultat sur la pile
    .0040DA4D: 689C104000         push        00040109C               <-- voir explication plus bas
    .0040DA52: 68F0534000         push        0004053F0               <-- offset du résultat en décimal
    .0040DA57: FF150C644000       call        wsprintfA               <-- conversion hexa/décimal
    .0040DA5D: 68D0534000         push        0004053D0               <-- sérial entré
    .0040DA62: 68F0534000         push        0004053F0               <-- sérial calculé
    .0040DA67: FF15B8634000       call        lstrcmpA                <-- comparaison 
    (on va rajouter quelque chose ici plus tard!!!)
    .0040DA6D: 85C0               test        eax,eax                 <-- ce sont les même ??
    .0040DA6F: 7416               je         .00040DA87               <-- oui, alors on saute en good boy
    .0040DA71: 6A00               push        000                     |
    .0040DA73: 6810D84000         push        00040D810               |Bad boy!
    .0040DA78: 6830D84000         push        00040D830               |Affichage de la msgbox
    .0040DA7D: 6A00               push        000                     |"Mauvais Code"
    .0040DA7F: FF15A8644000       call        MessageBoxA             |
    .0040DA85: C9                 leave
    .0040DA86: C3                 retn
    .0040DA87: 6A00               push        000                     |
    .0040DA89: 68C0D74000         push        00040D7C0               |Good boy!
    .0040DA8E: 68E0D74000         push        00040D7E0               |Affichage de la msgbox
    .0040DA93: 6A00               push        000                     |"Merci de votre soutien."
    .0040DA95: FF15A8644000       call        MessageBoxA             |
    .0040DA9B: C9                 leave
    .0040DA9C: C3                 retn
    
    Sous un éditeur hexa, ça donne:
    0000DA10 0068 8503 0000 FF75 08FF 157C 6440 00C6 .h.....u...|d@..
    0000DA20 05E0 5340 0000 33C0 33D2 33DB 8B0D C053 ..S@..3.3.3....S
    0000DA30 4000 8A82 A053 4000 8D1C 4342 3BCA 75F2 @....S@...CB;.u.
    0000DA40 81C3 2143 0000 81F3 3412 0000 5368 9C10 ..!C....4...Sh..
    0000DA50 4000 68F0 5340 00FF 150C 6440 0068 D053 @.h.S@....d@.h.S
    0000DA60 4000 68F0 5340 00FF 15B8 6340 0085 C074 @.h.S@....c@...t
    0000DA70 166A 0068 10D8 4000 6830 D840 006A 00FF .j.h..@.h0.@.j..
    0000DA80 15A8 6440 00C9 C36A 0068 C0D7 4000 68E0 ..d@...j.h..@.h.
    0000DA90 D740 006A 00FF 15A8 6440 00C9 C300 0000 .@.j....d@......
    
    Je vais éclaircir encore 2-3 petites choses.

    En 40DA1F, il s'agit d'un flag (un booléen) qui va nous servir plus tard. Je ne l'explique pas ici.

    En 40DA4D, il y a un push "bizarre". D'ou vient cet offset? Et bien quand on utilise la conversion hexa/décimal avec l'API wsprintf, on écrit en C/C++:
    wsprintf(buffer_décimal, %d, buffer_hexa);
    
    Le %d étant le paramètre qui signifie à wsprintf que l'on veut convertir en décimal. Donc il nous faut passer ce "%d" dans l'API. Et pour cela, on doit l'avoir en tant que chaîne de caractère dans la partie ascii sous un éditeur hexa. J'aurais pu le rajouter à la main, mais j'ai d'abord regardé s'il ne figurait pas déjà dans le code. Sous un éditeur hexa, j'ai lancé une recherche sur %d et j'ai trouvé une seule occurrence en 40109C. Il faut bien faire attention que le %d soit suivi de 00 dans la partie hexa de l'éditeur, sinon en mettant %d sur la pile, on risquerait de mettre d'autres choses avec. Il ne reste ensuite plus qu'à mettre l'offset 40109C sur la pile pour passer le paramètre %d, ce que j'ai fait! :) Wsprintf renvoie ensuite en 4053F0 la valeur décimale du sérial calculé.

    En 40DA67, lstrcmp renvoie 0 en eax si les 2 chaines sont identiques. Sinon eax est différent de 0. Le test à la ligne suivante vérifie eax, et le saut en 40DA6F agit en conséquence.

    A partir de maintenant, la REGBOX est pour ainsi dire terminée. On peut y rentrer un nom et un sérial pour s'enregistrer, et la REGBOX traite le sérial entré pour vérifier s'il correspond ou pas!

    Pour que vous puissiez vous amuser, j'ai mis un keygenerator avec ce tutorial. Dans mon cas, le nom + sérial seront "Anubis" et "21969" :o) J'ai codé ce keygen vite fait en pascal et sans interface graphique. Il s'ouvre sous DOS. Si vous avez des problèmes pour le l'ouvrir (win2k,...), passez par la fenêtre de commande.

    La partie bad boy peut être laissée telle quelle. On va maintenant développer la partie good boy.

    Cette partie va consister à écrire le nom + le sérial correct dans la base de registre dans une clé qu'il va falloir créer. Une fois ce travail effectué, il faudra désactiver les restrictions shareware (en effaçant aussi le menu d'enregistrement!) et rendre la main au notepad.

    Pour le travail sur la base de registre, on utilisera toutes les APIs de ADVAPI32 du notepad (regarder sous Wdasm dans les imports functions). Comme on va travailler sur la base de registre (bdr), il va de soit que l'on en fait une copie de sauvegarde avant de faire quoi que ce soit et de surtout bousiller la base!

    Voici les structures des APIs en relation avec la bdr:
    LONG RegCloseKey(
        HKEY hKey 	// handle of key to close  
       );
    
    LONG RegCreateKey(
        HKEY hKey,	// handle of an open key 
        LPCTSTR lpSubKey,	// address of name of subkey to open 
        PHKEY phkResult 	// address of buffer for opened handle 
       );	
    
    LONG RegSetValueEx(
        HKEY hKey,	// handle of key to set value for  
        LPCTSTR lpValueName,	// address of value to set 
        DWORD Reserved,	// reserved 
        DWORD dwType,	// flag for value type 
        CONST BYTE *lpData,	// address of value data 
        DWORD cbData 	// size of value data 
       );
    
    On va commencer par mettre un jump à la place de la msgbox good boy, et faire un nouvelle partie GOODBOY dans la quelle on mettra l'inscription au registre puis la msgbox good boy (que l'on enlève de la partie SERIAL-CALC). Cette inscription se fera dans la branche HKEY\CURRENT_USER\Software\Microsoft\Notepad dans l'ordre suivant:

    RegCreateKey
    RegSetValueEx (pour le nom)
    RegSetValueEx (pour le code)
    RegCloseKey

    Avant de passer au codage, une petite analyse s'impose!

    En regardant ces 3 APIs dans le listing du notepad sous wdasm, on remarque que:
    - RegCreateKey n'est présent qu'une fois
    - RegSetValueEx est présent deux fois (via deux calls différents)
    - RegCloseKey n'est présent qu'une fois

    Si on regarde le listing entre RegCreateKey et RegCloseKey, on a par exemple ceci:
     * Possible StringData Ref from Data Obj ->"iPointSize"
     |                                                
     :00402601 6820524000              push 00405220
     :00402606 FF75FC                  push [ebp-04]
     :00402609 E808FEFFFF              call 00402416
     :0040260E FF351C504000            push dword ptr [0040501C]
    
     [...]
    
     * Possible StringData Ref from Data Obj ->"fSavePageSettings"
     |
     :00402627 6838524000              push 00405238
     :0040262C FF75FC                  push [ebp-04]
     :0040262F E8E2FDFFFF              call 00402416
     :00402634 682C584000              push 0040582C
    
     * Possible StringData Ref from Data Obj ->"lfFaceName"
     |
     :00402639 6850524000              push 00405250
     :0040263E FF75FC                  push [ebp-04]
     :00402641 E8ECFDFFFF              call 00402432
    
    Suivant le type d'information à entrer dans la bdr (valeur binaire ou chaîne), on appelle "call 00402416" (valeur binaire) ou "call 00402432" (chaîne). Pour mieux comparer, jetez un coup d'oeil dans la branche HKEY\CURRENT_USER\Software\Microsoft\Notepad et regardez la différence entre lfFaceName et fSavePageSettings.

    Comme on veut rentrer du texte de la même manière que lfFaceName, on va utiliser la même structure de code. On remarque aussi que toutes les valeurs sont passées dans la bdr de la même manière: on appelle une fonction (le call) en lui passant 3 paramètres. Par exemple pour lfFaceName, on passe:
    - 0040582C = Valeur de la chaîne (pour moi ce sera "Anubis")
    - 00405250 = Nom de la chaîne (pour moi ce sera "Name")
    - [ebp-04] = handle de la clé ouverte

    Je fais une petite parenthèse. Jusqu'ici, je n'ai jamais touché à la bdr en programmation et dans aucun langage. Pour pouvoir écrire le code qui va suivre, j'ai tracé sous SI les 3 APIs mentionnées ci-dessus dans le notepad en utilisant le menu Edition>Choisir la police... qui mémorise les paramètres dans la bdr. La "difficulté" était de bien suivre les états de la pile pour savoir à quoi correspondent les [ebp+XX] et comprendre comment sont gérés les calls. Ainsi, je ne sors pas les explications qui suivent d'un chapeau tel un lapin blanc, mais de plusieurs traçage de ces APIs. Si mes explications ne vous paraissent pas suffisantes, faites de même. C'est le meilleur moyen pour comprendre! Mettez un bpx regcreatekeya (n'oubliez pas le "a" sinon vous tapez dans le kernel au lieu de taper dans advapi - et enlevez le ";" devant advapi32 dans le winice.dat si ce n'est pas déjà fait!), et à chaque fois où vous appuyez sur F10, regardez et notez la valeur de esp pour comprendre.

    Donc en analysant les 3 APIs du notepad sous SI, je parviens au code suivant:

    Attention, on a enlevé la msgbox goodboy de la partie SERIAL-CALC. Voilà la fin de cette partie pour comparaison que l'on a changé...:
    (Fin de SERIAL-CALC)
    .0040DA6F: 743F                         je         .00040DAB0      ;on saute à GOODBOY si sérial ok, sinon...
    .0040DA71: 6A00                         push        000            |...msgbox badboy
    .0040DA73: 6810D84000                   push        00040D810      |
    .0040DA78: 6830D84000                   push        00040D830      |
    .0040DA7D: 6A00                         push        000            |
    .0040DA7F: FF15A8644000                 call        MessageBoxA    |
    .0040DA85: C9                           leave
    .0040DA86: C3                           retn
    
    ...pour pouvoir jumper sur cette partie de code là qui s'appelle GOODBOY:
    (GOODBOY)
    .0040DAB0: 55                           push        ebp            ;sauve ebp
    .0040DAB1: 8BEC                         mov         ebp,esp        ;change de variable pour la pile
    .0040DAB3: 83EC04                       sub         esp,004        ;décalage de la pile d'un cran
    .0040DAB6: 8D45FC                       lea         eax,[ebp-04]   |RegCreateKeyA  
    .0040DAB9: 50                           push        eax            |
    .0040DABA: 6848514000                   push        000405148      |
    .0040DABF: 6801000080                   push        080000001      |
    .0040DAC4: FF15F0624000                 call        RegCreateKeyA  |
    .0040DACA: 85C0                         test        eax,eax        ;si échec pour création de la clé, on saute...
    .0040DACC: 7541                         jne        .00040DB0F      ;...ici
    .0040DACE: 68A0534000                   push        0004053A0      |RegSetValueEx (pour le nom)
    .0040DAD3: 6856524000                   push        000405256      |
    .0040DAD8: FF75FC                       push        d,[ebp-04]     |
    .0040DADB: E85249FFFF                   call       .000402432      |
    .0040DAE0: 68D0534000                   push        0004053D0      ¦RegSetValueEx (pour le code)
    .0040DAE5: 6838D84000                   push        00040D838      ¦
    .0040DAEA: FF75FC                       push        d,[ebp-04]     ¦
    .0040DAED: E84049FFFF                   call       .000402432      ¦
    .0040DAF2: FF75FC                       push        d,[ebp-04]     |RegCloseKey
    .0040DAF5: FF15E8624000                 call        RegCloseKey    |
    .0040DAFB: 6A00                         push        000            ¦Msgbox goodboy
    .0040DAFD: 68C0D74000                   push        00040D7C0      ¦
    .0040DB02: 68E0D74000                   push        00040D7E0      ¦
    .0040DB07: 6A00                         push        000            ¦
    .0040DB09: FF15A8644000                 call        MessageBoxA    ¦
    .0040DB0F: 8BE5                         mov         esp,ebp        ;remet la variable d'origine
    .0040DB11: 5D                           pop         ebp            ;pop ebp sur la pile
    .0040DB12: C9                           leave          
    .0040DB13: C3                           retn
    
    On commence par un petit changement de variable très courant: on utilise ebp au lieu de esp pour les mouvements de pile. Pour cela, on doit sauver ebp au début, et le restaurer à la fin de la procédure. Pour que les données de la pile soient cohérentes avec les [ebp+XX] marqués, il faut repositionner la pile. C'est le role du "sub esp,04" en DAB3.

    Ensuite, on peut ouvrir la bdr en écriture avec RegCreateKeyA. On lui passe 3 paramètres. Je n'ai pas pu identifier eax, dans mon code ça passe le sérial, mais comme ça marche ce n'est pas trop grave. J'ai juste recopié cette ligne du dead listing. Le "push 405148" correspond au nom de la clé à ouvrir (HKCU\Software\Mircosoft\Notepad), et le "push 80000001" est l'handle de la clé ouverte. Voilà pour l'ouverture!

    On vérifie si l'ouverture s'est bien faite en testant eax qui doit être nul, sinon on saute à la fin du code. Cela évite de faire des bêtises sur la bdr...

    On attaque ensuite l'écriture du nom. On pousse ici aussi 3 paramètres qui sont dans l'ordre "Anubis" (en 4053A0, qui provient de notre GetDlgItemTextA), "Name" (en 405256) et le handle de la clé. N'ayant pas de chaîne "Nom" à ma disposition, plutôt que de la rajouter j'en ai cherché une disponible. En cherchant le mot "Name", on trouve une seule occurrence en 405256 qui est en fait:
    00005250 6C66 4661 6365 4E61 6D65 0000 0000 0000 lfFaceName......
    
    Mais en pointant sur le "N" de Name (405256), pas de problème pour récupérer la partie qui va bien! Reverse rulez ;o)

    On appelle ensuite le call 402432 après avoir passé le handle de la clé ouverte. Ce call va d'abord calculer la longueur du paramètre passé en valeur (ici "Anubis") et calibrer l'API RegSetValueEx en fonction.

    Même astuce pour le sérial. On passe "21969" (stocké en mémoire en 4053D0), puis le mot Code que j'ai piqué à ma chaîne "Mauvais Code" ici:
    0000D830 4D61 7576 6169 7320 436F 6465 0000 0000 Mauvais Code....
    
    Ici on pointe sur le "C" de code (40D838), et c'est dans le sac!

    En 40DAED, on a le deuxième call appelé pour mettre le sérial dans la bdr.

    Puis on passe le handle de la clé, et on ferme la bdr. Il ne reste plus qu'à afficher la msgbox good boy, remettre les variables d'origines et voilà!

    Notre sharepad permet jusqu'ici de s'enregistrer et inscrit le nom + le bon sérial dans la base de registre. Voici un extrait de ma base de registre après m'être enregistré:



    Bien! Tout cela commence à devenir présentable :o)

    On a terminé le plus gros. Avant de passer au restrictions shareware, on va coder une partie analogue à celle que l'on vient de faire. Quand on démarre le sharepad, celui-ci doit vérifier s'il est déjà (correctement) enregistré ou non. Pour cela, il faut dévier le soft au PEP, aller lire les infos dans la bdr (s'il n'y a pas d'infos, on saute au sharepad), vérifier ces infos en renvoyant le nom dans la routine de calcul et en le comparant au sérial de la bdr (si le résultat n'est pas correct on saute au sharepad). Et si tout cela est correct, alors on peut sauter à la partie DESACTIV qui déverrouille le sharepad en notepad. Au boulot!

    Cette partie va s'appeler TEST-REG et va renvoyer à DESACTIV après être passée par SERIAL-CALC. Il faut encore coder TEST-REG et DESACTIV, mais faire quelques modifications dans SERIAL-CALC (voir plus loin).

    Pour la lecture de la bdr on va utiliser la séquence suivante d'API:

    RegOpenKey
    RegQueryValueEx (pour le nom)
    RegQueryValueEx (pour le sérial)
    RegCloseKey

    La structure de ces APIs est:
    LONG RegOpenKey(
        HKEY hKey,	// handle of open key 
        LPCTSTR lpSubKey,	// address of name of subkey to open 
        PHKEY phkResult 	// address of handle of open key 
       );	
     
    LONG RegQueryValueEx(
        HKEY hKey,	// handle of key to query 
        LPTSTR lpValueName,	// address of name of value to query 
        LPDWORD lpReserved,	// reserved 
        LPDWORD lpType,	// address of buffer for value type 
        LPBYTE lpData,	// address of data buffer 
        LPDWORD lpcbData 	// address of data buffer size 
       );	
    
    Comme toujours, on regarde sous Wdasm comment le notepad utilise ces APIs et on s'en inspire comme des poètes :o)

    Voilà pour RegOpenKeyA (avec le changement de registre au début)...:
    :00402693 55                      push ebp
    :00402694 8BEC                    mov ebp, esp
    :00402696 83EC40                  sub esp, 00000040
    [...]
    :004026AF 8D4DFC                  lea ecx, dword ptr [ebp-04]
    :004026B2 51                      push ecx
    
    * Possible StringData Ref from Data Obj ->"Software\Microsoft\Notepad"
    |
    :004026B3 6848514000              push 00405148
    :004026B8 6801000080              push 80000001
    
    * Reference To: ADVAPI32.RegOpenKeyA, Ord:0094h
    |
    :004026BD FF15EC624000            Call dword ptr [004062EC]
    :004026C3 85C0                    test eax, eax
    :004026C5 7407                    je 004026CE
    
    Et voilà pour RegQueryValueEx...:
    :004027C8 6A20                    push 00000020
    :004027CA 8D4DDC                  lea ecx, dword ptr [ebp-24]
    :004027CD 682C584000              push 0040582C
    :004027D2 A22B584000              mov byte ptr [0040582B], al
    :004027D7 51                      push ecx
    
    * Possible StringData Ref from Data Obj ->"lfFaceName"
    |
    :004027D8 6850524000              push 00405250
    :004027DD FF75FC                  push [ebp-04]
    :004027E0 E8C5FCFFFF              call 004024AA         
    :004027E5 6A78                    push 00000078
    
    ...dont le call 004024AA renvoie à la procédure.

    On est ici dans la même logique de lecture de la bdr que pour l'écriture. Notre code sera donc assez proche de celui qu'on a fait pour écrire (ne pas oublier de restaurer le changement de registres (du début) à la fin):
    (TEST-REG)
    .0040DB40: 55              push        ebp          ;on arrive directement du PEP et on fait...
    .0040DB41: 8BEC            mov         ebp,esp      ;...le changement de variable de la pile...
    .0040DB43: 83EC40          sub         esp,040      ;...que l'on recalibre
    .0040DB46: 8D4DFC          lea         ecx,[ebp-04] |RegOpenKeyA  
    .0040DB49: 51              push        ecx          |
    .0040DB4A: 6848514000      push        000405148    |
    .0040DB4F: 6801000080      push        080000001    |
    .0040DB54: FF15EC624000    call        RegOpenKeyA  |
    .0040DB5A: 85C0            test        eax,eax      ;si l'ouverture n'est pas faite...
    .0040DB5C: 7539            jne        .00040DB97    ;...on saute à la fin
    .0040DB5E: 6A20            push        020          |Lecture du nom ("Anubis") de la bdr
    .0040DB60: 68A0534000      push        0004053A0    |
    .0040DB65: 8D4DDC          lea         ecx,[ebp-24] |
    .0040DB68: 51              push        ecx          |
    .0040DB69: 6856524000      push        000405256    |
    .0040DB6E: FF75FC          push        [ebp-04]     |
    .0040DB71: E83449FFFF      call       .0004024AA    |
    .0040DB76: 6A10            push        010          ¦Lecture du sérial ("21969") de la bdr
    .0040DB78: 68D0534000      push        0004053D0    ¦
    .0040DB7D: 8D4DDC          lea         ecx,[ebp-24] ¦
    .0040DB80: 51              push        ecx          ¦
    .0040DB81: 6838D84000      push        00040D838    ¦
    .0040DB86: FF75FC          push        [ebp-04]     ¦
    .0040DB89: E81C49FFFF      call       .0004024AA    ¦ 
    .0040DB8E: FF75FC          push        [ebp-04]     |RegCloseKey  
    .0040DB91: FF15E8624000    call        RegCloseKey  |
    .0040DB97: 8BE5            mov         esp,ebp      ;on rechange les registres...
    .0040DB99: 5D              pop         ebp          ;...on remet ebp
    .0040DB9A: 55              push        ebp          |Ici, on remet les instructions
    .0040DB9B: 8BEC            mov         ebp,esp      |écrasées par le jump
    .0040DB9D: 83EC44          sub         esp,044      |au PEP...
    .0040DBA0: E92D35FFFF      jmp        .0004010D2    ;...et on saute juste après notre jump du PEP
    
    Au PEP, la déviation à cette tête là:
    .004010CC: E96FCA0000      jmp        .00040DB40       ;notre jump
    .004010D1: 90              nop                         ;on nop les restes des instructions écrasées 
    .004010D2: 56              push        esi             ;retour de la procédure ci-dessus
    .004010D3: FF15E0634000    call        GetCommandLineA 
    
    Petite analyse du code pour la lecture dans la bdr:

    De DB40 à DB43, j'ai purement recopié le listing Wdasm pour respecter "l'attitude" du soft. Même chose pour RegOpenKeyA, puisque je veux lire au même endroit (dans la même clé) que le notepad.

    Vient ensuite le "test eax,eax" qui s'assure de la bonne ouverture de la clé (si eax=0, je rappelle que l'API renvoie 0 en eax si les choses se sont passées correctement. Sinon on a un chiffre error différent de 0). J'ai par contre transformé le saut en DB5C. Dans le listing Wdasm, il y a un "je" incompréhensible que je passe en "jne", comme je l'ai fait lors de l'écriture de la bdr.

    Puis, on lit la valeur du nom (Name). On passe 0x20 comme longueur max du buffer, tel qu'on l'a fait pour l'écriture. On passe l'adresse du buffer qui reçoit "Anubis" avec 4053A0. Après, je n'ai pas pu comprendre le [ebp-24], alors je l'ai recopié! On passe ensuite le nom de la clé à lire (405256, soit Name), suivi du handle de la clé ouverte et de l'appel au call 4024AA pour RegQueryValueEx.

    Même chose ensuite pour la lecture du sérial où l'on passe dans l'ordre la taille du buffer (0x10), l'adresse du buffer (4053D0), le nom de la clé (Code soit 40D838).

    Les adresses des buffers qui reçoivent le nom et le sérial sont les même utilisées pour l'écriture dans la bdr, et pour la lecture des 2 champs de la REGBOX.

    La fin de la procédure est la même que pour la lecture de la bdr: on rechange les registres, puis on rajoute le code écrasé par notre jump mis au PEP et on saute à l'instruction qui suit ce jump du PEP. Ce jump au PEP est temporaire, et sert uniquement à vérifier que le code marche. En effet, il va falloir vérifier que le code lu dans la bdr est le bon. On devra pour cela retourner au calcul du sérial.

    Un petit traçage sous SI de cette partie de code (avec un bpx RegOpenKeyA) nous montre que les RegMachins renvoient tous 0 en eax, confirmé par un d 4053A0 (pour voir "Anubis") et un d 4053D0 (pour voir "21969"). Ca marche!

    Une fois les informations récupérées de la bdr, on les repasse dans la routine de calcul de sérial et on agit en conséquence. Mais comme on passe par cette routine de calcul quand on vient de la REGBOX, il ne faut pas se mélanger les pinceaux et aiguiller correctement le programme suivant l'origine de notre provenance. Pour clarifier les choses, voici un schéma:



    Je dois avouer que je ne pensais que ça serait un si gros travail au départ, sinon je n'aurais peut-être jamais commencé ;o) Mais avec ce plan de route, on va continuer tranquillement à coder, et vous allez voir que ce n'est pas si sorcier que ça!

    On va utiliser un booléen ou flag ou comme vous voulez :). Quand celui-ci sera à 1, on viendra de la Bdr, et quand il sera à 0 on viendra de la REGBOX. Ainsi, par quelques petits tests et sauts bien placés, on fera faire ce que l'on veut au programme. Maintenant vous pouvez comprendre l'utilité de...:
    .0040DA2B: C605E053400000     mov         byte ptr [0004053E0],00 <-- explication plus tard...
    
    ...qui se trouve dans la routine de calcul du sérial (bien plus haut). Notre flag est en 4053E0, à l'état 01 (Bdr) ou 00 (REGBOX).

    Continuons la suite! A la sortie de la lecture de la bdr, on a donc "Anubis" en 4053A0 que l'on renvoie au début de la routine de calcul du sérial en 40DA26 (après avoir mis notre flag 4053E0 à 1). On reprend la fin du code de lecture de la bdr:
    (Fin de TEST-REG)
    .0040DB8E: FF75FC          push        [ebp-04]         |RegCloseKey  
    .0040DB91: FF15E8624000    call        RegCloseKey      |
    .0040DB97: 8BE5            mov         esp,ebp          ;on rechange les registres...
    .0040DB99: 5D              pop         ebp              ;...on remet ebp
    .0040DB9A: C605E053400001  mov         [0004053E0],001  ;voilà notre flag bdr!
    .0040DBA1: E980FEFFFF      jmp        .00040DA26        ;on saute au calcul du sérial
    
    Il y a ici un point important à ne pas oublier! En déviant ce code sur le calcul du sérial, on arrive avec le nom et le sérial dans 2 buffers différents. ET C'EST TOUT! Vous allez me dire "oui, eh bien alors quoi??". Et bien, si on ne spécifie pas la longueur du buffer nom, le calcul du sérial se fera avec une boucle infinie, et le programme plantera au démarrage... Donc on doit mettre une API lstrlen juste après avoir lu le nom dans la bdr. On passera ensuite la longueur dans le buffer longueur destiné qui est [4053C0].

    La partie changée de TEST-REG ressemble à cela maintenant:
    (Fin de TEST-REG)
    .0040DB71: E83449FFFF          call       .0004024AA        ;retourne le nom "Anubis" de la bdr
    .0040DB76: 68A0534000          push        0004053A0        |renvoie la longueur de ce nom
    .0040DB7B: FF15B0634000        call        lstrlenA         |dans eax
    .0040DB81: A3C0534000          mov         [0004053C0],eax  ;on met eax dans son buffer pour la routine du sérial
    .0040DB86: 6A10                push        010              |début de l'API qui renvoie le sérial de la bdr
    .0040DB88: 68D0534000          push        0004053D0   
    .0040DB8D: 8B4DDC              mov         ecx,[ebp-24]
    .0040DB90: 51                  push        ecx
    .0040DB91: 6838D84000          push        00040D838   
    .0040DB96: FF75FC              push        [ebp-04]
    .0040DB99: E80C49FFFF          call       .0004024AA   
    .0040DB9E: FF75FC              push        [ebp-04]
    .0040DBA1: FF15E8624000        call        RegCloseKey 
    .0040DBA7: 8BE5                mov         esp,ebp
    .0040DBA9: 5D                  pop         ebp
    .0040DBAA: C605E053400001      mov         [0004053E0],001 
    .0040DBB1: E970FEFFFF          jmp        .00040DA26   
    
    De même, pour garder l'aspect "esthétique" des différentes parties, les 2 parties MSGBOX-PEP et -EXITPROC sont décalées d'une ligne vers le bas (dans l'éditeur hexa) et leur jump est recalibré en enlevant 0x10 au 2ème byte de l'instruction (j'èspère que tout le monde me suit :) ).

    Voilà ce que ça donne sous un éditeur hexa:
    0000DB30 5445 5354 2D52 4547 0000 0000 0000 0000 TEST-REG........
    0000DB40 558B EC83 EC40 8D4D FC51 6848 5140 0068 U....@.M.QhHQ@.h
    0000DB50 0100 0080 FF15 EC62 4000 85C0 7539 6A20 .......b@...u9j 
    0000DB60 68A0 5340 008D 4DDC 5168 5652 4000 FF75 h.S@..M.QhVR@..u
    0000DB70 FCE8 3449 FFFF 68A0 5340 00FF 15B0 6340 ..4I..h.S@....c@
    0000DB80 00A3 C053 4000 6A10 68D0 5340 008B 4DDC ...S@.j.h.S@..M.
    0000DB90 5168 38D8 4000 FF75 FCE8 0C49 FFFF FF75 Qh8.@..u...I...u
    0000DBA0 FCFF 15E8 6240 008B E55D C605 E053 4000 ....b@...]...S@.
    0000DBB0 01E9 70FE FFFF 0000 0000 0000 0000 0000 ..p.............
    0000DBC0 0000 0000 0000 0000 0000 0000 0000 0000 ................
    
    Maintenant, il faut mettre les aiguillages :)

    Il y a un changement à faire dans la partie SERIAL-CALC que l'on a déjà codé, et un aiguillage à mettre en début de la partie DESACTIV.

    Pour avoir une meilleure vue d'ensemble, je remets le "plan de route" du sharepad avec les lunettes qui vont bien pour nous faire voir les différentes parties ;o)



    Donc dans SERIAL-CALC, on doit regarder la valeur du booléen/flag en [4053E0] et agir (sauter) en conséquence. On va rajouter 2 instructions juste après le "call lstrcmpa":
    .0040DA67: FF15B8634000                 call        lstrcmpA 
    .0040DA6D: 803DE053400000               cmp         [0004053E0],000  ;notre flag est à 0?
    .0040DA74: 0F85E6010000                 jne        .00040DC60        ;non, donc on vient de la bdr et on va a DESACTIV
    .0040DA7A: 85C0                         test        eax,eax          ;sinon on continue normalement vers...
    .0040DA7C: 7432                         je         .00040DAB0        ;...GOODBOY ou...
    .0040DA7E: 6A00                         push        000
    .0040DA80: 6810D84000                   push        00040D810   
    .0040DA85: 6830D84000                   push        00040D830   
    .0040DA8A: 6A00                         push        000
    .0040DA8C: FF15A8644000                 call        MessageBoxA      ;...msgbox badboy
    .0040DA92: C9                           leave
    .0040DA93: C3                           retn
    
    Puis, toujours pour que le programme fonctionne quand on arrive dans DESACTIV où il n'y a encore rien, on met un jump en 40DC60 vers le PEP.
    .0040DC60: E96D34FFFF                   jmp        .0004010D2
    
    Voilà! Vous pouvez tester le programme, il ne marchera pas tout à fait suivant notre plan car il reste DESACTIV à faire mais ça fait toujours plaisir de voir le résultat du travail jusqu'ici.

    Avant de mettre la partie DESACTIV, j'ai choisi de mettre MSGBOX1-PEP et MSGBOX2-EXIT. Ne sachant pas combien de place allait me prendre DESACTIV, j'ai préféré régler ces 2 msgboxes qui sont toutes petites.
    * MSGBOX1-PEP 
    .0040DBE0: 6A00                         push        000         |Msgbox1 au PEP
    .0040DBE2: 6820D74000                   push        00040D720   |    
    .0040DBE7: 6840D74000                   push        00040D740   |   
    .0040DBEC: 6A00                         push        000         |
    .0040DBEE: FF15A8644000                 call        MessageBoxA | 
    .0040DBF4: 55                           push        ebp         ;instructions écrasées 
    .0040DBF5: 8BEC                         mov         ebp,esp     ;par le jump au PEP
    .0040DBF7: 83EC44                       sub         esp,044     ;
    .0040DBFA: E9D334FFFF                   jmp        .0004010D2   ;on saute juste après notre jump du PEP
    
    MSGBOX1-PEP commence directement à afficher la msgbox, et finit par retourner au PEP après avoir rétabli les instructions écrasées. On arrivera ici depuis la partie DESACTIV (qui se trouve plus bas dans ce tut).

    * MSGBOX2-EXIT
    .0040DC20: 6A00                         push        000          |Msgbox2 au EXITPROCESS
    .0040DC22: 6820D74000                   push        00040D720    |  
    .0040DC27: 6870D74000                   push        00040D770    |  
    .0040DC2C: 6A00                         push        000          |
    .0040DC2E: FF15A8644000                 call        MessageBoxA  ;
    .0040DC34: FF1598634000                 call        ExitProcess  ;
    .0040DC3A: E90A35FFFF                   jmp        .000401149    ;on saute juste après notre jump de l'EXITPROCESS
    
    Pour MSGBOX2-EXIT, c'est exactement la même chose que le sharepad1.

    Voilà le résultat sous un éditeur hexa:
    0000DBD0 4D53 4742 4F58 312D 5045 5090 0000 0000 MSGBOX1-PEP.....
    0000DBE0 6A00 6820 D740 0068 40D7 4000 6A00 FF15 j.h .@.h@.@.j...
    0000DBF0 A864 4000 558B EC83 EC44 E9D3 34FF FF00 .d@.U....D..4...
    0000DC00 0000 0000 0000 0000 0000 0000 0000 0000 ................
    0000DC10 4D53 4742 4F58 322D 4558 4954 0000 0000 MSGBOX2-EXIT....
    0000DC20 6A00 6820 D740 0068 70D7 4000 6A00 FF15 j.h .@.hp.@.j...
    0000DC30 A864 4000 FF15 9863 4000 E90A 35FF FF00 .d@....c@...5...
    
    N'oubliez pas de mettre un saut de déviation à l'EXITPROCESS du notepad en 401143 vers MSGBOX2-EXIT (si vous ne vous rappelez plus comment on fait, jetez un oeil à la partie I de ce tut...).

    On peut également faire les autres restrictions ici. Donc ici, pas très compliqué, on va appliquer les mêmes restrictions shareware que dans la partie I de ce tutorial. Je les remets ici:
    - Menus "Enregistrer" & "Enregistrer sous..." grisés
    - Le mot "Shareware" apparaît dans la barre des titres
    - Une msgbox nous prévient de la version shareware au lancement du notepad
    - Même chose à la fermeture du notepad
    - Menu "Enregistrement" qui appelle notre REGBOX (déjà fait)

    * On grise les menus:

    On fait une copie de sauvegarde du notepad (celui où vous travaillez dessus maintenant!), et on ouvre le programme sous un éditeur de ressources. On grise ET désactive les 2 menus pour enregistrer et on sauve/referme le programme.

    On compare ensuite les 2 fichiers avant/après modifs avec la commande "fc" du DOS:
    Comparaison des fichiers N.exe et N2.exe
    0000C980: 00 03
    0000C99E: 00 03
    
    La messe est dite! On patche ces 2 offsets pour avoir la modification en hard dans l'exe.

    * Shareware dans la barre des titres:

    Il faut trouver la bonne occurrence de "Bloc-notes" dans un éditeur hexa, et la remplacer par "SHAREWARE " (y compris l'espace à la fin). On la trouve à la ligne 8740. Il se peut que cette ligne soit différente pour vous selon l'éditeur de ressources utilisé au début. Mais ça n'est pas grave, avec la recherche vous trouverez la bonne occurrence. Voilà le résultat après modifications:
    00008740 2D00 2000 5300 4800 4100 5200 4500 5700 -. .S.H.A.R.E.W.
    00008750 4100 5200 4500 2000 0000 0000 0000 0000 A.R.E. .........
    00008760 1A00 4900 6D00 7000 6F00 7300 7300 6900 ..I.m.p.o.s.s.i.
    
    Maintenant, on va désactiver les protections shareware que l'on vient de coder. Car on est des utilisateurs officiels ENREGISTRES du notepad. J'en connais qui vont être content à redmond... ;o) Toutes les modifications ci-dessous ont été déjà expliquées à la partie I de ce tutorial.

    * Les MSGBOX-PEP et -EXITPROC:

    On patche le 1er byte de leur call avec 90 et elles seront désactivées. Je les remets ici pour mémoire.
    .0040DBEE: FF15A8644000                 call        MessageBoxA   
    .0040DC2E: FF15A8644000                 call        MessageBoxA 
    
    * SHAREWARE dans la barre des titres:

    On va le remplacer par le mot "Sharepad".

    * Activation des 2 menus grisés:

    Patch inverse de celui que l'on a hard codé, soit 03->00 aux offsets C980 et C99E.

    * Effacement du menu de la REGBOX:

    Même technique que pour les 2 msgboxes. On va patcher par 00 la 1ère lettre du menu "E&nregistrement" soit "E" qui se trouve en CC34.

    0000CC20 6900 7600 6100 6E00 7400 0900 4600 3300 i.v.a.n.t...F.3.
    0000CC30 0000 1000 4500 2600 6E00 7200 6500 6700 ....E.&.n.r.e.g.
    0000CC40 6900 7300 7400 7200 6500 6D00 6500 6E00 i.s.t.r.e.m.e.n.
    0000CC50 7400 0000 0000 8E03 4500 6E00 7200 6500 t.......E.n.r.e.
    Au final, on obtient pour DESACTIV:
    .0040DC60: 85C0                         test        eax,eax                 ;le sérial entré est correct??
    .0040DC62: 0F8578FFFFFF                 jne        .00040DBE0               ;non, alors on jump à la MSGBOX1-PEP, sinon
    .0040DC68: C605EEDB400090               mov         [00040DBEE],090         ;on patche MSGBOX1-PEP
    .0040DC6F: C6052EDC400090               mov         [00040DC2E],090         ;on patche MSGBOX2-EXITPROC
    .0040DC76: C60580C9400000               mov         [00040C980],000         ;on réactive le 1er menu grisé
    .0040DC7D: C6059EC9400000               mov         [00040C99E],000         ;on réactive le 2ème menu grisé
    .0040DC84: C6054687400068               mov         [000408746],068 ;"h"    |on patche (S)"HAREWARE" par (S)"harepad "
    .0040DC8B: C6054887400061               mov         [000408748],061 ;"a"    |
    .0040DC92: C6054A87400072               mov         [00040874A],072 ;"r"    |
    .0040DC99: C6054C87400065               mov         [00040874C],065 ;"e"    |
    .0040DCA0: C6054E87400070               mov         [00040874E],070 ;"p"    |
    .0040DCA7: C6055087400061               mov         [000408750],061 ;"a"    |
    .0040DCAE: C6055287400064               mov         [000408752],064 ;"d"    | 
    .0040DCB5: C6055487400020               mov         [000408754],020 ;" "    |
    .0040DCBC: C60534CC400000               mov         [00040CC34],000         ;on patche la lettre "E" de "E&nregistrement"
    .0040DCC3: 55                           push        ebp                     ¦
    .0040DCC4: 8BEC                         mov         ebp,esp                 ¦instructions écrasées par le jump au PEP
    .0040DCC6: 83EC44                       sub         esp,044                 ¦
    .0040DCC9: E90434FFFF                   jmp        .0004010D2               ;on saute après notre jump sauvage du PEP
    
    Bien évidement, comme on écrit en mémoire dans les sections (.rsrc en fait), il ne faut pas oublier de changer leurs caractéristiques en 0xC00000040 (read + write) sinon l'ordi plante! Cela revient à changer le byte 0x23F (dans le PE header) qui est à 40 en C0.




    Voilà! Voilà! Trois fois voilà! On a fini la phase alpha. Le sharepad est opérationnel. Maintenant on va chercher les petits bugs, ce qui correspond à la phase beta... Je fais mes tests avec la bdr ayant une entrée code et une entrée nom. Peu importe si le code correspond ou pas, mais il y a un cas que je ne connais encore pas: celui ou la bdr est vide au lancement du programme (lecture d'une clé qui n'existe pas). Comme je m'attends à un plantage du programme à ce niveau là, je ferai ce test en dernier.

    Bien en traçant sous SI toutes les routes possibles du schéma général, il y a quelques jumps qui sont décalés de 0x10 bytes dans leur appel (notamment celui de GOODBOY vers DESACTIV). Cela provient des différents déplacements des sections que l'on a fait en rajoutant les aiguillages. De plus, quand on s'enregistre dans la REGBOX avec le bon sérial, celle-ci n'est pas fermée par l'API DestroyWindow (héhé, on devrait l'envoyer à redmond cette API là!). Par contre l'écriture des bonnes informations dans la bdr se fait correctement, et ce même s'il y a déjà des informations erronées.

    Voilà la fin de GOODBOY:
    .0040DB02: 68E0D74000                   push        00040D7E0   
    .0040DB07: 6A00                         push        000
    .0040DB09: FF15A8644000                 call        MessageBoxA 
    .0040DB0F: FF7508                       push        [ebp+08]
    .0040DB12: FF15A0644000                 call        DestroyWindow 
    .0040DB18: 8BE5                         mov         esp,ebp
    .0040DB1A: 5D                           pop         ebp
    .0040DB1B: E9B0000000                   jmp        .00040DBD0  
    
    DBD0 est l'ancienne place (prévue) du début de DESACTIV. Maintenant il y a MSGBOX1 et 2. DESACTIV commence en DC60 avec le "test eax,eax" que l'on a déjà fait juste avant. Donc on peut jumper directement après, soit en DC68.

    Ensuite on remarque qu'une fois les désactivations passées, le programme retourne au PEP et se ferme tout seul. Si on le redémarre, il est en full version. Pour pallier à cette attitude (mon idée était que le programme se patchait en temps réel en mémoire...), on va rajouter une courte phrase dans la msgbox goodboy qui devient "Merci de votre soutien. Relancez le programme.":
    0000D7E0 4D65 7263 6920 6465 2076 6F74 7265 2073 Merci de votre s
    0000D7F0 6F75 7469 656E 2E20 5265 6C61 6E63 657A outien. Relancez
    0000D800 206C 6520 7072 6F67 7261 6D6D 652E 0000  le programme...
    0000D810 4572 7265 7572 2100 0000 0000 0000 0000 Erreur!.........
    0000D820 0000 0000 0000 0000 0000 0000 0000 0000 ................
    
    Et là, l'utilisateur comprend ce qu'il doit faire quand il voit le programme disparaître.

    Pour le handle de la REGBOX, on pourrait comparer le [ebp+08] de la routine de traitement des messages (dans REGBOX en D980) avec celui où je veux fermer la REGBOX. Mais comme le programme se ferme quand on vient de s'enregistrer, on n'a plus besoin de gérer cet événement! Il faut savoir s'adapter et profiter des bonnes surprises :o)

    Donc on change tout ça en (fin de GOODBOY):
    .0040DB02: 68E0D74000                   push        00040D7E0   
    .0040DB07: 6A00                         push        000
    .0040DB09: FF15A8644000                 call        MessageBoxA 
    .0040DB0F: FF7508                       push        [ebp+08]       ;on laisse comme ça finalement!
    .0040DB12: FF15A0644000                 call        DestroyWindow 
    .0040DB18: 8BE5                         mov         esp,ebp
    .0040DB1A: 5D                           pop         ebp
    .0040DB1B: E948010000                   jmp        .00040DC68      ;on ne change qu'ici.
    
    Héhé, notre sharepad a de la gueule maintenant! On va regarder encore un point, celui où on démarre le programme alors que le bdr est vide. Je n'ai pas pris en compte ce point là dans mon codage. On efface les 2 clé "Name" et "Code" de la bdr, puis un petit coup d'oeil sous SI va vite nous donner la réponse de ce qu'il faut faire.
    [quelques instructions sous SI plus tard...(utilisez le loader pour tracer depuis le PEP)]
    
    Héhéhéhé!!! Ca marche nickel! On n'a besoin de rien changer!

    Voilà ce qui se passe:
    On commence par ouvrir la bdr (on a eax=0, donc c'est ok), puis on lit la clé "Name" qui n'existe pas (on se retrouve avec eax=un offset de la pile) et on obtient une longueur de 0xB (chez moi). On lit ensuite la clé "Code" qui n'existe pas (eax=valeur farfelue), et on ferme la bdr (eax=0, donc ok).
    On va ensuite à la routine de calcul du sérial qui dit que les valeurs retournées dans eax pour "Name" et "Code" ne correspondent pas, et on jump après les aiguillages en MSGBOX1-PEP. Tout ce qu'il faut faire !!!

    Une dernière chose cloche encore. Quand on ne rentre rien dans la REGBOX et qu'on valide, le programme plante. En traçant avec un "bpx getdlgitemtexta", on va regarder ça de plus près.
    [quelques instructions sous SI plus tard...]
    
    Bien! La longueur du "nom" (vide) saisi est de 0. Il y aura une boucle infinie lors de l'instruction qui compare ecx et edx dans SERIAL-CALC. Pour y remédier, il faut gérer ce cas en 2 endroits (lecture du nom dans la bdr et lecture du nom dans la REGBOX). Je procède comme cela...:

  • Pour la bdr:
  • (Fin de TEST-REG)
    .0040DB71: E83449FFFF          call       .0004024AA        ;retourne le nom "Anubis" de la bdr
    .0040DB76: 68A0534000          push        0004053A0        |renvoie la longueur de ce nom
    .0040DB7B: FF15B0634000        call        lstrlenA         |dans eax
    .0040DB81: A3C0534000          mov         [0004053C0],eax  ;on met eax dans son buffer pour la routine du sérial
    .0040DB86: 6A10                push        010              |début de l'API qui renvoie le sérial de la bdr
    .0040DB88: 68D0534000          push        0004053D0   
    [...]
    
    ...que l'on transforme en (commentaire sur les lignes ajoutées uniquement):
    .0040DB71: E83449FFFF          call       .0004024AA   
    .0040DB76: 68A0534000          push        0004053A0   
    .0040DB7B: FF15B0634000        call        lstrlenA 
    .0040DB81: 85C0                test        eax,eax          ;eax est nul?
    .0040DB83: 7501                jne        .00040DB86        ;non, alors on saute
    .0040DB85: 40                  inc         eax              ;oui, alors on le passe à 1
    .0040DB86: A3C0534000          mov         [0004053C0],eax
    .0040DB8B: 6A10                push        010
    .0040DB8D: 68D0534000          push        0004053D0   
    .0040DB92: 8B4DDC              mov         ecx,[ebp-24]
    .0040DB95: 51                  push        ecx
    .0040DB96: 6838D84000          push        00040D838   
    .0040DB9B: FF75FC              push        [ebp-04]
    .0040DB9E: E80749FFFF          call       .0004024AA   
    .0040DBA3: FF75FC              push        [ebp-04]
    .0040DBA6: FF15E8624000        call        RegCloseKey 
    .0040DBAC: 8BE5                mov         esp,ebp
    .0040DBAE: 5D                  pop         ebp
    .0040DBAF: C605E053400001      mov         [0004053E0],001 
    .0040DBB6: E96BFEFFFF          jmp        .00040DA26   
    
    
  • Pour la REGBOX (maintenant dans SERIAL-CLAC):
  • .0040D9F7: 6884030000                   push        000000384 
    .0040D9FC: FF7508                       push        [ebp+08]
    .0040D9FF: FF157C644000                 call        GetDlgItemTextA 
    .0040DA05: A3C0534000                   mov         [0004053C0],eax
    .0040DA0A: 6A10                         push        010
    .0040DA0C: 68D0534000                   push        0004053D0   
    .0040DA11: 6885030000                   push        000000385 
    [...]
    
    ...que l'on transforme en (commentaire sur les lignes ajoutées uniquement):
    .0040D9FF: FF157C644000                 call        GetDlgItemTextA 
    .0040DA05: 85C0                         test        eax,eax          ;eax est nul?
    .0040DA07: 7501                         jne        .00040DA0A        ;non, alors on saute  
    .0040DA09: 40                           inc         eax              ;oui, alors on le passe à 1
    .0040DA0A: A3C0534000                   mov         [0004053C0],eax
    .0040DA0F: 6A10                         push        010
    .0040DA11: 68D0534000                   push        0004053D0   
    .0040DA16: 6885030000                   push        000000385 
    .0040DA1B: FF7508                       push        [ebp+08]
    .0040DA1E: FF157C644000                 call        GetDlgItemTextA 
    .0040DA24: C605E053400000               mov         [0004053E0],000 
    .0040DA2B: 33C0                         xor         eax,eax          ;attention! on arrive de la bdr ici (nouvelle adresse)
    .0040DA2D: 33D2                         xor         edx,edx
    .0040DA2F: 33DB                         xor         ebx,ebx
    .0040DA31: 8B0DC0534000                 mov         ecx,[0004053C0]
    .0040DA37: 8A82A0534000                 mov         al,[edx+004053A0]
    .0040DA3D: 8D1C43                       lea         ebx,[ebx+eax*2]
    .0040DA40: 42                           inc         edx
    .0040DA41: 3BCA                         cmp         ecx,edx
    .0040DA43: 75F2                         jne        .00040DA37   
    .0040DA45: 81C321430000                 add         ebx,000004321 
    .0040DA4B: 81F334120000                 xor         ebx,000001234 
    .0040DA51: 53                           push        ebx
    .0040DA52: 689C104000                   push        00040109C   
    .0040DA57: 68F0534000                   push        0004053F0   
    .0040DA5C: FF150C644000                 call        wsprintfA 
    .0040DA62: 68D0534000                   push        0004053D0   
    .0040DA67: 68F0534000                   push        0004053F0   
    .0040DA6C: FF15B8634000                 call        lstrcmpA 
    .0040DA72: 803DE053400000               cmp         [0004053E0],000 
    .0040DA79: 0F85E1010000                 jne        .00040DC60   
    .0040DA7F: 85C0                         test        eax,eax
    .0040DA81: 742D                         je         .00040DAB0   
    .0040DA83: 6A00                         push        000
    .0040DA85: 6810D84000                   push        00040D810   
    .0040DA8A: 6830D84000                   push        00040D830   
    .0040DA8F: 6A00                         push        000
    .0040DA91: FF15A8644000                 call        MessageBoxA 
    .0040DA97: C9                           leave
    .0040DA98: C3                           retn
    
    ...à la suite de quoi, il ne faut pas oublier de recalibrer le jump de TEST-REG qui pointe sur la nouvelle position de "xor eax,eax":
    .0040DBB6: E970FEFFFF                   jmp        .00040DA2B   ;DA26 devient DA2B
    
    Et pour un champs "Nom" vide validé, le sérial sera: 20757



    Voilà! Le sharepad est définitivement fini. Au final, les modifications auront pris un peu moins de 600 Bytes (0.6 Ko) pour le code à rajouter dans le padding de la section .rsrc. L'ajout/modification des ressources ne semble bizarrement pas avoir modifié la taille de l'exe.

    Reverse rulez!

    Si vous avez tenu le coup et tout lu jusqu'ici, ou bien vous êtes arrivé directement ici en utilisant votre souris pour descendre sur la fin de la page ou bien vous êtes fou! ;o) (et moi encore plus que vous d'avoir écris un truc aussi long...). Ah! je me rends compte que je n'ai pas codé le raccourci "Ctrl+T" qu'il y a dans le menu. Bon, ce n'est pas très grave, ça n'apporte rien de plus au sharepad et je suis trop fainéant pour le faire maintenant ;o), donc on oublie!

    Loin de moi l'idée de rajouter du texte à lire pour "rien", mais ce tut de la 2ème partie étant très très long, je mets ici TOUT le source (sauf les chaînes de caractères) avec les offsets et la structure finaux. Si vous avez perdu le fil au-dessus, vous trouverez la version finale complète ici et qui marche! ;o)

    * Détournement au PEP
    
    .004010CC: E96FCA0000                   jmp        .00040DB40   
    .004010D1: 90                           nop
    .004010D2: 56                           push        esi
    .004010D3: FF15E0634000                 call        GetCommandLineA 
    
    
    * Détournement dans la gestion des IDs
    
    Possible Ref to Menu: MenuID_0001, Item: "Couper Ctrl+X"
    |
    :00401288 3D00030000              cmp eax, 00000300
    :0040128D 7C21                    jl 004012B0
    :0040128F E92CC60000              jmp 0040D8C0
    :00401294 0F8E3E040000            jle 004016D8
    
    Possible Ref to Menu: MenuID_0001, Item: "Coller Ctrl+V"
    |
    :0040129A 3D02030000              cmp eax, 00000302
    :0040129F 0F8456040000            je 004016FB
    
    
    * Détournement au EXITPROCESS
    
    .00401143: E9D8CA0000                   jmp        .00040DC20   
    .00401148: 90                           nop
    .00401149: 8BC6                         mov         eax,esi
    .0040114B: 5E                           pop         esi
    .0040114C: 8BE5                         mov         esp,ebp
    .0040114E: 5D                           pop         ebp
    .0040114F: C3                           retn
    
    
    * Mes différentes parties
    
    ID-COMPARAISON
    .0040D8C0: 60                           pushad
    .0040D8C1: 3D8E030000                   cmp         eax,00000038E 
    .0040D8C6: 0F8484000000                 je         .00040D950   
    .0040D8CC: 3D8F030000                   cmp         eax,00000038F 
    .0040D8D1: 0F8439000000                 je         .00040D910   
    .0040D8D7: 61                           popad
    .0040D8D8: 3D01030000                   cmp         eax,000000301 
    .0040D8DD: E9B239FFFF                   jmp        .000401294   
    
    
    MSGBOX5
    .0040D910: 6A00                         push        000
    .0040D912: 6850D84000                   push        00040D850   
    .0040D917: 6870D84000                   push        00040D870   
    .0040D91C: 6A00                         push        000
    .0040D91E: FF15A8644000                 call        MessageBoxA 
    .0040D924: 61                           popad
    .0040D925: E9833FFFFF                   jmp        .0004018AD
    
    
    REGBOX
    .0040D950: 6A00                         push        000
    .0040D952: 6880D94000                   push        00040D980   
    .0040D957: 688C000000                   push        00000008C 
    .0040D95C: 6880060000                   push        000000680 
    .0040D961: 6800004000                   push        000400000 
    .0040D966: FF155C644000                 call        CreateDialogParamA 
    .0040D96C: A390534000                   mov         [000405390],eax
    .0040D971: E9373FFFFF                   jmp        .0004018AD 
    
    et 
    
    .0040D980: 55                           push        ebp
    .0040D981: 8BEC                         mov         ebp,esp
    .0040D983: 817D0C10000000               cmp         [ebp+0C],0010 
    .0040D98A: 750E                         jne        .00040D99A   
    .0040D98C: FF7508                       push        [ebp+08]
    .0040D98F: FF15A0644000                 call        DestroyWindow 
    .0040D995: E92D000000                   jmp        .00040D9C7   
    .0040D99A: 817D0C11010000               cmp         [ebp+0C],000111 
    .0040D9A1: 7524                         jne        .00040D9C7   
    .0040D9A3: 8B4510                       mov         eax,[ebp+10]
    .0040D9A6: 3D89030000                   cmp         eax,000000389 
    .0040D9AB: 750E                         jne        .00040D9BB   
    .0040D9AD: FF7508                       push        [ebp+08]
    .0040D9B0: FF15A0644000                 call        DestroyWindow 
    .0040D9B6: E90C000000                   jmp        .00040D9C7   
    .0040D9BB: 3D88030000                   cmp         eax,000000388 
    .0040D9C0: 7505                         jne        .00040D9C7   
    .0040D9C2: E829000000                   call       .00040D9F0   
    .0040D9C7: C9                           leave
    .0040D9C8: C3                           retn
    
    
    SERIAL-CALC
    .0040D9F0: 6A20                         push        020
    .0040D9F2: 68A0534000                   push        0004053A0   
    .0040D9F7: 6884030000                   push        000000384 
    .0040D9FC: FF7508                       push        [ebp+08]
    .0040D9FF: FF157C644000                 call        GetDlgItemTextA 
    .0040DA05: 85C0                         test        eax,eax
    .0040DA07: 7501                         jne        .00040DA0A   
    .0040DA09: 40                           inc         eax
    .0040DA0A: A3C0534000                   mov         [0004053C0],eax
    .0040DA0F: 6A10                         push        010
    .0040DA11: 68D0534000                   push        0004053D0   
    .0040DA16: 6885030000                   push        000000385 
    .0040DA1B: FF7508                       push        [ebp+08]
    .0040DA1E: FF157C644000                 call        GetDlgItemTextA 
    .0040DA24: C605E053400000               mov         [0004053E0],00 
    .0040DA2B: 33C0                         xor         eax,eax
    .0040DA2D: 33D2                         xor         edx,edx
    .0040DA2F: 33DB                         xor         ebx,ebx
    .0040DA31: 8B0DC0534000                 mov         ecx,[0004053C0]
    .0040DA37: 8A82A0534000                 mov         al,[edx+4053A0]
    .0040DA3D: 8D1C43                       lea         ebx,[ebx+eax*2]
    .0040DA40: 42                           inc         edx
    .0040DA41: 3BCA                         cmp         ecx,edx
    .0040DA43: 75F2                         jne        .00040DA37   
    .0040DA45: 81C321430000                 add         ebx,000004321 
    .0040DA4B: 81F334120000                 xor         ebx,000001234 
    .0040DA51: 53                           push        ebx
    .0040DA52: 689C104000                   push        00040109C   
    .0040DA57: 68F0534000                   push        0004053F0   
    .0040DA5C: FF150C644000                 call        wsprintfA 
    .0040DA62: 68D0534000                   push        0004053D0   
    .0040DA67: 68F0534000                   push        0004053F0   
    .0040DA6C: FF15B8634000                 call        lstrcmpA 
    .0040DA72: 803DE053400000               cmp         [0004053E0],00 
    .0040DA79: 0F85E1010000                 jne        .00040DC60   
    .0040DA7F: 85C0                         test        eax,eax
    .0040DA81: 742D                         je         .00040DAB0   
    .0040DA83: 6A00                         push        000
    .0040DA85: 6810D84000                   push        00040D810   
    .0040DA8A: 6830D84000                   push        00040D830   
    .0040DA8F: 6A00                         push        000
    .0040DA91: FF15A8644000                 call        MessageBoxA 
    .0040DA97: C9                           leave
    .0040DA98: C3                           retn
    
    
    GOODBOY
    .0040DAB0: 55                           push        ebp
    .0040DAB1: 8BEC                         mov         ebp,esp
    .0040DAB3: 83EC04                       sub         esp,004 
    .0040DAB6: 8D45FC                       lea         eax,[ebp-04]
    .0040DAB9: 50                           push        eax
    .0040DABA: 6848514000                   push        000405148   
    .0040DABF: 6801000080                   push        080000001 
    .0040DAC4: FF15F0624000                 call        RegCreateKeyA 
    .0040DACA: 85C0                         test        eax,eax
    .0040DACC: 7541                         jne        .00040DB0F   
    .0040DACE: 68A0534000                   push        0004053A0   
    .0040DAD3: 6856524000                   push        000405256   
    .0040DAD8: FF75FC                       push        [ebp-04]
    .0040DADB: E85249FFFF                   call       .000402432   
    .0040DAE0: 68D0534000                   push        0004053D0   
    .0040DAE5: 6838D84000                   push        00040D838   
    .0040DAEA: FF75FC                       push        [ebp-04]
    .0040DAED: E84049FFFF                   call       .000402432   
    .0040DAF2: FF75FC                       push        [ebp-04]
    .0040DAF5: FF15E8624000                 call        RegCloseKey 
    .0040DAFB: 6A00                         push        000
    .0040DAFD: 68C0D74000                   push        00040D7C0   
    .0040DB02: 68E0D74000                   push        00040D7E0 
    .0040DB07: 6A00                         push        000
    .0040DB09: FF15A8644000                 call        MessageBoxA 
    .0040DB0F: FF7508                       push        [ebp+08]
    .0040DB12: FF15A0644000                 call        DestroyWindow 
    .0040DB18: 8BE5                         mov         esp,ebp
    .0040DB1A: 5D                           pop         ebp
    .0040DB1B: E948010000                   jmp        .00040DC68 
    
    
    TEST-REG
    .0040DB40: 55                           push        ebp
    .0040DB41: 8BEC                         mov         ebp,esp
    .0040DB43: 83EC40                       sub         esp,040 
    .0040DB46: 8D4DFC                       lea         ecx,[ebp-04]
    .0040DB49: 51                           push        ecx
    .0040DB4A: 6848514000                   push        000405148   
    .0040DB4F: 6801000080                   push        080000001 
    .0040DB54: FF15EC624000                 call        RegOpenKeyA 
    .0040DB5A: 85C0                         test        eax,eax
    .0040DB5C: 7539                         jne        .00040DB97   
    .0040DB5E: 6A20                         push        020
    .0040DB60: 68A0534000                   push        0004053A0   
    .0040DB65: 8D4DDC                       lea         ecx,[ebp-24]
    .0040DB68: 51                           push        ecx
    .0040DB69: 6856524000                   push        000405256   
    .0040DB6E: FF75FC                       push        [ebp-04]
    .0040DB71: E83449FFFF                   call       .0004024AA   
    .0040DB76: 68A0534000                   push        0004053A0   
    .0040DB7B: FF15B0634000                 call        lstrlenA 
    .0040DB81: 85C0                         test        eax,eax
    .0040DB83: 7501                         jne        .00040DB86   
    .0040DB85: 40                           inc         eax
    .0040DB86: A3C0534000                   mov         [0004053C0],eax
    .0040DB8B: 6A10                         push        010
    .0040DB8D: 68D0534000                   push        0004053D0   
    .0040DB92: 8B4DDC                       mov         ecx,[ebp-24]
    .0040DB95: 51                           push        ecx
    .0040DB96: 6838D84000                   push        00040D838   
    .0040DB9B: FF75FC                       push        [ebp-04]
    .0040DB9E: E80749FFFF                   call       .0004024AA   
    .0040DBA3: FF75FC                       push        [ebp-04]
    .0040DBA6: FF15E8624000                 call        RegCloseKey 
    .0040DBAC: 8BE5                         mov         esp,ebp
    .0040DBAE: 5D                           pop         ebp
    .0040DBAF: C605E053400001               mov         [0004053E0],001 
    .0040DBB6: E970FEFFFF                   jmp        .00040DA2B 
    
    
    MSGBOX1-PEP
    .0040DBE0: 6A00                         push        000
    .0040DBE2: 6820D74000                   push        00040D720   
    .0040DBE7: 6840D74000                   push        00040D740   
    .0040DBEC: 6A00                         push        000
    .0040DBEE: FF15A8644000                 call        MessageBoxA 
    .0040DBF4: 55                           push        ebp
    .0040DBF5: 8BEC                         mov         ebp,esp
    .0040DBF7: 83EC44                       sub         esp,044 
    .0040DBFA: E9D334FFFF                   jmp        .0004010D2 
    
    
    MSGBOX2-EXITPROC
    .0040DC20: 6A00                         push        000
    .0040DC22: 6820D74000                   push        00040D720   
    .0040DC27: 6870D74000                   push        00040D770   
    .0040DC2C: 6A00                         push        000
    .0040DC2E: FF15A8644000                 call        MessageBoxA 
    .0040DC34: FF1598634000                 call        ExitProcess 
    .0040DC3A: E90A35FFFF                   jmp        .000401149 
    
    
    DESACTIV
    .0040DC60: 85C0                         test        eax,eax
    .0040DC62: 0F8578FFFFFF                 jne        .00040DBE0   
    .0040DC68: C605EEDB400090               mov         [00040DBEE],090 
    .0040DC6F: C6052EDC400090               mov         [00040DC2E],090 
    .0040DC76: C60580C9400000               mov         [00040C980],000 
    .0040DC7D: C6059EC9400000               mov         [00040C99E],000 
    .0040DC84: C6054687400068               mov         [000408746],068 ;"h"
    .0040DC8B: C6054887400061               mov         [000408748],061 ;"a"
    .0040DC92: C6054A87400072               mov         [00040874A],072 ;"r"
    .0040DC99: C6054C87400065               mov         [00040874C],065 ;"e"
    .0040DCA0: C6054E87400070               mov         [00040874E],070 ;"p"
    .0040DCA7: C6055087400061               mov         [000408750],061 ;"a"
    .0040DCAE: C6055287400064               mov         [000408752],064 ;"d"
    .0040DCB5: C6055487400020               mov         [000408754],020 ;" "
    .0040DCBC: C60534CC400000               mov         [00040CC34],000 
    .0040DCC3: 55                           push        ebp
    .0040DCC4: 8BEC                         mov         ebp,esp
    .0040DCC6: 83EC44                       sub         esp,044 
    .0040DCC9: E90434FFFF                   jmp        .0004010D2
    
    
    


    Le Mot de la Fin
    Après tous ces essais et tutoriaux où les protections ont été étudié, cela valait la peine de tenter de refaire ce que l'on a jusqu'ici défait, mais avec la même manière de faire, n'est ce pas?? Je suis persuadé que cet art ou cette science du Reverse Engineering en est juste à son commencement, et qu'une foule de choses merveilleuses sont possibles et vont être réalisée par de nouvelles générations de Reversers. Pour la première fois dans l'histoire, il est possible de créer et de transformer aussi loin que l'imagination le veut. Pouvons nous toujours parler de 'limites' ? Je ne suis pas sur que la réponse soit oui. Le futur le dira.

    J'espère que ce petit essai que j'ai écrit ouvrira aussi des portes dans vos esprits comme cela s'est passé avec moi quand j'ai lu ceux de LaZaRuS et NeuRaL_NoiSE. Nous sommes au début d'une nouvelle ère, c'est de votre ressort de l'explorer et d'aller d'avant. Un petit peu comme dans la Matrice, non ? ;o)

    De même, depuis le temps où j'ai lu/découvert il y a quelques années les essais de LaZaRuS et NeuRaL_NoiSE jusqu'à maintenant, de très bons essais en RE ont été écrit entre temps. Je ne peux pas tous les mentionner, mais mes salutations vont à ces gens là aussi ;o)

    Cet essai a été écris en même temps que je codais les 2 sharepads. Aussi, ne m'en veuillez pas si des passages ont l'air brouillon!

    Vous pouvez me joindre par mail:
    anubis@iname.com ou via le chan IRC de ma team: http://www.Shmeitcorp.tk. Si cette dernière url n'est plus valide, vous nous trouverez certainement à travers un moteur de recherche ;o)

    Ce tutorial a été originellement publié dans le n°5 de nos Mementos (série de cours de crack et de reverse, disponible sur notre homepage) de novembre 2002. Merci à tous les membres de la Shmeitcorp, je ne serai jamais devenu ce que je suis aujourd'hui si je n'avais pas eu la chance d'être accepté dans votre (notre) team!

    Un grand et spécial merci à Christal qui m'a aidé à résoudre un petit point sur lequel je buttais dans la 2ème partie de ce tutorial. Merci également aux membres de la Shmeitcorp pour avoir relu ce tutorial et corrigé mes maladresses ;o) Tout a été fait pour qu'il n'y ait plus d'erreur, mais vu la longueur du tut... je ne garantie rien =)

    A l'attention de LaZaRuS et de NeuRaL_NoiSE: si vous me lisez, merci de me contacter!! Il y a une tonne de choses dont je voudrais discuter avec vous ;o)

    Salutations et remerciements à (sans ordre particulier) :
    Fravia+, LaZaRuS, NeuRaL_NoiSE, +Malattia et Ringzer0, +ORC, +Mammon, +Spath, +Razzia, +Frog's Print, Iczelion, Masta, Tsehp, Carpathia, Crackz, Anarchriz, +Sandman, Zero, Santmat, The_Analyst & The Immortal Descendants, Mr.Philex, Christal, Teeji, Pass Partout, TaMaMBoLo, Lutin Noir, Silversandstorm, Lord Soth, Defiler, Minos et Detten de/et BIW, Chafe de/et TMG, tkc, tous les membres de la Shmeitcorp, mais aussi Iron Maiden, Cacophony, Dimmu Borgir, Ozzy Osbourne, Immortal, Manowar, Naglfar, Graveworm, Lord Belial, Marduk, Dissection, Mystic Circle, Cradle Of Filth et bien plus! ^_^
    Si je vous ai oublié, écrivez moi et je vous rajouterai!

    J'emmerde tout ceux (de la scène et dans la vraie vie) qui pensent qu'ils sont supérieurs aux autres parce qu'ils ont plus de connaissances qu'eux. Ils se reconnaîtront.

    La Sagesse est Mère de tout Savoir.

    Ob Duh
    Ne s'applique pas, non?