CRACKING | Par Nexxt |
L'ASSEMBLEUR - CHAPITRE 2 (1/2)
Introduction
Et c'est parti pour l'assembleur - épisode 2. je rassemble mon cerveau et prend mon courage à deux pattes... en effet, il va m'en falloir, car après les explications de bases, assez facile, et que vous connaissiez sans doute déjà, on va s'attaquer à un gros morceau très important dans la programmation en assembleur, puisqu'il s'agit de la gestion de la mémoire. il est vital de comprendre comment elle est organisée, et comment on y accède efficacement. D'ou le titre: (tain, ça c'est de la transition =)
CHAPITRE 2 - ORGANISATION ET ACCES A LA MEMOIRE
Donc comme je l'ai
dit plus haut, ce chapitre est extrèmement important. Car après
ça, on entrera de plein pied dans la programmation en abordant les variables
et la structure des données, puis dans le chapitre 4, nous commencerons
à apprendre des instructions en plus grosse quantité. Donc je
le souligne bien, il FAUT comprendre ce chapitre.
Pour décrire brièvement ce chapitre, je peux déjà
vous dire qu'il traitera de l'organisation de la mémoire, de la façon
dont le processeur communique avec, les différent régistre des
processeur 80x86, les modes d'adressage de ces processeur, etc... Enfin, nous
verons les premières instructions d'assembleur, liées donc à
la gestion de la mémoire.
I- Les processeurs 80x86
Pour ceux qui n'ont
entendus parlé que de pentium II, ou pentium III, eh bien il faut savoir
que les familles de processeur ce sont succèdé ajoutant leurs
lots d'améliorations, et pas uniquement en matière de rapidité.
Voici les principaux processeur x86: 8088/8086, 80188/80186, 80286, 80386, 80486,
80586/pentium.
Chaque type de processeur a ce qu'on appelle des registres (registers).
Chaque génération étant un amalgame et une amélioration
des précédents. Excepté pour les 8088, 8086, 80188 et 80186,
pour lesquels le registre est indentique. C'est pourquoi quand je parlerai de
8086, il sera en fait question de ces 4 processeurs.
Les régistres ont été classé en trois catégories:
- les régistres
généraux (general purpose resgisters): il sert en général
aux opérations arythmétiques, logiques etc...
- les registres de segments (segment registers): pour accèder aux blocs
de mémoire, appelés... segments
- les registres divers (miscellaneous registers): ils y a deux régistres
spéciaux dont nous parlerons plus tard
II- Le 8086
general purpose registers
Ils y 8 registres généraux de 16 bits pour le 8086: ax, bx, cx, dx, si, di, bp et sp. Bien qu'on puisse les utiliser comme l'on veut, certaines instructions marcheront plus efficacement avec des registre spécifique.
- le régistre ax (Accumulator): il est le plus souvent utilisé pour les calculs arythmétiques et logiques. Bien qu'il soit possible d'utiliser la plupart des autres régistres pour ça, ils sont plus efficace dans le régistre ax.
- le régistre bx (Base): ils sert à stocker les adresses indirectes (que j'expliquerai plus tard).
- le régistre cx (Count): comme son nom l'indique, il compte. Il est le plus souvent utilisé pour compter le nombre d'itération d'un boucle, ou le nombre de caractère dans une chaine.
- le régistre dx (Data): il a deux buts principaux; stocker le dépassement de capacité (overflow) de certaines opérations arythmétiques, et de contenir les adresses d'E/S lors d'un accès à des données.
-les régistres si et di (Source index et Destination Index): comme le régistre bx, ils vont pointer vers des adresses indirects. Ils sont aussi souvent utilisés pour traiter des chaines de caractères
- le régistre bp (Base pointer): il est similaire au régistre bx. Généralement utilisé pour accèder aux paramètres et aux variables locales dans une procédure.
- le régistre sp (Stack Pointer): il est a utiliser avec précautions. En temps normal, vous ne devriez pas utiliser le régistre dx pour le calcul arythmétique. l'execution correcte de la plupart des programmes dépend principalement de la bonne utilisation de ce régistre.
A coté des registres 16 bits, il y a les régistres 8 bits: al, ah, bl, bh, cl, ch, dl, dh. Vous avez sans doute remarqué une similitude avec les régistres 16 bits. En fait, al et ah seront le L.O. byte et le H.O. byte de ax. Il sera sans doute plus facile de comprendre sur le schéma récapitulatif. Il est a noté que les régistres 8 bits ne constituent pas un ensemble de régistre indépendents. En effet, si on modifie la valeur de al, on modifie par conséquent la valeur de ax. Si l'on modifie ax, on modifie à la fois al et ah. En revanche, les régistres si, di, bp et sp ne sont que 16 bits.
Si l'on schématise le régistre général du 8086:
|
|
||||||||
|
|
||||||||
|
|
||||||||
|
|
Segment registers
Il y a quatre régistre de segment: cs, ds, es et ss. Ils sont tous de 16 bits. Ils travaillent à la selection de blocs de mémoire (des segments). Un régistre de segment pointe au début d'un segment de mémoire.
les segments de mémoire du 8086 ne dépassent pas 65536 octets (64 Ko), ce qui a désapointé plus d'un programmeur. Nous verons les problème de cette limitation à 64 Ko plus tard.
- le régistre cs (Code Segment): il pointe vers le segment qui contient l'instruction en cours d'execution
- le régistre ds (Data Segment): il pointe vers une variable globale du programme. Bien que que le segment soit limité à 64 Ko, on peut détourner cette limitation en changeant la valeur de ds en temps voulu.
- le régistre es (Extra Segment): il est exactement à pointer vers ce que son nom indique: un extra-segment. Il est utilisé pour avoir accès à un segment lorsque qu'il est difficile ou impossible de modifier les autres régistre de segment.
- le régistre ss (Stack Segment): il pointe vers le segment qui contient la pile du programme. la pile sert à stocker les informations importante à l'execution du programme, comme l'adresse de retour d'une sous-routine, les paramètre de procédure, les variables locales etc... En général, on ne modifie pas le régistre ss, car trop de choses dans le système dépendent de lui. Bien qu'il reste possible de stocker des données dans le régistre ss, ce n'est jamais une bonne idée.
Miscellaneous registers
Il y a deux régistres spéciaux: ip (Instruction Pointer), et le Flags Register. On n'accède pas à ces régistre comme on fait pour les autres. En général, le processeur les modifie directement, tout seul.
- le régistre ip contient l'adresse de l'instruction en cours d'execution.
- le flag register n'est pas du tout comme les autres régistres. Bien qu'il soit lui aussi de 16 bits, chaque bit s'utilise indépendament. Seulement 9 de ces bits servent. Schéma:
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
1, 2, 3, 4,
11, 13 ,15: ne sont pas utilisés 5: overflow 6: direction 7: interrupt 8: trace 9: sign 10: zero 12: Auxiliary Carry 14: parity 15: carry |
III- Le 80286
Le
80286 ajoute une amélioration principale au 8086: l'execution en mode
protégé. Mais je ne vais pas beaucoup m'atarder sur ce mode. En
effet, il n'interesse que les programmeurs qui codent leurs propre système
d'exploitation ou des programme de bas-niveau. Même si vous écrivez
des logiciels pour des OS en mode protégé comme Unix ou OS/2,
vous ne devriez pas utiliser cette option du 80286. Il faut juste savoir que
des bits additionnels sont utilisé dans le flag register, et que 5 registres
additionnels sont utilisés par les sytèmes d"exploitation
pour supporter la gestion de la mémoire et les processus multiples:
- machine status word (msw)
- global descriptor table register (gdtr)
- local descriptor table register (ldtr)
- interrupt descriptor table register (idtr)
- task register (tr)
IV- Le 80386/80486
Le 80386 a grandement étendu le nombre de régistres, et a aussi étendu la définition des régistres existant Le 80486 n'a pas ajouté de régistre, mais il a défini quelques bits de registres qui restaient inutilisés par le 80386.
- general purpose register: le changement le plus important pour les programmeurs, c'est l'apparition des régistre 32 bits. Le ax, bx, cx, dx, si, di, bp et sp ont été étendu à 32 bits. Le 80386 les appelles respectivement Le eax, ebx, ecx, edx, esi, edi, ebp et esp pour les différencier de leur version 16 bits (les 16 bits restent tout de même utilisables sur le 80386).
- segment register: deux nouveaux régistres de segment ont été ajouté: fs et gs, qui permet au programmeur d'accèder à 6 segments en même temps sans avoir à les recharger. Il est a noter que les registres de segment n'ont pas été étendu à 32 bits.
- miscellaneous register: là aussi, extension de flags et ip en 32 bits. Ce qui donne respectivement les registre eflags et eip. Là aussi, les 16 bits restent utilisables.
Le 80386 a ajouté 4 registres de controle (control register): CR0 -> CR3. Ces régistres étendent le registre msw du 80286. En fait, le régsitre msw est émulé pour une histoire de compatibilité, mais les données apparaissent en réalité dans le régistre CRx. Sur le 80386 et le 80486, ces régistres controlent des fonctions comme la gestion de la mémoire paginée, l'utilisation ou pas du cache, l'opération en mode protégé etc...
8 régistres de débogage ont été ajoutés. les programmes de débogage comme Softice peuvent utiliser ces régistres pour poser des breakpoints quand vous essayez de trouver une erreur dans un programme. Bien que vous n'utiliserez surement pas ces régistres dans vos programmes, vous les trouverez utiles lorsque vous utiliserez des débugger pour trouver une erreur en un temps relativement réduit. Bien sur, les débuggers ne sont utilisables qu'a partir d'un processeur 80386 et supérieur.
Enfin, le 80386 et 80486 ont ajouté une série de régistres de test, qui test le bon fonctionnement du processeur à l'allumage du système. Intel a mis ces régistres pour pouvoir tester les processeur à la sortie de l'usine, mais les programmeur en on tirer parti pour faire des test de mise en route (power-on test).
Si vous vous en tenez à la programmation courante, beaucoup de ces nouveaux régistres vous seront inutiles. En revanche, les extension 32 bits et les extra-registre de segment sont courament utilisés. le schéma suivant vous résume ce qu'il y a à connaitre le plus:
|
|
|||||||||||||
|
|
|||||||||||||
|
|
|||||||||||||
|
|
|||||||||||||
|
|
|||||||||||||
|
||||||||||||||
|
A cause du manque de temps, suite au prochain épisode... (j'en suis sincèrement désolé)
T'es devenu un bon en cracking et tu veux distribuer ton travail? Tu viens de réussir ton premier crack, et tu veux l'immortaliser? Enfin, quelle que soit la raison, t'as surement envie de créer un programme qui va automatiser les changements à faire dans un programme pae exemple. Donc si le seul langage de programmation que tu connaisses c'est le visual basic (ça marche aussi mais bon...), ou que t'en connais aucun d'ailleur, cette page est faite pour toi. Je vais te donner la source que j'ai mise au point et que j'utilise, tout en sachant que ce n'est pas la seule solution. Mais je l'ai trouvée assez simple. je vais donc la détailler et expliquer chaque fonction pour ceux qui ont peu ou pas de connaissances en C++.
Ce dont vous avez besoin
- d'un logiciel
qui intègre l'édition, la compilation etc... style Visual C++
ou Borland C++
- ou d'un éditeur de texte et d'un compilateur sous dos, ça suffit
le code
Pour ceux qui ne connaissent vraiment rien au C++, les phrases entre /* et */ sont des commentaires, donc c'est pas obligatoire. J'ai pris un exemple qu'on a déjà vu dans la partie "techniques": CD-DA Extractor. Si vous avez réussi à suivre les explications jusqu'au bout, vous devez normalement avoir cracké le programme en 15 endroits au moins. Vous n'avez qu'a faire le parallèle en faisant attention aux conversion à faire entre les valeurs hexadécimales que vous avez trouvé, et les valeurs décimales utilisées dans ce code.
#include
"stdafx.h"
#include <stdio.h> /*
header qui va permettre d'utiliser des fonctions dos */
int main() /* Début du programme */
{
char prog[]= "CD-DA
Extractor"; /* déclaration de la variable
qui contient le nom du programme cracké */
char type[]= "Nagscreens"; /*déclaration
de la variable qui contient le type de protection*/
char fichier[]= "cddae.exe"; /* déclaration de la variable qui contient le nom exacte de l'executable à cracker*/
int noff; /*
déclaration de la variable qui contiendra le nombre d'offset à
modifier */
noff = 15; /* affectation
du nombre d'offset à la variable*/
int offsets[15]
= {12179, 20181, 21092, 23623, 23640, 24487, 256172, 256173, 256174,
256175, 256176, 256177, 256178, 256179, 256180};
/*création d'un tableau qui contiendra les offsets, c'est à dire
l'emplacement des données dans le programme. Le plus simple est de les
mettre dans l'odre croissant, sinon vous vous enbrouillerez. ATTENTION: ces
valeurs doivent être en décimal, donc vous devrez surement faire
des conversion avec la calculatrice windows par exemple*/
char opcode[15]
= {116, 116, 116, 116, 116, 116, ' ', ' ', 'N', 'e', 'x', 'x', 't', '
', ' '};
/*déclartion d'un tableau dont le nombre d'entrées (valeur entre
crochet) est égale au chiffre déclaré dans la variable
'noff'. Entre les acolades, vous mettrez les valeurs qui remplaceront celles
du programmes à leur offsets respectives. Par exemple, à l'offset
12179, la valeur originale sera remplacé par celle spécifié,
donc 116. ATTENTION: là aussi les valeurs sont à mettre
en décimal. Ici, 116 en décimal correspond à 74 en héxadécimal.
Il faut savoir aussi qu'on ne traite qu'un octet à la fois, c'est pourquoi
la modification de la barre de titre de CD-DA Extractor qui est un mot, va être
décomposé lettre par lettre, y compris les espaces. Remarquez
que lorsqu'il s'agit de lettre, on doit les mettre entre '. mais on pourrait
aussi mettre leur valeur décimale. Verifiez bien qu'a chaque offset déclaré
dans le tableau précédent il correspond bien la bonne valeur,
sinon le programme ne marchera pas*/
printf(" _______________________________________________
\n");
printf(" | |\n");
printf(" |
TIPIAK - www.tipiak2000.com ou www.tipiak.net |\n");
printf(" |_______________________________________________|\n");
/* affichage à l'écran du nom du groupe avec la commande 'printf'
*/
printf(" \n"); /* le \n sert à
passer à la ligne*/
printf("Crack pour : %s \n", prog); /*affichage
du contenu de la variable 'prog' déclarée plus haut */
printf("Protection : %s \n", type); /*affichage
du contenu de la variable 'type' déclarée plus haut */
printf("Crack par : Nexxt (Nexxt@tipiak.net)\n\n");
FILE *fff; /*utilisation de la structure FILE contenue
dans le header 'stdio', qui servira à travailler avec des fichiers*/
if ((fff = fopen(fichier, "rb+"))
== NULL) {
/*cette ligne regarde si l'ouverture du programme, dont le nom est contenu dans
la variable 'fichier', a réussi.
'rb+' sert à spécifier qu'on veut ouvrir le fichier en lecture/ecriture.*/
printf("\n Le fichier %s n'est pas dans le
repertoire.\n\n\n", fichier);
/* Si le résultat de l'ouverture du fichier est effectivement NULL, cette
ligne s'affiche. Cela arrive dans le cas ou le fichier n'est pas dans le même
répertoire, ou si le nom spécifié plus haut n'est pas le
même que celui de l'executable*/
} else {
printf("Modifications en cours...\n");
/* Si le fichier a bien été trouvé, on affiche cette ligne
*/
char c; /* on déclare une variable de type 'char' */
int i; /* on déclare une variable de type int */
for(i=0; i<noff; i++) {
/* On initialise la boucle qui modifiera un par un les 15 offsets qu'on a déclaré
dans les tableaux */
fseek(fff, offsets[i], SEEK_SET);
/* recherche dans le fichier ouvert, l'offset correspondant à l'entré
'i' du tableau, et y déplace le pointeur */
c = fputc(opcode[i], fff);
/* change la valeur à l'offset en cours */
}
/* fin de la boucle */
printf("Patch OK. Have fun! =)\n\n\n");
}
printf("Vous pouvez nous joindre:\n");
printf("- via notre site: www.tipiak2000.com
ou www.tipiak.net\n");
printf("- sur irc: serveur undernet et channel
#Tipiak\n\n");
printf("En cas de probleme avec ce crack:
Nexxt@tipiak.net\n\n\n");
printf("Appuyer sur enter pour quitter...");
/* affichage du texte de fin */
char d;
d = NULL;
for (d=' '; ;){ /* cette boucle va attendre que l'utilsateur appuie sur 'enter'
pour fermer le programme */
d = getchar();
if (d != NULL) {
return 0;
}
}
return 0; /* fin
du programme */
}
Voilà, ce code marche parfaitement, enfin chez moi du moins. je vous le remet maintenant sans les commentaires:
#include "stdafx.h"
#include <stdio.h>
int main()
{
char
prog[]= "CD-DA Extractor";
char type[]= "Nagscreens";
char fichier[]= "cddae.exe";
int noff;
noff = 15;
int offsets[15]
= {12179, 20181, 21092, 23623, 23640, 24487, 256172, 256173, 256174, 256175,
256176, 256177, 256178, 256179, 256180};
char opcode[15] = {116, 116, 116, 116, 116, 116, ' ', ' ', 'N', 'e', 'x', 'x',
't', ' ', ' '};
printf(" _______________________________________________
\n");
printf(" | |\n");
printf(" |
TIPIAK - www.tipiak2000.com ou www.tipiak.net |\n");
printf(" |_______________________________________________|\n");
printf(" \n");
printf("Crack pour : %s \n", prog);
printf("Protection : %s \n", type);
printf("Crack par : Nexxt (Nexxt@tipiak.net)\n\n");
FILE
*fff;
if ((fff = fopen(fichier, "rb+")) == NULL) {
printf("\n Le fichier %s n'est pas dans le repertoire.\n\n\n", fichier);
} else {
printf("Modifications en cours...\n");
char c;
int i;
for(i=0; i<noff; i++) {
fseek(fff, offsets[i], SEEK_SET);
c = fputc(opcode[i], fff);
}
printf("Patch OK. Have fun! =)\n\n\n");
}
printf("Vous
pouvez nous joindre:\n");
printf("- via notre site: www.tipiak2000.com ou www.tipiak.net\n");
printf("- sur irc: serveur undernet et channel #Tipiak\n\n");
printf("En cas de probleme avec ce crack: Nexxt@tipiak.net\n\n\n");
printf("Appuyer sur enter pour quitter...");
char d;
d = NULL;
for (d=' '; ;){
d = getchar();
if (d != NULL) {
return 0;
}
}
return 0;
}
Evidement, si vous utilisez ce code, vous le laissez pas les références à Tipiak... mais ça je suppose que vous l'aviez compris.
PROTECTION PAR CODE DE SERIALISATION: CRACK DE MIRC 5.51
Pour ceux qui suivent mes cours de cracking assidument (dommage que je n'ai pas énormément de les faire, encore désolé), je vais donc continuer sur ma lancé, en vous proposant un crack très facile. Mais il va vous permettre d'acquérir d'autre méthodes. En plus je sais que vous utilisez tous mIRC pour venir nous voir sur #Tipiak sur les serveurs Undernet.
Logiciel necessaire
-
un desassembleur (w32dasm)
- un éditeur hexadécimal (Hex workshop)
Avant de commencer à chercher
Avant
de commencer à désassembler le programme, il est necessaire de
savoir comment il est protégé. On démarre donc mIRC, et
on tombe sur la fenètre "About". On remarquera par la suite
qu'un fichier d'aide "How to register" apparait après x démarrages.
Maintenant on va chercher comment enrégistrer le logiciel pour ne plus
avoir ces fenètres. Le premier reflexe est d'aller dans le menu "Help".
Il y a souvent un sous-menu "Register", ou un menu "About..."
qui vous remplira la même fonction. Dans notre cas c'est la premère
solution. Ce menu nous donne accès à la fenètre d'enregistrement,
qui nous demande un nom et un code d'enregistrement. Il n'est pas difficile
de comprendre que le code sera généré en fonction du nom.
A ce stade, il est important de commencer à noter quelques informations,
par exemple, le nom de la fenètre d'nregistrement.
Ensuite il faut voir ce qui se passe lorsqu'on entre un mauvais mot de passe.
Dans notre cas, une fenètre d'alerte apparait. On a donc le reflexe de
noter le nom de cette fenètre: "mIRC Registration!", et éventuellement
le texte qu'elle contient: "Sorry, your registration name and number don't
match!" etc...
Le désassemblage
Maintenant
qu'on a un minimum d'informations, on peut désassembler le programme.
Si vous avez suivi mon précédent cour, j'ai déjà
parlé de w32dasm. Je vais pas tout redire. Donc puisque vous avez noté
des nom de fenètre, il va de soit d'aller voir du côté des
'String data reference". Je crois que le plus simple serait d'aller voir
ce qui déclenche l'apparition de la fenètre d'erreur quand on
entre un mauvais code. On va donc chercher une ligne qui contient le nom de
la fenètre d'erreur: "mIRC Registration!", ou du texte qu'elle
contient. Là, c'est une chance, ces deux lignes existent bien: string
Resource ID=01912 et 01913.
Un double click sur la deuxième va vous emmener à sa location
dans le programme. Vous tombez donc sur ça:
*
Reference To: USER32.SendDlgItemMessageA, Ord:0000h
|
:00436E52 E8512C0900 Call 004C9AA8
:00436E57 6A10 push 00000010
:00436E59 6A00 push 00000000
*
Possible Reference to String Resource ID=01912: "mIRC Registration!"
|
:00436E5B 6878070000 push 00000778
:00436E60 E8973AFDFF call 0040A8FC
:00436E65 50 push eax
:00436E66 6A00 push 00000000
*
Possible Reference to String Resource ID=01913: "Sorry, your registration
name and number don't match!
Pleas"
|
:00436E68 6879070000 push 00000779
:00436E6D E88A3AFDFF call 0040A8FC
:00436E72 50 push eax
:00436E73 8B4508 mov eax, dword ptr [ebp+08]
:00436E76 50 push eax
Maintenant qu'on a localisé le code, on va remonter petit à petit pour tomber sur ce qui l'a déclenché. Quelques ligne plus haut, on va tomber sur ça:
*
Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436D81(C)
|
:00436E22 6A00 push 00000000
La première
ligne en vert nous indique que cette partie du code va être appelée
suite à un saut conditionnel, situé à la location 00436D81.
On va donc se rendre à cette location en cliquant sur l'icone "Goto
Code Location" et en mettant la location correspondante.
On tombe évidement sur le saut conditionnel:
:00436D7F 85C0
test eax, eax
:00436D81 0F859B000000 jne 00436E22
jne est l'instruction qui fait que si les conditions ne sont pas réunies (en l'occurence, si le resultat du test n'est pas 1), le saut s'execute, et la suite du programme se fera à la location 00436E22. Ca provoquera donc l'apparition de la fenètre d'erreur. Le but est de faire en sorte que le saut ne s'execute pas quoi qu'il arrive. Ici, la meilleure solution sera de remplacer le code du saut conditionnel (0F859B000000) par 909090909090. L'instruction 90 (nop) n'a aucune action, elle est juste là pour combler les blancs on va dire. On va donc purement et simplement supprimer le saut. Dans w32dasm, on click sur la ligne qui contient l'instruction jne, et on regarde en bas l'offset ou elle se trouve. On démarre ensuite l'éditeur hexa, on edite mIRC.exe, et on va à l'offset qu'on a noté: 36381 (attention, c'est une valeur hexadécimale). A l'endroit ou on atterit, on remplace les 6 opcodes par des 90. On sauvegarde sous un autre nom, old_mirc.exe par exemple, et on lance le programme modifié. On va s'enregister, on met un nom et un numéro bidon, et hourra, ça marche niquel. On joue un peu avec, on quitte le logiciel, on le redémarre le lendemain, et là, fuck, on est plus enrégistré!
Ca veut dire qu'au
démarrage, le logiciel vérifie le numéro qui a été
stocké quelque part, pour voir si il est conforme. Premier reflexe, aller
voir dans la base de régistre pour voir si le code qu'on a entré
n'est pas stocké dedans. Donc on est pas con, on lance une recherche
sur le mot clé "mirc". Et là on tombe sur HKEY_CURRENT_USER\Software\mIRC,
et là on se dit tout de suite que le programmeur devait être troublé
pendant qu'il codait, puisqu'on retrouve les clés "code", "date"
et "name". Cool, tout est donc stocké dans la base de régistre.
On retourne au désassembleur, et on clique sur l'icone "Imports",
qui va lister les API qu'utilise mIRC. Celle qui nous interesse c'est "ADVAPI32.RegOpenKeyA",
qui sert à ouvrir une clé. Elle y est, donc on double click plusieurs
fois dessus, et à un moment, on tombe sur ça:
*
Reference To: ADVAPI32.RegOpenKeyA, Ord:0000h
|
:00493E2A E817550300 Call 004C9346
:00493E2F 85C0 test eax, eax
:00493E31 0F8548010000 jne 00493F7F
:00493E37 C7442404E7030000 mov [esp+04], 000003E7
:00493E3F 8D4C2404 lea ecx, dword ptr [esp+04]
:00493E43 51 push ecx
:00493E44 55 push ebp
*
Possible StringData Ref from Data Obj ->"name"
|
:00493E45 6849254D00 push 004D2549
:00493E4A 8B44240C mov eax, dword ptr [esp+0C]
:00493E4E 50 push eax
*
Reference To: ADVAPI32.RegQueryValueA, Ord:0000h
|
:00493E4F E8F8540300 Call 004C934C
:00493E54 85C0 test eax, eax
:00493E56 0F85A8000000 jne 00493F04
:00493E5C C7442404E7030000 mov [esp+04], 000003E7
:00493E64 8D542404 lea edx, dword ptr [esp+04]
:00493E68 52 push edx
:00493E69 682F834D00 push 004D832F
*
Possible StringData Ref from Data Obj ->"code"
|
:00493E6E 684F254D00 push 004D254F
:00493E73 8B4C240C mov ecx, dword ptr [esp+0C]
:00493E77 51 push ecx
*
Reference To: ADVAPI32.RegQueryValueA, Ord:0000h
|
:00493E78 E8CF540300 Call 004C934C
:00493E7D 85C0 test eax, eax
:00493E7F 7565 jne 00493EE6
:00493E81 6A02 push 00000002
:00493E83 682F834D00 push 004D832F
:00493E88 E8DBA7FAFF call 0043E668
:00493E8D 682F834D00 push 004D832F
:00493E92 55 push ebp
:00493E93 E864FEFFFF call 00493CFC
:00493E98 85C0 test eax, eax
:00493E9A 754A jne 00493EE6
:00493E9C 8B0424 mov eax, dword ptr [esp]
:00493E9F 50 push eax
Comme par miracle,
on retrouve les même mots "name" et "code" que dans
la base de régistre. Cette partie du code se charge donc de lire ces
valeurs pour pouvoir les vérifier après. On sait qu'elle les lit,
puisqu'on a un appelle de l'API ADVAPI32.RegQueryValueA.
Si on regarde un peu la suite du code, on voit qu'il y a 2 saut conditionnels.
Et encore un peu plus loin, on a ça:
*
Reference To: ADVAPI32.RegCloseKey, Ord:0000h
|
:00493EA0 E88F540300 Call 004C9334
:00493EA5 6A00 push 00000000
*
Possible Ref to Menu: MenuID_0017, Item: "Register..."
|
*
Possible Reference to Dialog: DialogID_0033, CONTROL_ID:0085, ""
|
:00493EA7 6885000000 push 00000085
:00493EAC 8B15904A4E00 mov edx, dword ptr [004E4A90]
:00493EB2 52 push edx
* Reference To: USER32.DeleteMenu, Ord:0000h
Ici le code parle de lui même. On a USER32.DeleteMenu, et au dessus, il y a une référence au menu "Register...", ça veut donc dire que ce menu va être effacé. Or il n'est effacé que si le code a été vérifié avec succès. Il ne faut donc pas que les sauts conditionnels qui se trouvent quelques lignes plus s'executent. Mais ayant essayé moi même, je peux vous dire que le premier saut ne s'execute pas. Pour le savoir, il suffit d'essayer. Il faudra donc changer le deuxième. On a ça:
:00493E9A 754A jne 00493EE6
Il faudra changer le 75 en 74, c'est à dire inverser la condition:
:00493E9A 744A je 00493EE6
Maintenant, on peut supposer que c'est à la location 00493CFC que va se trouver la vérification du code, puisqu'il y a un call juste avant le saut et le test. Mais ça on le verra plus en profondeur dans un autre cours. On verra qu'on peut intervenir directement à l'interieur du call, voir même faire ce qu'on appelle du "reverse engineering", pour retrouver l'algorythme qui vérifie le code en fonction du nom, et coder sois même son générateur de code pour mIRC 5.51. Mais ça, c'est pas pour tout de suite... =)
J'ai peut-être été un peu vite sur la fin, mais j'estime qu'à ce stade vous devriez avoir compris de vous même tout ce que je n'ai pas dit, mais qui était assez évident. Dans le cas contraire, reprenez les premiers cours disponibles sur le site.
<<(( NexxT ))>>