We don't display ads so we rely on your Bitcoin donations to 1KWEk9QaiJb2NwP5YFmR24LyUBa4JyuKqZ
Post date: Jul 17, 2010 5:42:22 PM
{
Pe File Unit
by ErazerZ
Datum: Tuesday, 10. July 2007
ToDo:
*) Addsection with FileAlign 4 does not work!
*) IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR parsing.
*) The ability to add imports individually
*) Make import, export, storage resources
*) Make better resource structure.
Note:
* ) Image sections are not directly modifiabluntPeFile;
}
unit untPeFileinterfaceuses Windows;type  // Dient der Zwischenspeicherung von Code-Höhlen (Daten die mit 0 Bytes  // gefüllt sind)  PCodeCave = ^TCodeCave;  TCodeCave = packed record    StartFileOffset: Cardinal;    StartRVA: Cardinal;    CaveSize: Cardinal;  end;  { IAT }  PImageImportDescriptor = ^TImageImportDescriptor;  TImageImportDescriptor = packed record    OriginalFirstThunk: DWORD;    TimeDateStamp: DWORD;    ForwarderChain: DWORD;    Name: DWORD;    FirstThunk: DWORD;  end;  PImageThunkData = ^TImageThunkData;  TImageThunkData = packed record    Name: DWORD;  end;  { BOUND IAT }  PImageBoundImportDescriptor = ^TImageBoundImportDescriptor;  TImageBoundImportDescriptor = packed record    TimeDateStamp: DWORD;    OffsetModuleName: Word;    NumberOfModuleForwarderRefs: Word;  end;  PImageBoundForwarderRef = ^TImageBoundForwarderRef;  TImageBoundForwarderRef = record    TimeDateStamp: DWORD;    OffsetModuleName: Word;    Reserved: Word;  end;  { DELAYED IAT }  PImgDelayDescr = ^TImgDelayDescr;  TImgDelayDescr = packed record    grAttrs: DWORD;    szName: DWORD;    phmod: PDWORD;    pIAT: TImageThunkData;    pINT: TImageThunkData;    pBoundIAT: TImageThunkData;    pUnloadIAT: TImageThunkData;    dwTimeStamp: DWORD;  end;  TImportsType = (itNormal, itBound, itDelay);  // Dient der Zwischenspeicherung der Imports  PImportsAPis = ^TImportsAPIs;  TImportsAPIs = packed record    ThunkRVA: DWORD;    ThunkOffset: DWORD;    ThunkValue: DWORD;    Hint: Word;    ApiName: string;  end;  PImports = ^TImports;  TImports = packed record    LibraryName: string;    ImportType: TImportsType;    OriginalFirstThunk: DWORD;    TimeDateStamp: DWORD;    ForwarderChain: DWORD;    Name: DWORD; // Offset    FirstThunk: DWORD;    IatFunctions: array of TImportsAPIs;  end;  PImportsArray = ^TImportsArray;  TImportsArray = array of TImports;  // Dient der Zwischenspeicherung der Exports  PExportAPIs = ^TExportAPIs;  TExportAPIs = packed record    Ordinal: Word;    Rva: DWORD;    FileOffset: DWORD;    ApiName: string;  end;  PExports = ^TExports;  TExports = packed record    LibraryName: string;    Base: DWORD;    Characteristics: DWORD;    TimeDateStamp: DWORD;    MajorVersion: Word;    MinorVersion: Word;    NumberOfFunctions: DWORD;    NumberOfNames: DWORD;    AddressOfFunctions: DWORD;    AddressOfNames: DWORD;    AddressOfNameOrdinals: Word;    ExportFunctions: array of TExportAPIs;  end;  { Thread Local Storage }  PImageTLSDirectory = ^TImageTLSDirectory;  TImageTLSDirectory = packed record    StartAddressOfRawData: DWORD;    EndAddressOfRawData: DWORD;    AddressOfIndex: DWORD;    AddressOfCallBacks: DWORD;    SizeOfZeroFill: DWORD;    Characteristics: DWORD;  end;  { RESOURCES }  { Resource Dir String }  PImageResourceDirString = ^TImageResourceDirString;  TImageResourceDirString = packed record    Length: Word;    NameString: array[0..0] of WCHAR;  end;  { Data Entry }  PImageResourceDataEntry = ^TImageResourceDataEntry;  TImageResourceDataEntry = packed record    OffsetToData: DWORD;    Size: DWORD;    CodePage: DWORD;    Reserved: DWORD;  end;  { Dir Entry }  PImageResourceDirectoryEntry = ^TImageResourceDirectoryEntry;  TImageResourceDirectoryEntry = packed record    Name: DWORD;    OffsetToData: DWORD;  end;  { Directory }  PImageResourceDirectory = ^TImageResourceDirectory;  TImageResourceDirectory = packed record    Characteristics: DWORD;    TimeDateStamp: DWORD;    MajorVersion: Word;    MinorVersion: Word;    NumberOfNamedEntries: Word;    NumberOfIdEntries: Word;  end;  { Table }  PImageResourceTableDirectoryEntry = ^TImageResourceTableDirectoryEntry;  TImageResourceTableDirectoryEntry = packed record    Table: TImageResourceDirectory;    Directory: TImageResourceDirectoryEntry;  end;  // Dient der Zwischenspeicherung der Resourcen  // Languages  PResourceLangs = ^TResourceLangs;  TResourceLangs = packed record    dwRVA: DWORD;    dwFileOffset: DWORD;    sLang: string;  end;  // Namen  PResourceNames = ^TResourceNames;  TResourceNames = packed record    sName: string;    dwRVA: DWORD;    dwFileOffset: DWORD;    lpLangs: array of TResourceLangs;    LangsCount: Integer;  end;  // Typen  PResourcesTyps = ^TResourceTyps;  TResourceTyps = packed record    sTyp: string;    lpNames: array of TResourceNames;    NamesCount: Integer;  end;  // Resourcen Block  PResources = ^TResources;  TResources = packed record    Characteristics: DWORD;    TimeDateStamp: DWORD;    MajorVersion: Word;    MinorVersion: Word;    NumberOfNamedEntries: Word;    NumberOfIdEntries: Word;    rtTyps: array of TResourceTyps;    TypCount: Integer;  end;  TPeFile = class(TObject)  private    // Datei    lpBuffer: Pointer; // Datei im Speicher    FFileSize: Cardinal;    FFilename: string;    // NtHeaders    FNumberOfSections: Word;    FAddressOfEntryPoint: Cardinal;    FImageBase: Cardinal;    FSectionAlign: Cardinal;    FFileAlign: Cardinal;  public    ImageDosHeader: PImageDosHeader;    ImageNtHeaders: PImageNtHeaders;    ImageSections: array of TImageSectionHeader; // alle Sektionen-Header    constructor Create;    destructor Destroy; override;    function LoadFromFile(const sFilename: string): Boolean;    function SaveToFile(const sFilename: string): Boolean;    function ValidHeaders: Boolean;    function ReadPeHeaders: Boolean;    function Align(Value, Align: Cardinal): Cardinal;    function SectionToString(Section: TImageSectionHeader): string;    procedure StringToSection(const sSectionName: string; var Section: TImageSectionHeader);    procedure CopyMemoryBuffer(CopyToOffset: DWORD; Source: Pointer; Length: DWORD);    // Änderungen    procedure SetAddressOfEntryPoint(AddressOfEntryPoint: Cardinal);    procedure SetImageBase(ImageBase: Cardinal);    // Umrechnungen    function RvaToFileOffset(dwRVA: Cardinal): Cardinal;    function FileOffsetToRva(dwFileOffset: Cardinal): Cardinal;    function VaToFileOffset(dwVA: Cardinal): Cardinal;    function FileOffsetToVa(dwFileOffset: Cardinal): Cardinal;    function VaToRva(dwVA: Cardinal): Cardinal;    function RvaToVa(dwRVA: Cardinal): Cardinal;    function RvaToSection(dwRVA: Cardinal): Word;    function FileOffsetToSection(dwFileOffset: Cardinal): Word;    // Hinzufügen/Entfernen    function InsertBytes(FromOffset, Count: Cardinal): Cardinal;    function DeleteBytes(FromOffset, Count: Cardinal): Cardinal;    function FindCodeCaves(FromOffset, Count: Cardinal): TCodeCave;    // Sektionen    function AddSection(const sSectionName: string; VirtualSize: Cardinal; dwCharacteristics: Cardinal = IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_CNT_CODE): Boolean;    function DeleteSection(wSection: Word): Boolean;    function DumpSection(wSection: Word; sFilename: string): Boolean;    function GetCharacteristics(dwCharacteristics: DWORD): string;    function GetCodeSection: Word;    function GetDataSection: Word;    function GetResourceSection: Word;    procedure GetImportAddressTable(var Imports: TImportsArray);    procedure GetExportsAddressTable(var ExportData: TExports);    function GetThreadLocalStorage: PImageTLSDirectory;    procedure GetResources(var Resources: TResources);    function GetDebugDirectory: PImageDebugDirectory;    function GetLoadConfigDirectory: PImageLoadConfigDirectory;    function GetEntryExceptionDirectory: PImageRuntimeFunctionEntry;  published    // Datei    property FileSize: Cardinal read FFileSize;    property Filename: string read FFilename;    // NtHeaders    property NumberOfSections: Word read FNumberOfSections;    property AddressOfEntryPoint: Cardinal read FAddressOfEntryPoint write SetAddressOfEntryPoint;    property ImageBase: Cardinal read FImageBase write SetImageBase;    property SectionAlign: Cardinal read FSectionAlign;    property FileAlign: Cardinal read FFileAlign;    // Noch mehr braucht man eigentlich nicht, man kann ja alles über die    // ImageNtHeaders erreichen.  protected  end;const  IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   = 13;  IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14;  RT_HTML                              = PChar(23);  RT_MANIFEST                          = PChar(24);var  // by Olli  ResourceTypeDefaultNames: array[0..20] of record    ResType: PChar;    ResTypeName: string;  end = (    (ResType: RT_ACCELERATOR; ResTypeName: 'Accelerator'; ),    (ResType: RT_ANICURSOR; ResTypeName: 'Animated Cursor'; ),    (ResType: RT_ANIICON; ResTypeName: 'Animated Icon'; ),    (ResType: RT_BITMAP; ResTypeName: 'Bitmap'; ),    (ResType: RT_CURSOR; ResTypeName: 'Cursor'; ),    (ResType: RT_DIALOG; ResTypeName: 'Dialog'; ),    (ResType: RT_DLGINCLUDE; ResTypeName: 'Dialog Include'; ),    (ResType: RT_FONT; ResTypeName: 'Font'; ),    (ResType: RT_FONTDIR; ResTypeName: 'Font Directory'; ),    (ResType: RT_GROUP_CURSOR; ResTypeName: 'Group Cursor'; ),    (ResType: RT_GROUP_ICON; ResTypeName: 'Group Icon'; ),    (ResType: RT_HTML; ResTypeName: 'Html'; ),    (ResType: RT_ICON; ResTypeName: 'Icon'; ),    (ResType: RT_MANIFEST; ResTypeName: 'Manifest'; ),    (ResType: RT_MENU; ResTypeName: 'Menu'; ),    (ResType: RT_MESSAGETABLE; ResTypeName: 'Messagetable'; ),    (ResType: RT_PLUGPLAY; ResTypeName: 'Plugplay'; ),    (ResType: RT_RCDATA; ResTypeName: 'RC Data'; ),    (ResType: RT_STRING; ResTypeName: 'String'; ),    (ResType: RT_VERSION; ResTypeName: 'Version'; ),    (ResType: RT_VXD; ResTypeName: 'VXD'; )    );implementationconstructor TPeFile.Create;begin  inherited;end;destructor TPeFile.Destroy;begin  if (lpBuffer <> nil) then    FreeMem(lpBuffer, FFileSize);  inherited;end;function TPeFile.Align(Value, Align: Cardinal): Cardinal;begin  if ((Value mod Align) = 0) then    Result := Value  else    Result := ((Value + Align - 1) div Align) * Align;end;function TPeFile.SectionToString(Section: TImageSectionHeader): string;var  x: Word;begin  Result := '';  for x := 0 to IMAGE_SIZEOF_SHORT_NAME -1 do    if (Section.Name[x] <> 0) then      Result := Result + Chr(Section.Name[x]);end;procedure TPeFile.StringToSection(const sSectionName: string; var Section: TImageSectionHeader);var  x: Word;begin  FillChar(Section.Name, SizeOf(Section.Name), #0);  for x := 0 to Length(sSectionName) -1 do    if (x < IMAGE_SIZEOF_SHORT_NAME) then      Section.Name[x] := Ord(sSectionName[x +1]);end;function TPeFile.ValidHeaders: Boolean;begin  Result := False;  if (ImageDosHeader^.e_magic = IMAGE_DOS_SIGNATURE) then    if (ImageNtHeaders^.Signature = IMAGE_NT_SIGNATURE) then      Result := True;end;function TPeFile.ReadPeHeaders: Boolean;var  x: Word;begin  Result := False;  ImageDosHeader := PImageDosHeader(Integer(lpBuffer));  if (ImageDosHeader^.e_magic = IMAGE_DOS_SIGNATURE) then  begin    ImageNtHeaders := PImageNtHeaders(Integer(lpBuffer) + ImageDosHeader._lfanew);    if (ImageNtHeaders^.Signature = IMAGE_NT_SIGNATURE) then    begin      FNumberOfSections := ImageNtHeaders^.FileHeader.NumberOfSections;      FAddressOfEntryPoint := ImageNtHeaders^.OptionalHeader.AddressOfEntryPoint;      FImageBase := ImageNtHeaders^.OptionalHeader.ImageBase;      FFileAlign := ImageNtHeaders^.OptionalHeader.FileAlignment;      FSectionAlign := ImageNtHeaders^.OptionalHeader.SectionAlignment;      SetLength(ImageSections, NumberOfSections);      for x := Low(ImageSections) to High(ImageSections) do      begin        CopyMemory(@ImageSections[x],          Pointer(Integer(lpBuffer) + ImageDosHeader^._lfanew + SizeOf(TImageNtHeaders) + (x * SizeOf(TImageSectionHeader))),          SizeOf(TImageSectionHeader));      end;      Result := True;    end;  end;end;function TPeFile.LoadFromFile(const sFilename: string): Boolean;var  hFile: THandle;  lpNumberOfBytesRead: DWORD;begin  Result := False;  hFile := CreateFile(PChar(sFilename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);  if (hFile <> INVALID_HANDLE_VALUE) then  begin    FFilename := sFilename;    FFileSize := GetFileSize(hFile, nil);    GetMem(lpBuffer, FileSize);    ReadFile(hFile, lpBuffer^, FileSize, lpNumberOfBytesRead, nil);    if (FileSize = lpNumberOfBytesRead) then    begin      Result := ReadPeHeaders;    end;    CloseHandle(hFile);  end;end;function TPeFile.SaveToFile(const sFilename: string): Boolean;var  hFile: THandle;  lpNumberOfBytesWritten,  dwTemp: DWORD;  x: Word;  bZeroAll: Boolean;begin  Result := False;  bZeroAll := True;  hFile := CreateFile(PChar(sFilename), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);  if (hFile <> INVALID_HANDLE_VALUE) then  begin    if ValidHeaders then    begin      CopyMemory(lpBuffer, ImageDosHeader, SizeOf(TImageDosHeader));      CopyMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew), ImageNtHeaders, SizeOf(TImageNtHeaders));      // zuerst prüfen wir mittels dieser kleinen funktion, ob wir irgendwelche      // brauchbaren daten in den headern haben, falls ja werden diese nicht entfernt,      dwTemp := ImageDosHeader._lfanew + SizeOf(TImageNtHeaders) + (FNumberOfSections * SizeOf(TImageSectionHeader));      for x := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES -1 do      begin        if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress <> 0) then        begin          if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress < ImageNtHeaders^.OptionalHeader.SizeOfHeaders) then          begin            bZeroAll := False;            if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress > dwTemp) then            begin              dwTemp := ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress - dwTemp;              ZeroMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders) + (FNumberOfSections * SizeOf(TImageSectionHeader))), dwTemp);            end else              bZeroAll := False;          end;        end;      end;      if (bZeroAll) then      begin        dwTemp := ImageDosHeader._lfanew + SizeOf(TImageNtHeaders);        ZeroMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders)), ImageSections[Low(ImageSections)].PointerToRawData - dwTemp);      end;      ZeroMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders)), FNumberOfSections * SizeOf(TImageSectionHeader));      CopyMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders)), ImageSections, FNumberOfSections * SizeOf(TImageSectionHeader));      SetFilePointer(hFile, 0, nil, FILE_BEGIN);      WriteFile(hFile, lpBuffer^, FileSize, lpNumberOfBytesWritten, nil);      if (FileSize = lpNumberOfBytesWritten) then      begin        Result := True;      end;    end;    CloseHandle(hFile);  end;end;procedure TPeFile.SetAddressOfEntryPoint(AddressOfEntryPoint: Cardinal);begin  ImageNtHeaders^.OptionalHeader.AddressOfEntryPoint := AddressOfEntryPoint;  FAddressOfEntryPoint := AddressOfEntryPoint;end;procedure TPeFile.SetImageBase(ImageBase: Cardinal);begin  ImageNtHeaders^.OptionalHeader.ImageBase := ImageBase;  FImageBase := ImageBase;end;function TPeFile.RvaToFileOffset(dwRVA: Cardinal): Cardinal;var  x: Word;begin  Result := 0;  for x := Low(ImageSections) to High(ImageSections) do  begin    if ((dwRVA >= ImageSections[x].VirtualAddress) and (dwRVA < ImageSections[x].VirtualAddress + ImageSections[x].SizeOfRawData)) then    begin      Result := dwRVA - ImageSections[x].VirtualAddress + ImageSections[x].PointerToRawData;      Break;    end;  end;end;function TPeFile.FileOffsetToRva(dwFileOffset: Cardinal): Cardinal;var  x: Word;begin  Result := 0;  for x := Low(ImageSections) to High(ImageSections) do  begin    if ((dwFileOffset >= ImageSections[x].PointerToRawData) and (dwFileOffset < ImageSections[x].PointerToRawData + ImageSections[x].SizeOfRawData)) then    begin      Result := dwFileOffset - ImageSections[x].PointerToRawData + ImageSections[x].VirtualAddress;      Break;    end;  end;end;function TPeFile.VaToFileOffset(dwVA: Cardinal): Cardinal;begin  if (dwVA > Cardinal(lpBuffer)) then    Result := RvaToFileOffset(dwVA - Cardinal(lpBuffer))  else    Result := 0;end;function TPeFile.FileOffsetToVa(dwFileOffset: Cardinal): Cardinal;begin  Result := FileOffsetToRva(dwFileOffset) + Cardinal(lpBuffer);end;function TPeFile.VaToRva(dwVA: Cardinal): Cardinal;begin  Result := dwVA - Cardinal(lpBuffer);end;function TPeFile.RvaToVa(dwRVA: Cardinal): Cardinal;begin  Result := RvaToFileOffset(dwRVA) + Cardinal(lpBuffer);end;function TPeFile.RvaToSection(dwRVA: Cardinal): Word;var  x: Word;begin  Result := High(Word);  for x := Low(ImageSections) to High(ImageSections) do  begin    if ((dwRVA >= ImageSections[x].VirtualAddress) and (dwRVA < ImageSections[x].VirtualAddress + ImageSections[x].SizeOfRawData)) then    begin      Result := x;      Break;    end;  end;end;function TPeFile.FileOffsetToSection(dwFileOffset: Cardinal): Word;var  x: Word;begin  Result := High(Word);  for x := Low(ImageSections) to High(ImageSections) do  begin    if ((dwFileOffset >= ImageSections[x].PointerToRawData) and (dwFileOffset < ImageSections[x].PointerToRawData + ImageSections[x].SizeOfRawData)) then    begin      Result := x;      Break;    end;  end;end;{  Achtung: Rückgabewert ist 0 falls man die Headers verändert, bzw. diese  ungültig gemacht werden!}function TPeFile.InsertBytes(FromOffset, Count: Cardinal): Cardinal;var  dwCopyFrom, dwCopyLength: Cardinal;  lpTemp: Pointer;begin  Result := 0;  if (FromOffset > FFileSize) then    dwCopyFrom := FFileSize  else    dwCopyFrom := FromOffset;  dwCopyLength := FFileSize - dwCopyFrom;  ReallocMem(lpBuffer, FFileSize + Count);  if (dwCopyLength > 0) then  begin    GetMem(lpTemp, dwCopyLength);    CopyMemory(lpTemp, Pointer(Cardinal(lpBuffer) + dwCopyFrom), dwCopyLength);    CopyMemory(Pointer(Cardinal(lpBuffer) + dwCopyFrom + Count), lpTemp, dwCopyLength);    FreeMem(lpTemp);  end;  ZeroMemory(Pointer(Cardinal(lpBuffer) + dwCopyFrom), Count);  if ReadPeHeaders then  begin    FFileSize := FFileSize + Count;    Result := FFileSize;  end;end;{  Achtung: Rückgabewert ist 0 falls man die Headers verändert, bzw. diese  ungültig gemacht werden!}function TPeFile.DeleteBytes(FromOffset, Count: Cardinal): Cardinal;var  dwCopyFrom, dwCopyLength: DWORD;  lpTemp: Pointer;begin  Result := 0;  if (FFileSize >= (FromOffset + Count)) then  begin    dwCopyFrom := FromOffset + Count;    dwCopyLength := FFileSize - dwCopyFrom;    if (dwCopyLength > 0) then    begin      GetMem(lpTemp, dwCopyLength);      CopyMemory(lpTemp, Pointer(Cardinal(lpBuffer) + dwCopyFrom), dwCopyLength);      CopyMemory(Pointer(Cardinal(lpBuffer) + FromOffset), lpTemp, dwCopyLength);      FreeMem(lpTemp);    end;    ReallocMem(lpBuffer, FFileSize - Count);    if ReadPeHeaders then    begin      FFileSize := FFileSize - Count;      Result := FFileSize;    end;  end;end;{  Sucht nach 0 Bytes ab einem bestimmten Offset. Dabei werden 4 bytes  ignoriert weil diese z.B. zum Code gehören können.}function TPeFile.FindCodeCaves(FromOffset, Count: Cardinal): TCodeCave;var  x, TempCave: Cardinal;const  IGNORE_BYTES = 4;begin  ZeroMemory(@Result, SizeOf(TCodeCave));  if (Count > 0) then  begin    TempCave := 0;    for x := 0 to Count do    begin      if (PByte(Cardinal(lpBuffer) + FromOffset + x)^ = 0) then        Inc(TempCave)      else        TempCave := 0;      if ((TempCave > Result.CaveSize) and (TempCave > IGNORE_BYTES)) then      begin        with Result do        begin          StartFileOffset := FromOffset + (x - TempCave) + IGNORE_BYTES;          StartRVA := FileOffsetToRva(StartFileOffset);          CaveSize := TempCave - IGNORE_BYTES;        end;      end;    end;  end;end;{  Dieser Code war ursprünglich um die 200 Zeilen. Warum? Ich habe alles  'per Hand' berechnet, war jedoch nicht nötig. :(}function TPeFile.AddSection(const sSectionName: string; VirtualSize: Cardinal; dwCharacteristics: Cardinal = IMAGE_SCN_MEM_WRITE or IMAGE_SCN_MEM_READ or IMAGE_SCN_MEM_EXECUTE or IMAGE_SCN_CNT_CODE): Boolean;var  Section, LastSection: TImageSectionHeader;  CodeCave: TCodeCave;  dwTemp, FileAlign: Cardinal;  x: Word;  lpDataDir: Pointer;begin  FileAlign := ImageNtHeaders^.OptionalHeader.FileAlignment;  dwTemp := ImageDosHeader._lfanew + SizeOf(TImageNtHeaders) + (FNumberOfSections * SizeOf(TImageSectionHeader));  for x := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES -1 do  begin    if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress <> 0) then    begin      if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress < ImageNtHeaders^.OptionalHeader.SizeOfHeaders) then      begin        if (ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress = dwTemp) then        begin          // wir verschieben die daten die unter den sektionen(!) sind, einfach in einer neuen sektion!!!          GetMem(lpDataDir, ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size);          CopyMemory(lpDataDir, Pointer(Cardinal(lpBuffer) + dwTemp), ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size);          ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress := 0;          AddSection('.bdata', ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size);          CopyMemory(Pointer(Cardinal(lpBuffer) + ImageSections[High(ImageSections)].PointerToRawData), lpDataDir,            ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size);          ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress := ImageSections[High(ImageSections)].VirtualAddress;          FreeMem(lpDataDir);        end;      end;    end;  end;  if (ImageNtHeaders^.OptionalHeader.SizeOfHeaders > dwTemp) then    CodeCave := FindCodeCaves(dwTemp, ImageNtHeaders^.OptionalHeader.SizeOfHeaders - dwTemp)  else    CodeCave := FindCodeCaves(dwTemp, dwTemp - ImageNtHeaders^.OptionalHeader.SizeOfHeaders);  if (CodeCave.CaveSize < SizeOf(TImageSectionHeader)) then  begin    dwTemp := ImageDosHeader._lfanew + SizeOf(TImageNtHeaders) + (FNumberOfSections * SizeOf(TImageSectionHeader));    // wir fügen einmal FileAlign-bytes ein dann ist mal ruhe für die nächsten 13 sektionen ..    if (FileAlign <= SizeOf(TImageSectionHeader)) then      FileAlign := Align(SizeOf(TImageSectionHeader), FileAlign);    if (InsertBytes(dwTemp, FileAlign) <> 0) then    begin      ImageNtHeaders^.OptionalHeader.SizeOfHeaders := ImageNtHeaders^.OptionalHeader.SizeOfHeaders + FileAlign;      for x := Low(ImageSections) to High(ImageSections) do        ImageSections[x].PointerToRawData := ImageSections[x].PointerToRawData + FileAlign;      CopyMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders)),        ImageSections, FNumberOfSections * SizeOf(TImageSectionHeader));    end;    FileAlign := ImageNtHeaders^.OptionalHeader.FileAlignment;  end;  LastSection := ImageSections[High(ImageSections)];  StringToSection(sSectionName, Section);  with Section do  begin    VirtualAddress := ImageNtHeaders^.OptionalHeader.SizeOfImage;    Misc.VirtualSize := Align(VirtualSize, SectionAlign);    SizeOfRawData := (VirtualAddress div FileAlign +1) * FileAlign - ImageNtHeaders^.OptionalHeader.SizeOfImage;    PointerToRawData := LastSection.PointerToRawData + LastSection.SizeOfRawData;    Characteristics := dwCharacteristics;  end;  // ok struktur wurde eingelesen  Inc(ImageNtHeaders^.FileHeader.NumberOfSections);  FFileSize := FFileSize + Section.SizeOfRawData;  ImageNtHeaders^.OptionalHeader.SizeOfImage := Align(ImageNtHeaders^.OptionalHeader.SizeOfImage + Section.Misc.VirtualSize, SectionAlign);  CopyMemory(Pointer(Integer(lpBuffer) + ImageDosHeader._lfanew + SizeOf(TImageNtHeaders) +    (FNumberOfSections * SizeOf(TImageSectionHeader))), @Section, SizeOf(TImageSectionHeader));  ReallocMem(lpBuffer, FFileSize);  Result := ReadPeHeaders;  ZeroMemory(Pointer(Cardinal(lpBuffer) + FFileSize - Section.SizeOfRawData), Section.SizeOfRawData);end;function TPeFile.DeleteSection(wSection: Word): Boolean;var  dwTempFileSize, ImageSize, dwTemp,  SectionOffset, SectionSize, SectionAlign: Cardinal;  x: Word;begin  Result := False;  if (wSection < FNumberOfSections) then  begin    SectionOffset := ImageSections[wSection].PointerToRawData;    SectionSize := ImageSections[wSection].SizeOfRawData;    SectionAlign := ImageNtHeaders^.OptionalHeader.SectionAlignment;    dwTempFileSize := FFileSize;    DeleteBytes(SectionOffset, SectionSize);    if (FFileSize = dwTempFileSize - SectionSize) then    begin      if (wSection > 0) then      begin        for x := Low(ImageSections) to wSection -1 do        begin          ImageSections[x].Misc.VirtualSize := Align(ImageSections[x].Misc.VirtualSize, SectionAlign);          if (x = wSection -1) then            ImageSections[x].Misc.VirtualSize  := Align(ImageSections[x].Misc.VirtualSize + SectionAlign, SectionAlign);          CopyMemory(            Pointer(Integer(lpBuffer) + ImageDosHeader^._lfanew + SizeOf(TImageNtHeaders) + (x * SizeOf(TImageSectionHeader))),            @ImageSections[x],            SizeOf(TImageSectionHeader));        end;      end;      for x := wSection +1 to FNumberOfSections -1 do      begin        ImageSections[x].PointerToRawData := ImageSections[x].PointerToRawData - SectionSize;        CopyMemory(          Pointer(Integer(lpBuffer) + ImageDosHeader^._lfanew + SizeOf(TImageNtHeaders) + ((x -1) * SizeOf(TImageSectionHeader))),           @ImageSections[x],           SizeOf(TImageSectionHeader));      end;      for x := 0 to IMAGE_NUMBEROF_DIRECTORY_ENTRIES -1 do      begin        if ((ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress <> 0) and (ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size <> 0)) then        begin          dwTemp := RvaToFileOffset(ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress);          if (dwTemp = 0) then            dwTemp := ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress;          if (dwTemp = SectionOffset) then          begin            ImageNtHeaders^.OptionalHeader.DataDirectory[x].VirtualAddress := 0;            ImageNtHeaders^.OptionalHeader.DataDirectory[x].Size := 0;          end;        end;      end;      if (ImageNtHeaders^.OptionalHeader.SizeOfHeaders mod SectionAlign = 0) then        ImageSize := ImageNtHeaders^.OptionalHeader.SizeOfHeaders      else        ImageSize := Align(ImageNtHeaders^.OptionalHeader.SizeOfHeaders, SectionAlign);      for x := Low(ImageSections) to High(ImageSections) do      begin        if (x <> wSection) then          ImageSize := ImageSize + Align(ImageSections[x].Misc.VirtualSize, SectionAlign);      end;      ImageNtHeaders^.OptionalHeader.SizeOfImage := ImageSize;      Dec(ImageNtHeaders^.FileHeader.NumberOfSections);      Dec(FNumberOfSections);      Result := ReadPeHeaders;    end;  end;end;function TPeFile.GetCharacteristics(dwCharacteristics: DWORD): string;type  TCharacteristics = packed record    Mask: DWORD;    InfoChar: Char;  end;const  Info: array[0..8] of TCharacteristics = (    (Mask: IMAGE_SCN_CNT_CODE; InfoChar: 'C'),    (Mask: IMAGE_SCN_MEM_EXECUTE; InfoChar: 'E'),    (Mask: IMAGE_SCN_MEM_READ; InfoChar: 'R'),    (Mask: IMAGE_SCN_MEM_WRITE; InfoChar: 'W'),    (Mask: IMAGE_SCN_MEM_NOT_PAGED; InfoChar: 'P'),    (Mask: IMAGE_SCN_CNT_INITIALIZED_DATA; InfoChar: 'I'),    (Mask: IMAGE_SCN_CNT_UNINITIALIZED_DATA; InfoChar: 'U'),    (Mask: IMAGE_SCN_MEM_SHARED; InfoChar: 'S'),    (Mask: IMAGE_SCN_MEM_DISCARDABLE; InfoChar: 'D'));var  x: Word;begin  for x := Low(Info) to High(Info) do  begin    if ((dwCharacteristics and Info[x].Mask) = Info[x].Mask) then      Result := Result + Info[x].InfoChar;  end;end;function TPeFile.GetCodeSection: Word;begin  Result := RvaToSection(ImageNtHeaders^.OptionalHeader.BaseOfCode);end;function TPeFile.GetDataSection: Word;begin  Result := RvaToSection(ImageNtHeaders^.OptionalHeader.BaseOfData);end;function TPeFile.GetResourceSection: Word;var  dwTemp: Cardinal;begin  Result := High(Word);  dwTemp := ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;  if (dwTemp <> 0) then    Result := RvaToSection(dwTemp);end;procedure TPeFile.GetImportAddressTable(var Imports: TImportsArray);var  x, y: Cardinal;  ImportDescriptor: PImageImportDescriptor;  DelayDescriptor: PImgDelayDescr;  BoundImportDescriptor: PImageBoundImportDescriptor;  lpszLibraryName: PChar;  ImageThunk: PImageThunkData;  lpszAPIName: PChar;  { Is Import By Ordinal? }  function IsImportByOrdinal(ImportDescriptor: DWORD): Boolean;  begin    Result := (ImportDescriptor and $80000000) <> 0;  end;begin  x := 0;  SetLength(Imports, 1);  ZeroMemory(Imports, SizeOf(Imports) * High(Imports));  // NORMALE IAT  if ((ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress <> 0) and      (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size <> 0)) then  begin    ImportDescriptor := PImageImportDescriptor(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));    while (ImportDescriptor^.Name <> 0) do    begin      SetLength(Imports, x +1);      lpszLibraryName := PChar(RvaToVa(ImportDescriptor^.Name));      Imports[x].LibraryName := lpszLibraryName;      Imports[x].ImportType := itNormal;      Imports[x].OriginalFirstThunk := ImportDescriptor^.OriginalFirstThunk;      Imports[x].TimeDateStamp := ImportDescriptor^.TimeDateStamp;      Imports[x].ForwarderChain := ImportDescriptor^.ForwarderChain;      Imports[x].Name := ImportDescriptor^.Name;      Imports[x].FirstThunk := ImportDescriptor^.FirstThunk;      if (ImportDescriptor^.OriginalFirstThunk <> 0) then        ImageThunk := PImageThunkData(RvaToVa(ImportDescriptor^.OriginalFirstThunk))      else        ImageThunk := PImageThunkData(RvaToVa(ImportDescriptor^.FirstThunk));      y := 0;      while (ImageThunk^.Name <> 0) do      begin        SetLength(Imports[x].IatFunctions, y +1);        if IsImportByOrdinal(ImageThunk^.Name) then        begin          lpszAPIName := '(by ordinal)';          Imports[x].IatFunctions[y].Hint := ImageThunk^.Name and $ffff;        end else        begin          lpszAPIName := PChar(RvaToVa(ImageThunk^.Name + SizeOf(Word)));          Imports[x].IatFunctions[y].Hint := 0;        end;        Imports[x].IatFunctions[y].ThunkOffset := Cardinal(ImageThunk) - Cardinal(lpBuffer);        if (ImportDescriptor^.OriginalFirstThunk <> 0) then          Imports[x].IatFunctions[y].ThunkRVA := ImportDescriptor^.OriginalFirstThunk + DWORD(y * SizeOf(DWORD))        else          Imports[x].IatFunctions[y].ThunkRVA := ImportDescriptor^.FirstThunk + DWORD(y * SizeOf(DWORD));        Imports[x].IatFunctions[y].ThunkValue := ImageThunk^.Name;        Imports[x].IatFunctions[y].ApiName := lpszAPIName;        Inc(y);        Inc(ImageThunk);      end;      Inc(x);      Inc(ImportDescriptor);    end;  end;  // DELAYED IAT  if ((ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress <> 0) and      (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size <> 0)) then  begin    DelayDescriptor := PImgDelayDescr(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress));    while (DelayDescriptor^.szName <> 0) do    begin      SetLength(Imports, x +1);      lpszLibraryName := PChar(RvaToVa(DelayDescriptor^.szName));      Imports[x].LibraryName := lpszLibraryName;      Imports[x].OriginalFirstThunk := DelayDescriptor^.pINT.Name;      Imports[x].ImportType := itDelay;      Imports[x].TimeDateStamp := DelayDescriptor^.dwTimeStamp;      Imports[x].FirstThunk := PImageImportDescriptor(DelayDescriptor)^.FirstThunk;      ImageThunk := PImageThunkData(RvaToVa(DelayDescriptor^.pINT.Name));      y := 0;      while (ImageThunk^.Name <> 0) do      begin        SetLength(Imports[x].IatFunctions, y +1);        if IsImportByOrdinal(ImageThunk^.Name) then        begin          lpszAPIName := '(by ordinal)';          Imports[x].IatFunctions[y].Hint := ImageThunk^.Name and $ffff;        end else        begin          lpszAPIName := PChar(RvaToVa(ImageThunk^.Name + SizeOf(Word)));          Imports[x].IatFunctions[y].Hint := 0;        end;        Imports[x].IatFunctions[y].ThunkOffset := Cardinal(ImageThunk) - Cardinal(lpBuffer);        Imports[x].IatFunctions[y].ThunkRVA := DelayDescriptor^.pINT.Name + DWORD(y * SizeOf(DWORD));        Imports[x].IatFunctions[y].ThunkValue := ImageThunk^.Name;        Imports[x].IatFunctions[y].ApiName := lpszAPIName;        Inc(y);        Inc(ImageThunk);      end;      Inc(x);      Inc(DelayDescriptor);    end;  end;  // BOUND IAT  if ((ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress <> 0) and      (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size <> 0)) then  begin    BoundImportDescriptor := PImageBoundImportDescriptor(Cardinal(lpBuffer) + ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress);    while (BoundImportDescriptor^.OffsetModuleName <> 0) do    begin      SetLength(Imports, x +1);      lpszLibraryName := PChar(Integer(lpBuffer) + ImageDosHeader^._lfanew + SizeOf(TImageNtHeaders) + (FNumberOfSections * SizeOf(TImageSectionHeader)) + BoundImportDescriptor^.OffsetModuleName);      Imports[x].TimeDateStamp := BoundImportDescriptor.TimeDateStamp;      Imports[x].LibraryName := lpszLibraryName;      Imports[x].ImportType := itBound;      Imports[x].Name := BoundImportDescriptor^.OffsetModuleName;      if (BoundImportDescriptor^.NumberOfModuleForwarderRefs > 0) then      begin        for y := 0 to BoundImportDescriptor^.NumberOfModuleForwarderRefs -1 do        begin          Inc(PImageBoundForwarderRef(BoundImportDescriptor));        end;      end;      Inc(x);      Inc(BoundImportDescriptor);    end;  end;  // ToDo: COM IATend;procedure TPeFile.GetExportsAddressTable(var ExportData: TExports);type  PDWORDArray = ^TDWORDArray;  TDWORDArray = array[Word] of DWORD;  PWordArray = ^TWordArray;  TWordArray = array[Word] of Word;var  ExportDirectory: PImageExportDirectory;  Functions: PDWORDArray;  Ordinals: PWordArray;  Names: PDWORDArray;  CounterFunctions, CounterOrdinals: DWORD;  VA: DWORD;  sName: string;  x: Integer;begin  SetLength(ExportData.ExportFunctions, 1);  if ((ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress <> 0) and      (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size <> 0)) then  begin    ExportDirectory := PImageExportDirectory(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));    Functions := Pointer(RvaToVa(Cardinal(ExportDirectory^.AddressOfFunctions)));    Ordinals := Pointer(RvaToVa(Cardinal(ExportDirectory^.AddressOfNameOrdinals)));    Names := Pointer(RvaToVa(Cardinal(ExportDirectory^.AddressOfNames)));    with ExportData do    begin      LibraryName := PChar(RvaToVa(ExportDirectory^.Name));      Base := ExportDirectory^.Base;      Characteristics := ExportDirectory^.Characteristics;      TimeDateStamp := ExportDirectory^.TimeDateStamp;      MajorVersion := ExportDirectory^.MajorVersion;      MinorVersion := ExportDirectory^.MinorVersion;      NumberOfFunctions := ExportDirectory^.NumberOfFunctions;      NumberOfNames := ExportDirectory^.NumberOfNames;      AddressOfFunctions := DWORD(ExportDirectory^.AddressOfFunctions);      AddressOfNames := DWORD(ExportDirectory^.AddressOfNames);      AddressOfNameOrdinals := Word(ExportDirectory^.AddressOfNameOrdinals);    end;    if (Functions <> nil) then    begin      x := 0;      for CounterFunctions := 0 to ExportDirectory^.NumberOfFunctions -1 do      begin        sName := '';        if (Functions[CounterFunctions] = 0) then          continue;        SetLength(ExportData.ExportFunctions, x +1);        ExportData.ExportFunctions[x].Ordinal := CounterFunctions + ExportDirectory^.Base;        if (Ordinals <> nil) and (Names <> nil) then        begin          for CounterOrdinals := 0 to ExportDirectory^.NumberOfNames -1 do          begin            if (Ordinals[CounterOrdinals] = CounterFunctions) then            begin              sName := PChar(RvaToVa(Names[CounterOrdinals]));              Break;            end;          end;        end;        VA := Functions[CounterFunctions];        if DWORD(VA - ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) <                  ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size then        begin          sName := PChar(RvaToVa(Va));          VA := 0;        end;        ExportData.ExportFunctions[x].Rva := VA;        ExportData.ExportFunctions[x].FileOffset := RvaToFileOffset(VA);        ExportData.ExportFunctions[x].ApiName := sName;        Inc(x);      end;    end;  end;end;function TPeFile.GetThreadLocalStorage: PImageTLSDirectory;begin  Result := nil;  if (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress <> 0) then  begin    Result := PImageTLSDirectory(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));  end;end;{  Resourcen sind einwenig blöd aufgebaut, aber anhand der Count-Variable in jedem  Block braucht man kein High mehr benützen ..}procedure TPeFile.GetResources(var Resources: TResources);var  Table: PImageResourceDirectory;  VA: DWORD;  TypCount, NameCountPublic: Integer;  function WideCharToMultiByteEx(var lp: PWideChar): string;  var    len: Word;  begin    len := Word(lp^);    SetLength(Result, len);    Inc(lp);    WideCharToMultiByte(CP_ACP, 0, lp, Len, PChar(Result), Len +1, nil, nil);    Inc(lp, len);    Result := PChar(Result);  end;    function GetResourceStr(IsResID: Boolean; IsType: Boolean; Addr: DWORD): string;  var    lpTmp: PWideChar;    x: Word;  begin    if IsResID then    begin      if IsType then      begin        for x := 0 to Length(ResourceTypeDefaultNames) -1 do        begin          if (MAKEINTRESOURCE(Addr) = MAKEINTRESOURCE(ResourceTypeDefaultNames[x].ResType)) then          begin            Result := ResourceTypeDefaultNames[x].ResTypeName;            Exit;          end;        end;      end;      Str(Addr, Result);    end else    begin      lpTmp := PWideChar(RvaToVa(VA + (Addr and $7fffffff)));      Result := WideCharToMultiByteEx(lpTmp);    end;  end;  procedure ParseResources(Offset: DWORD; Level: Byte);  var    Table: PImageResourceDirectory;    Entry: PImageResourceDirectoryEntry;    i, Count: Integer;    IsResID: Boolean;    NameCount, LangsCount: Integer;    lpTyp, lpName, lpLang: string;  begin    NameCount := 0;    LangsCount := 0;    Table := Pointer(RvaToVa(VA + Offset));    Count := Table^.NumberOfNamedEntries + Table^.NumberOfIdEntries;    Entry := Pointer(RvaToVa(VA + Offset + SizeOf(TImageResourceDirectory)));    for i := 0 to Count -1 do    begin      IsResID := i >= Table^.NumberOfNamedEntries;      case Level of        0:          begin            // Typen            NameCountPublic := 0;            lpTyp := GetResourceStr(IsResId, True, Entry^.Name);            SetLength(Resources.rtTyps, TypCount +1);            Resources.rtTyps[TypCount].sTyp := lpTyp;            Inc(Resources.TypCount);            Inc(TypCount);          end;        1:          begin            // Namen            lpName := GetResourceStr(IsResId, False, Entry^.Name);            SetLength(Resources.rtTyps[TypCount -1].lpNames, NameCount +1);            Resources.rtTyps[TypCount -1].lpNames[NameCount].sName := lpName;            Resources.rtTyps[TypCount -1].lpNames[NameCount].dwRVA := VA + (Entry^.OffsetToData and $7fffffff);            Resources.rtTyps[TypCount -1].lpNames[NameCount].dwFileOffset := FileOffsetToRva(VA + (Entry^.OffsetToData and $7fffffff));            Inc(Resources.rtTyps[TypCount -1].NamesCount);            Inc(NameCount);            Inc(NameCountPublic);          end;        2:          begin            // Langs            lpLang := GetResourceStr(IsResId, False, Entry^.Name);            SetLength(Resources.rtTyps[TypCount -1].lpNames[(NameCountPublic-1) + LangsCount].lpLangs, LangsCount +1);            Resources.rtTyps[TypCount -1].lpNames[(NameCountPublic-1) + LangsCount].lpLangs[LangsCount].sLang := lpLang;            Resources.rtTyps[TypCount -1].lpNames[(NameCountPublic-1) + LangsCount].lpLangs[LangsCount].dwRVA := VA + (Entry^.OffsetToData and $7fffffff);            Resources.rtTyps[TypCount -1].lpNames[(NameCountPublic-1) + LangsCount].lpLangs[LangsCount].dwFileOffset := RvaToFileOffset(VA + (Entry^.OffsetToData and $7fffffff));            Inc(Resources.rtTyps[TypCount -1].lpNames[(NameCountPublic-1) + LangsCount].LangsCount);           Inc(LangsCount);          end;      end;      if (Entry^.OffsetToData and $80000000) > 0 then        ParseResources(Entry^.OffsetToData and $7fffffff, Level +1);      Inc(Entry);    end;  end;begin  if (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress <> 0) then  begin    TypCount := 0;    VA := ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;    FillChar(Resources, SizeOf(TResources), #0);    Table := Pointer(RvaToVa(VA));    with Resources do    begin      Characteristics := Table^.Characteristics;      TimeDateStamp := Table^.TimeDateStamp;      MajorVersion := Table^.MajorVersion;      MinorVersion := Table^.MinorVersion;      NumberOfNamedEntries := Table^.NumberOfNamedEntries;      NumberOfIdEntries := Table^.NumberOfIdEntries;    end;    ParseResources(0, 0);  end;end;function TPeFile.GetDebugDirectory: PImageDebugDirectory;begin  Result := nil;  if (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress <> 0) then  begin    Result := PImageDebugDirectory(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress));  end;end;function TPeFile.GetLoadConfigDirectory: PImageLoadConfigDirectory;begin  Result := nil;  if (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress <> 0) then  begin    Result := PImageLoadConfigDirectory(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress));  end;end;function TPeFile.GetEntryExceptionDirectory: PImageRuntimeFunctionEntry;begin  Result := nil;  if (ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress <> 0) then  begin    Result := PImageRuntimeFunctionEntry(RvaToVa(ImageNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress));  end;end;procedure TPeFile.CopyMemoryBuffer(CopyToOffset: DWORD; Source: Pointer; Length: DWORD);begin  CopyMemory(Pointer(Cardinal(lpBuffer) + CopyToOffset), Source, Length);end;function TPeFile.DumpSection(wSection: Word; sFilename: string): Boolean;var  hFile: THandle;  lpNumberOfBytesWritten: DWORD;  lpBuff: Pointer;begin  Result := False;  if (wSection <> High(Word)) then  begin    hFile := CreateFile(PChar(sFilename), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);    if (hFile <> INVALID_HANDLE_VALUE) then    begin      lpBuff := Pointer(Cardinal(lpBuffer) + ImageSections[wSection].PointerToRawData);      WriteFile(hFile, lpBuff^, ImageSections[wSection].SizeOfRawData, lpNumberOfBytesWritten, nil);      Result := lpNumberOfBytesWritten = ImageSections[wSection].SizeOfRawData;      CloseHandle(hFile);    end;  end;end;end.