Vous êtes sur la page 1sur 41

Utiliser un débogueur - OllyDbg

Introduction à l'utilisation d'un débogueur de bas niveau - OllyDbg

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.

Tout d'abord, il serait intéressant de clarifier un peu ce qu'est un débogueur et ce qu'est un


désassembleur, car bien qu'ils aillent presque toujours ensemble, ils ont des objectifs
différents.

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.

Site officiel d'OllyDbg, avec lien de téléchargement : http://www.ollydbg.de

1.1 A quoi sert un débogueur ?


Beaucoup de gens se demandent pourquoi utiliser un débogueur, puisque dans la plupart des
cas, vous avez accès au code source d'origine (si vous avez programmé l'application). Je
citerai ci-dessous quelques-unes des plus grandes utilisations d'un débogueur :

 La gestion des erreurs. Certainement l'un des principaux. Parfois, lors de la


programmation d'une application, une petite erreur passait inaperçue, provoquant un
dysfonctionnement ou une opération illégale. Dans de nombreux cas, il vous est plus
facile d'analyser le binaire déjà compilé dans un débogueur que d'essayer de trouver
l'erreur dans le code d'origine. Au sein de ce même poste, on peut citer la correction de
bugs dans les applications déjà abandonnées (à condition d'avoir l'autorisation de la
société détentrice des droits).
 Ingénierie inverse. Le processus d'ingénierie inverse du logiciel ne pourrait pas être
effectué efficacement sans l'utilisation d'un débogueur/désassembleur. Beaucoup de
gens ont tendance à confondre craquage et ingénierie inverse, car ce sont des concepts
différents. L'ingénierie inverse en soi est une activité complètement cool, car une
grande partie de ce que nous voyons aujourd'hui n'était possible que grâce à
l'ingénierie inverse. La création de pilotes Linux pour des périphériques qui ne
fonctionnaient auparavant qu'avec Windows (WinModems) est un bon exemple de la
façon dont la rétro-ingénierie nous apporte de bonnes choses.
 Apprentissage. L'utilisation de débogueurs et d'ingénierie inverse est l'un des meilleurs
moyens d'apprendre le langage assembleur. Vous programmez quelque chose dans un
langage de niveau moyen ou élevé, puis analysez la sortie du binaire compilé dans un
débogueur. Avec ces connaissances, il est possible de mieux maîtriser le langage et de
créer des algorithmes plus optimisés et plus efficaces.

1.2 Concepts nécessaires

Pour comprendre le fonctionnement d'un débogueur, il est nécessaire de connaître un peu


certains concepts liés à l'informatique, comme le fonctionnement de la mémoire, du
processeur, des batteries et des adresses. Des connaissances de base en assembleur sont
également requises, car c'est le langage que nous devrons analyser. Si vous débutez dans
l'assemblage, soyez assuré que dans les chapitres suivants je vous en donnerai un aperçu,
suffisant pour comprendre notre applet d'étude. Voici une brève liste de concepts :

 Processeur/CPU : C'est le cerveau de chaque ordinateur. C'est lui qui décode les


instructions et exécute les codes opérationnels. Il est essentiellement composé d'une
unité logique-arithmétique (ALU), d'une unité à virgule flottante (FPU), de registres,
d'un cache, d'un bus et d'un générateur d'horloge.
 Mémoire RAM : Emplacement de stockage temporaire des données (elles sont
effacées lorsque l'ordinateur est éteint). Chaque application utilise de la mémoire pour
stocker ses données et celles-ci sont récupérées et gérées par le processeur.
 Adressage mémoire : Il s'agit d'une plage de valeurs qui pointent vers un
emplacement mémoire spécifique. Chaque fois que vous écrivez ou lisez des données
en mémoire, il est nécessaire d'indiquer l'adresse où se trouve cette valeur, afin que le
processeur puisse la récupérer.
 Pile : C'est une structure de données. Sa principale caractéristique est son
fonctionnement, où il suffit de mettre ou de supprimer des valeurs, sans indiquer
d'adresse (LIFO – Last in, First Out – Last in, first out). Cela fonctionne de la même
manière qu'une pile de livres où vous les empilez. Lorsque vous devez supprimer l'un
d'entre eux, il est nécessaire de supprimer tous les livres d'en haut.'
 Registres : petits morceaux de mémoire présents à l'intérieur des processeurs (à ne pas
confondre avec la mémoire RAM). Extrêmement rapide, car le processeur les utilise
comme moyen temporaire de stocker des données et d'effectuer des opérations. La
quantité de données pouvant être stockées dépend du type de processeur. Les
processeurs 32 bits peuvent stocker des nombres jusqu'à 32 bits dans chaque registre,
sans avoir besoin de routines de conversion.

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 .

Je n'ai pas l'intention d'expliquer maintenant tout le fonctionnement, la structure et les


commandes de la langue. Je vais juste vous donner un aperçu de certains termes et une brève
description des commandes les plus basiques et les plus courantes que vous pouvez trouver.
Nous devons d'abord définir ce que sont les mnémoniques et quels sont les opcodes.

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.

La principale difficulté du langage assembleur est certainement sa structure, qui s'écarte du


standard des langages de niveau supérieur comme le C ou le Pascal. Pas de si avec plusieurs
comparaisons, commutateurs, pour ou pendant. Tout se fait avec de simples comparaisons et
sauts, perdant sa linéarité (similaire au GoTo de BASIC).
Heureusement, nous disposons aujourd'hui de débogueurs très intelligents capables de
structurer et d'identifier les routines et les répétitions, ce qui facilite grandement le travail
d'interprétation. Même avec ces améliorations, je pense toujours qu'il est important d'avoir un
stylo et du papier à vos côtés, où vous pouvez prendre des notes et aller structurer/convertir le
code au fur et à mesure que vous les interprétez.

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;

if((a == 4) && (b == 6)) {


c = 5;
}
}

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):

00000000 MOV EAX,4h ;move o valor 4 para EAX


00000005 MOV EBX,6h ;move o valor 6 para EBX
0000000A CMP EAX,4h ;compara EAX com 4, se for verdadeiro: ZF = 1
0000000D JNE 00000019h ;se ZF != 1, pule para endereço 00000019h
0000000F CMP EBX,6h ;compara EBX com 6, se for verdadeiro: ZF = 1
00000012 JNE 00000019h ;se ZF != 1, pule para endereço 00000019h
00000014 MOV ECX,5h ;move o valor 5 para ECX
00000019 RETN ;finaliza execução e retorna

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).

Les adresses en langage assembleur constituent la base du flux de l'application et du stockage


des données. Les variables que vous utilisez lors de la programmation sont remplacées par des
adresses qui pointent vers une zone de mémoire paginée avec accès en lecture et en écriture.
Les destinations de saut dépendent également des adresses d'instructions, car c'est à travers
elles que vous renseignez la destination de saut.
Le code ci-dessous montre une seule chaîne d'assemblage où vous pouvez voir l'adresse
d'instruction (00401000) et l'adresse d'un octet de mémoire (00403000) vers lequel le nombre
neuf est déplacé :

00401000 MOV BYTE PTR DS:[00403000], 09h

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).

 MOV destination, source Déplace la valeur du champ source vers la destination.


Cette instruction a plusieurs variantes, elle peut donc apparaître de différentes
manières (vous pouvez travailler avec des constantes, de la mémoire, une pile, etc.).
Quelques exemples:
 MOV EAX, 10h
 MOV AX, WORD PTR DS:[00403000]
 MOV BYTE PTR DS:[00403002], 1Ch
 CMP arg1, arg2 Effectue une comparaison entre les deux opérandes. La comparaison
se fait simplement en soustrayant les deux opérandes et si le résultat est nul (valeurs
égales), on met le ZF à 1. Rappelons que cette opération ne change pas les valeurs des
opérandes, seulement les drapeaux.
 CMP EAX, 04h
 Adresse JMP Effectue un saut inconditionnel et obligatoire à l'adresse indiquée.
 JMP 00401008h
 Adresse JZ / Adresse JE Effectue un saut conditionnel. Si la valeur du drapeau zéro
est 1, il effectue le saut. Généralement utilisé avec un CMP pour effectuer un
branchement si la comparaison est vraie.
 JE 0040101Ah
 Adresse JNZ / Adresse JNE Similaire à l'élément ci-dessus, mais ne saute que
lorsque le drapeau zéro n'a pas été défini (ZF = 0).
 JNZ 0040102Ch
 AJOUTER la cible, arg1 Ajoute la valeur de arg1 à la cible. Elle a également
plusieurs variantes, pour les mêmes raisons que la commande MOV. Si le résultat
dépasse la limite cible, le CF est défini.
 ADD EBX, 04h
 ADD EBX, DWORD PTR DS:[00403032]
 Destination SUB, arg1 Effectue une soustraction d'opérandes. Les variantes et
caractéristiques sont les mêmes que pour la commande ADD.
 SUB ECX, 2Ah
 PUSH value Met la valeur en haut de la pile (Stack). La commande PUSH est
largement utilisée dans les appels de fonction (CALL), car c'est via la pile que la
fonction récupère ses arguments.
 PUSH 08h
 Destination POP Supprime la valeur du haut de la pile et la stocke dans la
destination.
 POP EAX
 local CALL Appelle une fonction. Il est possible de passer le local de plusieurs
manières à la commande CALL, à partir d'une constante, d'un registre ou même d'une
fonction externe à l'intérieur d'une DLL. La commande CALL utilise la pile pour
indiquer l'adresse à laquelle la fonction doit retourner une fois son exécution terminée.
 CALL User32!GetDlgItemTextA
 CALL 0040115Fh

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 :

L'interface de l'application se compose de quelques boutons. Le secret d'Olly est le bouton


droit de la souris. La plupart des fonctions existantes dans l'application sont accessibles via le
bouton droit de la souris, et les éléments affichés dans le menu contextuel varient selon
l'endroit où le clic a été effectué (selon la colonne et la région).

J'ai numéroté les principales régions de l'écran de 1 à 4.

Région 1

C'est l'écran principal du programme, où le démontage de l'application est présenté. Il est


divisé en quatre colonnes :

 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 :

 Colonne 1 - Adresse. Affiche les adresses virtuelles de la mémoire.


 Colonne 2 - Hex Dump. Cet espace contient la valeur de chaque octet de mémoire.
Par défaut Olly met 8 octets par ligne et pour cette raison la colonne d'adresse
augmente de 8 octets.
 Colonne 3 - ASCII. Cette colonne peut être utilisée pour afficher les valeurs
contenues en mémoire de différentes manières. Par défaut Olly choisit d'afficher la
représentation ASCII de ces valeurs. Le mode de représentation peut être modifié à
l'aide du bouton droit de la souris.

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.

En plus des régions, nous avons la barre d'outils :

Vous trouverez ci-dessous une description de chaque bouton, de gauche à droite.

 Ouvrir - Ouvrir l'exécutable pour le débogage


 Redémarrer - Recharger l'application en cours
 Fermer – Ferme l'application chargée
 Jouer – Démarre l'exécution et le débogage de l'application. Si aucun point d'arrêt n'a
été défini (nous verrons plus tard), le programme fonctionnera normalement.
 Pause – Suspend l'application en cours
 Step Into – Si un point d'arrêt a été placé dans un appel de fonction, ce bouton vous
permet de déboguer le contenu de cette fonction.
 Step Over – L'opposé de l'élément précédent. Il n'entre tout simplement pas dans
l'appel (mais l'exécute toujours), continuant à déboguer sur la déclaration suivante.
 Trace Into – Utilisé uniquement lors du backtracing. Il enregistre les actions et les
adresses dans un journal, enregistrant également le contenu des fonctions appelées.
 Trace Over – Similaire à l'élément ci-dessus, mais n'enregistre pas le contenu des
appels.
 Execute Till Return – Exécute les instructions jusqu'à ce qu'il trouve la première
commande de retour (RETN).
 Aller à l'adresse – Permet à l'utilisateur de spécifier une adresse de code à afficher.

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é.

Enfin, nous avons les boutons de configuration et d'aide.

 Options de débogage – Affiche la fenêtre de configuration d'Olly. Au début, vous


n'avez pas besoin de changer quoi que ce soit pour déboguer, à moins que vous ne
sachiez où vous allez.
 Apparence – Vous permet de configurer le schéma de couleurs. Je recommande de
modifier ces paramètres en quelque chose que vous aimez, en faisant une « mise en
évidence de la syntaxe » du code, ce qui le rend plus facile à lire.
 Aide – Affiche la fenêtre d'aide d'Olly. L'aide est en anglais.

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) :

C'était exactement comme nous le voulions. On s'arrête juste à l'endroit où l'adresse du


message est mise sur la pile pour être utilisée par la fonction MessageBoxA :

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 :

1. Adquire os dados digitados pelo usuário


2. Compara com o valor real
3. É igual?
4. Caso não seja igual, pule para ...
5. Caso seja igual continue/pule para outro local

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 :

1. Compare EAX com 1


2. Se for menor, pule para 0040108F
3. Compare EAX com 14 (os números são em hex, logo 14h = 20 decimal)
4. Se for maior, pule para 0040108F
5. Compare EAX com 4
6. Se forem diferentes (JNZ/JNE), pule para 00401079

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 :

Declara variável inteira X;


X = Número contido na caixa de texto;

Se X < 1 ou X > 20 Então


Exibe mensagem de texto “Número Inválido”;
Fim Se

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.

Voici la liste des fonctions utilisées :

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.

Je préfère particulièrement cette méthode aux références pour plusieurs raisons :

 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 :

 Modifiez le code en forçant la valeur 4 à être déplacée vers EAX avant la


comparaison.
 Annulez le dernier saut (après le CMP EAX, 4), faisant en sorte que l'application se
dirige directement vers le message correct.
 Détournement et forçage d'un saut vers le bon message dans la première comparaison
effectuée.

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

Auteur : Joe Stewart


Version : 0.1
Téléchargement : http://www.openrce.org/downloads/download_file/220

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).

Gestionnaire de barre d'outils Olly

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

01. Trouver le message secret


Ceci est mon premier tutoriel d'ingénierie inverse. Si vous en savez autant que moi (c'est-à-
dire presque rien), cette page est un bon point de départ. Je vais expliquer quelques choses de
base et faire un "débogage" manuel d'un programme fait en assembleur (votre objectif sera de
trouver la phrase cachée).

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"

00401000 2BC0 SUB EAX,EAX


00401002 83F8 00 CMP EAX,0
00401005 74 0E JE SHORT fergo\_ex.00401015
00401007 8D05 25304000 LEA EAX,DWORD PTR DS:\[403025\]
0040100D 8D1D 25304000 LEA EBX,DWORD PTR DS:\[403025\]
00401013 EB 0C JMP SHORT fergo\_ex.00401021
00401015 8D05 00304000 LEA EAX,DWORD PTR DS:\[403000\]
0040101B 8D1D 09304000 LEA EBX,DWORD PTR DS:\[403009\]
00401021 6A 00 PUSH 0 ; Style = MB\_OK|MB\_APPLMODAL
00401023 50 PUSH EAX ; Title
00401024 53 PUSH EBX ; Text
00401025 6A 00 PUSH 0 ; hOwner = NULL
00401027 E8 14000000 CALL <JMP.&user32.MessageBoxA> ; MessageBoxA
0040102C 6A 00 PUSH 0 ; ExitCode = 0
0040102E E8 01000000 CALL <JMP.&kernel32.ExitProcess> ; ExitProcess
00401033 CC INT3
00401034 -FF25 00204000 JMP DWORD PTR DS:\[<&kernel32.ExitProcess>;
kernel32.ExitProcess
0040103A -FF25 0C204000 JMP DWORD PTR DS:\[<&user32.wsprintfA>\] ;
user32.wsprintfA
00401040 $-FF25 08204000 JMP DWORD PTR DS:\[<&user32.MessageBoxA>\] ;
user32.MessageBoxA

Passons à notre débogage alors.

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).

Ligne 2 : CMP EAX, 0


CMP signifie Comparer. Il compare son premier argument avec le second. Si la comparaison
est vraie, elle définit un "drapeau" indiquant qu'elle est vraie. Dans ce cas, il compare EAX à
0 ( quelque chose comme "if ( eax == 0 )" en C ). Dans la ligne précédente, EAX a été remis à
zéro, et maintenant il est comparé à 0, donc cette comparaison est vraie.

Ligne 3 : JE SHORT fergo\_ex.00401015


Sauter si égal. Comme son nom l'indique déjà, si les arguments de la comparaison précédente
sont égaux ( comparaison vraie ), il effectue un saut vers une autre région du code. Dans ce
cas, puisque la comparaison était vraie, il sautera à l'adresse 00401015 de l'exécutable
fergo_ex1.exe.

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 7 : LEA EAX, DWORD PTR DS:\[403000\]


La commande LEA fait pointer le premier argument vers le deuxième argument. Il ne prend
pas la valeur du deuxième argument, il prend juste "l'emplacement" où se trouve cette valeur.
Dans ce cas, il se déplacera vers l'adresse du registre EAX 403000 (qui correspond à une
valeur de 32 bits ( DWORD )).

Ligne 8 : LEA EBX,DWORD PTR DS:\[403009\]


Même chose que la commande top, sauf qu'elle déplace une adresse différente vers une
variable différente (403009 pour EBX)

Ligne 9 : PUSH 0


Il "tire" simplement son argument ( 0 ) vers un emplacement temporaire, il n'exécute aucune
commande. Voir plus ci-dessous.

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.

Ligne 13 : CALL <JMP.&user32.MessageBoxA>


Fait un appel à n'importe quelle fonction. Dans ce cas, il appellera la fonction MessageBoxA,
contenue dans la DLL user32.dll. Comme vous l'avez peut-être deviné, cette fonction affiche
un message texte. Vous avez peut-être également deviné qu'il s'agit du message texte qui
apparaît lorsque vous démarrez le programme.
D'accord, mais où obtient-elle le contenu à afficher ? Jetons un coup d'œil aux arguments que
prend la fonction MessageBoxA (recherchez-la sur google si vous voulez savoir d'où je tiens
cela):

MessageBoxA ( propriétaire, adresse de texte, adresse de titre, type )

Propriétaire indique le propriétaire de la fenêtre, cela n'a plus d'importance maintenant.


L'adresse de texte et l'adresse de titre sont ce que dit le nom. Type est le type de message
(bouton OK/Annuler, Oui/Non, etc... ). Mais où sont passés ces arguments dans notre code ?
Chaque fonction d'appel dans ASM prendra les arguments que vous avez "tirés" dans l'ordre
inverse. C'est-à-dire que le propriétaire l'obtiendra à partir de l'adresse 00401025, le texte qu'il
obtiendra à partir de 00401024 et ainsi de suite. Chaque "Push" que vous avez donné, il a mis
la valeur au-dessus d'une pile, et pour obtenir les valeurs de cette pile, vous commencez par la
dernière valeur (le dernier Push). Imaginez-vous empiler des livres puis les ramasser pour les
ranger dans un ordre ;D
Ligne 14 : PUSH 0 Une nouvelle valeur est mise dans la "pile" (vous devez maintenant
imaginer qu'une autre fonction qui utilisera cette valeur doit venir). Et viens!

Ligne 15 : CALL <JMP.&kernel32.ExitProcess> Encore une fois, un appel de fonction est


effectué. Cette fois, la fonction est ExitProcess. Vous avez peut-être déjà remarqué que cette
fonction termine le programme si son argument a une certaine valeur. Vous avez remarqué
lorsque vous avez exécuté l'exécutable que dès que vous cliquez sur OK, le programme se
ferme, donc c'est logique. Dans la ligne précédente, vous avez mis une valeur de 0 dans la
"pile". Cette fonction reçoit cette valeur zéro. Si votre programme se termine lorsque vous
fermez la fenêtre et que la fonction pour terminer le processus reçoit la valeur 0, vous savez
que si la fonction reçoit la valeur 0, elle termine le programme.

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 !

02. Recherche du mot de passe correct


Dans ce tutoriel, nous allons apprendre à trouver un code valide pour que le bon message
apparaisse. N'oubliez pas que l'ingénierie inverse est tout à fait légale tant qu'elle n'implique
pas de logiciel commercial ou qu'elle n'enfreint pas le droit d'auteur. Comme dans ce cas,
nous utiliserons une application créée exclusivement pour ce type d'étude, pas de problème.

Tout d'abord, téléchargez notre cible :

-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>

Comme vous pouvez le voir, c'est le deuxième argument de la fonction MessageBoxA.


D'accord, mais quand cette fonction est-elle appelée ? Nous devons trouver comment nous
pouvons nous arrêter ici. Pour cela, sélectionnez la première ligne de cette séquence dans la
boîte de message ( 0041068 ). Maintenant, juste sous la fenêtre de code, un texte "Jump from
00401050" est apparu.

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 :

00401050 74 16 JE COURT v2.00401068

Si 2 éléments comparés sont égaux, il saute à 00401068 (où apparaît la MessageBox


contenant le message de réussite). Quels éléments ? Les éléments de la ligne précédente.
Faites un tour d'horizon des lignes qui précèdent ce saut :

00401043 E8 56000000 CALL <JMP.&user32.GetDlgItemInt>


00401048 BB 9A030000 MOV EBX,39A
0040104D 4B DEC EBX
0040104E 3BC3 CMP EAX,EBX
00401050 74 16 JE SHORT v2.00401068

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 !

03. Comprendre les algorithmes


Rappel : L'ingénierie inverse est tout à fait légale tant qu'elle n'implique pas de logiciel
commercial ou qu'elle n'enfreint pas le droit d'auteur. Comme dans ce cas, nous utiliserons
une application créée exclusivement pour ce type d'étude, pas de problème.

Comme toujours, téléchargez notre cible :

-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 ).

BINGO ! Vous venez de trouver la bonne clé pour votre 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é.

-Analyse de la première séquence ( 00401208 )

Commençons alors l'analyse à l'adresse 00401208. Il prend d'abord la longueur du nom et la


stocke dans EAX. Ensuite, il définit la valeur EAX sur l'adresse [40DC86]. Dans les lignes
suivantes il compare la longueur du nom ( qui est en [40DC86] ) avec 4 puis avec 32 ( 50 en
décimal ). S'il est supérieur à 50 ou inférieur à 4, il saute pour indiquer que le nom est soit
trop gros, soit trop petit. En supposant que vous ayez saisi un nom d'une longueur de 4 <=
nom >= 50, nous pouvons continuer.

A 00401231 démarre le calcul de la première séquence de la touche. Il réinitialise EAX, EBX


et ECX ( XOR X, X réinitialise la valeur X). Ensuite, il déplace le nom tapé vers EDI et la
longueur du nom vers EDX. Sur la ligne suivante, une "Loop" démarre, c'est-à-dire une
séquence qui se répète jusqu'à ce qu'une certaine condition soit atteinte. Voir la séquence

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]

-Analyse de la première séquence ( 00401263 )

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:

Chaîne2 = Chaîne1 * Chaîne1 * Chaîne1

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]

-Analyse de la première séquence ( 0040128A )

Comme toujours, cela commence par mettre à zéro EAX, EBX, EDX, ECX

00401292 B8 F8E04000 MOV EAX,keygenme.0040E0F8 ; Move para EAX o NÚMERO


0040E0F8 ( não se iluda nesta parte )
00401297 03D8 ADD EBX,EAX ; Move para EBX o mesmo número
00401299 33CB XOR ECX,EBX ; Realiza um XOR entre ECX e EBX
0040129B 0FAFCB IMUL ECX,EBX ; Multiplica EBX por ECX
0040129E 2BC8 SUB ECX,EAX ; Subtrai EAX de EBX

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

Nous avons déchiffré l'ensemble de l'algorithme. Comment il assemble la chaîne complète


(met tout ensemble) ne nous intéresse pas, mais au cas où vous voudriez comprendre, il le fait
à partir de la ligne 004012C5. N'oubliez pas non plus qu'il ajoute un "Bon-" au début de la
touche. Maintenant, ce que vous devez faire est de choisir une langue pour programmer votre
générateur. Je vais le faire en VisualBASIC car tout le monde comprend.

-Code générateur, en VB

Private Sub Gerar\_Click()


....Dim seq1 As Double, seq2 As Double
....Dim tamanho As Integer, i As Integer

....'pega o tamanho do nome


....tamanho = Len(txtNome.Text)
....If (tamanho < 4) Or (tamanho > 50) Then Exit Sub

....'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

C'est ça. C'est la fin du tutoriel!

F3rGO !

04. Supprimer les nag-screens


C'est certainement mon tutoriel le plus simple, spécialement conçu pour ceux qui font de
l'ingénierie inverse pour la première fois.

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 :

00401023 6A 30 PUSH 30 ; Puxa o tipo da msgbox para janela com ícone de


exlamação
00401025 50 PUSH EAX ; Puxa o título
00401026 53 PUSH EBX ; Puxa o texto da msgbox
00401027 6A 00 PUSH 0 ; Puxa o dono da janela
00401029 E8 B0010000 CALL <JMP.&user32.MessageBoxA> ; Chama a função, que
usa como argumentos os 4 valores puxados anteriormente

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".

Après avoir changé de ligne, continuez et lancez le programme ( F9 ) et bang ! L'écran


bourrin est parti ! Nous avons atteint notre objectif. Si vous souhaitez enregistrer les
modifications, cliquez sur "Bouton droit->Copier depuis l'exécutable->Toutes les
modifications", puis sur "Copier tout". Dans la fenêtre qui s'ouvre, faites à nouveau un clic
droit et allez dans "Enregistrer le fichier".

F3rGO !

05. Création d'un patcher


Ce tutoriel vous apprend à changer les octets d'un exécutable pour changer son comportement
sans avoir besoin d'OllyDbg. Je vais utiliser l'exécutable du tutoriel précédent ( Tutoriel #4 ).

-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 !

Allez. Nous avons eu la situation suivante dans le tutoriel 4


Je dois expliquer certaines choses. Chaque instruction dans ASM a une valeur, qui occupe
généralement 1 octet, suivie d'un argument. La deuxième colonne d'Olly, contient la valeur de
l'instruction ( OpCode ) en Hexadécimal, et la troisième colonne montre ce que nous appelons
Mnemonic, c'est-à-dire le "surnom" de l'OpCode, ce qui facilite notre compréhension.

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.

Maintenant, je vais parler un peu de "Adresse", le numéro de ligne. Le numéro de ligne


indique simplement l'emplacement de chaque instruction à exécuter, en hexadécimal. Il
commence à 0 et augmente à chaque instruction. Disons que j'ai une commande à l'adresse 00,
et cette commande occupe 2 octets (un PUSH suivi d'une constante, par exemple : PUSH 69 ).
La prochaine instruction sera à l'adresse 00 plus les 2 octets qu'occupe l'instruction
précédente, donc, elle sera à l'adresse 02. C'est par cette adresse qu'on va se situer pour faire le
Patch, mais il y a un hic : l'exécutable le fichier ne démarre pas correctement avec les
commandes. Avant de lancer les commandes, il a tout un en-tête, qui indique différentes
caractéristiques, etc. Cet en-tête a une taille de 1024 octets (400 en hexadécimal) et ce n'est
qu'après que les instructions commencent. C'est-à-dire,la première commande ne sera pas
dans l'octet 0, mais dans l'octet 1025 ( 401 en Hex ).

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 :

octets d'origine Octets modifiés


23 6A (POUSSER) 90
24 30 90
25 50 (POUSSER EAX) 90
26 53 (POUSSER EBX) 90
27 6A (POUSSER) 90
28 00 90
29 E8 (APPEL) 90
2A B1 90
2B 01 90
2C 00 90
2D 00 90
2E 56 (POUSSER ESI) 90

CRÉATION DU PATCHER

Avant de démarrer le patcher, rappelons-nous quoi et où changer. Nous devons remplir 11


octets (du premier PUSH à l'adresse 00401023 à 00 à l'adresse 0040102D ) avec la valeur 90,
ce qui indique aucune opération. Où allons-nous changer ? Dans le fichier exécutable bien
sûr. Quels octets ? 23 (35 en décimal), 24 (36 en décimal) et ainsi de suite ? NON! N'oubliez
pas qu'avant de lancer les commandes, 1024 octets composent l'en-tête de l'exécutable. 1024
vaut 400 en hexadécimal (utilisez la calculatrice de windows), nous devrons donc passer de
l'octet 423 à 42D (1059 à 1069).

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

Private Sub cmbPatch\_Click()


....Dim bytFile() As Byte 'Nosso array ( vetor ) de bytes
....Dim strFile As String 'Nosso alvo
....Dim i As Integer 'Só para as iterações

....strFile = App.Path & "\\fergonag.exe" 'Define o local onde está o alvo

....ReDim bytFile(FileLen(strFile) - 1) As Byte 'Redimensiona o nosso array


de bytes para o tamanho do alvo

....Open strFile For Binary As #1


........Get #1, , bytFile() 'Pega todos os bytes do alvo e coloca no nosso
array
....Close #1

....For i = &H423 To &H42D


........bytFile(i) = &H90 'Coloca o valor 90 do byte 423 (hex) até 42D
....Next

....Open strFile For Binary As #1


........Put #1, , bytFile() 'Devolve os bytes já modificados para o alvo
........MsgBox "Alvo alterado com sucesso", vbInformation, "Wee" 'Mostra
mensagem de texto avisando que tudo ocorreu bem
....Close #1
End Sub

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 !

06. Déballage de l'UPX


Plusieurs applications distribuées là-bas sont compressées avec un certain type de
compresseur, pour réduire la taille de l'exécutable et rendre le débogage difficile. L'un de ces
compresseurs, peut-être le plus connu, est l'UPX ( Ultimate Packer for eXecutables ). Il a une
excellente compression et décompresse l'exécutable d'origine très rapidement. Il est Open
Source et peut être téléchargé gratuitement sur http://upx.sourceforge.net

Il existe plusieurs façons de décompresser les exécutables. Vous pouvez utiliser le


décompresseur UPX lui-même, utiliser un décompresseur tiers ou décompresser à la main, ce
que nous allons faire dans ce didacticiel. Tout d'abord, je vais vous expliquer comment
fonctionne un compresseur de type UPX.

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 :

EP -> Loader -> Décompresser le contenu de l'exécutable en mémoire -> Déplacer EP


vers OEP.

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).

Appuyez sur F9 pour continuer l'exécution du programme. Presque instantanément, nous


sommes arrivés au point d'arrêt défini. Olly s'est arrêté ici :

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.

00401190 68 A09E4000 PUSH UnpackMe.00409EA0


00401195 E8 EEFFFFFF CALL UnpackMe.00401188
0040119A 0000 ADD BYTE PTR DS:\[EAX\],AL

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).

Démarrez maintenant ImpRec et configurez-le comme indiqué dans la figure :

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 !

07. Pièges et changement de code


Certaines applications disposent de certaines protections contre les programmes de débogage
(OllyDBG, SoftICE, WinDbg, etc.), comme c'est le cas avec notre cible. La protection qu'il
utilise est très simple, il génère simplement une exception (une branche dans le code, qui
génère souvent une erreur dans le programme) qui affiche un message texte avertissant que
nous utilisons un débogueur et termine le programme après cela.

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 :

Événement en une seule étape à crackme2.00401047 - utilisez Shift+F7/F8/F9 pour


transmettre l'exception au programme

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.

Remarquez à nouveau la fonction "lstrcmpA", elle a besoin de 2 arguments ( les 2 chaînes )


pour être comparée. L'une des chaînes est évidemment le numéro de série que nous avons tapé
et l'autre est le numéro de série valide. L'une des chaînes est stockée dans 004060BA (premier
argument extrait) et l'autre est stockée dans 004062B6 (deuxième argument). Dans lequel des
2 arguments est le bon numéro de série ? Soit vous analysez le code de génération de la clé
(juste au dessus), soit vous procédez par essais et erreurs (test avec une adresse, puis avec
l'autre). Je sais déjà que le vrai numéro de série est à l'adresse 4062B6 et que le numéro de
série que nous avons tapé est à 4060BA. Donc ce que nous devons faire est de changer le
texte de la MsgBox : au lieu de dire "Wrong Serial - try again!", il affiche le bon numéro de
série. Faire cela est très facile, allez à l'endroit où il tire le texte "Mauvais numéro de
série..."de msgbox ( 401274 ):

00401274 68 60604000 PUSH crackme2.00406060 ; ASCII "Wrong serial - try


again!"

Double-cliquez sur "PUSH crackme2.00406060" et changez-le en "PUSH 004062B6" :

00401274 68 60604000 PUSH crackme2.004062B6

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 !

08. Activer les commandes


Ce didacticiel vous apprendra comment modifier l'état d'un contrôle (un bouton de
commande, dans ce cas) dans n'importe quelle application créée en Visual Basic. Nous
n'allons pas utiliser Olly (il peut être utilisé aussi, mais cela n'en vaut pas la peine). Au lieu de
cela, utilisons n'importe quel éditeur hexadécimal doté d'un moteur de recherche intégré.
J'aime WinHex

Comme toujours, téléchargez la cible (codée en VB)

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

Avant de Plus tard


EF 01 08 00 EF 01 08 01

Maintenant, enregistrez simplement le fichier via WinHex ("Fichier->Enregistrer" ). Si vous


relancez la cible, le bouton sera activé ;D

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.

Partie 2 - Activer le bouton

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.

Ouvrez DUMPED_.exe dans WinHex et effectuez une recherche ("Rechercher->Rechercher


du texte") en mode ASCII pour le texte du bouton désactivé : "S'inscrire" (sans les
guillemets). Nous avons été emmenés au 6CC3 Offset, où il y a le mot "Record".

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é.

Lisez le didacticiel n°8 pour une explication plus détaillée du processus.

Partie 3 - Désactivation de la protection contre Olly

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 :

00408AF1 75 6E JNZ SHORT DUMPED\_.00408B61

Basculez vers (sélectionnez la ligne et appuyez sur espace) :


00408AF1 EB 6E JMP SHORT DUMPED\_.00408B61

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É

Partie 4 - Recherche de la bonne série

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é).

Bingo ! Pour le nom F3rGO!, le numéro de série est 418.

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 ).

Partie 5 - Écran Nag

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 !

Vous aimerez peut-être aussi