123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- unit Shared.ResUpdateFunc;
- {
- Inno Setup
- Copyright (C) 1997-2016 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
- uses
- Shared.Int64Em;
- 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: Integer64;
- 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: Integer64;
- SizeOfStackCommit: Integer64;
- SizeOfHeapReserve: Integer64;
- SizeOfHeapCommit: Integer64;
- 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: Integer64): 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: Integer64): 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;
- Offset: Integer64;
- P: Integer;
- begin
- { Read the manifest resource into a string }
- SetString(S, nil, SeekToResourceData(F, 24, 1));
- 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');
- Inc64(Offset, P-1);
- F.Seek64(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: Integer64;
- 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: Integer64;
- 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: Integer64;
- 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.Seek64(OptHeaderOffset);
- F.WriteBuffer(OptHeader, SizeOf(OptHeader));
- end;
- end;
- end.
|