Valideur PE

Nouveaux concepts :

Utilisation de la boîte de dialogue de sélection de fichier
Travailler avec des structures :
                                   - la structure OpenFileName
                                  - les headers de fichier PE

Nouvelles fonctions API :

GetOpenFileName

 


Dans ce tutoriel, nous allons coder une application simple qui utilise la boîte de dialogue commune de Windows pour ouvrir un fichier exécutable et nous dire s'il s'agit ou non d'un fichier PE valide.
Le code est basé sur le tutoriel PE 2 d'Iczelion, mais avec quelques modifications et l'élimination des éléments SEH pour simplifier un peu les choses pour nos besoins.

L'idée ici est de se familiariser avec la manipulation de structures, à la fois lors de la configuration de la structure OPENFILENAME et lors de la navigation dans les PE headers.

Pour démontrer qu'un fichier est un fichier PE valide, il suffit généralement de montrer que le fichier commence par le texte "MZ" au début du header DOS et que la fin du header DOS contient un pointeur vers le PE header qui commence par le texte "PE" suivi de 2 NULL. Ces signatures ont été définies de manière pratique dans windows.inc :

IMAGE_DOS_SIGNATURE   equ   5A4Dh          ("MZ")
IMAGE_NT_SIGNATURE     equ   00004550h    ("PE" 00 00)
 


Lancez WinAsm, ouvrez un nouveau projet, ajoutez un nouveau fichier .rc et disposez une boîte de dialogue comme ceci :


1

Le script (validate.rc) est inclus à l'endroit habituel. Le bouton marqué de 3 points sert à parcourir les fichiers à ouvrir au lieu de taper le chemin complet dans la zone d'édition. Ensuite, collez le code validate.asm dans WinAsm :


1

La plupart de ces éléments devraient être compréhensibles par eux-mêmes à présent. Nous devons cependant aborder trois nouvelles variables. La structure OFN est déclarée dans windows.inc de la manière suivante :


1

Comme expliqué dans le dernier chapitre, ceci est juste un modèle. Pour l'utiliser dans notre code, nous devons en définir une instance et lui donner un nom comme une variable. Nous l'appellerons ofn, mais nous n'initialiserons aucune de ses valeurs pour le moment, donc nous utilisons la ligne :

.data?
ofn    OPENFILENAME   <>

Seules 5 champs nous importent et doivent être remplis avant d'utiliser l'API GetOpenFileName. Cela se fait dans la procédure de dialogue après avoir cliqué sur le bouton "..." (parcourir pour le fichier).

L'opérateur SIZEOF renvoie la taille de la variable de structure ofn que nous avons définie ci-dessus. Le champ lpstrFilter pointe vers la variable strFilter qui contient le texte qui apparaît dans le menu déroulant du type de fichier de la boîte de dialogue d'ouverture. Le champ lpstrFile pointe vers le tampon TargetName où le nom et le chemin du fichier ouvert seront stockés. Le champ nMaxFile contient le nombre maximum de caractères du nom de fichier et du chemin (la taille maximale du tampon).


1

Ensuite, GetOpenFileName remplit le tampon TargetName avec le nom et le chemin du fichier choisi dans la boîte de dialogue d'ouverture. Si cela réussit, le nom est affiché dans la zone d'édition et le tampon est effacé pour la prochaine fois avec la fonction RtlZeroMemory.

En cliquant sur le bouton GO!, le nom de fichier est récupéré à partir de la zone d'édition, vérifié pour s'assurer qu'il y a effectivement eu une saisie de l'utilisateur, puis passé à la procédure Validate.


1

Le fichier cible est ouvert, un objet de mappage est créé et une vue de l'ensemble du fichier est mappée en mémoire. Toutes ces opérations sont effectuées avec un accès en lecture seule spécifié car c'est tout ce dont nous avons besoin ici. Comme décrit précédemment, MapViewOfFile renvoie un pointeur dans eax vers le premier octet du fichier en mémoire.

La partie suivante illustre une manière légèrement différente d'utiliser des structures pour naviguer dans les PE headers. Les structures d'en-tête sont déjà présentes dans windows.inc et cette fois nous n'avons pas besoin de définir de variables de structure pour celles que nous utiliserons, car nous les utilisons uniquement comme des modèles à superposer sur notre vue de fichier en mémoire.

Tout d'abord, nous avons besoin de le header DOS et les seuls champs qui nous intéressent sont les premiers et derniers membres appelés e_magic et e_lfanew :


1

Tout d'abord, nous devons regarder la valeur de e_magic. L'expression pour cela est bien sûr IMAGE_DOS_HEADER.e_magic, donc pour superposer cela sur notre vue de fichier, nous prenons le pointeur dans eax et faisons [eax.IMAGE_DOS_HEADER.e_magic]

Si la valeur de e_magic est égale à celle définie par IMAGE_DOS_SIGNATURE, nous devons continuer à récupérer la valeur de e_lfanew et l'ajouter à notre pointeur pMapping afin qu'il pointe maintenant vers le PE header :


1

Maintenant que nous sommes à le PE header, nous examinons le premier champ "Signature" pour voir si la valeur correspond à celle définie dans IMAGE_NT_SIGNATURE et si c'est le cas, nous disons que le fichier est valide.

Le code présenté ici utilise des noms de structure pour faciliter la lisibilité, mais vous trouverez souvent du code source où divers champs sont accédés en ajoutant des décalages connus sous forme numérique (hexadécimale). Par exemple, le champ e_lfanew est toujours à 3Ch octets du début du fichier, donc pour obtenir le PE header, vous verrez souvent add eax,[eax+3Ch] au lieu de add eax, [eax.IMAGE_DOS_HEADER.e_lfanew]. Il y a d'autres exemples où cela se produit. Dans le prochain tutoriel, nous allons développer ce code avec un utilitaire pour ajouter une section à un fichier PE.

 


Copyright (C)- xtx Team (2021)

XHTML valide 1.1 CSS Valide !