Pour mémoire, l'entête facultatif est le dernier membre de la structure TImageNtHeaders. Il contient des informations
sur l'organisation logique du fichier PE. Cette structure comporte 31 champs.
Certains d'entre eux sont cruciaux et d'autres ne sont pas utiles. Nous verrons uniquement les champs qui sont réellement
utiles.
Un mot revient fréquemment en relation avec le format PE : RVA.
RVA signifie Relative Virtual Address. Vous savez ce qu'est une adresse virtuelle(1).
RVA est un terme un peu rebutant pour un concept aussi simple. Pour parler simplement, une RVA est une distance
à partir d'un point de référence dans l'espace d'adressage virtuel. J'imagine que vous savez ce qu'est un offset fichier : une
RVA est exactement la même chose qu'un offset fichier. Toutefois, elle est relative à une adresse virtuelle plutôt
qu'au début d'un fichier.
Voici un exemple :
Si un fichier PE est chargé à l'adresse $400000 dans l'espace d'adressage virtuel et que le programme commence son
exécution à l'adresse $401000, on peut dire que le programme débute à la RVA $1000. Une RVA est relative à
l'adresse virtuelle du premier octet du module.
Pourquoi le format PE utilise-t-il des RVA ?
Le but est de réduire le temps de chargement du PE Loader. Sachant qu'un module peut être déplacé n'importe où dans
l'espace d'adressage virtuel, ce serait infernal pour le PE Loader de fixer les adresses de chaque élément à position
variable du module(2). Par opposition, si tous les éléments ayant une position variable dans le fichier
utilisent des RVA, le PE Loader n'a alors pas besoin de fixer quoi que ce soit : il déplace simplement tout le
module à une nouvelle adresse virtuelle. Tout cela rejoint le concept de chemin relatif et chemin absolu : une RVA est
assimilable à un chemin relatif, une adresse virtuelle à un chemin absolu.
Voici les champs intéressants de l'entête facultatif :
Champ | Contenu |
---|---|
AddressOfEntryPoint | Il s'agit de la RVA de la première instruction qui sera exécutée lorsque le PE Loader sera prêt à lancer le fichier. Si vous souhaitez détourner le flux d'exécution dès le démarrage du programme, vous devez changer cette valeur pour une autre RVA, et l'instruction à cette nouvelle RVA sera alors exécutée en premier. |
ImageBase | C'est l'adresse de chargement souhaitable pour le fichier PE. Par exemple, si la valeur de ce champ est $400000, le PE Loader tentera de charger le fichier dans l'espace d'adressage virtuel à l'adresse $400000. Le mot "souhaitable" signifie que le PE Loader peut ne pas charger le fichier à cette adresse si un autre module l'occupe déjà. |
SectionAlignment | La granularité de l'alignement des sections en mémoire. Par exemple, si la valeur est 4096 ($1000), chaque section doit débuter à un multiple de 4096 octets. Si la première section est à l'adresse $401000 et que sa taille est de 10 octets, la prochaine section doit se trouver à l'adresse $402000, même si l'espace entre $401000 et $402000 sera pour la plupart inutilisé. |
FileAlignment | La granularité de l'alignement des sections dans le fichier. Par exemple, si la valeur est 512 ($200), chaque section doit débuter à un multiple de 512 octets. Si la première section est à l'adresse $200 et que sa taille est de 10 octets, la prochaine section doit se trouver à l'offset fichier $400 : l'espace entre les offsets 522 et 1024 est inutilisé/indéfini. |
MajorSubSystemVersion
MinorSubSystemVersion |
La version du système Win32. Si le fichier PE a été créé pour Win32, la version doit être 4.0 sans quoi les dialogues n'auront pas d'apparence 3D. |
SizeOfImage | La taille totale du fichier PE en mémoire. C'est la somme de tous les entêtes et des sections alignées avec la valeur SectionAlignment. |
SizeOfHeaders | La taille de tous les entêtes et de la table des sections. Cette valeur est égale à la taille du fichier moins la taille de toutes les sections du fichier. Vous pouvez utiliser cette valeur comme l'offset fichier de la première section dans le fichier PE. |
Subsystem | Donne pour quel sous-système NT le fichier PE est prévu. Pour la plupart des programmes Win32, seules deux valeurs sont utilisées : Windows GUI (IMAGE_SUBSYSTEM_WINDOWS_GUI) et Windows GUI (console) (IMAGE_SUBSYSTEM_WINDOWS_CUI). |
DataDirectory | Un tableau de structures IMAGE_DATA_DIRECTORY. Chaque structure fournit la RVA d'une structure de données importantes, comme la table d'importation. |
Liens
Tutoriel suivant : La table des sections