Nous avons vu le MZ header (du DOS) et quelques membres du PE header. Voici le dernier, le plus grand et probablement le membre le plus important du PE header, l'Optional header.
Pour vous rafraîchir la mémoire, l'Optional header est une des structures du IMAGE_NT_HEADERS c'est son dernier membre. Il contient des informations sur la disposition (constuction) logique du PE File. Cette structure possède 31 paramètres. Quelques-uns d'entre eux sont cruciaux, par contre d'autres ne sont pas utiles. J'expliquerai seulement les paramètres qui sont vraiment utiles pour nous.
Il y a un mot qui est fréquemment employé en rapport avec le format du PE file : c'est le RVA
RVA (relative virtual address) est le diminutif de 'l'adresse virtuelle relative'. Vous savez ce qu'est une adresse virtuelle. Le RVA est un terme qui sert à simplifier le concept. Simplement, le RVA est une distance par rapport à un point de référence dans l'espace d'adresses virtuelles. Je parie que vous êtes familiers avec les offsets d'un fichier: le RVA c'est exactement la même chose que pour les offsets (les offsets ont pour référence le segments où ils se trouvent). Cependant, le RVA est référencé par rapport à un point de l'espace d'adresses virtuelles, et non pas par rapport à un fichier. Je vais vous montrer un exemple.
Si le PE file se charge à l'adresse 00400000h dans l'espace d'adresses virtuelles (VA) et que le programme commence son exécution à l'adresse virtuelle 00401000h, alors nous pouvons dire que le programme commence son exécution à un RVA de 1000h. UN RVA est pris par rapport au départ VA du programme.
L'espace d'adresses virtuelles (VA) (00400000h) est pris comme point d'origine (0) où est stocké votre programme, mais son code d'exécution ne commence qu'en 00401000h et le RVA est la distance entre les deux.
Pourquoi le PE file utilise-t-il le RVA ? C'est pour réduire le travail du PE Loader. Puisque un module (un programme ou une DLL) peut être transféré n'importe où dans l'espace d'adresses virtuelles, ce serait un véritable enfer pour le PE Loader de retrouver chaque variable réadressable dans le programme.
Au contraire, si toutes les variables réadressables dans le fichier utilisent le RVA, le PE Loader n'a aucun besoin de convertir quoi que ce soit : il transfère simplement le programme en entier vers un nouveau VA de départ. C'est un peu comme le concept de chemin relatif et de chemin absolu : le RVA est apparenté au chemin relatif, et le VA représente le chemin absolu.
Paramètres | Signification |
---|---|
AddressOfEntryPoint | est l'adresse de la première instruction qui sera exécutée. Si vous voulez que votre programme commence à une autre adresse, vous avez besoin de changer la valeur de ce paramètre. |
ImageBase | est l'adresse de chargement préférentielle pour charger le PE file. Par exemple, si la valeur dans ce paramètre est 400000h, le PE Loader essayera de charger le fichier dans l'espace d'adresses virtuelles commençant à 400000h. Le mot "préférentielle" signifie que le PE Loader ne peut pas charger le fichier à cette adresse si d'autres programmes occupent déjà cette zone d'adresses. |
SectionAlignment | représente l'alignement des sections en mémoire. Par exemple, si la valeur de ce paramètre est 1000h (4096), chaque section doit commencer à un multiples de 4096 octets. Si la première section commence à l'adresse 401000h et qu'elle a un taille de 10 octets seulement, alors la section suivante doit quand même commencer à 402000h, même si l'espace d'adresse entre 401000ème et 402000ème n'est pas entièrement inutilisée. |
FileAlignment | représente l'alignement des sections dans le fichier. Par exemple, si la valeur dans ce paramètre est 200h (512), chaque section doit commencer à un multiples de 512 octets. Si la première section est à l'offset(de fichier) 200h et que la taille est de 10 octets, alors la section suivante doit être placée à l'offset(de fichier) 400h : l'espace entre les offsets(de fichier) 512 et 1024 est inutilisé/ou non défini. |
MajorSubsystemVersion MinorSubsystemVersion |
est la version de votre sous-système win32. Si le PE file est conçu pour une plate-forme Win32, la version du sous-système doit être 4.0. |
SizeOfImage | est la taille complète que le PE prend en mémoire. C'est la somme de tous les Headers et de toutes les sections qui sont regroupés dans SectionAlignment. |
SizeOfHeaders | est la taille de toutes les headers tables + sections tables . Bref, cette valeur est égale à la taille du fichier moins la taille combinée de toutes les sections dans le fichier. Vous pouvez aussi employer cette valeur comme étant l'offset(de fichier) de la première section du PE file. |
Subsystem | dit pour quel sous-système NT le PE file est destiné. Pour la plupart des progs win32, seuls deux valeurs sont utilisées : le GUI Windows et le CUI Windows. |
DataDirectory | est un tableau de structures appartenant à IMAGE_DATA_DIRECTORY. Chaque structure donne le RVA d'une structure de données importante du PE file comme l'adresse de la table des importations. |
[Iczelion's Win32 Assembly Homepage]