瀏覽代碼

Cleanup: there was a Shared.ResUpdateFunc claiming it was used by Setup while it wasn't. Move its code into Compiler.ExeUpdateFunc and remove it.

Martijn Laan 2 周之前
父節點
當前提交
5c9f6e828f

+ 0 - 1
Projects/ISCmplr.dpr

@@ -26,7 +26,6 @@ uses
   Compiler.ScriptFunc in 'Src\Compiler.ScriptFunc.pas',
   Compiler.ScriptFunc in 'Src\Compiler.ScriptFunc.pas',
   Compiler.ScriptCompiler in 'Src\Compiler.ScriptCompiler.pas',
   Compiler.ScriptCompiler in 'Src\Compiler.ScriptCompiler.pas',
   Compiler.ScriptClasses in 'Src\Compiler.ScriptClasses.pas',
   Compiler.ScriptClasses in 'Src\Compiler.ScriptClasses.pas',
-  Shared.ResUpdateFunc in 'Src\Shared.ResUpdateFunc.pas',
   Compiler.ExeUpdateFunc in 'Src\Compiler.ExeUpdateFunc.pas',
   Compiler.ExeUpdateFunc in 'Src\Compiler.ExeUpdateFunc.pas',
   Compression.Base in 'Src\Compression.Base.pas',
   Compression.Base in 'Src\Compression.Base.pas',
   Compression.Zlib in 'Src\Compression.Zlib.pas',
   Compression.Zlib in 'Src\Compression.Zlib.pas',

+ 0 - 1
Projects/ISCmplr.dproj

@@ -94,7 +94,6 @@
         <DCCReference Include="Src\Compiler.ScriptFunc.pas"/>
         <DCCReference Include="Src\Compiler.ScriptFunc.pas"/>
         <DCCReference Include="Src\Compiler.ScriptCompiler.pas"/>
         <DCCReference Include="Src\Compiler.ScriptCompiler.pas"/>
         <DCCReference Include="Src\Compiler.ScriptClasses.pas"/>
         <DCCReference Include="Src\Compiler.ScriptClasses.pas"/>
-        <DCCReference Include="Src\Shared.ResUpdateFunc.pas"/>
         <DCCReference Include="Src\Compiler.ExeUpdateFunc.pas"/>
         <DCCReference Include="Src\Compiler.ExeUpdateFunc.pas"/>
         <DCCReference Include="Src\Compression.Base.pas"/>
         <DCCReference Include="Src\Compression.Base.pas"/>
         <DCCReference Include="Src\Compression.Zlib.pas"/>
         <DCCReference Include="Src\Compression.Zlib.pas"/>

+ 0 - 1
Projects/Setup.dpr

@@ -71,7 +71,6 @@ uses
   Setup.Helper in 'Src\Setup.Helper.pas',
   Setup.Helper in 'Src\Setup.Helper.pas',
   Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
   Shared.VerInfoFunc in 'Src\Shared.VerInfoFunc.pas',
   Setup.RegDLL in 'Src\Setup.RegDLL.pas',
   Setup.RegDLL in 'Src\Setup.RegDLL.pas',
-  Shared.ResUpdateFunc in 'Src\Shared.ResUpdateFunc.pas',
   Setup.SpawnCommon in 'Src\Setup.SpawnCommon.pas',
   Setup.SpawnCommon in 'Src\Setup.SpawnCommon.pas',
   Setup.SpawnServer in 'Src\Setup.SpawnServer.pas',
   Setup.SpawnServer in 'Src\Setup.SpawnServer.pas',
   Setup.SpawnClient in 'Src\Setup.SpawnClient.pas',
   Setup.SpawnClient in 'Src\Setup.SpawnClient.pas',

+ 0 - 1
Projects/Setup.dproj

@@ -144,7 +144,6 @@
         <DCCReference Include="Src\Setup.Helper.pas"/>
         <DCCReference Include="Src\Setup.Helper.pas"/>
         <DCCReference Include="Src\Shared.VerInfoFunc.pas"/>
         <DCCReference Include="Src\Shared.VerInfoFunc.pas"/>
         <DCCReference Include="Src\Setup.RegDLL.pas"/>
         <DCCReference Include="Src\Setup.RegDLL.pas"/>
-        <DCCReference Include="Src\Shared.ResUpdateFunc.pas"/>
         <DCCReference Include="Src\Setup.SpawnCommon.pas"/>
         <DCCReference Include="Src\Setup.SpawnCommon.pas"/>
         <DCCReference Include="Src\Setup.SpawnServer.pas"/>
         <DCCReference Include="Src\Setup.SpawnServer.pas"/>
         <DCCReference Include="Src\Setup.SpawnClient.pas"/>
         <DCCReference Include="Src\Setup.SpawnClient.pas"/>

+ 362 - 1
Projects/Src/Compiler.ExeUpdateFunc.pas

@@ -14,6 +14,14 @@ interface
 uses
 uses
   Windows, SysUtils, Shared.FileClass, Shared.VerInfoFunc;
   Windows, SysUtils, Shared.FileClass, Shared.VerInfoFunc;
 
 
+function ReadSignatureAndChecksumFields(const F: TCustomFile;
+  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+function ReadSignatureAndChecksumFields64(const F: TCustomFile;
+  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+function SeekToResourceData(const F: TCustomFile; const ResType, ResId: Cardinal): Cardinal;
+function UpdateSignatureAndChecksumFields(const F: TCustomFile;
+  const ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+  
 procedure UpdateSetupPEHeaderFields(const F: TCustomFile;
 procedure UpdateSetupPEHeaderFields(const F: TCustomFile;
   const IsTSAware, IsDEPCompatible, IsASLRCompatible: Boolean);
   const IsTSAware, IsDEPCompatible, IsASLRCompatible: Boolean);
 procedure UpdateIcons(const FileName, IcoFileName: String; const DeleteUninstallIcon: Boolean);
 procedure UpdateIcons(const FileName, IcoFileName: String; const DeleteUninstallIcon: Boolean);
@@ -27,7 +35,360 @@ procedure PreventCOMCTL32Sideloading(const F: TCustomFile);
 implementation
 implementation
 
 
 uses
 uses
-  Shared.ResUpdateFunc, Math;
+  Math;
+
+const
+  IMAGE_NT_SIGNATURE = $00004550;
+  IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b;
+  IMAGE_NT_OPTIONAL_HDR64_MAGIC = $20b;
+  IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
+  IMAGE_SIZEOF_SHORT_NAME = 8;
+  IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
+  IMAGE_DIRECTORY_ENTRY_SECURITY = 4;
+
+type
+  PImageFileHeader = ^TImageFileHeader;
+  TImageFileHeader = packed record
+    Machine: Word;
+    NumberOfSections: Word;
+    TimeDateStamp: DWORD;
+    PointerToSymbolTable: DWORD;
+    NumberOfSymbols: DWORD;
+    SizeOfOptionalHeader: Word;
+    Characteristics: Word;
+  end;
+  PImageDataDirectory = ^TImageDataDirectory;
+  TImageDataDirectory = record
+    VirtualAddress: DWORD;
+    Size: DWORD;
+  end;
+  PImageOptionalHeader = ^TImageOptionalHeader;
+  TImageOptionalHeader = packed record
+    { Standard fields. }
+    Magic: Word;
+    MajorLinkerVersion: Byte;
+    MinorLinkerVersion: Byte;
+    SizeOfCode: DWORD;
+    SizeOfInitializedData: DWORD;
+    SizeOfUninitializedData: DWORD;
+    AddressOfEntryPoint: DWORD;
+    BaseOfCode: DWORD;
+    BaseOfData: DWORD;
+    { NT additional fields. }
+    ImageBase: DWORD;
+    SectionAlignment: DWORD;
+    FileAlignment: DWORD;
+    MajorOperatingSystemVersion: Word;
+    MinorOperatingSystemVersion: Word;
+    MajorImageVersion: Word;
+    MinorImageVersion: Word;
+    MajorSubsystemVersion: Word;
+    MinorSubsystemVersion: Word;
+    Win32VersionValue: DWORD;
+    SizeOfImage: DWORD;
+    SizeOfHeaders: DWORD;
+    CheckSum: DWORD;
+    Subsystem: Word;
+    DllCharacteristics: Word;
+    SizeOfStackReserve: DWORD;
+    SizeOfStackCommit: DWORD;
+    SizeOfHeapReserve: DWORD;
+    SizeOfHeapCommit: DWORD;
+    LoaderFlags: DWORD;
+    NumberOfRvaAndSizes: DWORD;
+    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
+  end;
+  PImageOptionalHeader64 = ^TImageOptionalHeader64;
+  TImageOptionalHeader64 = packed record
+    { Standard fields. }
+    Magic: Word;
+    MajorLinkerVersion: Byte;
+    MinorLinkerVersion: Byte;
+    SizeOfCode: DWORD;
+    SizeOfInitializedData: DWORD;
+    SizeOfUninitializedData: DWORD;
+    AddressOfEntryPoint: DWORD;
+    BaseOfCode: DWORD;
+    { NT additional fields. }
+    ImageBase: Int64;
+    SectionAlignment: DWORD;
+    FileAlignment: DWORD;
+    MajorOperatingSystemVersion: Word;
+    MinorOperatingSystemVersion: Word;
+    MajorImageVersion: Word;
+    MinorImageVersion: Word;
+    MajorSubsystemVersion: Word;
+    MinorSubsystemVersion: Word;
+    Win32VersionValue: DWORD;
+    SizeOfImage: DWORD;
+    SizeOfHeaders: DWORD;
+    CheckSum: DWORD;
+    Subsystem: Word;
+    DllCharacteristics: Word;
+    SizeOfStackReserve: Int64;
+    SizeOfStackCommit: Int64;
+    SizeOfHeapReserve: Int64;
+    SizeOfHeapCommit: Int64;
+    LoaderFlags: DWORD;
+    NumberOfRvaAndSizes: DWORD;
+    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
+  end;
+  TISHMisc = packed record
+    case Integer of
+      0: (PhysicalAddress: DWORD);
+      1: (VirtualSize: DWORD);
+  end;
+  PImageSectionHeader = ^TImageSectionHeader;
+  TImageSectionHeader = packed record
+    Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;
+    Misc: TISHMisc;
+    VirtualAddress: DWORD;
+    SizeOfRawData: DWORD;
+    PointerToRawData: DWORD;
+    PointerToRelocations: DWORD;
+    PointerToLinenumbers: DWORD;
+    NumberOfRelocations: Word;
+    NumberOfLinenumbers: Word;
+    Characteristics: DWORD;
+  end;
+  TImageResourceDirectory = packed record
+    Characteristics: DWORD;
+    TimeDateStamp: DWORD;
+    MajorVersion: Word;
+    MinorVersion: Word;
+    NumberOfNamedEntries: Word;
+    NumberOfIdEntries: Word;
+  end;
+  TImageResourceDirectoryEntry = packed record
+    Id: DWORD;
+    Offset: DWORD;
+  end;
+  TImageResourceDataEntry = packed record
+    OffsetToData: DWORD;
+    Size: DWORD;
+    CodePage: DWORD;
+    Reserved: DWORD;
+  end;
+
+procedure Error(const Msg: String);
+begin
+  raise Exception.Create('Resource update error: ' + Msg);
+end;
+
+function SeekToPEHeader(const F: TCustomFile): Boolean;
+var
+  DosHeader: packed record
+    Sig: array[0..1] of AnsiChar;
+    Other: array[0..57] of Byte;
+    PEHeaderOffset: LongWord;
+  end;
+  Sig: DWORD;
+begin
+  Result := False;
+  F.Seek(0);
+  if F.Read(DosHeader, SizeOf(DosHeader)) = SizeOf(DosHeader) then begin
+    if (DosHeader.Sig[0] = 'M') and (DosHeader.Sig[1] = 'Z') and
+       (DosHeader.PEHeaderOffset <> 0) then begin
+      F.Seek(DosHeader.PEHeaderOffset);
+      if F.Read(Sig, SizeOf(Sig)) = SizeOf(Sig) then
+        if Sig = IMAGE_NT_SIGNATURE then
+          Result := True;
+    end;
+  end;
+end;
+
+function SeekToAndReadPEOptionalHeader(const F: TCustomFile;
+  var OptHeader: TImageOptionalHeader; var OptHeaderOffset: Int64): Boolean;
+var
+  Header: TImageFileHeader;
+begin
+  Result := False;
+  if SeekToPEHeader(F) then begin
+    if (F.Read(Header, SizeOf(Header)) = SizeOf(Header)) and
+       (Header.SizeOfOptionalHeader = SizeOf(OptHeader)) then begin
+      OptHeaderOffset := F.Position;
+      if F.Read(OptHeader, SizeOf(OptHeader)) = SizeOf(OptHeader) then
+        if OptHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC then
+          Result := True;
+    end;
+  end;
+end;
+
+function SeekToAndReadPEOptionalHeader64(const F: TCustomFile;
+  var OptHeader: TImageOptionalHeader64; var OptHeaderOffset: Int64): Boolean;
+var
+  Header: TImageFileHeader;
+begin
+  Result := False;
+  if SeekToPEHeader(F) then begin
+    if (F.Read(Header, SizeOf(Header)) = SizeOf(Header)) and
+       (Header.SizeOfOptionalHeader = SizeOf(OptHeader)) then begin
+      OptHeaderOffset := F.Position;
+      if F.Read(OptHeader, SizeOf(OptHeader)) = SizeOf(OptHeader) then
+        if OptHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC then
+          Result := True;
+    end;
+  end;
+end;
+
+procedure FindResourceSection(const F: TCustomFile;
+  var SectionVirtualAddr, SectionPhysOffset, SectionPhysSize: Cardinal);
+var
+  EXESig: Word;
+  PEHeaderOffset, PESig: Cardinal;
+  PEHeader: TImageFileHeader;
+  PEOptHeader: TImageOptionalHeader;
+  PESectionHeader: TImageSectionHeader;
+  I: Integer;
+begin
+  { Read DOS header }
+  F.Seek(0);
+  F.ReadBuffer(EXESig, SizeOf(EXESig));
+  if EXESig <> $5A4D {'MZ'} then
+    Error('File isn''t an EXE file (1)');
+  F.Seek($3C);
+  F.ReadBuffer(PEHeaderOffset, SizeOf(PEHeaderOffset));
+  if PEHeaderOffset = 0 then
+    Error('File isn''t a PE file (1)');
+
+  { Read PE header & optional header }
+  F.Seek(PEHeaderOffset);
+  F.ReadBuffer(PESig, SizeOf(PESig));
+  if PESig <> $00004550 {'PE'#0#0} then
+    Error('File isn''t a PE file (2)');
+  F.ReadBuffer(PEHeader, SizeOf(PEHeader));
+  if PEHeader.SizeOfOptionalHeader <> SizeOf(PEOptHeader) then
+    Error('File isn''t a PE file (3)');
+  F.ReadBuffer(PEOptHeader, SizeOf(PEOptHeader));
+  if PEOptHeader.Magic <> IMAGE_NT_OPTIONAL_HDR32_MAGIC then
+    Error('File isn''t a PE file (4)');
+
+  { Scan section headers for resource section }
+  if (PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = 0) or
+     (PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = 0) then
+    Error('No resources (1)');
+  SectionVirtualAddr := PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+  SectionPhysOffset := 0;
+  for I := 0 to PEHeader.NumberOfSections-1 do begin
+    F.ReadBuffer(PESectionHeader, SizeOf(PESectionHeader));
+    if (PESectionHeader.VirtualAddress = SectionVirtualAddr) and
+       (PESectionHeader.SizeOfRawData <> 0) then begin
+      SectionPhysOffset := PESectionHeader.PointerToRawData;
+      SectionPhysSize := PESectionHeader.SizeOfRawData;
+      Break;
+    end;
+  end;
+  if SectionPhysOffset = 0 then
+    Error('No resources (2)');
+end;
+
+function FindResOffset(const F: TCustomFile; const AnyId: Boolean;
+  const Id: Cardinal; const FindSubdir: Boolean; var Offset: Cardinal): Boolean;
+var
+  Dir: TImageResourceDirectory;
+  Entry: TImageResourceDirectoryEntry;
+  I: Integer;
+begin
+  F.ReadBuffer(Dir, SizeOf(Dir));
+  { Skip over named entries }
+  for I := 0 to Dir.NumberOfNamedEntries-1 do
+    F.ReadBuffer(Entry, SizeOf(Entry));
+  { Now process ID entries }
+  Result := False;
+  for I := 0 to Dir.NumberOfIdEntries-1 do begin
+    F.ReadBuffer(Entry, SizeOf(Entry));
+    if (AnyId or (Entry.Id = Id)) and
+       ((Entry.Offset and $80000000 <> 0) = FindSubdir) then begin
+      Offset := Entry.Offset and $7FFFFFFF;
+      Result := True;
+      Break;
+    end;
+  end;
+end;
+
+function SeekToResourceData(const F: TCustomFile; const ResType, ResId: Cardinal): Cardinal;
+{ Seeks to the specified resource's data, and returns its size. Raises an
+  exception if the resource cannot be found. }
+var
+  SectionVirtualAddr, SectionPhysOffset, SectionPhysSize, Ofs: Cardinal;
+  DataEntry: TImageResourceDataEntry;
+begin
+  FindResourceSection(F, SectionVirtualAddr, SectionPhysOffset, SectionPhysSize);
+
+  { Scan the resource directory }
+  F.Seek(SectionPhysOffset);
+  if not FindResOffset(F, False, ResType, True, Ofs) then
+    Error('Can''t find resource (1)');
+  F.Seek(SectionPhysOffset + Ofs);
+  if not FindResOffset(F, False, ResId, True, Ofs) then
+    Error('Can''t find resource (2)');
+  F.Seek(SectionPhysOffset + Ofs);
+  if not FindResOffset(F, True, 0, False, Ofs) then
+    Error('Can''t find resource (3).');
+  F.Seek(SectionPhysOffset + Ofs);
+  F.ReadBuffer(DataEntry, SizeOf(DataEntry));
+
+  { Sanity check: DataEntry.OffsetToData is an RVA. It's technically possible
+    for the RVA to point to a different section, but we don't support that. }
+  if Cardinal(DataEntry.OffsetToData) < SectionVirtualAddr then
+    Error('Invalid resource (1)');
+  if Cardinal(DataEntry.OffsetToData - SectionVirtualAddr + DataEntry.Size) > SectionPhysSize then
+    Error('Invalid resource (2)');
+
+  { Seek to the resource }
+  F.Seek(SectionPhysOffset + (DataEntry.OffsetToData - SectionVirtualAddr));
+  Result := DataEntry.Size;
+end;
+
+function ReadSignatureAndChecksumFields(const F: TCustomFile;
+  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+{ Reads the signature and checksum fields in the specified file's header.
+  If the file is not a valid PE32 executable, False is returned. }
+var
+  OptHeader: TImageOptionalHeader;
+  OptHeaderOffset: Int64;
+begin
+  Result := SeekToAndReadPEOptionalHeader(F, OptHeader, OptHeaderOffset);
+  if Result then begin
+    ASignatureAddress := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
+    ASignatureSize := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+    AChecksum := OptHeader.CheckSum;
+  end;
+end;
+
+function ReadSignatureAndChecksumFields64(const F: TCustomFile;
+  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+{ Reads the signature and checksum fields in the specified file's header.
+  If the file is not a valid PE32+ executable, False is returned. }
+var
+  OptHeader: TImageOptionalHeader64;
+  OptHeaderOffset: Int64;
+begin
+  Result := SeekToAndReadPEOptionalHeader64(F, OptHeader, OptHeaderOffset);
+  if Result then begin
+    ASignatureAddress := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
+    ASignatureSize := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+    AChecksum := OptHeader.CheckSum;
+  end;
+end;
+
+function UpdateSignatureAndChecksumFields(const F: TCustomFile;
+  const ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
+{ Sets the signature and checksum fields in the specified file's header.
+  If the file is not a valid PE32 executable, False is returned. }
+var
+  OptHeader: TImageOptionalHeader;
+  OptHeaderOffset: Int64;
+begin
+  Result := SeekToAndReadPEOptionalHeader(F, OptHeader, OptHeaderOffset);
+  if Result then begin
+    OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress := ASignatureAddress;
+    OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size := ASignatureSize;
+    OptHeader.CheckSum := AChecksum;
+    F.Seek(OptHeaderOffset);
+    F.WriteBuffer(OptHeader, SizeOf(OptHeader));
+  end;
+end;
 
 
 procedure UpdateSetupPEHeaderFields(const F: TCustomFile;
 procedure UpdateSetupPEHeaderFields(const F: TCustomFile;
   const IsTSAware, IsDEPCompatible, IsASLRCompatible: Boolean);
   const IsTSAware, IsDEPCompatible, IsASLRCompatible: Boolean);

+ 1 - 1
Projects/Src/Compiler.SetupCompiler.pas

@@ -304,7 +304,7 @@ uses
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
   Commctrl, TypInfo, AnsiStrings, Math, WideStrUtils,
   PathFunc, TrustFunc, ISSigFunc, ECDSA, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
   PathFunc, TrustFunc, ISSigFunc, ECDSA, Shared.CommonFunc, Compiler.Messages, Shared.SetupEntFunc,
   Shared.FileClass, Shared.EncryptionFunc, Compression.Base, Compression.Zlib, Compression.bzlib,
   Shared.FileClass, Shared.EncryptionFunc, Compression.Base, Compression.Zlib, Compression.bzlib,
-  Shared.LangOptionsSectionDirectives, Shared.ResUpdateFunc, Compiler.ExeUpdateFunc,
+  Shared.LangOptionsSectionDirectives, Compiler.ExeUpdateFunc,
 {$IFDEF STATICPREPROC}
 {$IFDEF STATICPREPROC}
   ISPP.Preprocess,
   ISPP.Preprocess,
 {$ENDIF}
 {$ENDIF}

+ 0 - 410
Projects/Src/Shared.ResUpdateFunc.pas

@@ -1,410 +0,0 @@
-unit Shared.ResUpdateFunc;
-
-{
-  Inno Setup
-  Copyright (C) 1997-2025 Jordan Russell
-  Portions by Martijn Laan
-  For conditions of distribution and use, see LICENSE.TXT.
-
-  Resource update functions used by both Setup and the compiler
-}
-
-interface
-
-uses
-  Windows, SysUtils, Shared.FileClass;
-
-function ReadSignatureAndChecksumFields(const F: TCustomFile;
-  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-function ReadSignatureAndChecksumFields64(const F: TCustomFile;
-  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-function SeekToResourceData(const F: TCustomFile; const ResType, ResId: Cardinal): Cardinal;
-function UpdateSignatureAndChecksumFields(const F: TCustomFile;
-  const ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-procedure UpdateManifestRequestedExecutionLevel(const F: TCustomFile;
-  const RequireAdministrator: Boolean);
-
-implementation
-
-const
-  IMAGE_NT_SIGNATURE = $00004550;
-  IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b;
-  IMAGE_NT_OPTIONAL_HDR64_MAGIC = $20b;
-  IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
-  IMAGE_SIZEOF_SHORT_NAME = 8;
-  IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
-  IMAGE_DIRECTORY_ENTRY_SECURITY = 4;
-
-type
-  PImageFileHeader = ^TImageFileHeader;
-  TImageFileHeader = packed record
-    Machine: Word;
-    NumberOfSections: Word;
-    TimeDateStamp: DWORD;
-    PointerToSymbolTable: DWORD;
-    NumberOfSymbols: DWORD;
-    SizeOfOptionalHeader: Word;
-    Characteristics: Word;
-  end;
-  PImageDataDirectory = ^TImageDataDirectory;
-  TImageDataDirectory = record
-    VirtualAddress: DWORD;
-    Size: DWORD;
-  end;
-  PImageOptionalHeader = ^TImageOptionalHeader;
-  TImageOptionalHeader = packed record
-    { Standard fields. }
-    Magic: Word;
-    MajorLinkerVersion: Byte;
-    MinorLinkerVersion: Byte;
-    SizeOfCode: DWORD;
-    SizeOfInitializedData: DWORD;
-    SizeOfUninitializedData: DWORD;
-    AddressOfEntryPoint: DWORD;
-    BaseOfCode: DWORD;
-    BaseOfData: DWORD;
-    { NT additional fields. }
-    ImageBase: DWORD;
-    SectionAlignment: DWORD;
-    FileAlignment: DWORD;
-    MajorOperatingSystemVersion: Word;
-    MinorOperatingSystemVersion: Word;
-    MajorImageVersion: Word;
-    MinorImageVersion: Word;
-    MajorSubsystemVersion: Word;
-    MinorSubsystemVersion: Word;
-    Win32VersionValue: DWORD;
-    SizeOfImage: DWORD;
-    SizeOfHeaders: DWORD;
-    CheckSum: DWORD;
-    Subsystem: Word;
-    DllCharacteristics: Word;
-    SizeOfStackReserve: DWORD;
-    SizeOfStackCommit: DWORD;
-    SizeOfHeapReserve: DWORD;
-    SizeOfHeapCommit: DWORD;
-    LoaderFlags: DWORD;
-    NumberOfRvaAndSizes: DWORD;
-    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
-  end;
-  PImageOptionalHeader64 = ^TImageOptionalHeader64;
-  TImageOptionalHeader64 = packed record
-    { Standard fields. }
-    Magic: Word;
-    MajorLinkerVersion: Byte;
-    MinorLinkerVersion: Byte;
-    SizeOfCode: DWORD;
-    SizeOfInitializedData: DWORD;
-    SizeOfUninitializedData: DWORD;
-    AddressOfEntryPoint: DWORD;
-    BaseOfCode: DWORD;
-    { NT additional fields. }
-    ImageBase: Int64;
-    SectionAlignment: DWORD;
-    FileAlignment: DWORD;
-    MajorOperatingSystemVersion: Word;
-    MinorOperatingSystemVersion: Word;
-    MajorImageVersion: Word;
-    MinorImageVersion: Word;
-    MajorSubsystemVersion: Word;
-    MinorSubsystemVersion: Word;
-    Win32VersionValue: DWORD;
-    SizeOfImage: DWORD;
-    SizeOfHeaders: DWORD;
-    CheckSum: DWORD;
-    Subsystem: Word;
-    DllCharacteristics: Word;
-    SizeOfStackReserve: Int64;
-    SizeOfStackCommit: Int64;
-    SizeOfHeapReserve: Int64;
-    SizeOfHeapCommit: Int64;
-    LoaderFlags: DWORD;
-    NumberOfRvaAndSizes: DWORD;
-    DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory;
-  end;
-  TISHMisc = packed record
-    case Integer of
-      0: (PhysicalAddress: DWORD);
-      1: (VirtualSize: DWORD);
-  end;
-  PImageSectionHeader = ^TImageSectionHeader;
-  TImageSectionHeader = packed record
-    Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;
-    Misc: TISHMisc;
-    VirtualAddress: DWORD;
-    SizeOfRawData: DWORD;
-    PointerToRawData: DWORD;
-    PointerToRelocations: DWORD;
-    PointerToLinenumbers: DWORD;
-    NumberOfRelocations: Word;
-    NumberOfLinenumbers: Word;
-    Characteristics: DWORD;
-  end;
-  TImageResourceDirectory = packed record
-    Characteristics: DWORD;
-    TimeDateStamp: DWORD;
-    MajorVersion: Word;
-    MinorVersion: Word;
-    NumberOfNamedEntries: Word;
-    NumberOfIdEntries: Word;
-  end;
-  TImageResourceDirectoryEntry = packed record
-    Id: DWORD;
-    Offset: DWORD;
-  end;
-  TImageResourceDataEntry = packed record
-    OffsetToData: DWORD;
-    Size: DWORD;
-    CodePage: DWORD;
-    Reserved: DWORD;
-  end;
-
-procedure Error(const Msg: String);
-begin
-  raise Exception.Create('Resource update error: ' + Msg);
-end;
-
-function SeekToPEHeader(const F: TCustomFile): Boolean;
-var
-  DosHeader: packed record
-    Sig: array[0..1] of AnsiChar;
-    Other: array[0..57] of Byte;
-    PEHeaderOffset: LongWord;
-  end;
-  Sig: DWORD;
-begin
-  Result := False;
-  F.Seek(0);
-  if F.Read(DosHeader, SizeOf(DosHeader)) = SizeOf(DosHeader) then begin
-    if (DosHeader.Sig[0] = 'M') and (DosHeader.Sig[1] = 'Z') and
-       (DosHeader.PEHeaderOffset <> 0) then begin
-      F.Seek(DosHeader.PEHeaderOffset);
-      if F.Read(Sig, SizeOf(Sig)) = SizeOf(Sig) then
-        if Sig = IMAGE_NT_SIGNATURE then
-          Result := True;
-    end;
-  end;
-end;
-
-function SeekToAndReadPEOptionalHeader(const F: TCustomFile;
-  var OptHeader: TImageOptionalHeader; var OptHeaderOffset: Int64): Boolean;
-var
-  Header: TImageFileHeader;
-begin
-  Result := False;
-  if SeekToPEHeader(F) then begin
-    if (F.Read(Header, SizeOf(Header)) = SizeOf(Header)) and
-       (Header.SizeOfOptionalHeader = SizeOf(OptHeader)) then begin
-      OptHeaderOffset := F.Position;
-      if F.Read(OptHeader, SizeOf(OptHeader)) = SizeOf(OptHeader) then
-        if OptHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC then
-          Result := True;
-    end;
-  end;
-end;
-
-function SeekToAndReadPEOptionalHeader64(const F: TCustomFile;
-  var OptHeader: TImageOptionalHeader64; var OptHeaderOffset: Int64): Boolean;
-var
-  Header: TImageFileHeader;
-begin
-  Result := False;
-  if SeekToPEHeader(F) then begin
-    if (F.Read(Header, SizeOf(Header)) = SizeOf(Header)) and
-       (Header.SizeOfOptionalHeader = SizeOf(OptHeader)) then begin
-      OptHeaderOffset := F.Position;
-      if F.Read(OptHeader, SizeOf(OptHeader)) = SizeOf(OptHeader) then
-        if OptHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC then
-          Result := True;
-    end;
-  end;
-end;
-
-procedure FindResourceSection(const F: TCustomFile;
-  var SectionVirtualAddr, SectionPhysOffset, SectionPhysSize: Cardinal);
-var
-  EXESig: Word;
-  PEHeaderOffset, PESig: Cardinal;
-  PEHeader: TImageFileHeader;
-  PEOptHeader: TImageOptionalHeader;
-  PESectionHeader: TImageSectionHeader;
-  I: Integer;
-begin
-  { Read DOS header }
-  F.Seek(0);
-  F.ReadBuffer(EXESig, SizeOf(EXESig));
-  if EXESig <> $5A4D {'MZ'} then
-    Error('File isn''t an EXE file (1)');
-  F.Seek($3C);
-  F.ReadBuffer(PEHeaderOffset, SizeOf(PEHeaderOffset));
-  if PEHeaderOffset = 0 then
-    Error('File isn''t a PE file (1)');
-
-  { Read PE header & optional header }
-  F.Seek(PEHeaderOffset);
-  F.ReadBuffer(PESig, SizeOf(PESig));
-  if PESig <> $00004550 {'PE'#0#0} then
-    Error('File isn''t a PE file (2)');
-  F.ReadBuffer(PEHeader, SizeOf(PEHeader));
-  if PEHeader.SizeOfOptionalHeader <> SizeOf(PEOptHeader) then
-    Error('File isn''t a PE file (3)');
-  F.ReadBuffer(PEOptHeader, SizeOf(PEOptHeader));
-  if PEOptHeader.Magic <> IMAGE_NT_OPTIONAL_HDR32_MAGIC then
-    Error('File isn''t a PE file (4)');
-
-  { Scan section headers for resource section }
-  if (PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = 0) or
-     (PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = 0) then
-    Error('No resources (1)');
-  SectionVirtualAddr := PEOptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
-  SectionPhysOffset := 0;
-  for I := 0 to PEHeader.NumberOfSections-1 do begin
-    F.ReadBuffer(PESectionHeader, SizeOf(PESectionHeader));
-    if (PESectionHeader.VirtualAddress = SectionVirtualAddr) and
-       (PESectionHeader.SizeOfRawData <> 0) then begin
-      SectionPhysOffset := PESectionHeader.PointerToRawData;
-      SectionPhysSize := PESectionHeader.SizeOfRawData;
-      Break;
-    end;
-  end;
-  if SectionPhysOffset = 0 then
-    Error('No resources (2)');
-end;
-
-function FindResOffset(const F: TCustomFile; const AnyId: Boolean;
-  const Id: Cardinal; const FindSubdir: Boolean; var Offset: Cardinal): Boolean;
-var
-  Dir: TImageResourceDirectory;
-  Entry: TImageResourceDirectoryEntry;
-  I: Integer;
-begin
-  F.ReadBuffer(Dir, SizeOf(Dir));
-  { Skip over named entries }
-  for I := 0 to Dir.NumberOfNamedEntries-1 do
-    F.ReadBuffer(Entry, SizeOf(Entry));
-  { Now process ID entries }
-  Result := False;
-  for I := 0 to Dir.NumberOfIdEntries-1 do begin
-    F.ReadBuffer(Entry, SizeOf(Entry));
-    if (AnyId or (Entry.Id = Id)) and
-       ((Entry.Offset and $80000000 <> 0) = FindSubdir) then begin
-      Offset := Entry.Offset and $7FFFFFFF;
-      Result := True;
-      Break;
-    end;
-  end;
-end;
-
-function SeekToResourceData(const F: TCustomFile; const ResType, ResId: Cardinal): Cardinal;
-{ Seeks to the specified resource's data, and returns its size. Raises an
-  exception if the resource cannot be found. }
-var
-  SectionVirtualAddr, SectionPhysOffset, SectionPhysSize, Ofs: Cardinal;
-  DataEntry: TImageResourceDataEntry;
-begin
-  FindResourceSection(F, SectionVirtualAddr, SectionPhysOffset, SectionPhysSize);
-
-  { Scan the resource directory }
-  F.Seek(SectionPhysOffset);
-  if not FindResOffset(F, False, ResType, True, Ofs) then
-    Error('Can''t find resource (1)');
-  F.Seek(SectionPhysOffset + Ofs);
-  if not FindResOffset(F, False, ResId, True, Ofs) then
-    Error('Can''t find resource (2)');
-  F.Seek(SectionPhysOffset + Ofs);
-  if not FindResOffset(F, True, 0, False, Ofs) then
-    Error('Can''t find resource (3).');
-  F.Seek(SectionPhysOffset + Ofs);
-  F.ReadBuffer(DataEntry, SizeOf(DataEntry));
-
-  { Sanity check: DataEntry.OffsetToData is an RVA. It's technically possible
-    for the RVA to point to a different section, but we don't support that. }
-  if Cardinal(DataEntry.OffsetToData) < SectionVirtualAddr then
-    Error('Invalid resource (1)');
-  if Cardinal(DataEntry.OffsetToData - SectionVirtualAddr + DataEntry.Size) > SectionPhysSize then
-    Error('Invalid resource (2)');
-
-  { Seek to the resource }
-  F.Seek(SectionPhysOffset + (DataEntry.OffsetToData - SectionVirtualAddr));
-  Result := DataEntry.Size;
-end;
-
-procedure UpdateManifestRequestedExecutionLevel(const F: TCustomFile;
-  const RequireAdministrator: Boolean);
-const
-  ElementText: AnsiString = '<requestedExecutionLevel level="';
-  Levels: array[Boolean] of AnsiString = (
-    'highestAvailable"    ',
-    'requireAdministrator"');
-var
-  S: AnsiString;
-  P: Integer;
-begin
-  { Read the manifest resource into a string }
-  SetString(S, nil, SeekToResourceData(F, 24, 1));
-  var Offset := F.Position;
-  F.ReadBuffer(S[1], Length(S));
-
-  { Locate and update the requestedExecutionLevel element }
-  P := Pos(ElementText, S);
-  if P = 0 then
-    Error('Element not found');
-  Inc(P, Length(ElementText));
-  if Copy(S, P+21, 10) <> ' uiAccess=' then
-    Error('Level too short');
-  Inc(Offset, P-1);
-  F.Seek(Offset);
-  F.WriteAnsiString(Levels[RequireAdministrator]);
-end;
-
-function ReadSignatureAndChecksumFields(const F: TCustomFile;
-  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-{ Reads the signature and checksum fields in the specified file's header.
-  If the file is not a valid PE32 executable, False is returned. }
-var
-  OptHeader: TImageOptionalHeader;
-  OptHeaderOffset: Int64;
-begin
-  Result := SeekToAndReadPEOptionalHeader(F, OptHeader, OptHeaderOffset);
-  if Result then begin
-    ASignatureAddress := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
-    ASignatureSize := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
-    AChecksum := OptHeader.CheckSum;
-  end;
-end;
-
-function ReadSignatureAndChecksumFields64(const F: TCustomFile;
-  var ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-{ Reads the signature and checksum fields in the specified file's header.
-  If the file is not a valid PE32+ executable, False is returned. }
-var
-  OptHeader: TImageOptionalHeader64;
-  OptHeaderOffset: Int64;
-begin
-  Result := SeekToAndReadPEOptionalHeader64(F, OptHeader, OptHeaderOffset);
-  if Result then begin
-    ASignatureAddress := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
-    ASignatureSize := OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
-    AChecksum := OptHeader.CheckSum;
-  end;
-end;
-
-function UpdateSignatureAndChecksumFields(const F: TCustomFile;
-  const ASignatureAddress, ASignatureSize, AChecksum: DWORD): Boolean;
-{ Sets the signature and checksum fields in the specified file's header.
-  If the file is not a valid PE32 executable, False is returned. }
-var
-  OptHeader: TImageOptionalHeader;
-  OptHeaderOffset: Int64;
-begin
-  Result := SeekToAndReadPEOptionalHeader(F, OptHeader, OptHeaderOffset);
-  if Result then begin
-    OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress := ASignatureAddress;
-    OptHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size := ASignatureSize;
-    OptHeader.CheckSum := AChecksum;
-    F.Seek(OptHeaderOffset);
-    F.WriteBuffer(OptHeader, SizeOf(OptHeader));
-  end;
-end;
-
-end.