Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Contenu
1. introduction
o A quoi sert un débogueur
o Notions nécessaires
2. un petit montage
3. Interface OllyDbg
4. Voies d'approche
5. Remontage
6. Plugins
1. Introduction
Suite à ma ligne de tutoriels destinés à la programmation, je vais aborder un sujet qui
m'intéresse beaucoup et peut-être intéressant pour les programmeurs en général : le
désassembleur et les débogueurs.
Le désassembleur est quelque chose qui peut transformer le langage machine en langage
assembleur, transcrivant les instructions envoyées au processeur à ses mnémoniques en
assembleur (asm). À ne pas confondre avec un décompilateur, qui cherche à convertir le code
natif en un langage de niveau supérieur tel que C, C++ ou Basic.
Les débogueurs sont des programmes capables d'analyser, de déboguer et de tester des
applications. Actuellement, la plupart des IDE de programmation ont un débogueur intégré
(Visual Studio, par exemple). Leur utilisation principale est l'identification et la gestion des
erreurs, car il est possible d'exécuter le code ligne par ligne (ou instruction par instruction) et
d'analyser l'évolution des variables et le comportement du code. Les débogueurs de fichiers
binaires déjà compilés - comme les exécutables Windows (EXE) - suivent le même concept
que les débogueurs normaux, mais comme le code a déjà été compilé, il doit avoir un
désassembleur intégré au débogueur pour décoder les instructions.
Il existe actuellement des dizaines de débogueurs et désassembleurs, parmi lesquels les plus
connus sont : W32DASM, IDA, WinDbg, SoftICE et Ollydbg. Dans ce tutoriel, vous
utiliserez OllyDbg car c'est l'un des meilleurs et des plus puissants débogueurs (y compris un
désassembleur) disponibles sur le marché. C'est aussi petit et gratuit.
2. Un petit montage
Pour déboguer les binaires compilés, il est nécessaire d'avoir une connaissance (au moins
basique) du langage assembleur, car c'est là que le langage machine est traduit.
Assembly (ou asm, pour faire court) est un langage de bas niveau qui interprète
essentiellement les codes opérationnels (opcodes, voir ci-dessous) et les transcrit dans leurs
mnémoniques. C'est littéralement une traduction en langage machine. L'utilisation du langage
assembleur peut être variée et peut faire un peu de tout, mais il est largement utilisé dans la
programmation de base du noyau et dans les algorithmes qui doivent être hautement
optimisés, où asm est le langage idéal, car il s'agit d'un langage purement traduit par machine .
Les opcodes (traduits en code opérationnel ou code d'opération) sont l'instruction envoyée et
interprétée par le processeur. Chaque opcode, lorsqu'il est interprété par le processeur,
effectuera une opération. Les mnémoniques sont les mots ou les combinaisons de lettres
utilisés pour représenter un opcode, rendant le langage machine plus lisible. Voici un exemple
de mnémonique de commande MOV :
MOV EAX,1
Cette commande d'assemblage déplace simplement la valeur 1 dans le registre EAX (nous
verrons cela plus loin dans l'explication des commandes). Lors de la transformation en
langage machine (par un assembleur), cette commande est traduite en un ensemble de
nombres pouvant être interprétés par le processeur :
B801000000
La théorie derrière la traduction des mnémoniques en opcode (et vice versa) est assez
complexe, en particulier pour la plate-forme Intel sur l'architecture IA32. C'est un processus
qui doit être réalisé petit à petit et sortirait un peu du contexte de ce tutoriel.
Pour l'assemblage, l'emplacement des valeurs et des variables est toujours basé sur les
adresses qu'elles occupent en mémoire. Le nom que vous définissez pour une variable lors de
la programmation est remplacé par l'adresse mémoire qu'elle occupe. Chaque instruction a
également une adresse, qui est utilisée pour contrôler le flux et la structure du code. Chaque
fois que vous faites un saut, il est nécessaire d'indiquer l'adresse à laquelle le code doit aller,
comme ce qui s'est passé dans les numéros de ligne des anciens BASIC. Voir un exemple ci-
dessous de ce à quoi ressemblerait un code en C et son résultat compilé en assembleur, en
utilisant uniquement des registres communs :
void main() {
int a = 4;
int b = 6;
int c;
Le code ci-dessus, une fois compilé, peut se transformer en quelque chose de similaire à celui-
ci (une grande partie du code ci-dessus est inutile, je l'utilise juste comme exemple):
Pour comprendre le code ci-dessus, il est nécessaire de comprendre ce qui constitue le langage
assembleur. Il est essentiellement composé de registres, d'adresses et d'instructions
(mnémoniques).
Les bureaux d'enregistrement ont été expliqués dans le chapitre précédent, mais sachons
maintenant qui ils sont. Les processeurs d'architecture Intel 32 bits ont essentiellement neuf
registres 32 bits communs : EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI et EIP.
Théoriquement, chacun de ces registres a une certaine « fonction par défaut », mais en raison
de leur rareté, ils sont souvent utilisés comme registres à n'importe quelle fin. Vous pouvez
créer du code librement en utilisant les huit premiers registres, ce qui ne posera pas trop de
problèmes (tant que vous savez ce que vous faites/modifiez). Le dernier registre, EIP, est
presque toujours conservé intact, car il est chargé de compter les instructions et d'informer
l'adresse de l'instruction suivante.Changer sa valeur peut contourner complètement le flux de
l'application et entraînera probablement un défaut de segmentation ou une opération illégale.
Ces registres présentés sont tous de 32 bits. Cependant, il est également possible de n'utiliser
que 8 ou 16 bits, comme le montre le tableau ci-dessous en utilisant EAX comme exemple (la
théorie est également valable pour les autres registres) :
Pour le cas de la partie à 8 bits, le registre à terminaison L correspond aux 8 bits les moins
significatifs de AX et celui à terminaison H correspond aux 8 bits les plus significatifs de AX.
Pour la partie 16 bits, les 16 bits les moins significatifs de la partie 32 bits sont utilisés.
En plus des registres, il existe également des Flags, qui sont des bits utilisés à la suite
d'opérations (vrai ou faux, par exemple). Ils sont principalement utilisés pour l'analyse
conditionnelle dans des instructions telles que CMP et TEST. Parmi les différents drapeaux,
les plus courants sont : ZF (Zero Flag), CF (Carry Flag) et SF (Signal Flag). Le ZF est défini
chaque fois qu'une opération donne zéro (une comparaison entre deux nombres à l'aide de la
commande CMP soustrait leurs opérandes sans modifier les valeurs et définit le ZF si le
résultat de la soustraction est zéro, indiquant des valeurs égales). Le drapeau CF est
positionné lorsque le résultat d'une opération dépasse la valeur maximale supportée par le
registre/local sans tenir compte du signal (débordement). Enfin, fois SF, qui est défini chaque
fois que le bit le plus significatif d'un opérande est 1,indiquant une valeur négative (recherche
du complément à deux).
Enfin, nous avons les instructions, qui ne sont rien de plus que les opcodes traduits en un
mnémonique, comme démontré et illustré dans quelques paragraphes ci-dessus.
Ci-dessous, je passe en revue une petite liste montrant certaines des instructions les plus
utilisées, car il serait impossible de toutes les mettre (il existe environ 130 instructions de base
pour l'architecture Intel).
Ce sont les instructions les plus courantes dans un binaire compilé. Bien sûr il y en a plus
d'une centaine, mais j'ai essayé de ne mettre ici que ceux qui seront utilisés dans l'application
d'apprentissage. Pour une liste complète avec une explication plus approfondie des opcodes,
je recommande de voir la liste présentée à cette adresse :
http://www.numaboa.com.br/informatica/oiciliS/assembler/referencias/opcodes/
Le prochain chapitre couvrira la partie de l'introduction de l'interface OllyDbg afin que plus
tard nous puissions vraiment nous salir les mains et analyser un binaire.
3. Interface OllyDbg
Après une bonne partie de la théorie, le moment est venu de mettre en pratique ce que nous
venons d'étudier. Dans ce chapitre je vais vous présenter un peu l'interface d'OllyDbg, qui
bien qu'intuitive mérite d'être clarifiée.
Pour notre étude, j'ai créé une application simple que nous déboguerons plus tard. Il est
nécessaire plus haut dans ce chapitre (pas pour le débogage, mais pour présenter les éléments
Olly). Vous pouvez télécharger le fichier exécutable avec son code source (programmé en
assembleur en syntaxe MASM32 en utilisant WinAsm Studio comme IDE) sur le lien ci-
dessous :
http://www.fergonez.net/files/guess.rar
OllyDbg peut être téléchargé gratuitement sur http://www.oldydbg.de . Il est très petit et n'a
pas besoin d'être installé, il suffit d'extraire le contenu dans n'importe quel dossier.
Une fois extrait, ouvrez Olly, allez dans "Fichier->Ouvrir" et ouvrez notre fichier d'étude
(guess.exe). Rapidement Olly interprétera le fichier et affichera le démontage dans la fenêtre
principale. Sautons cette partie plus tard, car le but de ce chapitre est juste de montrer
l'interface, sans déboguer l'application pour l'instant. L'écran devrait ressembler à ceci :
Région 1
Colonne 1 - Adresse. Il nous montre l'adresse virtuelle des instructions (pour en savoir
plus sur cet adressage, voir mon article sur le fonctionnement des exécutables). Vous
remarquerez peut-être que les adresses ne sont pas à intervalles égaux pour chaque
instruction. Cela est dû au fait que la taille des instructions est variable, comme on
peut le voir dans la deuxième colonne.
Colonne 2 - Hex Dump. Ici nous avons le code de l'instruction dans son format
hexadécimal (tous les 2 caractères, nous avons 1 octet). Ces valeurs sont stockées dans
le fichier exécutable et transmises au processeur. Comme mentionné dans le
paragraphe précédent, les instructions varient en taille, l'adresse de l'instruction
suivante étant donnée par l'adresse de l'instruction courante plus la somme des octets
de l'instruction. Voir l'exemple de notre exemple d'application. Il démarre à l'adresse
00401000 (Windows par défaut) et sa première instruction est composée de 2 octets
(6A 00). L'adresse de l'instruction suivante (sur la ligne du bas) sera l'adresse actuelle
plus la taille de l'instruction (00401000+2) = 00401002.
Colonne 3 – Démontage. Cette colonne n'est rien de plus que l'interprétation et la
traduction d'assemblage des instructions présentes dans la deuxième colonne.
L'analyse des applications se fait presque entièrement à l'intérieur de celui-ci.
Colonne 4 – Commentaires. Cette colonne n'influence pas l'application, elle est
uniquement utilisée pour les commentaires et informations. Olly l'utilise pour
identifier les appels de fonction avec leurs arguments (vous pouvez voir qu'il identifie
les appels d'API Windows en rouge et vous montre les arguments, ce qui rend
l'interprétation très facile).
Région 2
Cette zone affiche tous les registres et drapeaux que nous avons vus précédemment (ainsi que
plusieurs autres valeurs). A chaque instruction, cet écran est mis à jour, indiquant l'état actuel
de chaque élément. Si l'un de ces éléments a été modifié d'une instruction à une autre, Olly le
colore avec une autre couleur (dans ce cas, c'est le rouge). Les drapeaux sont affichés juste en
dessous des registres, abrégés par la lettre C (Carry Flag), Z (Zero Flag) et S (Signal Flag)
Région 3
Cette région nous montre la mémoire physique (RAM) allouée à l'application. Vous pouvez
consulter la valeur de chaque octet de mémoire dans l'espace alloué à l'application. Il se
compose de trois colonnes :
Région 4
Affiche l'état actuel de la pile (pile). Comme vu précédemment, la pile est largement utilisée
lors des appels de fonction. VisualBasic est un langage qui utilise beaucoup la pile,
principalement en raison de la quantité de fonctions utilisées par l'application. Il est également
divisé en 3 colonnes :
Colonne 1 - Adresse. Elle remplit le même rôle que les autres colonnes d'adresses.
Notez que l'adresse grandit tous les quatre octets, car chaque position de pile est
occupée par un type DWORD (4 octets)
Colonne 2 – Valeur. Valeur stockée à cette adresse de pile
Colonne 3 – Commentaire. Utilisé pour les commentaires et pour afficher des
informations pertinentes sur cette adresse. Olly identifie divers éléments de la pile
(comme les adresses de retour) et ajoute ces informations dans la colonne des
commentaires.
Après les commandes de débogage de base, nous avons les boutons de la fenêtre :
L – Show Log Window : affiche un journal, dans lequel Olly enregistre certaines
actions telles que le chargement de plugin, etc.
E – Fenêtre Show Modules : affiche tous les modules et fonctions externes utilisés
par le programme (DLL). Avec le menu de droite, il est possible d'accéder à une
gamme d'options au sein de cette fenêtre (il en va de même pour toutes les autres
fenêtres mentionnées). Cette fenêtre de module est très importante pour définir des
points d'arrêt dans les API Windows, ce qui facilite l'approche d'une certaine région du
code.
M – Show Memory Window : affiche l'état de la mémoire utilisée par l'application, y
compris les sections exécutables et les tables d'import/export. Pour une répartition
octet par octet de la mémoire, la région de mémoire physique affichée dans la fenêtre
principale de l'application doit être utilisée.
T – Show Threads : affiche l'état de chaque thread contenu dans l'application. Dans
les applications multi-threading il est possible, à travers cette fenêtre, d'avoir le
contrôle sur chacun des threads.
W – Show Windows : montre la structure et la configuration des fenêtres chargées par
l'application (définies par WinProc). Les données ne sont affichées que lorsque le
programme est en cours d'exécution et doivent être mises à jour manuellement par
l'utilisateur (via le bouton droit de la souris).
H – Afficher les poignées : affiche des informations détaillées sur les poignées
(référence à un objet) utilisées par l'application. Lorsque l'application ouvre un fichier,
elle renvoie un handle, qui sert à lire et à écrire, par exemple.
C – Show CPU : fenêtre standard de l'application, qui s'ouvre automatiquement lors
du chargement de la cible. Son contenu a déjà été expliqué dans les rubriques
précédentes (où les régions étaient numérotées de 1 à 4).
/ - Show Patches : les modifications apportées à l'exécutable sont enregistrées dans
cette fenêtre, facilitant la modification ou le retour à l'instruction d'origine.
K – Show Call Stack : affiche une pile de tous les appels de fonction effectués par
l'application jusqu'à présent.
B – Afficher la fenêtre des points d'arrêt : affiche tous les points d'arrêt définis dans
le programme cible.
R – Afficher les références : affiche toutes les références trouvées lors d'une
recherche (que ce soit une constante, une instruction, une chaîne). Nous verrons plus à
leur sujet plus tard.
... – Run Trace : cette fenêtre affiche le résultat de l'opération de traçage (évoquée
lorsque l'on parle de Trace Into/Over). Le traçage est un processus un peu compliqué,
donc son explication détaillée sera présentée plus tard (vous pouvez trouver une bonne
explication dans l'aide d'Olly).
S – Show Source : lorsque l'application cible est compilée avec des informations de
débogage, normalement le code assembleur résultant est également stocké. Dans ce
cas, cette fenêtre affiche ce code et montre en temps réel l'emplacement dans le code
source d'origine en cours d'exécution. Très utile pour comparer le code assembleur
écrit et compilé.
Ce sont les options contenues dans la barre d'outils. Olly a également un menu traditionnel,
qui contient essentiellement les mêmes fonctions que la barre d'outils. Les plugins sont l'un
des éléments de menu qui méritent d'être mentionnés. Olly prend en charge la création de
plugins, dont certains sont très utiles. Par défaut, ils ne sont livrés qu'avec deux plugins, un
pour les signets et un pour les commandes, qui ajoutent une zone de texte au bas du
programme où vous pouvez entrer des actions et des commandes de la même manière que
SoftICE.
Au pied d'Olly se trouve une petite barre d'état, qui en plus de montrer l'état actuel de la cible
(terminée, en pause ou en cours d'exécution), sert d'information.
4. Façons d'aborder
L'une des plus grandes difficultés du débogage de bas niveau (en assembleur) est d'identifier
où se trouve le morceau de code que vous souhaitez analyser. Il y a plusieurs façons d'arriver
au bon endroit, et je vais mentionner deux des plus utilisées.
La première consiste à rechercher et rechercher des chaînes. Dans la plupart des cas, tout le
texte présent dans une application est stocké dans une table de chaînes (string table), chacune
avec son numéro d'identification. Habituellement, c'est le compilateur qui décide de ce qui
entre dans la table de chaînes ou de ce qui est référencé directement dans le code. Cette
méthode n'est donc pas toujours entièrement fonctionnelle, mais elle donne généralement de
bons résultats.
D'accord, mais quelles chaînes devons-nous rechercher ? Ce que nous voulons, c'est trouver
l'endroit où le nombre entré est comparé au nombre correct. Si le numéro n'est pas celui que
vous avez entré, il affichera un message contenant un titre et du texte. C'est assez intéressant,
car la logique probable du programme est de vérifier le nombre entré et s'il est incorrect,
montrez-nous la MessageBox. Si nous trouvons l'emplacement où le texte est utilisé par la
MsgBox, nous savons que nous sommes proches et un peu en avance sur l'endroit où la
vérification a été effectuée.
Il existe un moyen assez simple de savoir où se trouve l'appel à la MsgBox, mais je vais me
concentrer davantage sur le système de recherche de chaînes. Allez. Entrez n'importe quelle
valeur (supérieure à 0 et inférieure à 21) et faites-la vérifier. Vous avez probablement reçu un
message similaire à celui-ci :
Notez qu'il se compose d'un titre et d'un texte. Que diriez-vous de vérifier s'il est possible de
rechercher ces textes dans OllyDbg. Pour cela, dans la fenêtre principale, lors du démontage
du code, cliquez avec le bouton droit et allez dans « Rechercher -> Toutes les chaînes de
texte référencées » . Cela fera qu'Olly affichera une fenêtre contenant toutes les chaînes
référencées par une commande dans le code. Notez que trois éléments apparaissent dans le
contenu de la fenêtre :
Nous pouvons voir que nous avons trois références au texte du message, se produisant à
différentes adresses. « Intéressant » la chaîne « Message ». est le titre du message texte que
nous avons reçu lors de la saisie d'une valeur erronée. Cela signifie que nous avons trouvé 3
endroits possibles où la zone de texte est affichée. Un moyen simple de savoir lequel des trois
est vrai (nous verrons plus tard qu'aucun d'entre eux n'est réellement « faux », ce sont juste
des messages texte différents) consiste à définir un point d'arrêt chaque fois que le message
texte est référencé. Pour ce faire, cliquez avec le bouton droit sur l'une des lignes et
sélectionnez "Définir un point d'arrêt sur chaque commande" . Chaque fois que le
message est utilisé, Olly suspendra l'exécution et vous montrera où l'exécution a été gelée.
Avec le point d'arrêt défini, il suffit de ressaisir le numéro dans l'application de test (sans
fermer ni redémarrer Olly). Dès que vous cliquez sur le bouton, au lieu d'afficher le message
de mauvais numéro, Olly suspendra l'exécution et vous montrera l'emplacement où la
référence de texte a été utilisée. Vous auriez dû vous arrêter ici (ligne marquée en gris) :
Par curiosité, notez que nous avons 3 appels à la fonction MessageBox. Par le texte de
chacun, il est possible d'identifier que le premier fait référence au texte lorsque vous appuyez
sur le chiffre, le second (ce que nous sommes) est lorsque vous faites une erreur et le dernier
est pour lorsque vous entrez une valeur en dehors du plage spécifiée. Cela explique aussi le
fait que nous ayons trois références à la chaîne "Message.", telle qu'elle est utilisée par les
trois appels.
Comme mentionné précédemment, cette méthode nous fait converger vers un emplacement
au-delà de celui où la comparaison a été effectuée (puisque le message texte n'est affiché
qu'une fois la valeur vérifiée). Pour trouver la comparaison à partir de l'emplacement actuel,
plusieurs méthodes peuvent être utilisées. Certains préfèrent simplement analyser le code au-
dessus de la MsgBox « à la main » ou faire un backtrace, qui consiste à analyser le code asm
en sens inverse. Comme cette application est très petite, il est facile de trouver l'emplacement
par la force, mais je vais vous donner un aperçu du backtracing. Olly a heureusement
plusieurs fonctions qui aident à interpréter le code, et nous allons utiliser des références de
saut pour cette situation. Pour accéder au message texte, un saut a probablement été fait, car la
logique probable serait :
Savoir où le saut a eu lieu nous rapproche encore plus du lieu de comparaison. Étant donné
que le saut a été effectué pour afficher le message texte, la destination la plus probable du saut
est lorsque les données du message texte commencent à s'accumuler. Sélectionnez la ligne
juste au-dessus de la ligne actuelle, qui a la commande PUSH 0 (première valeur placée sur la
pile). Notez qu'Olly identifie cet emplacement comme étant la cible d'un saut (voir en bas de
la zone de démontage) :
En gros, cela vous dit que pour arriver à l'emplacement actuel, un saut a été effectué à
l'adresse 00401061. Nous pouvons aller à cet endroit et vérifier si ce saut existe vraiment.
Faites un clic droit sur cette ligne (à l'adresse 00401079) et allez dans « GoTo -> JNZ from
00401061 » . Cela nous mènera directement au site de saut :
Nous avons été conduits à l'adresse 00401061 où il y a vraiment un saut (JNZ SHORT
devinez quoi.00401079) et nous sommes probablement assez proches du site de comparaison.
Nous le sommes vraiment. Analysez les lignes qui précèdent le saut. Nous avons un appel à la
fonction GetDlgItemInt (récupère un entier contenu dans un élément de fenêtre, qui dans ce
cas est une zone de texte) et le stocke dans EAX (c'est la valeur par défaut, chaque retour de
fonction est dans EAX). Ensuite nous avons :
Je crois que vous avez déjà compris ce qui se passe. Il vérifie d'abord que le nombre saisi est
dans la plage (20 >= X >= 1). S'ils sont à portée, aucun saut n'a été effectué, il continue donc à
courir. Juste après la comparaison de la valeur entrée avec le nombre 4, et si elles sont
différentes, le programme saute au message texte dans lequel nous nous trouvions plus tôt.
Que diriez-vous d'essayer de mettre le chiffre 4 dans la zone de texte du programme d'études
et de voir le résultat ? Bingo, on retrouve le lieu de comparaison et par conséquent, le numéro
avec lequel on compare la valeur saisie.
Ce code asm serait essentiellement généré par une structure similaire à celle-ci, dans un
pseudocode :
Se X = 4 Então
Exibe mensagem de texto “Parabéns”;
Caso Contrário
Exibe mensagem de texto “Você Errou”;
Fim Se
C'est l'un des moyens de trouver des extraits de code dans un débogueur. Il est utilisé par
beaucoup de gens, et cet exemple que j'ai présenté est un « classique ». Un autre moyen,
beaucoup plus direct, mais qui nécessite une connaissance de l'API Windows est de
rechercher les appels de fonction de l'API Windows.
En supposant que l'utilisateur ait une certaine expérience de la programmation (que ce soit en
asm ou en C), il connaît probablement certaines fonctions de Windows car elles sont
nécessaires à toute application visuelle. Comme la logique de ce programme est basée sur la
recherche et la comparaison de données saisies dans une zone de texte, un utilisateur
connaissant déjà un peu l'API sait qu'il est nécessaire d'utiliser une fonction Windows pour
effectuer ce processus. Les deux fonctions les plus connues qui obtiennent des données à
partir de contrôles sont : GetDlgItemText et GetDlgItemInt .
Olly a une fenêtre qui montre toutes les fonctions utilisées par le programme, nous pouvons
donc vérifier si l'une de ces deux fonctions existe dans l'application cible. Pour cela, cliquez
sur le bouton E (ou utilisez le raccourci ALT+E) pour ouvrir la fenêtre des modules. Vous
aurez une brève liste, contenant le programme lui-même dans la première ligne et les DLL
dépendantes dans les autres. Cliquez sur la ligne qui contient notre application (devinez quoi)
et allez dans "Afficher les noms" . Cela affichera une liste de toutes les fonctions utilisées
par l'application.
Notez que la fonction GetDlgItemInt a été utilisée, comme nous le recherchions. Pour savoir
où il est utilisé, vous pouvez utiliser la même méthode que précédemment, en cliquant avec le
bouton droit et en sélectionnant « Définir un point d'arrêt sur chaque référence ». Ensuite,
continuez simplement à exécuter le programme, tapez un nombre et cliquez sur le bouton.
Lorsque la cible est d'appeler la fonction, Olly se fige et affiche l'endroit où l'appel sera
effectué, qui se trouve juste au-dessus de l'endroit où la vérification est effectuée, comme
nous l'avons vu précédemment.
Cela nous emmène généralement dans une région beaucoup plus proche et avant la
vérification. En utilisant les références, vous pouvez être emmené dans un endroit bien
au-delà, nécessitant beaucoup de retour en arrière.
Certaines références de texte n'apparaissent pas dans la liste des tables de chaînes, ce
qui rend cette méthode plus pratique.
Il ne repose pas sur les SMS ou MessageBox, qui ne sont pas toujours présents dans
toutes les applications.
5. Remontage
Olly, en plus d'être un excellent débogueur, est un excellent assembleur. Il est également
possible d'éditer du code en temps réel et d'observer les changements de comportement.
Toutes les modifications que vous apportez au code sont déjà enregistrées dans la fenêtre
« Afficher les correctifs » ( /). Voyons maintenant comment nous pouvons modifier le code
et réenregistrer notre exécutable (très utile pour la correction de bogues).
Rouvrez notre dossier sur Olly, s'il est fermé. Dans les chapitres précédents, nous avons
discuté un peu du fonctionnement de notre application de test, nous allons donc maintenant y
apporter une petite modification afin qu'elle affiche toujours le message « Vous avez bien
compris ».
Nous avons eu une séquence de comparaisons suivie de leurs sauts respectifs. Le premier
vérifiait si le nombre était inférieur à 1, le deuxième s'il était supérieur à 20 et le troisième s'il
était lui-même le nombre caché (4). Il existe plusieurs façons de faire en sorte que le nombre
soit toujours juste. Je vais en lister quelques-uns :
Il existe également d'autres moyens, mais restons-en avec ces trois car ils sont les plus
évidents. Je vais utiliser la dernière méthode de ce tutoriel pour illustrer le processus.
Ce que nous allons essentiellement faire, c'est forcer un saut juste après la fonction
GetDlgItemInt directement vers la région qui appelle notre message texte « You got it
right... », comme le montre l'image ci-dessous :
Pour modifier le démontage, il suffit de cliquer sur la ligne que vous souhaitez modifier et
d'appuyer sur la touche "Espace" . Cela ouvrira une fenêtre avec un emplacement où vous
pourrez indiquer l'instruction que vous souhaitez placer dans l'emplacement.
Notre objectif ici est de remplacer le CMP EAX, 1par un saut inconditionnel à l'endroit où nos
arguments de message texte commencent à être sélectionnés (non PUSH 0, situé à l'adresse
0x00401063).
Cliquez sur la ligne qui contient le CMP EAX, 1(dans l'adresse 0x00401054) et appuyez sur «
Espace » . La fenêtre suivante s'ouvrira :
La zone de texte est l'endroit où vous entrez l'instruction d'assemblage que vous souhaitez
remplacer. Si l'instruction que l'on insère est plus petite (en octets) que l'instruction
précédente, Olly remplace ces octets restants par l'instruction NOP, qui n'effectue aucune
opération, évitant ainsi les restes et les « indésirables » de la commande précédente (dans le
cas de le " Fill with NOP's " est sélectionné, bien sûr).
Modifiez le CMP EAX, 1par JMP 00401063, comme indiqué sur la figure :
Cliquez ensuite simplement sur Assembler pour confirmer la modification. Vous avez peut-
être remarqué qu'Olly a coloré en rouge ce qui a été modifié. Notez également qu'il a inséré
une commande NOP après le saut, indiquant que notre code opération de saut était 1 octet
plus petit que la commande précédente.
Vous pouvez exécuter notre application dans Olly et observer le changement. Maintenant,
quelle que soit la valeur que vous entrez (même celles hors limites), le programme affichera le
message que nous voulions.
Comme mentionné précédemment, toutes les modifications sont stockées dans la fenêtre de
patch, accessible en cliquant sur le bouton \ou via le raccourci CTRL+P. Pour basculer entre
l'instruction modifiée et l'instruction d'origine, sélectionnez simplement la modification
souhaitée dans la fenêtre des correctifs et appuyez sur "Espace" (ou via le bouton droit ->
"Restaurer le code d'origine" ).
Enregistrer le nouvel exécutable est très simple. Dans la fenêtre de démontage, faites un clic
droit et allez dans "Copier dans l'exécutable -> Toutes les modifications" . Une petite
fenêtre s'ouvrira vous demandant si vous souhaitez copier le code modifié. Sélectionnez
« Tout copier » . Une nouvelle fenêtre, contenant tout le code modifié, s'affichera. Faites un
clic droit dessus et sélectionnez "Enregistrer le fichier" . Choisissez simplement
l'emplacement et vous aurez un nouvel exécutable, contenant la modification apportée.
6. Plugins
IDAFicator
Auteur : AT4RE
Version : 1.2.12
Téléchargement :
http://www.at4re.com/tools/Releases/Zool@nder/IDAFicator/IDAFicator_1.2.12.zip
L'un des meilleurs plugins jamais créés pour Olly. Il apporte à OllyDbg de nombreuses
fonctionnalités et fonctionnalités disponibles dans IDA (Interactive Disassembler)
dépotoir olly
Auteur : Gigapede
Version : 2.21
Téléchargement : http://www.openrce.org/downloads/download_file/108
Plugin extrêmement utile lorsque l'on travaille avec une décompression exécutable, dans
laquelle il est nécessaire d'effectuer un vidage de processus en mémoire (récupérer les
données de la mémoire et les jeter sur le disque, simplement). Cela fonctionne très bien avec
ImpRec (Import Reconstructor), qui réaligne à nouveau l'ensemble de l'exécutable.
ollyscript
Auteur : SHaG
Version : 0.94
Téléchargement : http://www.openrce.org/downloads/download_file/106
Indispensable. Avec ce plugin, vous pouvez exécuter des scripts à l'intérieur du débogueur,
automatisant plusieurs processus et vous faisant gagner du temps. Il est facile de trouver des
sites contenant des centaines de scripts, mais je recommande celui-ci :
http://www.tuts4you.com/download.php?list.53
OllyPerl
Une autre façon d'automatiser Olly, en écrivant des scripts en langage Perl. Pour utiliser le
plugin, vous devez avoir installé ActivePerl.
Barre de commande
Auteur : Gigapede
Version : 3.00.108
Téléchargement : http://www.openrce.org/downloads/download_file/105
Quiconque a utilisé le bon vieux (et malheureusement éteint =()) SoftICE aimera certainement
ce plugin. C'est une zone de texte dans laquelle vous pouvez pratiquement contrôler Olly
grâce à des commandes qui suivent la même syntaxe utilisée dans SoftICE (bpx , bd, cpu,
etc).
Auteur : arjuns
Version : 0.3
Téléchargement : http://tuts4you.com/request.php?84
Avec ce plugin, vous pouvez ajouter des éléments à la barre d'outils d'OllyDbg. Très bon pour
mettre des raccourcis vers le Bloc-notes, la calculatrice, l'éditeur hexadécimal, l'éditeur de
ressources. De cette façon, vous n'avez pas à perdre de temps et à naviguer jusqu'au dossier
(ou menu Démarrer) où se trouvent les applications. Je le recommande fortement.
OllyFlow
Auteur : henryouly
Version : 0.1
Téléchargement : http://www.openrce.org/downloads/download_file/178
Peut-être l'un des plugins les plus intéressants. OllyFlow génère des graphiques et des
organigrammes de démontage pour faciliter l'identification et l'interprétation du flux applicatif
(fonctionnalité présente dans IDA).
Pour l'instant, ce sont. Plus tard, j'ajouterai des plugins et laisserai un avis ici dans ce sujet,
vous informant de la mise à jour.
Je vais profiter de ce sujet pour mettre mon jeu de couleurs que j'ai créé et utilisé dans Olly.
Pour l'utiliser, modifiez le fichier ollydbg.ini en ajoutant les entrées suivantes (vérifiez la
bonne section et remplacez l'astérisque par l'index souhaité) :
[Colours]
Scheme
[*]=0,12,8,18,7,8,7,13
Scheme name
[*]=Fergo
[Syntax]
Commands
[*]=15,4,10,10,9,10,112,13,111,8,12,0,0,0
Operands
[*]=1,11,11,11,2,2,4,4,0,0,0,0,0,0
Scheme name
[*]=Fergo
Le programme que je vais utiliser dans ce tutoriel est extrêmement simple, réalisé en
assembleur et compilé en MASM32. Le code est inclus avec l'exécutable (mais ne regardez
pas le code avant d'avoir terminé ce tutoriel).
-Télécharger fergo_ex1.zip
Tout d'abord, nous avons besoin de quelque chose qui transforme notre exécutable en un
langage que les êtres humains peuvent comprendre (ou au moins essayer). Pour cela, vous
avez besoin d'un débogueur ou d'un désassembleur. Dans ce tutoriel, je vais utiliser l'un des
débogueurs les plus complets actuellement (l'un des plus célèbres également), pour avoir une
interface plus visuelle et être un freeware : OllyDbg
Au démarrage d'Olly vous obtiendrez un écran similaire à celui-ci (les couleurs peuvent varier
selon la configuration de l'utilisateur)
Ouvrons ensuite notre exécutable pour analyser votre code (en langage machine, assembleur (
asm )). Allez dans "Fichier->Ouvrir" et sélectionnez "fergo ex1.exe". Parce qu'il s'agit d'un
petit exécutable, il s'ouvre instantanément et contient peu de lignes de code efficaces. Vous
aurez quelque chose comme ça :
Combien, non ? Mais ne vous inquiétez pas, avec le temps, vous deviendrez plus familier.
Dans la fenêtre principale (en haut à gauche), vous avez 4 colonnes : Adresse, Hex Dump,
Désassemblage, Commentaire. L'adresse contient l'adresse de chaque instruction, c'est par
cette adresse que vous déterminerez les sauts (sauts), appels (appels), etc...
Hex Dump est l'instruction au format hexadécimal (peu importe maintenant). Le démontage
est le même que Hex Dump, mais "traduit" en paroles, pour ainsi dire. Les commentaires
n'ont rien à voir avec le code, ils permettent juste d'identifier quelques éléments (appels de
fonction par exemple).
Comme le code est petit, je vais numéroter les lignes pour que nous puissions commencer
notre "debug"
Ligne 1 : SUB EAX, EAX SUB indique une opération de soustraction, suivie de ses 2
arguments. EAX est un registre, un lieu de stockage temporaire de données, où les valeurs
sont normalement placées à des fins de comparaison, etc. Cette commande, plus précisément,
met dans son premier argument, la soustraction d'elle-même avec le deuxième élément,
quelque chose comme "EAX = EAX - EAX". Oui, c'est zéro (c'est l'un des moyens de mettre
à zéro une valeur dans ASM).
Je vais sauter les lignes 4, 5 et 6 pour ne pas tuer l'énigme dès le départ. on parlera d'elle plus
tard
Ligne 10, 11, 12 : PUSH ... fait la même chose que la ligne précédente, en changeant
simplement son argument. Il tirera la variable EAX, EBX puis à nouveau un 0.
Bon, le programme se termine ici. Mais qu'en est-il de mon message caché, où est-il ?
Réanalysez le code. Notez qu'aux lignes 7 et 8, vous définissez des valeurs pour l'EAX et
l'EBX, puis vous appelez une fonction qui place ces 2 registres en tant que texte et titre du
message. Il est maintenant clair que ces 2 lignes mettent le titre et le texte du message dans les
registres. Notez maintenant les lignes 4 et 5. Nous avons également 2 LEA qui font à peu près
la même chose. Eh bien, dans ces 2 lignes, il doit attribuer le message caché à EAX et EBX,
mais pourquoi ne le fait-il pas ? Voyez qu'à la ligne 3, il effectue un saut si la condition est
vraie (c'est ce qui se passe, vous vous souvenez ?). Au fur et à mesure que le saut se produit, il
ne passe même pas par ces 2 lignes pour pouvoir attribuer le message secret. Maintenant,
pensez à ce que vous pourriez faire pour le faire passer par ces 2 lignes de code ? Bon,il existe
plusieurs alternatives, mais il vous vient probablement à l'esprit de simplement supprimer ce
saut de la ligne 3 ou de l'inverser, de sorte que si la condition n'est PAS vraie, il effectue le
saut (le saut ne se produira jamais, car la comparaison de 0 avec 0 sera toujours vrai).
On va "supprimer" ce saut, car c'est plus simple (en fait le travail est le même :P ). Vous ne
pouvez pas "supprimer" une ligne, car cela changerait l'adresse de toutes les instructions et le
programme cesserait de fonctionner. Heureusement, il existe la commande "NOP" ( No
OPERAtion ), qui "annule" la ligne sans changer aucune adresse. Pour cela, faites un clic
droit sur la ligne 3, allez dans "Binaire->Remplir avec les NOP". Là, tu as annulé le saut.
Notez qu'il va maintenant atteindre la ligne 3 et continuer son chemin, sans sauter. Il
attribuera une valeur à l'EAX et à l'EBX (probablement notre message caché), puis il sautera
simplement (JMP, ligne 6) à l'adresse 00401015 (00401021 après le changement), qui est
exactement là où il commence à extraire des valeurs pour le MessageBoxA appel de fonction
(notez qu'en faisant cela, cela empêche les valeurs de message d'origine d'être réaffectées à
EAX et EBX).
Et si vous testiez ce que nous avons fait ? Faites un clic droit sur n'importe quelle ligne, allez
dans "Copier dans l'exécutable->Toutes les modifications" puis "Copier tout". Une nouvelle
fenêtre s'ouvrira. Faites à nouveau un clic droit dessus, sélectionnez "Enregistrer le fichier" et
enregistrez votre fichier modifié.
D'accord, exécutez maintenant votre fichier nouvellement enregistré et vous verrez que le
message secret était "Félicitations, vous l'avez trouvé !".
J'espère avoir donné le coup d'envoi à ceux qui ne savaient pas par où commencer ou ne
connaissaient pas la signification des instructions de montage de base.
F3rGO !
-Télécharger : fwdv2.zip
Allez. Avant de démarrer Olly, lancez le programme, entrez n'importe quel code et cliquez sur
'S'inscrire'. Euh, le message de Wrong Code est apparu. Ceci, assez curieusement, est bon,
pour plusieurs raisons, dont 2 :
1) Le message apparaît dans une MessageBox (qui est un appel API). Nous pouvons localiser
la région où le code correct est calculé en plaçant un point d'arrêt à tous les endroits où un
appel à la fonction MessageBoxA est effectué
2) Grâce à ce message "Wrong Code", nous pouvons également trouver le bon endroit en
voyant où il est utilisé (probablement en conjonction avec la MessageBox).
Passons à la deuxième méthode. Démarrez Olly et ouvrez notre cible. Le code est très petit,
peu de lignes. Bon pour nous. Cliquez avec le bouton droit sur la fenêtre principale, allez dans
"Rechercher -> Toutes les chaînes de texte référencées". Une nouvelle fenêtre s'ouvrira
montrant tous les textes utilisés dans le programme. Tout de suite, vous trouvez déjà le
message "Désolé, mauvais code". Mais voir ci-dessous. Il y a un message « Succès ! Merci
d'avoir joué ». Eh bien, ce message est probablement utilisé lorsque nous appuyons sur le
code.
Double-cliquez sur le "bon message". Nous serons conduits à l'endroit où il est utilisé. Vous
vous arrêterez ici :
00401068 6A 40 PUSH 40
0040106A 68 00304000 PUSH v2.00403000
0040106F 68 2A304000 PUSH v2.0040302A
00401074 FF75 08 PUSH DWORD PTR SS:\[EBP+8\]
00401077 E8 28000000 CALL <JMP.&user32.MessageBoxA>
Cela signifie que pour que ce message apparaisse, un saut vers l'adresse 00401050 devra être
effectué. Allez à l'adresse 00401050 (appuyez sur CTRL G et tapez l'adresse ou regardez-la
simplement dans les yeux, car le code est petit.
À l'adresse 00401050 nous avons :
En 00401043, il appelle une fonction qui prend un nombre tapé dans une zone de texte (vous
vous doutez déjà du nombre qu'elle prend, n'est-ce pas ?). Normalement, cette fonction met
son résultat (la valeur) dans le registre EAX (rappelez-vous ceci). Puis il passe au registre
EBX la valeur hexadécimale 39A (922 en décimal). Dans la ligne suivante, il décrémente
l'EBX (soustrait 1 de l'EBX). Comme EBX avait la valeur 922, il est maintenant 921. A
l'adresse 0040104E, il compare EBX avec EAX. EBX c'est 921, mais qu'en est-il de EAX,
c'est combien ? Quelques lignes plus haut, j'ai dit que la valeur prise dans la zone de texte est
stockée dans le registre EAX, il comparera donc l'EAX (921) avec le texte tapé. Si les 2 sont
identiques, il effectuera le saut (à partir de la ligne 00401050) qui nous amènera au message
de mot de passe correct, sinon,il continue sans faire le saut et affiche le message de mot de
passe erroné.
Nous tuons l'énigme. Si la valeur saisie est égale à EBX ( 921) , il affiche le message de mot
de passe valide, sinon nous obtiendrons un message de mot de passe erroné. Essayez de taper
921 dans la zone de texte du programme et de cliquer sur « S'inscrire ». Voila ! J'ai trouvé le
mot de passe d'accès :)
Il existe quelques autres façons de trouver l'emplacement de l'algorithme qui vérifie le mot de
passe correct. L'un d'eux est celui que nous utilisons. Une autre façon serait de placer des
points d'arrêt dans les appels de fonction classiques (si le programme les utilise). Voici
quelques-uns d'entre eux :
GetDlgItemText ou GetDlgItemText
LStrCmp ou StrCmp
GetWindowTextA ou GetWindowText
MessageBoxA
GetDlgItemInt
Les noms de fonction disent tout. Le premier prend le texte tapé dans des boîtes de dialogue.
La seconde compare les chaînes. Le troisième récupère le texte de la fenêtre. Le quatrième
affiche une boîte de message ( comme c'était le cas dans ce tutoriel ), et le dernier prend un
nombre tapé dans la zone de texte ( également dans ce tutoriel ).
Une autre méthode qui pourrait être utilisée consiste à modifier le code afin qu'il accepte la
valeur que vous entrez. Pour ce faire, vous devez forcer le programme à effectuer le saut, pas
seulement lorsque la comparaison est vraie. Vous y parvenez en changeant le JE ( Jump if
Equal ) en simplement JMP ( Jump ). Il sautera toujours à la bonne Msgbox, peu importe si la
valeur entrée est correcte ou non. Lisez mon tutoriel précédent pour savoir comment modifier
le code et enregistrer à nouveau le fichier.
F3rGO !
-Télécharger : keygenme1.zip
PARTIE 1
Avant d'ouvrir Olly, lancez le programme (il a même de la musique), devinez n'importe quel
nom (la référence ne devine jamais les noms avec moins de 5 caractères et plus de 16) et
devinez n'importe quelle clé. À moins que vous ne soyez large, mais vraiment large, le
message "Bonjour, M. Badboy!" doit être apparu. Nous avons raté la clé.
OK, ouvrez Olly et ouvrez notre cible sur lui. Pour trouver où la vérification est effectuée,
examinons les fonctions que le programme utilise à partir des API Windows. Appuyez sur
ALT E. Dans la liste qui est apparue, faites un clic droit sur le premier ( Name = keygenme )
puis View Names. Dans le tutoriel précédent, j'ai parlé de certaines fonctions intéressantes
auxquelles nous devrions prêter plus d'attention. Ce sont ceux marqués en rouge :
Tous finiront par nous amener à l'algorithme, mais l'un d'eux en particulier nous y amènera
plus rapidement : lstrcmpA. Cette fonction fait une comparaison entre 2 chaînes et est
largement utilisée pour comparer une vraie clé avec la clé que vous avez tapée. Définissons
un point d'arrêt partout où il est appelé. Faites un clic droit sur la ligne contenant le lstrcmpA
et cochez 'Définir le point d'arrêt pour chaque référence'.
Vous pouvez fermer ces fenêtres (tant les fonctions que les dll utilisées) et revenir à l'écran de
code standard. Exécutez le programme depuis Olly, saisissez à nouveau un nom et une clé et
appuyez sur « Vérifier ». Pimba, nous nous sommes arrêtés à notre point d'arrêt juste à l'appel
de fonction. Bon, on s'arrête juste au moment où il va comparer 2 cordes.
Notez maintenant les 2 arguments que prend cette fonction lstrcmpA (les 2 lignes précédant
cet appel). EBX contient 123456 (qui est le numéro de série que j'ai deviné) et EAX contient
une autre chaîne, dans un format de clé TRÈS typique. Après cela, il appelle la fonction
lstrcmpA qui comparera les 2 valeurs (123456 avec "Von-FF...") et si la comparaison est
vraie, il saute à 00401338 (JE en dessous de CALL). Si vous allez à l'adresse 00401338, vous
verrez que c'est là qu'il affiche le message que la clé est correcte.
Essayez d'écrire la valeur de EBX ( String1 ) et testez-la dans ce KeyGenMe ( utilisez le
même nom qu'avant, car la clé est générée à partir du nom ).
PARTIE 2
D'accord, nous avons trouvé la vraie clé de votre nom, mais que diriez-vous d'aller de l'avant
et de découvrir comment cette clé est générée ?
Supprimez les points d'arrêt actuels (appuyez sur ALT B et supprimez tout). Retournez à la
fenêtre des modules ( ALT E ), sélectionnez "Afficher les noms" dans le premier élément de
la liste. Définissons un point d'arrêt partout où il appelle la fonction GetDlgItemTextA (prend
une valeur saisie dans la zone de texte). Si vous ne savez pas comment faire, relisez le début
de ce tutoriel.
Après avoir défini les points d'arrêt, cliquez sur « Play », entrez un nom et une clé et cliquez à
nouveau sur « Vérifier ». A droite, nous nous sommes arrêtés à l'endroit où il acquiert le texte
d'une des zones de texte. Notez qu'il y a 2 appels à cette fonction, l'un après l'autre.
Évidemment, l'un obtiendra le nom et l'autre la clé. Appuyez sur F9 pour continuer l'exécution
du programme et à nouveau nous nous sommes arrêtés à l'appel de fonction (maintenant pour
obtenir la valeur de la deuxième zone de texte)
004010E9 6A 28 PUSH 28
004010EB 68 F8DC4000 PUSH keygenme.0040DCF8 ; Armazena o nome em 0040DCF8
004010F0 68 EE030000 PUSH 3EE
004010F5 FF75 08 PUSH DWORD PTR SS:\[EBP+8\]
004010F8 E8 B3020000 CALL <JMP.&user32.GetDlgItemTextA> ; Chama a função
para pegar o nome
004010FD 6A 28 PUSH 28
004010FF 68 F8DE4000 PUSH keygenme.0040DEF8 ; Armazena a key em 0040DEF8
00401104 68 EF030000 PUSH 3EF
00401109 FF75 08 PUSH DWORD PTR SS:\[EBP+8\]
0040110C E8 9F020000 CALL <JMP.&user32.GetDlgItemTextA> ; Chama a função
para pegar a key
00401111 E8 F2000000 CALL keygenme.00401208
Après avoir pris les 2 textes et les avoir stockés à certains endroits, il fait un saut au 00401208
(à l'adresse 00401111). L'instinct nous dit que cet appel génère probablement une clé à partir
du nom qui est comparée plus tard (comme nous l'avons vu tout à l'heure). Allons "dans" cette
fonction pour voir ce qu'elle fait. Sélectionnez la ligne 00401111 et appuyez sur ENTER.
En raison de la longueur du code, je n'expliquerai pas exactement ce que fait chaque ligne, je
mettrai en évidence les plus importantes. On se rend compte tout de suite qu'il y a une certaine
« symétrie », disons. Vous pouvez voir que l'algorithme est divisé en 3 séquences similaires.
Au cas où vous ne l'auriez pas remarqué, la bonne touche consiste en un "Bon-" suivi de 3
séquences numériques. On peut alors supposer que chacun des blocs de code (marqués en
rouge), est responsable de la génération de chaque partie de la clé.
00401242 0FB60439 MOVZX EAX,BYTE PTR DS:\[ECX+EDI\] ; Move para EAX o byte
indicado por ECX ( inicialmente zero )
00401246 83E8 19 SUB EAX,19 ; Subtrai 19 ( 25 em decimal ) de EAX ( EAX =
EAX - 25 )
00401249 2BD8 SUB EBX,EAX ; Subtrai EAX de EBX ( EBX = EBX - EAX )
0040124B 41 INC ECX ; Incrementa ECX ( ECX = ECX + 1 )
0040124C 3BCA CMP ECX,EDX ; Compara ECX com EDX ( que contém o tamanho do
nome )
0040124E 75 F2 JNZ SHORT keygenme.00401242 ; Caso a comparação seja falsa (
ECX diferente de EDX ), volte para o início do loop ( 1242 )
En résumant l'algorithme, il prend la valeur ASCII de chaque caractère, prend 25, puis
soustrait cette valeur trouvée d'EBX, quelque chose comme :
For i = 1 to Name
length ....String1 = String1 - ASC(Character(i)) - 25
Next
Après avoir calculé la première chaîne, il appelle une fonction qui formate le texte et le stocke
à une adresse donnée. Dans ce cas, il déplacera le résultat (qui est dans EBX) vers
l'emplacement mémoire [0040E0F8]
Encore une fois, il commence par mettre à zéro EAX, EDX et ECX.
00401269 03C3 ADD EAX,EBX ; EAX = EBX ( ou seja, EAX vai ter o valor da
sequência do alg. anterior, que foi armazenada em EBX )
0040126B 0FAFC3 IMUL EAX,EBX ; EAX = EAX \* EBX ( com os 2 registradores
tem o mesmo valor, é a mesma coisa que elevar EAX ao quadrado )
0040126E 03C8 ADD ECX,EAX ; ECX = EAX ( ECX passa a ter o valor da
multiplicação anterior )
00401270 2BD3 SUB EDX,EBX ; EDX = EDX - EBX ( EDX adquire o valor negativo
de EBX ) - instrução INÚTIL
00401272 33D0 XOR EDX,EAX ; EDX recebe o valor da operação binária XOR
entre EDX e EAX - instrução INÚTIL
00401274 0FAFD8 IMUL EBX,EAX ; EBX = EBX \* EAX ( EBX é multiplicado por
EAX ( que anteriormente foi multiplicado por EBX )
En regardant attentivement cette dernière déclaration, vous constatez que la séquence 2 n'est
rien de plus que la valeur générée dans la première séquence, au cube. Alors:
La valeur de la séquence 2 est stockée de la même manière que dans la première séquence,
mais dans l'adresse mémoire [0040E1F8]
Comme toujours, cela commence par mettre à zéro EAX, EBX, EDX, ECX
Cette dernière séquence a quelque chose de particulier. Notez qu'aucune des "variables" n'est
variable ( WTF ?! ). A aucun moment il n'utilise quoi que ce soit qui puisse varier selon le
nom saisi. La valeur EAX dans l'instruction 00401292 sera toujours 0040E0F8, car l'adresse
de l'instruction ne changera jamais. En faisant tous les calculs nécessaires (utilisez la
calculatrice Windows), vous arriverez à la valeur '41720F48', qui est alors stockée dans la
position [0040E2F8].
Séquence3 = 41720F48
-Code générateur, en VB
....'sequencia 1
....For i = 1 To tamanho
........seq1 = seq1 - (Asc((Mid(txtNome.Text, i, 1))) - 25)
....Next
....'sequencia 2
....seq2 = seq1 ^ 3
....txtSerial.Text = "Bon-" & Hex(seq1) & "-" & Hex(seq2) & "-41720F48"
End Sub
F3rGO !
L'objectif principal est de supprimer quelque chose que nous appelons "Nag Screen", ces
petites fenêtres ennuyeuses qui apparaissent lorsque vous démarrez certains programmes.
Dans ce cas, c'est aussi simple que possible, alors c'est parti. Télécharger notre cible
(programmée en ASM, par moi-même)
-Télécharger : fergo_nag.zip
Faites pivoter notre cible. Tout de suite, une MessageBox apparaît pour vous avertir du
bourrin, et ce n'est qu'après avoir cliqué sur OK que nous pouvons entrer dans le
"programme".
D'accord, allons voir Olly. Ouvrez Olly et chargez l'exécutable. Nous avons plusieurs façons
d'arriver à l'endroit où la boîte de message est affichée. L'une recherche toutes les chaînes
contenues dans le programme (Clic droit->Rechercher->Toutes les chaînes de texte
référencées). Une autre consiste à rechercher l'appel de fonction MessageBox. La seconde,
dans ce cas, nous amène directement à appeler nagscreen, car il n'y a qu'une seule
MessageBox dans le programme.
Appuyez sur ALT E, dans la liste qui apparaît, faites un clic droit sur le premier élément de la
liste ( fergonag ) et sélectionnez Afficher les noms. Une nouvelle liste est apparue, contenant
toutes les fonctions utilisées par l'exécutable. Notez que l'un d'eux est MessageBox.
Définissons un point d'arrêt où la fonction est appelée. Faites un clic droit sur
"user32.MessageBoxA" et sélectionnez "Définir un point d'arrêt sur chaque référence". Lors
de l'exécution du programme, il se bloque lorsque la fonction Messagebox est appelée.
Appuyez sur F9 (ou cliquez sur le bouton Lecture en haut).
Dès que vous cliquez sur le bouton de lecture, l'appel de fonction est lancé et Olly affiche là
où nous nous sommes arrêtés :
D'accord, quel était notre objectif de toute façon ? Supprimez cette boîte de message. Eh bien,
nous pouvons simplement le contenu faisant référence à msgbox. Mais est-ce vraiment si
facile ? Ce qui est pire. Pour annuler une ligne, nous utilisons la commande NOP ( No
OPERAtion ). Sélectionnez les 5 lignes faisant référence à MsgBox (de l'adresse 00401023 à
00401029), faites un clic droit, allez dans "Binary->Fill with Nops".
F3rGO !
-Télécharger : fergo_nag.zip
INTRODUCTION
Si vous avez lu le tutoriel n°4, vous vous souvenez peut-être que nous avons dû annuler une
ligne pour qu'un message texte ne s'affiche pas. Dans ce cas, nous remplissons l'appel de
fonction messagebox avec des NOP (dont le code est 90 en hexadécimal et n'occupe que 1
octet). Mais comment faire sans que l'utilisateur ait connaissance de RCE et/ou OllyDbg ?
Vous faites un autre utilitaire qui modifie la cible !
Regardez la ligne 00401029. Nous avons l'OpCode "E8 B0010000" et le mnémonique faisant
référence à l'OpCode : "CALL <SMP.&user32.MessageBoxA". Dans ce cas, E8 indique un
CALL et les 4 autres octets "B0010000" (rappelons que nous travaillons avec des valeurs
hexadécimales, allant de 00 à FF (0 à 255) et 2 chiffres occupent 1 octet en mémoire)
représentent la fonction MessageBoxA.
Retour au programme. Regardez la ligne 00401023. Là, les 4 arguments dont CALL a besoin
pour afficher la MessageBox commencent à être extraits.
Dans le tutoriel précédent, nous avons annulé tout ce qui concerne MsgBox. Lorsque vous
aviez les lignes remplies de NOP, par exemple, il a mis la valeur 90 ( NOP ) dans l'octet 29
( qui contenait le E8 ( CALL )), mais a également inclus plusieurs autres NOP dans des lignes
qui n'existaient même pas, voulez-vous savoir pourquoi? Comme il ne lui suffit pas d'annuler
l'octet 29, il doit également annuler les 4 octets suivants (rappelez-vous que c'était E8 B1 01
00 00). C'est pourquoi il a également ajouté des NOP dans les octets 29, 2A, 2B, 2C, 2D.
Donc, si nous voulons faire un patcher, nous devons annuler tout ce qui concerne notre
message texte.
Voir le tableau ci-dessous qui montre les octets d'origine du fichier et les octets que nous
allons modifier :
CRÉATION DU PATCHER
Allez. Je vais réécrire le code en VB car il est simple à comprendre. J'aurais pu l'écrire de
façon plus petite, mais la compréhension aurait été plus compliquée. Ajoutez un bouton de
commande nommé cmbPatch ). Se rappeler que le patcher doit être dans le même dossier que
la cible
Bon, maintenant compilez et allez faire des câlins. Pas sûr, mais peut-être que cela fonctionne
même avec VB Script :P
Si vous souhaitez télécharger le code source ci-dessus déjà dans les normes VB, cliquez ici
F3rGO !
Lorsque vous utilisez un packer, tel que UPX, l'EP (Point d'entrée, où commence le code du
programme) est détourné vers une autre adresse, qui contient quelque chose que nous
appelons Loader. La fonction du chargeur est simplement de décompresser l'exécutable en
mémoire, puis d'appeler l'OEP (Original Entry Point, qui contient le code vrai et non
compressé). La séquence ressemble à ceci :
Le processus pour décompresser l'UPX à la main est à peu près le même. Il suffit de suivre la
même séquence que vous pourrez décompresser sans difficultés majeures. Je ne vais pas
expliquer ce qui arrive au chargeur ou comment il se décompresse, nous allons simplement
déterminer où se trouve le point de départ du code initial ( OEP ) et récupérer l'exécutable
compressé de la mémoire. Pour cela, nous utiliserons OllyDbg et également un autre utilitaire
qui réassemble la base Imports de fichiers exécutables (si vous souhaitez savoir de quoi il
s'agit, recherchez le format de fichier des fichiers exécutables) appelé ImportREC
Alors, commençons. Tout d'abord, notre cible. Un exécutable simple fait en VB et compressé
avec UPX.
-Télécharger : unpackme.zip
Comment savoir si c'est compressé ? Pour voir si l'exécutable contient une sorte de protection,
j'utilise PEiD , qui analyse et détecte presque tous les types de compresseurs. Téléchargez et
décompressez la dll du plugin OllyDump dans le dossier Olly , que nous utiliserons plus tard.
D'accord, il a été compressé avec UPX (la version n'a pas d'importance car le processus est le
même pour tout le monde). Ouvrez Olly et chargez notre exécutable. Il avertira qu'il a été
compressé et demandera si nous voulons continuer, cliquez sur Oui. Olly nous laisse déjà au
point d'entrée (du chargeur toujours):
0040EA80 60 POUSSOIR
Gardez bien cette ligne. C'est TYPIQUE UPX. Chaque fichier compressé avec celui-ci
commencera par un PUSHAD. Comme je l'ai dit, je ne vais pas expliquer pourquoi nous
faisons un tel processus, etc., je vais juste souligner ce que vous devriez faire.
Appuyez sur F7 pour qu'il exécute l'instruction PUSHAD et passe à la ligne suivante
( EA81 ). Notez que dans la fenêtre des registres (à droite), l'ESP est coloré, indiquant qu'il a
changé de valeur. Nous allons définir un point d'arrêt matériel sur le contenu du premier octet
de l'ESP, car il n'est accessible qu'au début et à la fin du chargeur, nous allons donc atterrir
très près de l'endroit où le chargeur se termine et il appelle via l'OEP, c'est ce que nous
faisons. Nous avons besoin.
Faites un clic droit sur la valeur ESP et allez dans "Follow in Dump". Nous surveillons
maintenant le contenu ESP en bas de l'écran. Faites un clic droit sur le premier octet de la
fenêtre de vidage (38 ) et sélectionnez "Breakpoint->Hardware, on access->DWord". Ce point
d'arrêt nous amènera tout à la fin du loader, très proche de l'appel à l'OEP (pour savoir
pourquoi vous définissez ces points d'arrêt, il faut étudier le comportement du Loader, ce qui
n'est pas l'objet de ce tutoriel).
0040EC06 61 POPAD
0040EC07 8D4424 80 LEA EAX,DWORD PTR SS:\[ESP-80\] ; Paramos aqui
0040EC0B 6A 00 PUSH 0
0040EC0D 39C4 CMP ESP,EAX
0040EC0F 75 FA JNZ SHORT UnpackMe.0040EC0B
0040EC11 83EC 80 SUB ESP,-80
0040EC14 E9 7725FFFF JMP UnpackMe.00401190
Remarquez le POPAD qui est apparu. Comme je l'ai dit, c'est typique d'UPX, commençant
par un PUSHAD et se terminant par un POPAD. Remarquez maintenant sur la dernière ligne,
un saut obligatoire vers l'adresse 1190. Ce saut indique que nous avons atteint la fin du
Loader, l'application non compressée est déjà en mémoire, et ce JMP nous ramènera au point
de départ d'origine. (En voyant le saut, vous pouvez déjà savoir que l'OEP est 00401190).
Placez un point d'arrêt commun sur la ligne de saut ( 0040EC14 ) en appuyant sur F2.
Appuyez sur F9 pour continuer jusqu'à ce que nous atteignions le saut. Une fois là-bas,
appuyez une fois sur F7 pour sauter au point d'entrée d'origine.
Si vous avez tout fait correctement, vous devriez maintenant être à l'adresse 00401190 qui
nous montre le code original du .exe non compressé. Ce que nous devons faire est de
décompresser l'application de la mémoire et de réassembler un nouvel exécutable à partir de
celle-ci, en indiquant le bon point de départ (1190). Pour ce faire, utilisons OllyDump. Avec
le programme encore geléà la ligne 1190, allez dans "Plugins->OllyDump->Dump debugged
process".
Olly calcule déjà tout pour vous, y compris l'OEP, mais si vous voulez garantir, cliquez sur
"Get EIP as OEP". Décochez également la case "Reconstruire l'importation", car nous allons
utiliser un autre programme pour reconstruire la base des importations. Cliquez sur "Dump" et
choisissez le nom et l'emplacement où vous souhaitez enregistrer le fichier décompressé. J'ai
utilisé le nom "Dumped.exe".
Vous étiez probablement très excité, vous avez déjà exécuté ce fichier créé et vous êtes tombé
sur une erreur d'échec de démarrage. En effet, UPX déroge à la section Imports de
l'exécutable et nous devons la réassembler. Pour cela, utilisons ImpRec, dont j'ai parlé au
début du tutoriel. Laissez Olly ouvert comme il est, ne le fermez pas. Exécutez également le
fichier .exe d'origine (fourni avec le zip, le même que celui qui s'exécute sur Olly).
En 2, vous devez mettre la valeur acquise dans la zone de texte "Modifier" de la fenêtre Olly's
Dump.
Lorsque vous cliquez sur Obtenir les importations ( 4 ), certains éléments devraient apparaître
dans la liste "Fonctions importées trouvées". Tous les éléments doivent apparaître avec un
OUI à la fin, sinon il ne pourra pas assembler correctement la table d'importation. La dernière
chose à faire est de cliquer sur Fix Dump (5). En cliquant, il demande un fichier exécutable.
Sélectionnez celui qui a été créé dans Olly, que j'ai nommé "Dumped.exe". Juste après avoir
sélectionné le fichier, il générera l'exécutable définitif décompressé (avec un soulignement à
la fin du nom : Dumped_.exe) et affichera dans le journal ImpRec que le fichier a été créé
avec succès. Maintenant, vous pouvez fermer Olly, tout le reste de l'attirail et exécuter
"Dumped_.exe". Si tout s'est bien passé, vous avez dû recevoir un message d'encouragement
de unpackme :P
Si vous voulez prouver qu'il a été décompressé, faites un nouveau scan avec le PEiD dans
"Dumped_.exe" et voyez (ou comparez simplement la taille des fichiers) ;D
F3rGO !
Notre cible:
Télécharger : crackme2.zip
(crédits à mucki)
Ouvrez la cible sur Olly et appuyez sur F9 pour lancer l'exécution. Tout de suite, vous
remarquez que le programme ne démarre pas et s'arrête en 401047. Remarquez dans le pied
de page d'Olly que quelque chose comme ceci est apparu :
Cela indique que le programme a rencontré une "exception" et s'est arrêté avant de s'exécuter.
Si vous appuyez sur F9, il continuera et affichera la MessageBox dans l'image ci-dessus, puis
fermera le programme. Olly vous permet de "sauter" l'exception et de continuer à exécuter le
programme normalement, appuyez simplement sur Shift+F9. Vous avez maintenant le
programme qui fonctionne correctement.
Nous avons déjà passé le système anti-débogage, alors allons-y et changeons notre code.
L'application demande un nom et un mot de passe, compare et vérifie que les informations
sont cohérentes. Si tel est le cas, il affiche un message indiquant que le code est correct.
Sinon, cela indique que le numéro de série n'est pas valide.
Au lieu de définir un point d'arrêt dans l'appel de fonction MessageBox (pour nous emmener
là où la clé est vérifiée), utilisons une autre approximation (celle de MsgBox est plus simple,
mais varions un peu). Cherchons d'autres fonctions classiques. Appuyez sur CTRL+N pour
ouvrir la fenêtre avec les noms des fonctions utilisées. Analysez la liste et notez la fonction
"lstrcmp". Ce qu'il fait, c'est comparer 2 chaînes, si elles sont égales, il définit le "Zero Flag"
sur true. Sélectionnez "lstrcmp" dans la liste et appuyez sur ENTER. Une nouvelle fenêtre est
apparue avec toutes les occurrences de son utilisation dans le code. Comme il n'y a que 2
occurrences, essayez simplement l'une des deux pour voir si nous avons été emmenés au bon
endroit. Sélectionnez la première occurrence et appuyez à nouveau sur ENTER. nous tombons
ici
Euh, on dirait que nous sommes au bon endroit. Remarquez les fonctions "autour" d'elle.
Nous avons plusieurs fonctions typiques, comme formater un texte au format série
( wsprintfA ), GetDlgItemTextA ( obtenir notre série à comparer ), et les 2 MsgBox indiquant
si la série est valide ou non.
Que diriez-vous de changer le code MsgBox ? Au lieu d'afficher le message de série invalide,
il affiche le bon numéro de série. Faisons cela.
Ce que nous avons fait, c'est qu'au lieu d'appeler l'adresse 406060 qui contient "Wrong...",
nous appelons l'adresse qui contient le bon numéro de série (4062B6). Pour tester, il suffit de
sauvegarder les modifications dans un nouvel exécutable. Faites un clic droit sur la fenêtre
principale, allez dans "Copier dans l'exécutable->Toutes les modifications->Copier tout".
Dans la nouvelle fenêtre, faites à nouveau un clic droit et choisissez "Enregistrer le fichier".
Enregistrez le nouveau fichier, exécutez-le, tapez un nom et n'importe quel numéro de série et
voyez la MessageBox qui apparaît :
Bingo ! Au lieu d'un message de série incorrect, le vrai numéro de série est apparu. Écrivez-le
et utilisez-le!
En tant que tâche, déchiffrez l'algorithme de la série (commence à 004011F6 ). Ce n'est pas
compliqué, il effectue simplement une série d'opérations de base avec chaque lettre du nom
tapé.
Avant de conclure, je veux juste rappeler que dans ce cas, le code pourrait être modifié sans
même contrôler l'exception, je voulais juste expliquer cela pour que dans d'autres cas, vous
n'abandonnez pas simplement parce que le programme a cessé de fonctionner dans le
débogueur ;RÉ
F3rGO !
Télécharger : activateme.zip
Tout d'abord, je vais expliquer un peu le code VB. Contrairement à ce que beaucoup de gens
pensent, les applications VB, si elles sont compilées en code natif, génèrent du code
assembleur normal, qui peut être ouvert dans n'importe quel débogueur. La différence est
qu'en plus de l'application, il utilise un "linker", une dll ( MSVBM60.dll ) qui contient toutes
les fonctions que VB utilise. Ainsi, lorsque vous effectuez une comparaison de chaînes par
exemple, il appelle la fonction "vbaStrCmp" à partir de MSVBM60.dll. En raison de cette
connexion entre l'exécutable et la DLL, ils sont généralement (lorsqu'ils sont compilés en
code natif) plus compliqués à déboguer.
Bien qu'il soit plus compliqué de rétablir le code assembleur créé par VB, il a quelque chose
qui facilite également son édition. Toutes les informations sur les contrôles, telles que l'état, le
nom, la couleur, le texte et la taille, sont stockées sous forme de texte dans l'exécutable. Cela
signifie que si nous recherchons le texte d'un bouton dans un éditeur hexadécimal (ou même
l'ouvrons dans le bloc-notes et le recherchons), nous pourrons modifier ses propriétés de base.
Si vous avez déjà exécuté notre cible, vous avez peut-être vu que l'objectif est d'activer un
bouton de commande, alors c'est parti. Ouvrez la cible dans un éditeur hexadécimal.
Comme je l'ai dit ci-dessus, il stocke les informations de contrôle sous forme de texte dans
l'exécutable. Et si on cherchait le texte du bouton ( Activez-moi ) ? Allez dans "Rechercher ->
Rechercher du texte". Sélectionnez le mode ASCII et recherchez "Activez-moi" (si les
guillemets). WinHex doit l'avoir pris pour compenser 125A (ligne 1250, colonne A).
Dans la partie centrale vous pouvez voir les valeurs hexadécimales de chaque octet du fichier,
et dans la partie droite, les caractères ASCII correspondant à ces valeurs. Peu importe
d'expliquer ce qu'est chaque pièce, la partie importante est ce qui est marqué en rouge. L'état
du bouton vient juste après la valeur qui définit sa hauteur, suivi de l'octet 08 (TOUJOURS).
La hauteur du bouton dans ce cas est indiquée par "EF 01" (dans l'ordre des octets inverse,
c'est 01EFh = 495d ), suivi par l'octet 08 et un octet 00. 00 indique que le bouton est désactivé
(Enabled = False ), et 01 indique qu'il est actif ( Enabled = True ). Alors changez simplement
l'octet 00 en 01
F3rGO !
09. Défi de solutions #1
Dans ce tutoriel, je vais expliquer l'une des façons de résoudre le premier défi (vous pouvez le
trouver dans l'index des tutoriels), allons droit au but.
La première chose à faire est d'ouvrir la cible et de lui donner une analyse générale. Au début,
nous avons déjà remarqué que le bouton pour vérifier la série est désactivé. Ensuite, lors de la
fermeture, un écran Nag apparaît, que nous devons supprimer. Voyons aussi si une sorte de
packer a été utilisé dessus.
Partie 1 - Déballage
Ouvrez-le dans PEiD et voyez qu'il a été compressé avec UPX ( Ultimate Packer for
eXecutables ).
Si vous avez lu tous les didacticiels, vous devriez être en mesure de résoudre tous les
problèmes que vous avez rencontrés jusqu'à présent. Commençons par décompresser le
fichier. Cible ouverte sur Olly. Il vous positionne au point d'entrée de l'emballeur (remarquez
la caractéristique PUSHAD). Appuyez une fois sur F7 et la valeur du registre ESP changera.
Faites un clic droit sur la valeur ESP et sélectionnez "Follow in Dump". Nous surveillons
l'adresse stockée par ESP dans la fenêtre de vidage d'olly (en bas). Faites un clic droit sur le
premier octet de la fenêtre de vidage ( 38 ), sélectionnez "Breakpoint->Hardware, on write-
>DWord". Lorsque la cible est d'écrire quelque chose à cette adresse mémoire, Olly gèle le
programme, ce qui nous amène généralement très près de la fin du processus de
décompression. Appuyez sur F9 pour continuer à courir, puis nous nous arrêtons ici :
00412AF6 61 POPAD
00412AF7 8D4424 80 LEA EAX,DWORD PTR SS:\[ESP-80\]
00412AFB 6A 00 PUSH 0
00412AFD 39C4 CMP ESP,EAX ; Paramos aqui
00412AFF 75 FA JNZ SHORT Desafio\_.00412AFB
00412B01 83EC 80 SUB ESP,-80
00412B04 E9 97E8FEFF JMP Desafio\_.004013A0 ; Como visto no tutorial de
UPX, este jump nos leva ao EP original do programa
Afin de vider le programme non compressé, nous devons accéder à ce dernier saut et
l'exécuter. Ajoutez un point d'arrêt ( F2 ) au dernier saut ( 00412B04 ) et appuyez sur F9.
Super, nous nous sommes arrêtés au saut et maintenant nous devons l'exécuter. Appuyez une
fois sur F7 et nous sommes dirigés vers l'OEP (Original Entry Point), ce qui signifie que nous
sommes au début du code du programme décompressé. « Extrayons » le programme non
compressé de la mémoire et lisons-le dans un exécutable séparé. En utilisant le plugin
OllyDump, allez dans "Plugins->OllyDump->Dump Debugged Process". Dans la fenêtre qui
apparaît, cliquez sur "Obtenir EIP en tant qu'OEP" et décochez "Rebuild Import". Cliquez sur
"Dump" et enregistrez-le sous n'importe quel nom (j'ai utilisé DUMPED.exe, je vais donc m'y
référer comme ceci).
Nous n'avons pas encore fini, nous devons réassembler la base des Imports, pour cela nous
utiliserons ImpRec (ne fermez pas Olly avec notre programme).
À l'étape 5, sélectionnez le fichier Olly exporté ( DUMPED.exe ). Il créera un fichier
DUMPED_.exe qui est notre fichier final non compressé.
Si vous ne comprenez pas le processus utilisé, lisez le tutoriel #6, qui explique en détail
chaque étape utilisée ici.
J'ai décidé de faire cette partie en premier pour ne pas avoir à changer de programme plus
tard. Activer le bouton maintenant, alors j'ai juste besoin d'utiliser Olly, c'est tout.
Les octets importants que nous recherchions sont marqués en violet. Le 08 indique la
propriété "Enabled" et le 00 indique alors qu'elle est désactivée ( Enabled = False ). Pour
inverser cela, changez le 08 00 en 08 01 et enregistrez le fichier par WinHex ("Fichier-
>Enregistrer" ). Nous avons maintenant notre bouton activé.
Revenons maintenant à Olly. Obtenez le DUMPED_.exe déjà édité avec le bouton qui
fonctionne. Un message d'avertissement concernant l'EP en dehors du module de programme
s'affiche. Selon les cas, cela rend le processus difficile, mais dans ce cas le seul inconvénient
est que cela ne permet pas de sauvegarder toutes les modifications dans l'exécutable,
seulement les sélections.
Appuyez sur F9. Un message texte apparaît indiquant que nous utilisons Olly. Désactivons-le
pour pouvoir le déboguer. Redémarrez la cible dans Olly ( CTRL F2 ) et tapez "bpx
rtcMsgBox" dans la ligne de commande ("Plugins->Command Line" ). Cela définit un point
d'arrêt dans l'appel de fonction MsgBox. Commencez à courir ( F9 ) et Olly se fige où le
message "Anti-Olly" apparaît (4008B3A).
Nous devons trouver un moyen de contourner le code afin que la MsgBox ne s'affiche pas.
Revoyez le code un peu plus haut. Notez qu'à l'adresse 408AF1, nous avons un saut
conditionnel qui saute à une zone de code juste APRÈS l'affichage de la MsgBox, c'est-à-dire
que si le saut est effectué, la MsgBox n'apparaît pas. On peut alors forcer le saut à toujours se
produire. Pour ce faire, il suffit de passer de JNZ à JMP :
Sélectionnez cette ligne modifiée, faites un clic droit et allez dans "Copier dans l'exécutable-
>Sélection". Ensuite, dans la fenêtre qui apparaît, cliquez à nouveau avec le bouton droit,
allez dans "Enregistrer le fichier" et sélectionnez l'exécutable lui-même ( DUMPED_.exe ).
Après l'enregistrement, appuyez sur CTRL F2 pour réinitialiser l'application. Si vous appuyez
sur F9, le programme s'ouvre maintenant normalement, sans afficher la MsgBox. ;RÉ
Avec le programme exécuté à l'écran demandant un nom et une série, tapez "bpx
__vbaStrCmp" dans la ligne de commande pour définir un point d'arrêt dans la fonction qui
compare 2 chaînes (vrai série avec la série que nous avons tapée). Tapez n'importe quel nom
avec plus de 4 lettres (voir plus loin) et n'importe quel nom de série (j'ai utilisé F3rGO! et
132456, respectivement) et cliquez sur "S'inscrire". Nous nous sommes arrêtés à l'appel de
fonction.
Notez qu'il prend 2 arguments puis appelle la fonction. Ces arguments sont ce que la fonction
comparera (dans ce cas, elle comparera ECX avec EDX). Voir l'écran des registres (côté
droit). Dans mon cas, ECX contient 123456 et EDX 418. Il compare 123456 (notre faux
numéro de série) à 418 (qui est le vrai numéro de série du nom tapé).
Quant au nombre minimum de lettres dans le nom, il suffit de regarder le code ci-dessus.
Avant que tout le processus de génération en série ne commence, il compare le texte saisi
avec la valeur 4 ( adresse 408459 ).
Nous avons déjà trouvé la série. Il ne reste plus qu'à supprimer l'écran Nag qui apparaît à la
fermeture du programme. Tapez à nouveau "bpx rtcMsgBox" pour définir des points d'arrêt
où la fonction "rtcMsgBox" est appelée. Fermez la fenêtre de notre cible (par le X dans le
coin de la fenêtre elle-même). Olly se figea à nouveau lors de l'appel de la fonction pour
afficher l'écran Nag. Comme cette MsgBox ne dépend pas d'une condition à afficher (comme
dans le cas d'Anti-Debug ), nous ne pouvons pas échanger un JNZ contre un JMP ou quelque
chose comme ça. Ce que nous devons faire, c'est annuler les lignes de code qui affichent la
MsgBox.
Nous devons annuler la ligne qui appelle la fonction ( CALL DWORD PTR... ) à l'adresse
408C5D et les 5 arguments qu'elle prend. Pour annuler les commandes, nous devons remplir
avec des NOP ( NO operation ). Faites un clic droit sur "CALL DWORD..." ( 408C5D ), allez
dans "Binary-> Fill with NOPs". Faites de même pour les 5 lignes avant qui contiennent
"PUSH"
Il ne nous reste plus qu'à enregistrer les modifications. Sélectionnez l'adresse 00408C51 à
004008C62 (région qui couvre toutes les modifications) en utilisant SHIFT. Cliquez à
nouveau avec le bouton droit sur la sélection, allez dans "Copier dans l'exécutable->Sélection"
et dans la fenêtre qui s'ouvre, cliquez avec le bouton droit et allez dans "Enregistrer le
fichier". Peut écraser à nouveau le fichier DUMPED_.exe.
Prêt! Avaient fini! Nous avons fait tout ce qui a été demandé. Nous décompressons, activons
le bouton, supprimons la protection anti-débogage, trouvons le numéro de série et supplantons
le nag-screen. Si vous avez réussi à tout suivre, félicitations, d'autres défis arrivent bientôt. Si
vous rencontrez des difficultés dans une partie, lisez les autres tutoriels trouvés dans l'index
de la page. Là, les sujets vus dans ce tutoriel sont traités de manière beaucoup plus complète.
Au suivant!
F3rGO !