PARTIE 1 : Aperçu du format PE

| Iczelion | Traduction et adaptation par Olivier Lance |

Cette première partie offre une vue globale du format PE.
Article original : Tutorial 1: Overview of PE file format

Retour à la liste des tutoriels

Tutoriel suivant : Vérifier la validité d'un fichier PE

- Titre : PARTIE 1 : Aperçu du format PE

- Auteurs : Iczelion, Traduction et adaptation par Olivier Lance

- Parution : 3 septembre 2005

- Licence : Copyright ® 2005 Olivier Lance. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Le format PE

- Liens

Le format PE

PE signifie Portable Executable. Il s'agit du format de fichier natif Win32. Sa spécification est quelque peu dérivée du format Unix COFF (Common Object File Format). Le sens de "Portable Executable" vient du caractère commun de ce format entre les différentes plateformes Win32 : le PE Loader(1) de n'importe quelle plateforme Win32 reconnaît et utilise ce format de fichier même quand Windows est lancé avec un processeur autre qu'Intel. Cela ne signifie pas que vos exécutables PE pourront être portés sur d'autres architectures processeur sans modification.
Tout exécutable Win32 (à l'exception des VxD et des DLL 16 bits) utilise le format PE. Les drivers NT en mode Kernel(2) utilisent également ce format. Ainsi, étudier le format PE constitue une très bonne exploration de la structure interne de Windows.

Voyons sans plus attendre l'organisation globale d'un fichier au format PE :

Organisation générale d'un fichier PE

Tous les fichiers PE (y compris les DLL 32 bits) doivent débuter avec un simple entête DOS MZ. Cet entête n'est pas foncièrement intéressant. Il est présent dans le cas où le programme serait lancé à partir de DOS, permettant à celui-ci de reconnaître le fichier comme un exécutable valide et donc d'exécuter le segment DOS stocké à la suite de l'entête MZ. Le segment DOS est en fait un EXE valide qui est exécuté dans le cas où le système d'exploitation ne reconnaît pas le format PE. Il peut tout simplement afficher un message comme "Ce programme nécessite Windows pour fonctionner" ou peut être un véritable programme DOS, ceci au choix du programmeur. Ce segment DOS n'a pas non plus grande importance : il est généralement fourni par l'assembleur/compilateur. Dans la plupart des cas, il utilise juste l'interruption 21h, service 9(3) pour afficher le message "Ce programme ne peut être exécuté en mode MS-DOS"(4).

Après le segment DOS vient l'entête PE. L'entête PE n'est qu'un terme général faisant référence à la structure appelée IMAGE_NT_HEADERS. Cette structure contient de nombreux champs indispensables, utilisés par le PE Loader. Votre connaissance de cette structure s'améliorera au fur et à mesure que nous découvrirons le format PE. Lorsque le programme est exécuté à partir d'un système d'exploitation qui connaît le format PE, le PE Loader peut trouver l'offset de départ de l'entête PE dans l'entête DOS MZ. Il peut ainsi passer ce dernier et se rendre directement à l'entête PE, qui est l'entête réel du fichier.

Le contenu d'un fichier PE est divisé en blocs appelés sections. Une section n'est rien de plus qu'un bloc de données possédant des propriétés communes comme code/données, lecture/écriture etc. Vous pouvez considérer un fichier PE comme un disque logique. L'entête PE en est le secteur d'amorce et les sections sont les fichiers sur le disque. Les fichiers peuvent avoir différents attributs : lecture seule, fichier système, fichier caché, archive...

Les données sont groupées dans une section sur la base d'attributs communs, et non sur une base logique (code avec code, données avec données etc.).

Peu importe la manière dont le code/les données sont utilisés, s'ils ont les mêmes attributs dans le fichier PE, alors ils peuvent être réunis dans une même section. Vous ne devez pas penser à une section "données" et à une autre "code" ou quelque autre groupement logique : les sections peuvent contenir à la fois du code et des données, du moment que ces derniers ont les mêmes propriétés. Si vous disposez d'un bloc de données que vous souhaitez protéger en lecture seule, vous pouvez placer ces données dans la section identifiée comme étant en lecture seule. Quand le PE Loader copie les sections en mémoire, il en vérifie les attributs et les affecte aux zones mémoires qu'elles occupent.

En considérant un fichier PE comme un disque logique, l'entête PE comme le secteur d'amorce et les sections comme des fichiers, nous n'avons pas d'informations sur l'emplacement de ces fichiers : nous n'avons pas parlé de l'équivalent des répertoires dans le format PE. Immédiatement après l'entête PE se trouve la table des sections, qui est un tableau de structures. Chaque structure contient les informations de chaque section dans le fichier PE, telles que ses attributs, l'offset dans le fichier, l'offset en mémoire. S'il y a cinq sections dan sle fihier PE, il y aura exactement cinq membres dans ce tableau de structures. On peut alors voir la table des sections comme le répertoire racine du disque logique, chaque membre du tableau étant l'équivalent de chaque répertoire dans le répertoire racine.

Tout est dit en ce qui concerne l'agencement physique des données du format PE. Les principales étapes du chargement d'un fichier PE en mémoire peuvent résumer comme suit :

1. Quand le fichier PE est exécuté, le PE Loader examine l'entête DOS MZ pour y trouver l'offset de l'entête PE. S'il le trouve, il passe directement à l'entête PE.

2. Le PE Loader vérifie la validité de l'entête PE. Le cas échéant, il se rend à la fin de ce dernier.

3. L'entête PE est directement suivi de la table des sections. Le PE Loader lit les informations des sections et copie celles-ci en mémoire. Il donne également à chaque section les attributs spécifiés dans la table des sections.

4. Une fois que le fichier PE est copié en mémoire, le PE Loader s'intéresse aux parties logiques du fichier PE, comme la table d'importation.

Les étapes ci-dessus sont très simplifiées, et sont basées sur mes propres observations. Il subsiste sans doute quelques imprécisions, mais cela devrait vous donner une idée claire du processus suivi.

Vous pouvez télécharger la description du format PE de Luevelsmeyer. Elle est très détaillée, et devrait être gardée comme référence.

Liens

- MSDN : Image Help Library

- Document officiel de Microsoft décrivant le format PE (ainsi que le format COFF)

Tutoriel suivant : Vérifier la validité d'un fichier PE

(1)Il s'agit d'un élément du système d'exploitation, ayant pour fonction de reconnaître et de charger en mémoire les fichiers exécutables, DLLs etc. C'est par son intermédiaire que Windows est capable de faire exécuter les instructions d'un EXE au processeur.

(2)Drivers s'interfaçant directement avec le noyau (Kernel) du système d'exploitation

(3)Interruption BIOS pour afficher du texte à l'écran.

(4)"This program cannot run in DOS mode"