PARTIE 2 : Vérifier la validité d'un fichier PE

Iczelion

Traducteur

Traduction et adaptation par Olivier Lance

Dans cette partie, nous verrons comment vérifier qu'un fichier donné respecte le format PE.
Article original : Tutorial 2: Detecting a Valid PE File

Retour à la liste des tutoriels

Tutoriel précédent : Aperçu du format PE
Tutoriel suivant : Entête de fichier

- Titre : PARTIE 2 : Vérifier la validité d'un fichier PE

- Auteur : Iczelion

- Traducteur : Traduction et adaptation par Olivier Lance

- Parution : 8 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

- Théorie

- Exemple

- Liens

Théorie

Comment savoir si un fichier est un fichier PE valide ?
C'est une question à laquelle il est difficile de répondre. Cela dépend du temps que vous voulez passer à faire la vérification. Vous pouvez vérifier chaque donnée de chaque structure définie dans les spécifications du format PE, ou simplement vous satisfaire de la vérification des données cruciales que ces structures contiennent.
La plupart du temps, il est relativement inutile de vérifier les données une à une dans le fichier. Si les structures principales sont valides, on peut considérer le fichier comme un fichier PE valide. Nous nous bornerons à cette considération.

La principale structure que nous vérifierons est l'entête PE lui-même. Nous avons donc besoin d'en savoir un peu plus à son sujet, du point de vue programmation.
L'entête PE est en fait une structure appelée TImageNtHeaders. Sa définition dans l'unité Windows.pas de Delphi est la suivante :

_IMAGE_NT_HEADERS = packed record
Signature: DWORD;
FileHeader: TImageFileHeader;
OptionalHeader: TImageOptionalHeader;
end;

TImageNtHeaders = _IMAGE_NT_HEADERS;

- Signature est un DWord contenant la valeur $50, $45, $00, $00. Pour être plus clair, il contient le texte "PE" suivi de deux zéros terminaux. Ce membre est la signature PE, nous l'utiliserons donc dans le processus de vérification.

- FileHeader est une structure qui contient des informations à propos de l'organisation physique du fichier PE, comme le nombre de sections, la machine pour laquelle le fichier est destiné etc.

- OptionalHeader est une structure qui contient des informations supplémentaires sur l'organisation du fichier PE. Malgré le terme "Optional" figurant dans son nom, il est toujours présent.

Notre but est maintenant clair. Si la valeur de la signature de l'entête PE est égale à "PE" suivie de deux zéros, alors le fichier est un fichier PE valide. En réalité, à des fins de comparaison, Microsoft a défini quelques constantes nommées IMAGE_XX_SIGNATURE que l'on peut facilement utiliser :

IMAGE_DOS_SIGNATURE                     = $5A4D;      { MZ }
IMAGE_OS2_SIGNATURE                     = $454E;      { NE }
IMAGE_OS2_SIGNATURE_LE                  = $454C;      { LE }
IMAGE_VXD_SIGNATURE                     = $454C;      { LE }
IMAGE_NT_SIGNATURE                      = $00004550;  { PE00 }

La question est maintenant : comment savoir où se trouve l'entête PE ?
La réponse est simple : l'entête DOS MZ contient l'offset dans le fichier de l'entête PE. L'entête DOS MZ est défini par la structure TImageDosHeader. Vous pouvez en consulter la composition dans l'unité Windows.pas. Le membre _lfanew de la structure TImageDosHeader contient l'offset de l'entête PE.

Les étapes sont donc les suivantes :

1. Vérifier que le fichier a un entête DOS MZ valide en comparant le premier Word du fichier avec la valeur IMAGE_DOS_SIGNATURE.

2. Si le fichier a un entête DOS valide, utiliser la valeur contenue dans le membre _lfanew pour trouver l'entête PE.

3. Comparer le premier DWord de l'entête PE avec la valeur IMAGE_NT_SIGNATURE. Si les deux valeurs concordent, alors on peut considérer le fichier comme un fichier PE valide.

Exemple

La fonction suivante renvoie True si le fichier donné en paramètre est un fichier PE, False s'il n'est pas valide ou s'il y a un problème lors de la lecture du fichier :

function IsValidPE(Fichier: String): Boolean;
var
EnteteDOS: TImageDosHeader;  //Structure pour l'entête DOS MZ
EntetePE : TImageNtHeaders;  //Structure pour l'entête PE
FStream  : TFileStream;      //Stream de lecture
begin

Result := True;

If not FileExists(Fichier) then
begin
Result := False;
Exit;
end;

FStream := TFileStream.Create(Fichier, fmOpenRead);
try
try
//Lecture de l'entête DOS MZ
FStream.ReadBuffer(EnteteDOS, SizeOf(EnteteDOS));

//Comparaison de la signature du fichier avec la signature DOS
If EnteteDOS.e_magic <> IMAGE_DOS_SIGNATURE then
Result := False
else
begin
//Déplacement jusqu'à l'entête PE dont l'offset est indiqué par _lfanew
FStream.Seek(EnteteDOS._lfanew, soFromBeginning);
//Lecture de l'entête PE
FStream.ReadBuffer(EntetePE, SizeOf(EntetePE));

//Comparaison de la signature de l'entête avec la signature PE
If EntetePE.Signature <> IMAGE_NT_SIGNATURE then
Result := False;
end;
except
//En cas de problème, on renvoie False
On Exception do
Result := False;
end;
finally
FStream.Free;
end;
end;

Liens

- MSDN : Image Help Library

- MSDN : IMAGE_NT_HEADERS (TImageNtHeaders)

Tutoriel suivant : Entête de fichier