unit PE;

interface

uses Windows, SysUtils, Classes, Dialogs;

type
  //////////////////////////////////////////////////////////////////////////////
  ///Lecture de la table des sections///////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  TSection = record
    Header : TImageSectionHeader;
    Donnees: pChar;
  end;

  TSectionArray = Array of TSection;

  TSectionTable = class
  private
    fSections: TSectionArray;

    procedure LireSections(const Fichier: String);

    function  GetSection(Index: Integer): TSection;
    procedure SetSection(Index: Integer; const Value: TSection);
    function  GetName(Index: Integer): String;
    function  GetCount: Integer;
    function  GetCharacteristics(Index: Integer): String;
  public
    constructor Create(Fichier: String);
    destructor  Destroy; override;
    function    SectionHasCharacteristic(Index: Integer; Charac: Cardinal): Boolean;

    property Sections[Index: Integer]  : TSection read GetSection write SetSection; default;
    property Name    [Index: Integer]  : String              read GetName;
    property Count                     : Integer             read GetCount;
    property StrCharacs[Index: Integer]: String              read GetCharacteristics;
  end;
  //////////////////////////////////////////////////////////////////////////////

  //////////////////////////////////////////////////////////////////////////////
  ///Lecture de la table d'importation//////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////
  _IMAGE_IMPORT_DESCRIPTOR = record
    OriginalFirstThunk: DWORD;
    TimeDateStamp: DWORD;
    ForwarderChain: DWORD;
    Name1: DWORD;
    FirstThunk: DWORD;
  end;

  TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR;

  _IMAGE_IMPORT_BY_NAME = record
    Hint: WORD;
    Name: String;
  end;

  TImageImportByName = _IMAGE_IMPORT_BY_NAME;

  TImportedDLL = record
    Name: String;
    Functions: Array of TImageImportByName;
  end;

  TImportTable = class
  private
    fDLL: Array of TImportedDLL;
    fDLLCount: Integer;
    fFCount: Integer;

    procedure LireTable(Fichier: String);

    function GetDLL(Index: Integer): TImportedDLL;
    function GetFunction(DLL, Index: Integer): TImageImportByName;
    procedure SetDLL(Index: Integer; const Value: TImportedDLL);
    procedure SetFunction(DLL, Index: Integer; const Value: TImageImportByName);
  public
    constructor Create(Fichier: String);

    function IsFunctionImported(Name: String; out iDLL: Integer): Boolean;
    function IsDLLImported(DLL: String): Boolean;
    function FindDLLByName(Name: String): Integer;
    function FindFunctionByName(Name: String; iDLL: Integer): Integer;

    property DLLs[Index: Integer]: TImportedDLL read GetDLL write SetDLL;
    property Functions[DLL, Index: Integer]: TImageImportByName read GetFunction write SetFunction;
    property DLLCount     : Integer read fDLLCount write fDLLCount;
    property FunctionCount: Integer read fFCount   write fFCount;
  end;
  //////////////////////////////////////////////////////////////////////////////

resourcestring
  ///Erreurs/////////////////////////////////////////////////////////////////////
  sFileDoesntExists = 'Le fichier "%s" n''existe pas !';
  sNotAValidPE      = '"%s" n''est pas un fichier PE valide !';
  //////////////////////////////////////////////////////////////////////////////

  ///Caractéristiques d'une section//////////////////////////////////////////////
  sCntCode          = 'La section contient du code exécutable';
  sCntInitialized   = 'La section contient des données initialisées';
  sCntUnInitialized = 'La section contient des données non initialisées';
  sLnkComDat        = 'La section contient des données COMDAT';

  sAlign1Bytes      = 'Données alignées sur un octet';
  sAlign2Bytes      = 'Données alignées sur deux octets';
  sAlign4Bytes      = 'Données alignées sur quatre octets';
  sAlign8Bytes      = 'Données alignées sur huit octets';
  sAlign16Bytes     = 'Données alignées sur seize octets';
  sAlign32Bytes     = 'Données alignées sur 32 octets';
  sAlign64Bytes     = 'Données alignées sur 64 octets';
  sAlign128Bytes    = 'Données alignées sur 128 octets';
  sAlign256Bytes    = 'Données alignées sur 256 octets';
  sAlign512Bytes    = 'Données alignées sur 512 octets';
  sAlign1024Bytes   = 'Données alignées sur un kilo-octet';
  sAlign2048Bytes   = 'Données alignées sur deux kilo-octets';
  sAlign4096Bytes   = 'Données alignées sur quatre kilo-octets';
  sAlign8192Bytes   = 'Données alignées sur huit kilos-octets';

  sLnkNRelocOVFL    = 'La section contient des relocations étendues';
  
  sMemDiscardable   = 'La section peut être supprimée après utilisation';
  sMemNotCached     = 'La section ne peut être mise en cache';
  sMemNotPaged      = 'La section ne peut être placée en mémoire paginée';
  sMemShared        = 'La section peut être partagée en mémoire';
  sMemExecute       = 'La section peut être exécutée comme du code';
  sMemRead          = 'La section peut être lue';
  sMemWrite         = 'La section peut être écrite';
  //////////////////////////////////////////////////////////////////////////////


const
  ///Déclaration de certaines constantes manquantes pour les caractéristiques///
  ///d'une section (inutilisées selon windows.pas)//////////////////////////////
  IMAGE_SCN_ALIGN_128BYTES  = $00800000;
  IMAGE_SCN_ALIGN_256BYTES  = $00900000;
  IMAGE_SCN_ALIGN_512BYTES  = $00A00000;
  IMAGE_SCN_ALIGN_1024BYTES = $00B00000;
  IMAGE_SCN_ALIGN_2048BYTES = $00C00000;
  IMAGE_SCN_ALIGN_4096BYTES = $00D00000;
  IMAGE_SCN_ALIGN_8192BYTES = $00E00000;

  ///Tableau des caractéristiques d'une section/////////////////////////////////
  SectionCharacs: Array[0..25]Of Cardinal = (IMAGE_SCN_CNT_CODE,
                                             IMAGE_SCN_CNT_INITIALIZED_DATA,
                                             IMAGE_SCN_CNT_UNINITIALIZED_DATA,
                                             IMAGE_SCN_LNK_COMDAT,
                                             IMAGE_SCN_ALIGN_1BYTES,
                                             IMAGE_SCN_ALIGN_2BYTES,
                                             IMAGE_SCN_ALIGN_4BYTES,
                                             IMAGE_SCN_ALIGN_8BYTES,
                                             IMAGE_SCN_ALIGN_16BYTES,
                                             IMAGE_SCN_ALIGN_32BYTES,
                                             IMAGE_SCN_ALIGN_64BYTES,
                                             IMAGE_SCN_ALIGN_128BYTES,
                                             IMAGE_SCN_ALIGN_256BYTES,
                                             IMAGE_SCN_ALIGN_512BYTES,
                                             IMAGE_SCN_ALIGN_1024BYTES,
                                             IMAGE_SCN_ALIGN_2048BYTES,
                                             IMAGE_SCN_ALIGN_4096BYTES,
                                             IMAGE_SCN_ALIGN_8192BYTES,
                                             IMAGE_SCN_LNK_NRELOC_OVFL,
                                             IMAGE_SCN_MEM_DISCARDABLE,
                                             IMAGE_SCN_MEM_NOT_CACHED,
                                             IMAGE_SCN_MEM_NOT_PAGED,
                                             IMAGE_SCN_MEM_SHARED,
                                             IMAGE_SCN_MEM_EXECUTE,
                                             IMAGE_SCN_MEM_READ,
                                             IMAGE_SCN_MEM_WRITE);
  //////////////////////////////////////////////////////////////////////////////                                             

  ///Tableau des strings correspondantes////////////////////////////////////////
  StrSectionCharacs: Array[0..25]Of String = (sCntCode,
                                              sCntInitialized,
                                              sCntUnInitialized,
                                              sLnkComDat,
                                              sAlign1Bytes,
                                              sAlign2Bytes,
                                              sAlign4Bytes,
                                              sAlign8Bytes,
                                              sAlign16Bytes,
                                              sAlign32Bytes,
                                              sAlign64Bytes,
                                              sAlign128Bytes,
                                              sAlign256Bytes,
                                              sAlign512Bytes,
                                              sAlign1024Bytes,
                                              sAlign2048Bytes,
                                              sAlign4096Bytes,
                                              sAlign8192Bytes,
                                              sLnkNRelocOVFL,
                                              sMemDiscardable,
                                              sMemNotCached,
                                              sMemNotPaged,
                                              sMemShared,
                                              sMemExecute,
                                              sMemRead,
                                              sMemWrite);
  //////////////////////////////////////////////////////////////////////////////

  //Constante qui devrait être déclarée dans Windows.pas. Permet de tester la
  //nature des IMAGE_THUNK_DATA dans TImportTable.LireTable.
  IMAGE_ORDINAL_FLAG32 = $80000000;


////////////////////////////////////////////////////////////////////////////////
///Fonctions utiles/////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

(*
  Fonction vérifiant que le fichier dont le chemin est passé en paramètre est bien
  un fichier au format PE.
  S'il y a une erreur ou que ce n'est pas un fichier PE, la fonction renvoie False
*)
function IsValidPE(Fichier: String): Boolean;

(*
  Fonction de conversion d'une Adresse Virtuelle Relative (RVA) vers un offset
  de fichier valide.
  FichierPE est un stream contenant les données du fichier PE dans lequel
  retrouver l'offset de fichier à partir de RVA.
*)
function RVAToFileOffset(FichierPE: TStream; RVA: Cardinal): Cardinal;

(*
  IsZeroFilled renvoie True si la mémoire pointée par Mem est entièrement remplie
  de 0 (sur Taille octets), False sinon
*)
function IsZeroFilled(Mem: pByte; Taille: Integer): Boolean;

implementation

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
    raise Exception.Create(Format(sFileDoesntExists, [Fichier]));

  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;


function RVAToFileOffset(FichierPE: TStream; RVA: Cardinal): Cardinal;
var
  OrgPos: Int64;
  EnteteMZ: TImageDosHeader;
  EntetePE: TImageNtHeaders;
  Section : TImageSectionHeader;
  i, Nbr  : Integer;
begin
  (*
    Par défaut on renvoie la RVA donnée en paramètre, dans le cas où celle-ci
    pointe sur une zone qui n'est pas mappée en mémoire (et qui est donc déjà
    un offset de fichier)
  *)
  Result := RVA;

  //Sauvegarde de la position actuelle du stream
  OrgPos := FichierPE.Position;
  try
    FichierPE.Seek(0, soFromBeginning);
    FichierPE.Read(EnteteMZ, SizeOf(EnteteMZ));
    FichierPE.Seek(EnteteMZ._lfanew, soFromBeginning);
    FichierPE.Read(EntetePE, SizeOf(EntetePE));

    //Nombre de sections dans le fichier
    Nbr := EntetePE.FileHeader.NumberOfSections;

    if Nbr <> 0 then
      for i := 0 to Nbr - 1 do
      begin
        FichierPE.Read(Section, SizeOf(Section));

        //Si la RVA fournie se situe dans la section actuelle
        if (RVA >= Section.VirtualAddress) and (RVA < Section.VirtualAddress + Section.SizeOfRawData) then
        begin
          //On calcule l'offset de fichier à partir des informations d'adresses de la section
          Result := RVA - Section.VirtualAddress + Section.PointerToRawData;
          Break;
        end;
      end;
  finally
    //Retour à la position initiale
    FichierPE.Seek(OrgPos, soFromBeginning);
  end;
end;


function IsZeroFilled(Mem: pByte; Taille: Integer): Boolean;
begin
  Result := False;

  while (pByte(Integer(Mem) + Taille - 1)^ = 0) and (Taille >= 0) do
    Dec(Taille);

  if Taille = -1 then
    Result := True;
end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

{ TSectionTable }

constructor TSectionTable.Create(Fichier: String);
begin
  //Vérification de la validité du fichier
  If not IsValidPE(Fichier) then
    raise Exception.Create(Format(sNotAValidPE, [Fichier]));

  //Lecture et stockage des sections dans le tableau fSections
  LireSections(Fichier);
end;

function TSectionTable.GetSection(Index: Integer): TSection;
begin
  If (Index >= 0) and (Index < Length(fSections)) then
    Result := fSections[Index];
end;

procedure TSectionTable.SetSection(Index: Integer; const Value: TSection);
begin
  If (Index >= 0) and (Index < Length(fSections)) then
    fSections[Index] := Value;
end;

(*
  Le champ Name de TImageSectionHeader est un tableau d'octets où chaque octet
  représente un caractère du nom. La fonction GetName, getter de la propriété
  Name de la classe, permet de retourner directement ce nom sous forme de string 
*)
function  TSectionTable.GetName(Index: Integer): String;
var
  i: Integer;
begin
  Result := '';

  If (Index < 0) or (Index > Length(fSections)) then
    Exit;

  for i := 0 to Length(fSections[Index].Header.Name) - 1 do
    Result := Result + Chr(fSections[Index].Header.Name[i]);
end;

function TSectionTable.GetCount: Integer;
begin
  Result := Length(fSections);
end;

(*
  LireSections parcourt la table des sections du fichier PE fournit à la création
  de la classe et stocke dans le tableau fSections les informations de chaque
  section.
*)
procedure TSectionTable.LireSections(const Fichier: String);
var
  FichierPE : TFileStream;
  EnteteDOS : TImageDosHeader;  //Structure pour l'entête DOS MZ
  EntetePE  : TImageNtHeaders;  //Structure pour l'entête PE
  SectionNbr: Integer;
  i         : Integer;
begin
  FichierPE := TFileStream.Create(Fichier, fmOpenRead);

  Try
    //Lecture de l'entête PE
    FichierPE.Read(EnteteDOS, SizeOf(EnteteDOS));
    FichierPE.Seek(EnteteDOS._lfanew, soFromBeginning);
    FichierPE.Read(EntetePE, SizeOf(EntetePE));

    //On récupère le nombre de sections dans le fichier
    SectionNbr := EntetePE.FileHeader.NumberOfSections;

    If SectionNbr <> 0 then
    begin
      SetLength(fSections, SectionNbr);

      //Les sections sont à la suite dans le fichier, on les lit une à une
      for i := 0 to SectionNbr - 1 do
        FichierPE.Read(fSections[i].Header, SizeOf(fSections[i].Header));

      //Lecture et stockage des données de chaque section
      for i := 0 to SectionNbr - 1 do
      begin
        FichierPE.Seek(fSections[i].Header.PointerToRawData, soFromBeginning);

        GetMem(fSections[i].Donnees, fSections[i].Header.SizeOfRawData);
        FichierPE.Read(fSections[i].Donnees^, fSections[i].Header.SizeOfRawData);
      end;

    end;       
  Finally
    FreeAndNil(FichierPE);
  end;
end;

(*
  SectionHasCharacteristic renvoie True si la ième section de la table a la
  caractéristique Charac présente dans son champ Characteristics
*)
function TSectionTable.SectionHasCharacteristic(Index: Integer; Charac: Cardinal): Boolean;
begin
  Result := (fSections[Index].Header.Characteristics and Charac) <> 0;
end;

(*
  GetCharacteristics renvoie sous forme d'une string l'intégralité des caractéristiques
  de la ième section de la table.
*)
destructor TSectionTable.Destroy;
var
  i: Integer;
begin
  for i := 0 to Length(fSections) - 1 do
    FreeMem(fSections[i].Donnees, fSections[i].Header.SizeOfRawData);    

  inherited;
end;

function TSectionTable.GetCharacteristics(Index: Integer): String;
var
  i: Integer;
begin
  Result := '';

  for i := Low(SectionCharacs) to High(SectionCharacs) do
    if SectionHasCharacteristic(Index, SectionCharacs[i]) then
      Result := Result + StrSectionCharacs[i] + #13;
end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

{ TImportTable }

constructor TImportTable.Create(Fichier: String);
begin
  //Vérification de la validité du fichier
  If not IsValidPE(Fichier) then
    raise Exception.Create(Format(sNotAValidPE, [Fichier]));

  //Lecture de la table d'importations
  LireTable(Fichier);
end;

(*
  FindDLLByName renvoie l'index de la DLL nommée Name dans le tableau de DLL,
  afin de pouvoir y accéder directement par la propriété DLLs.
  La recherche n'est pas sensible à la casse.
  Name doit contenir l'extension du fichier.
*)
function TImportTable.FindDLLByName(Name: String): Integer;
var
  i: Integer;
begin
  Result := -1;

  for i := Low(fDLL) to High(fDLL) do
    if LowerCase(fDLL[i].Name) = LowerCase(Name) then
    begin
      Result := i;
      Break;
    end;
end;

(*
  FindFunctionByName renvoie l'index de la fonction nommée Name dans le
  tableau Functions de la DLL d'index iDLL.
  La recherche n'est pas sensible à la casse.
  Name peut contenir indifféremment un nom ou l'index d'exportation de la fonction.
  Par défaut la fonction comparera Name au nom d'exportation de la fonction, et à
  son index d'exportation (champ Hint) si le nom est vide.
*)
function TImportTable.FindFunctionByName(Name: String; iDLL: Integer): Integer;
var
  i: Integer;
begin
  Result := -1;

  for i := Low(fDLL[iDLL].Functions) to High(fDLL[iDLL].Functions) do
    if (fDLL[iDLL].Functions[i].Name <> '') and (LowerCase(fDLL[iDLL].Functions[i].Name) = Name) then
    begin
      Result := i;
      Break;
    end
    else if (fDLL[iDLL].Functions[i].Name = '') and (StrToIntDef(Name, -1) = fDLL[iDLL].Functions[i].Hint) then
    begin
      Result := i;
      Break;
    end;
end;

(*
  Renvoie True si un DLL du nom DLL est importée dans ce fichier PE.
*)
function TImportTable.IsDLLImported(DLL: String): Boolean;
begin
  Result := (FindDLLByName(DLL) <> -1);
end;

(*
  Renvoie True si une fonction de nom Name est importée dans ce fichier PE.
  Renvoie également dans iDLL l'index de la DLL dans laquelle la fonction a été
  trouvée.
*)
function TImportTable.IsFunctionImported(Name: String; out iDLL: Integer): Boolean;
var
  i, j: Integer;
begin
  Result := False;

  for i := Low(fDLL) to High(fDLL) do
    for j := Low(fDLL[i].Functions) to High(fDLL[i].Functions) do
      if (fDLL[i].Functions[j].Name <> '') and (LowerCase(fDLL[i].Functions[j].Name) = Name) then
      begin
        Result := True;
        iDLL   := i;
        Break;
      end
      else if (fDLL[i].Functions[j].Name = '') and (StrToIntDef(Name, -1) = fDLL[i].Functions[j].Hint) then
      begin
        Result := True;
        iDLL   := i;
        Break;
      end;
end;

procedure TImportTable.LireTable(Fichier: String);
var
  FichierPE  : TMemoryStream; //Utilisation d'un MemoryStream pour avoir le pointeur Memory
  EnteteMZ   : TImageDosHeader;
  EntetePE   : TImageNtHeaders;
  DataDir,o  : TImageDataDirectory;
  ImportDescs: Array of TImageImportDescriptor;
  i, j       : Integer;
  k          : Byte;
  Nom        : pChar;
  Hint       : WORD;
  ThunkData  : Cardinal;
begin
  FichierPE := TMemoryStream.Create;
  FichierPE.LoadFromFile(Fichier);
  try
    //On se rend à l'entête PE
    FichierPE.Read(EnteteMZ, SizeOf(EnteteMZ));
    FichierPE.Seek(EnteteMZ._lfanew, soFromBeginning);
    FichierPE.Read(EntetePE, SizeOf(EntetePE));

    //Dans l'entête facultatif, on récupère le deuxième Data Directory
    DataDir := EntetePE.OptionalHeader.DataDirectory[1];

    //Grâce à l'adresse contenue  dans le Data Directory on récupère tous les Import Descriptors
    FichierPE.Seek(RVAToFileOffset(FichierPE, DataDir.VirtualAddress), soFromBeginning);

    SetLength(ImportDescs, 1);
    FichierPE.Read(ImportDescs[0], SizeOf(ImportDescs[0]));

    //Lecture de tous les Import Descriptors. Un enregistrement vide indique la fin du tableau
    while not IsZeroFilled(@ImportDescs[High(ImportDescs)], SizeOf(ImportDescs[High(ImportDescs)])) do
    begin
      SetLength(ImportDescs, Length(ImportDescs) + 1);
      FichierPE.Read(ImportDescs[High(ImportDescs)], SizeOf(ImportDescs[High(ImportDescs)]));
    end;

    for i := 0 to High(ImportDescs) - 1 do
    begin
      FichierPE.Seek(RVAToFileOffset(FichierPE, ImportDescs[i].Name1), soFromBeginning);

      //Recherche de la taille du nom (= recherche du zéro terminal de la chaine)
      k := 0;
      while Byte(Pointer(Integer(FichierPE.Memory) + FichierPE.Position + k)^) <> 0 do
        Inc(k);

      GetMem(Nom, k + 1);
      FichierPE.Read(Nom^, k + 1); 

      //Ajout d'une DLL
      SetLength(fDLL, Length(fDLL) + 1);
      fDLL[High(fDLL)].Name := Nom;
      SetLength(fDll[High(fDLL)].Functions, 0);

      Inc(fDLLCount);

      FreeMem(Nom);
      
      j := 0;
      ThunkData := 1;

      while ThunkData <> 0 do
      begin
      	//On vérifie d'abord OriginalFirstThunk, et on n'utilise FirstThunk qu'à défaut.
        if ImportDescs[i].OriginalFirstThunk  <> 0 then
          FichierPE.Seek(RVAToFileOffset(FichierPE, ImportDescs[i].OriginalFirstThunk) + Cardinal(j) * SizeOf(ThunkData), soFromBeginning)
        else
          FichierPE.Seek(RVAToFileOffset(FichierPE, ImportDescs[i].FirstThunk) + Cardinal(j) * SizeOf(ThunkData), soFromBeginning);


        FichierPE.Read(ThunkData, SizeOf(ThunkData));

        if ThunkData = 0 then
          Break;

        //Exportation par ordinal seulement ?
        if ThunkData and IMAGE_ORDINAL_FLAG32 <> 0 then
        begin  
	  	    //Ajout d'une fonction
          SetLength(fDLL[High(fDLL)].Functions, Length(fDLL[High(fDLL)].Functions) + 1);
          fDLL[High(fDLL)].Functions[High(fDLL[High(fDLL)].Functions)].Hint := Word(ThunkData);
          fDLL[High(fDLL)].Functions[High(fDLL[High(fDLL)].Functions)].Name := '';

          Inc(fFCount);
        end
        else
          begin
            FichierPE.Seek(RVAToFileOffset(FichierPE, ThunkData), soFromBeginning);
            FichierPE.Read(Hint, SizeOf(Hint));

            //Recherche de la taille du nom (= recherche du zéro terminal de la chaine)
            k := 0;
            while Byte(Pointer(Integer(FichierPE.Memory) + FichierPE.Position + k)^) <> 0 do
              Inc(k);

            GetMem(Nom, k + 1);
            FichierPE.Read(Nom^, k + 1);

	    	    //Ajout d'une fonction
            SetLength(fDLL[High(fDLL)].Functions, Length(fDLL[High(fDLL)].Functions) + 1);
            fDLL[High(fDLL)].Functions[High(fDLL[High(fDLL)].Functions)].Hint := Hint;
            fDLL[High(fDLL)].Functions[High(fDLL[High(fDLL)].Functions)].Name := Nom;

            Inc(fFCount);

            FreeMem(Nom);
          end;

        Inc(j);
      end;
    end;
  finally
    SetLength(ImportDescs, 0);
    FichierPE.Free;
  end;
end;

function TImportTable.GetDLL(Index: Integer): TImportedDLL;
begin
  if (Index > High(fDLL)) then
    Exit;

  Result := fDLL[Index];
end;

function TImportTable.GetFunction(DLL, Index: Integer): TImageImportByName;
begin
  if (DLL > High(fDLL)) or (Index > High(fDLL[DLL].Functions)) then
    Exit;

  Result := fDll[DLL].Functions[Index];
end;

procedure TImportTable.SetDLL(Index: Integer; const Value: TImportedDLL);
begin
  fDLL[Index] := Value;
end;

procedure TImportTable.SetFunction(DLL, Index: Integer; const Value: TImageImportByName);
begin
  fDLL[DLL].Functions[Index] := Value;
end;

end.
