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 :
- 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.
- Si le fichier a un entête DOS valide, utiliser la valeur contenue dans le membre _lfanew pour trouver l'entête PE.
- 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