[tuto]prise en main et création de .exe à l'aide d'un débugueur 32bits fournit avec windows

Description

#### Prérequis :

Windows XP ou 2000. Non testé sous Vista.
notepad.exe, dans la même version que moi (Fournie dans le zip).
Aucun logiciel, même pas un assembleur, n'est nécessaire.
Des connaissances en assembleur, niveau très débutant, sont requises (Connaître call, push, lea, mov xor...)
De la patience.

Evidemment, je décline toute responsabilité en cas de problème.

#### Objectifs de ce tutorial :

1 Faire de l'assembleur 32 bits et des .exe sur un PC sans installer de logiciels.
2 Apprendre à se servir d'un débogueur ring 3 de Microsoft.
3 Apprendre à récupérer des informations sur un executable, et mieux connaître le format PE.

Et surtout, se faire plaisir en discutant avec le processeur !!

Source / Exemple :


#### Introduction :

Vous partez en vacance à la campagne chez tante Martine.

Tante Martine a un PC sous XP qui lui sert de machine à écrire, mais n'a pas le net.

Vous prenez donc vos précautions en mettant votre environement de développement préféré sur votre clé USB, histoire de pouvoir l'installer pèpère chez elle.

Manque de chance, à peine arrivé, vous perdez votre clé USB en batifolant dans un champ.

Le soir, désespéré devant le PC de tante Martine, vous vous demandez ce que vous allez bien pouvoir faire...

Un PC sortie d'usine ne propose que peu d'options pour faire du développement.

On peut faire de l'assembleur DOS 16 bits avec debug. On est coincé dans une console, et on ne peut utiliser que les interruption DOS et BIOS, dont vous avez forcément oublié les numéros (Et oui, il n'y a pas le net chez tantine).

On peut faire du DOS. Cette fois, la liste des commande (Plus complète que celle de help) est présente dans l'aide et support, et les commandes s'autodocumentent avec /?. Manque de chance vous connaissez déjà bien le DOS, et vous ne voyez pas grand chose d'intéressant à faire avec...

Le navigateur est capable de dessiner des pages web à partir de code HTML. Mais vous vous êtes toujours dit qu'appelez le HTML du code, c'était un peu exagéré. 

On peut faire des scripts VB et JS, qui seront executés par wscript, cscript, ou encore les mêler à de l'HTML pour les exécuter sous IE. Si office est présent on peut faire aussi du VBA. Mais le problème c'est que ces langages vous donnent de l'urticaire (Et vi, ce tuto est pas sur usineàgazfr.com).

Ne commencez pas une partie de démineur : il reste une option !

Le vieux Bill a en effet décidé de nous livrer en standard sous XP un débugueur 32 bits. Vivi, même à tante Martine.

Celui-ci répond au doux nom de ntsd.exe et se trouve fort peu originalement dans system32.

#### Présentation de ntsd :

Pour ceux qui connaissent WinDbg, la prise en main de ntsd ne posera pas de problème. ntsd est comme WinDbg à plusieurs différences près :

1 Il ne permet que de déboguer en ring 3.
2 Il est en invite de commande.
3 Des dlls d'extension proposant des commandes supplémentaires fournies avec WinDbg ne sont pas présentes en standard.
4 Il lui arrive de planter si on fait une faute de frappe...
5 Une bonne partie des commandes des extensions fonctionnent mal ou plantent.
6 Il vaut mieux oublier les pseudo registres ($ra, $ea, $exp...).

Les débogueurs Microsoft (WinDbg, kd, ntsd, cdb...) se différencient de certains débugueurs/désassembleurs classiques (IDA, TD32, W32DASM...) par le fait qu'ils se manipulent en entrant des commandes en invite, comme avec le bon vieux debug.exe. Ils proposent toutes les fonctionnalités nécessaires en matière de pas à pas, points d'arrêts... mais ne propose pas forcément autant d'outils d'extraction d'information. Par exemple, IDA est capable d'éssayer de déterminer quel compilo à généré un exe, ou W32DASM affiche les tables d'import et d'export directement.

#### Démarrage de ntsd :

Si on lance ntsd sans lui passer de paramètre, il affiche son aide et se ferme.

Voici quelques possibilités de lancement :

1 On peut passer un fichier .exe en paramètre de ntsd pour qu'il démarre son débogage.
2 On peut s'attacher à un processus existant, via son pid et l'option -p.
3 On peut s'attacher à un processus existant, via son nom de module, mais il faut qu'il y en ai un seul qui ait ce nom. Exemple :
ntsd -pn notepad.exe
4 On peut le mettre en remplacement du docteur Watson, pour qu'il s'attache automatiquement à un processus qui plante.
Pour cela, il faut changer la clé :
HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug
La valeur auto permet de définir la présence d'une MessageBox qui demande si on veut déboguer le processus.
Dans la valeur Debugger, on peut par exemple mettre :
ntsd -p %ld -g

#### Prise en main :

? permet d'afficher une partie des commandes, et .help une autre partie.

Au début, le débugueur affiche des erreurs ou des warnings en parlant de symboles. Les symboles de débogages facilitent celui-ci. Cependant, on ne dispose généralement pas des symboles d'une application que l'on a pas compilé.

Quand le débugueur laisse tourner le processus (On ne peut plus rentrer de commandes et le processus à un fonctionnement normal), il faut utiliser ctrl + c.

q permet de quitter ntsd, et tuera l'application débuguée.

Alt + entrée est le raccourcis qui permet de mettre une application DOS en mode plein écran. Mais je n'ai pas trouver d'instruction more.

ctrl + b permet de quitter plus violemment que que q.

Pour se détacher d'une application sans la tuer, il faut commencer par faire .detach, puis q.

.restart permet de redémarrer l'application, mais ne fonctionne pas si on s'est attaché à un processus.

Le processus peut avoir plusieurs threads. On affiche la liste des threads avec ~*.

On peut executer une commande sur un seul thread en la préfixant :
~NumeroThreadCommande

Un ? suivie d'une expression provoque l'évaluation de celle-ci.

echap permet d'effacer la ligne.

Les registres doivent parfois être préfixés par @.

#### S'attacher à un processus en cours de fonctionnement :

On a vu que l'on pouvait utiliser l'option -pn.

ntsd crée alors un thread pour mettre un point d'arrêt.
On met alors souvent en place un point d'arrêt sur une fonction de l'API Win32 probablement utilisée dans le code que l'on veut voire.
Par exemple :
bp BitBlt
Puis on utilise la commande g pour reprendre l'execution.

Si la fonction est appelée par le programme, celui-ci va être arrêter par le point d'arrêt.
On se trouve alors au tout début de la fonction BitBlt.
On peut examiner les paramètres passés à cette fonction de Windows, mais son code nous intéresse moins que le code de l'appelant.

L'adresse de l'appelant est empilée sur la pile.
Pour faire un step out il faut donc faire (La commande gu et le pseudo registre $ra de WinDbg semblent mal supportés par ntsd) :
g poi(esp)

poi() permet de déférencer un pointeur.

#### Les dlls d'extension :

Ces dlls permettent de rajouter des commandes à ntsd.
Ces commandes commencent par un ! et certaines d'entres-elles fonctionnent mal sous ntsd.

Pour afficher la liste des dlls dans lesquelles ntsd cherche les commandes, on utilise la commande .chain.
Elle affiche le chemin de recherche des dlls, ainsi que les dlls chargées et non chargées.

Les dlls non chargées peuvent provoquer l'affichage de messages d'erreurs génants. On peut les décharger avec la commande .unload.

Les dlls présentes en standard sur mon XP sont :
dbghelp.dll
exts.dll
ntsdexts.dll

Vous pouvez charger une dll d'extension avec la commande .load.

Pour lister les commandes d'une dll, on utilise la syntaxe suivante :

!module.help

Elle ne fonctionne pas sur dbghelp.dll.

#### Format PE et loader de windows :

Chez tantine, on souhaite pouvoir rédiger et tester du code assembleur, et pourquoi pas s'arranger pour obtenir des .exe valides.

Un .exe est au format PE. Il est composé de headers et de sections. Le loader de windows charge les headers dans la mémoire à une certaine adresse qui peut théoriquement être arbitraire. En réalité, la plupart des .exe exigent d'être chargés à une adresse bien précise (Les dlls ont par contre une base de relocation qui leurs permet d'être chargées à n'importe quelle adresse). Les headers précisent à quelles adresses doivent être chargées les sections, relativement à l'adresse des headers (L'adresse du module quoi).

Les PE disposent d'une table d'importation qui définit quelles fonctions de l'API Win32 sont nécessaires à l'application. Le loader de Windows complète cette table avec les adresses qui vont bien lors du chargement de l'exe. Dans le code machine, lors de l'appel d'une fonction de l'API, le call récupère l'adresse dans cette table. Il connait l'adresse de cette table car elle se trouve toujours au même endroit, à un certains offset depuis l'adresse du module qui elle même est fixe.

La construction d'un exe valide au format PE à la main et sans documentation est du pur suicide. Il est bien plus simple d'utiliser un .exe éjà existant sur le PC de tantine.

On souhaite pouvoir executer n'importe quelle fonction de l'API Win32... Il faut donc disposer des fonctions LoadLibrary et GetProcAddress. notepad.exe importe ces deux fonctions, et servirat donc de base de travail.

#### Récupération des informations sur un executable :

Voyons voir ce que notepad a dans le ventre :
ntsd notepad.exe

ntsd charge le programme et s'arrête sur un point d'arrêt.

La commande lm affiche les modules (.dll, .exe, .ocx...) chargés par l'appli, ainsi que leurs adresses de début et fin.
Notons l'adresse du module notepad : 01000000.

La command !lmi, suivie d'un nom de module, donne un peu plus d'informations sur celui-ci.

Mais la commande !dh est nettement plus efficace : elle affiche tout un tas d'infos sur les headers et les sections.

On remarquera par exemple dans les caractéristiques "Relocations stripped", qui signifie que ce module ne peut être chargée qu'à une seule adresse.

On peut vérifier que le champ "Image Base" a bien la valeure qu'on a noté tout à l'heure : 01000000.

On prend note du point d'entrée (entry point), 739D.

Sous le "optional header", il y a les data directories. Ce sont des pointeurs vers des données particulières, elles même se trouvant généralement dans les sections. Ces données sont par exemple les tables d'import et d'export, les tables de relocation qui permettent aux dlls d'être chargées à n'importe quelle adresse, les ressources...

Notons l'adresse de la table d'importation, 7604.

Finalement, on a les informations sur les sections.

notepad à 3 sections :

1 .text : Contient le code. Dans le fichier, cette section se trouve à l'adresse 400 à partir du bébut de fichier, pour une taille de 
7800 octets (Informations "raw data"). Dans la mémoire elle se trouve à l'adresse du module (01000000) + 1000, pour une taille de 7748 (Informations "virtual") On remarque que le point d'entrée et la table d'importation sont dans cette section.

2 .data : Contient les données initialisées ou non. On constate que la taille dans le fichier (raw data) est très inferieure à la taille dans la mémoire (virtual). Les données non initialisée seront placés dans cet espace supplémentaire. Les données initialisées ou non sont par exemple les variables globales.

3 .rsrc : Les ressources. Menu, bitmap, chaînes...

Jettons un coup d'oeil à la table d'importation. Elle se trouve en 01000000 + 7604. Pour l'afficher, on utilise la commande db. db prend une adresse ou une plage.
db notepad + 7604 L1000 affiche les 0x1000 premiers octets de la table.
Cela affiche les noms des fonctions importées, même si le formatage n'est pas terrible...

On peut préciser la base d'un nombre en le préfixant :

0x prefix (hexadecimal)
0n prefix (decimal)
0t prefix (octal)
0y prefix (binary)

Les commandes classiques d'affichage du contenu de la mémoire sont :

dd : dword
da : ASCII
du : Unicode
db : byte
dw : 16 bits
dq : 64 bits
dyd : Binaire

Toujours concernant la récupération d'informations sur les modules, on peut récupérer la liste des fonctions exportées par une dll. Par exemple :
x kernel32!Get*

Affiche toutes les fonctions exportées par kernel32 qui commencent par Get.

Certaines API sont en deux versions, une suffixée A pour l'ASCII, une autre suffixée W pour l'Unicode.
Pour se simplifier la vie, on peut utiliser la commande ss, suivie de w(Unicode), a(ASCII) ou n(Aucun).
De cette manière, lorsque l'on entre un symbole que ntsd ne trouve pas, il ajoute le suffixe au symbole, et recommence la recherche.

La commande ln nous donne les symboles les plus proches d'une adresse. Dans notre cas où l'on a pas de symboles autres que les fonctions exportées, cela nous permet de savoir à quelle fonction appartient une adresse facilement.

Enfin, la commande !handle liste les handles sur des objets systèmes et leurs types.

#### Détourner le comportement d'un executable :

A présent, on se propose de modifier notepad pendant son execution.

On commence par repartir sur une base propre :
ntsd notepad.exe

On se souvient de l'adresse du point d'entré : c'est là que l'on va assembler notre code.

Jettons un coup d'oeil au code actuel :
u notepad + 739D

On va appeler MessageBoxA, puis ExitProcess.

On va commencer par mettre deux chaînes dans la mémoire, une pour le contenu de la MessageBox, une autre pour le titre.

Ou mettre ces chaînes ?
On a beaucoup de place, mais ce n'est pas une raison pour écraser quelque-chose.
On va donc écrire dans les données non initialisées.
!dh notepad

Section .data.

    1BA8 virtual size
    9000 virtual address
     800 size of raw data
    7C00 file pointer to raw data

On ecrira donc en notepad + 9000 + 800.

Les commandes pour écrire dans la mémoire sont les suivantes :

ea : Ecrire une chaîne de caractère dans la mémoire, sans caractère terminal.
eb : Ecrire des octets dans la mémoire.
ew, ed, eq : Ecrire de la taille spécifiée dans la mémoire.

La commande d'écriture de chaînes à zéro terminal eza de WinDbg n'est pas utilisable... On écrit donc :
eb notepad + 9800 'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' 0

on vérifie :
db notepad + 9800

On écrit le titre un peu plus loin :
eb notepad + 9810 'Y' 'e' 'a' 'h' '!' 0

A présent, il ne reste plus qu'à coder !! (Enfin !)
Pour assembler, c'est a :
a notepad + 739D

Pour arrêter d'assembler, il suffit de ne rien entrer sur la ligne et de presser entrée.

Il faut pousser les arguments de MessageBoxA, de la droite vers la gauche :

xor @eax, @eax
push @eax
lea @ebx, [notepad + 9810]
push @ebx
lea @ebx, [notepad + 9800]
push @ebx
push @eax
call MessageBoxA
xor @eax, @eax
push @eax
call ExitProcess

On désassemble pour vérifier :
u notepad + 739D

Et go ! :
g

#### Travailler depuis un fichier :

Bon, le code que l'on a écrit, on préfèrerait le conserver...
Avec debug, on pouvait envoyer des commandes contenues dans un fichier avec une redirection <, ou encore en utilisant un pipe et la commande type.
Avec ntsd, on peut utiliser l'option -c et la commande $< comme je l'ai fait dans le zip.

Si on souhaite mettre des lignes vides dans le fichier en question, il faut mettre celles-ci en commentaire, car une pression sur entrée demande à ntsd de réexecuter la dernière commande. Pour mettre en commentaire une ligne, on utilise $. On garderat la commande * pour mettre des vrais commentaires. Cela peut nous permettre de faciliter l'imortation du code dans un assembleur classique. Ces caractères provoqueront une erreur mineure au milieu du code (Par contre cela ne facilite pas vérification que l'assemblage s'est bien passé), lors de l'assemblage, sans poser plus de problèmes.

===============================
eb notepad + 9800 'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' 0
eb notepad + 9810 'Y' 'e' 'a' 'h' '!' 0
$
a notepad + 739D
$
xor @eax, @eax
push @eax
lea @ebx, [notepad + 9810]
push @ebx
lea @ebx, [notepad + 9800]
push @ebx
push @eax
call MessageBoxA
xor @eax, @eax
push @eax
call ExitProcess

$
g
q

===============================

On copie ça, on lance ntsd notepad.exe, puis clique gauche sur l'icône en haut à gauche de la console, coller.

#### Principe de la sauvegarde de l'exe sur le disque :

Devoir faire un copier coller lors du développement, c'est déjà bof, mais alors être obligé de le faire sur l'application finale, ce serait horrible. Qui plus est, si on pouvait éviter de réassembler l'application à chaque lancement, ce ne serait pas plus mal...

On va donc écrire notre notepad depuis la RAM vers le disque.

Le programme de compilation sera placé dans les données non initialisées pour pouvoir disparaître.
Les chaînes de notre application vont devoir se trouver dans les données initialisées.
Notre code devra se trouver dans la section .text.

On exploiterat donc les zones suivantes :

Données non initialisées :
9800 -> ABA8

Données initialisées (2 milles caractères) :
9000 -> 9800

Code :
3000 -> 7604

Le point d'entrée est en 739D. La valeur de 3000 comme début du code est arbitraire mais assure une bonne marge de sécurité tout en nous donnant bien assez de place. Le point d'entrée en 739D était un peu près de la table d'import en 7604. On va donc faire un saut à l'adresse 3000 dès le début du programme.

Le code de compilation est théoriquement simple : il faut claquer la mémoire dans un fichier. Mais pas n'importe comment car il faut penser aux section.

L'écriture se fait en 4 phase :
1 Copie des headers et des bits qui le suive (On dirait que la Bound Import Table n'est pas dans une section...) :
  raw data : 0 -> 400
  virtual : 0
  taille : 400
2 Copie de la section .text (On remplit jusqu'à tomber sur l'offset de la section .data : 
  raw data : 400 -> 7C00
  virtual : 1000
  taille : 7800
3 Copie de la section .data
  raw data : 7C00 -> 8400
  virtual : 9000
  taille : 800
4 Copie de la section .rsrc
  raw data : 8400 -> 11400
  virtual : B000
  taille : 9000

0x11400 = 70656 octets = la taille de notepad.exe !

#### L'utilisation des fonctions de l'API Win32 :

Les fonctions de l'API Win32 sont dans des dlls, et sont donc suceptibles de ne pas être chargées aux mêmes adresse d'une execution sur l'autre. En fait si, on fait des éssais, on s'aperçoit que les principale dlls (kernel32...) sont toujours chargées au même endroit.

Mais essayons de travailler proprement.
On sait que le loader va mettre les adresses de LoadLibrary et GetProcAddress à une adresse précise en mémoire car ces fonctions sont dans la table d'import de notepad.

La première étape consiste à déterminer les emplacement de ses adresses.
On pourrait décrypter la table d'import. Mais on va plutôt laisser faire le travail à ntsd.

La dernière section est à l'adresse virtuelle notepad + B000, avec une taille qu'on arrondit à 9000.
On va donc bourriner en cherchant de notepad à notepad + 14000.

La commande s permet de rechercher dans une plage mémoire :
s -b : 8 bits
s -w : 16 bits
s -d : 32 bits
s -q : 64 bits
s -a : ASCII
s -u : Unicode

Les commandes sa et su permettent de cherher des chaînes repectivement ASCII et Unicode sans préciser de pattern.

s -d notepad L14000 LoadLibraryA
s -d notepad L14000 GetProcAddress

Les résultats nous donnent une adresse et une série de valeur. On peut vérifier que c'est bien la première valeur en évaluant le symbole :
? LoadLibraryA

On obtient :
LoadLibraryA -> 10c8
GetProcAddress -> 1110

On peut essayer de vérifier tout ça en utilisant une fonction intéressante de ntsd. On va placer un point d'arrêt qui ne va pas se déclencher lorsque eip pointera dessus, mais lorsque qu'un accès mémoire sera effectué à cette adresse. ntsd peut refuse la mise en place de ce type de breakpoint lorsque l'on est pas passé par l'entry point, ce qui arrive lorsque l'on lance ntsd en même temps que le processus (Il suffit alors de faire tourner celui-ci puis de le stopper avec ctrl+c), ou, plus grave, lorsque l'on s'attache à un processus.

Dans notre cas, lOadLibraryA est suceptible de n'être appeler qu'en début de prorgamme, on va donc mettre un point d'arrêt sur l'entry point.

ntsd notepad.exe
bp notepad + 739D
g
ba r4 notepad + 10c8
ba r4 notepad + 1110

Ces breaks point seront déclenchés lors de la lecture ou écriture de 4 octets à l'adresse spécifiée.
bl liste les breakpoints, et bc permet d'en supprimer un à partir de son id.

Pas de chance, LoadLibrary est appelée avant l'entry point (On voit bien les ModLoad)...
Mais on va quand même se stopper sur un GetProcAddress.

#### Le code de l'application :

L'application serat identique à la précédente, à trois différences près :
1 MessageBox et ExitProcess seront appelés quelles que soient leurs adresses.
2 Les chaînes seront stockées dans la mémoire initialisée de manière à être sauvegardée sur le disque quand on compilera.
3 On mettra seulement un saut vers notre code à l'entry point.

========================================

  • Mise en place du saut au niveau de l'entry point
a notepad + 739D jmp notepad + 3000
  • Mise en place des chaines dans la mémoire
eb notepad + 9000 'H' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' 0 eb notepad + 9010 'Y' 'e' 'a' 'h' '!' 0 eb notepad + 9020 'k' 'e' 'r' 'n' 'e' 'l' '3' '2' 0 eb notepad + 9030 'u' 's' 'e' 'r' '3' '2' 0 eb notepad + 9040 'M' 'e' 's' 's' 'a' 'g' 'e' 'B' 'o' 'x' 'A' 0 eb notepad + 9050 'E' 'x' 'i' 't' 'P' 'r' 'o' 'c' 'e' 's' 's' 0 $ a notepad + 3000 $
  • Récupération d'un handle sur kernel32
lea @ebx, [notepad + 9020] push @ebx call dword ptr [notepad + 10c8] mov @edi, @eax $
  • Récupération d'un handle sur user32
lea @ebx, [notepad + 9030] push @ebx call dword ptr [notepad + 10c8] mov @esi, @eax $
  • Récupération de l'adresse de MessageBoxA
lea @ebx, [notepad + 9040] push @ebx push @esi call dword ptr [notepad + 1110] mov @esi, @eax $
  • Récupération de l'adresse de ExitProcess
lea @ebx, [notepad + 9050] push @ebx push @edi call dword ptr [notepad + 1110] mov @edi, @eax $
  • Execution du programme
xor @eax, @eax push @eax lea @ebx, [notepad + 9010] push @ebx lea @ebx, [notepad + 9000] push @ebx push @eax call @esi xor @eax, @eax push @eax call @edi ======================================== Comme on est dans un débogueur, il ne faut pas hésiter à utiliser t (Step into) et p (step over) pour vérifier le comportement du programme. La commande ln de recherche du symbole le plus proche, et db, d'affichage de données, nous permettent de contrôler que l'on tape bien au bon endroit. On peut afficher les registres avec r, et les affecter de la manière suivante : r eip = notepad + 3000 Ne pas oublier aussi .restart qui permet de redémarrer le programme sans quitter ntsd. #### Le code de compilation : Le code de compilation est par définition executé dans ntsd. Il n'y a donc pas besoin de prendre des précautions au niveau de l'emploi des API Win32. Chez tante Martine, l'absence de documentation est génante, tout spécialement lorsque l'on emploie des structures, dont on a oublié les champs, ou lorsque l'on emploie des constantes, dont on connait plus les identifiants que les valeurs. Une solution qui peut aider consiste à mettre des points d'arrêts sur ces fonctions, de manière à déterminer les paramètres passés à celles-ci. ========================================
  • Le nom de l'exe que l'on va créer
eb notepad + 9800 'c' ':' '\\' 'T' 'e' 's' 't' '.' 'e' 'x' 'e' 0 $ a notepad + A000 $
  • Ouverture du fichier
xor @eax, @eax push @eax
  • FILE_ATTRIBUTE_NORMAL
mov @ebx, 80 push @ebx
  • CREATE_ALWAYS
mov @ebx, 2 push @ebx push @eax push @eax
  • GENERIC_WRITE
mov @ebx, 40000000 push @ebx lea @ebx, [notepad + 9800] push @ebx call CreateFileA mov @edi, @eax $
  • Ecriture des headers et sections
$ xor @eax, @eax push @eax lea @eax, [notepad + 9810] push @eax mov @eax, 0x400 push @eax lea @eax, [notepad] push @eax push @edi call WriteFile $ xor @eax, @eax push @eax lea @eax, [notepad + 9810] push @eax mov @eax, 0x7800 push @eax lea @eax, [notepad + 0x1000] push @eax push @edi call WriteFile $ xor @eax, @eax push @eax lea @eax, [notepad + 9810] push @eax mov @eax, 0x800 push @eax lea @eax, [notepad + 0x9000] push @eax push @edi call WriteFile $ xor @eax, @eax push @eax lea @eax, [notepad + 9810] push @eax mov @eax, 0x9000 push @eax lea @eax, [notepad + 0xB000] push @eax push @edi call WriteFile $
  • Fermeture du fichier
$ push @edi call CloseHandle nop r eip = notepad + A000 bp CloseHandle g g poi(esp) q ======================================== C'est aussi simple que cela : la copie successive des deux codes précédents dans une console crée avec ntsd notepad.exe génère un executable nommé Test.exe, à la racine de C:\. Cette executable a la même taille que notepad.exe (70 656 octets), mais affiche simplement une MessageBox. #### Conclusion : On est tout à fait en mesure de faire des .exe valides, codés en assembleurs, chez tantine. La seule condition nécessaire (Qui est malheureusement de taille...) est de très bien connaître les fonctions, structures et valeurs des constantes de l'API Win32. #### Commandes diverses : ctrl + v : Active/désactive le mode verbose (Affichage d'informations supplémentaires). .time : Affiche le temps depuis le démarrage du système et depuis le débogage. .tlist : Liste les processus du système. .imgscan : Cherche les images (MZ). wt : Trace une fonction, et affiche les fonctions appelées. pa : Step jusqu'à une adresse, avec affichage d'infos. .shell : Execution d'une commande DOS. .echo : Même comportement que la echo du DOS. !str : Affichage d'une chaîne ASCII ou OEM (La chaîne doit être précédée par sa taille et sa taille max). !ustr : Affichage d'une chaîne Unicode (La chaîne doit être précédée par sa taille et sa taille max). #### Commandes pouvant être utiles lorsque le débogueur s'attache à un processus en perdition : .kframes : Spécification de la profondeur d'inspection de la pile d'appel. .lastevent : Affiche des infos sur le dernier évènement ou exception. !error : Affiche la description d'une erreur Win32 à partir de son numéro. !gle : Dernières erreurs Win32 et NTDLL. .cxr : affiche les infos de contexte. .ecxr : affiche les infos de contexte de l'exception.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.