File set-linker-version.pl of Package shim.3181
#!/usr/bin/perl
use strict;
use warnings;
use FileHandle;
sub read_file($)
{
my ($file) = @_;
my $contents;
my $len;
open(FD, "<$file") || die $file;
binmode FD;
my @st = stat(FD);
die $file if (!@st);
$len = read(FD, $contents, $st[7]) || die $file;
close(FD) || die $file;
die "$file: Wanted length ", $st[7], ", got ", $len, "\n"
if ($len != $st[7]);
return $contents;
}
sub write_file($)
{
my ($file, $contents) = @_;
open(FD, ">$file") || die $file;
binmode FD;
print FD $contents;
close(FD) || die $file;
}
if ($#ARGV != 2) {
print "Usage: set-linker-version.pl <efi file> <minor linker version> <checksum hex>\n";
print " try \"objdump -p <efi file>\" to get the information\n";
exit;
}
my $input = $ARGV[0];
my $minor_linker_version = $ARGV[1];
my $checksum = hex($ARGV[2]);
my $packed;
my $pe_image = read_file($input);
# Match e_magic. it must be 'M''Z'
my($e_magic) = unpack("v", substr($pe_image, 0, 2));
die "not a EFI Image\n" unless ($e_magic == 0x5A4D);
my($e_lfanew) = unpack("V", substr($pe_image, 60, 4));
# Match Signature 'P''E''\0''\0'
my($Signature) = unpack("V", substr($pe_image, $e_lfanew, 4));
die "not a PE Image\n" unless ($Signature == 0x4550);
# Check the pe header magic
my($pe_magic) = unpack("v", substr($pe_image, $e_lfanew+24, 2));
die "Not a PE32+ image\n" unless ($pe_magic == 0x20b);
# The offset of the optional header: $e_lfanew + 24
my $opthdr_offset = $e_lfanew + 24;
# Optional Header Standard Fields for PE32+
# Standard fields
# UINT16 Magic;
# UINT8 MajorLinkerVersion;
# UINT8 MinorLinkerVersion;
# UINT32 SizeOfCode;
# UINT32 SizeOfInitializedData;
# UINT32 SizeOfUninitializedData;
# UINT32 AddressOfEntryPoint;
# UINT32 BaseOfCode;
# UINT64 ImageBase;
# UINT32 SectionAlignment;
# UINT32 FileAlignment;
# UINT16 MajorOperatingSystemVersion;
# UINT16 MinorOperatingSystemVersion;
# UINT16 MajorImageVersion;
# UINT16 MinorImageVersion;
# UINT16 MajorSubsystemVersion;
# UINT16 MinorSubsystemVersion;
# UINT32 Win32VersionValue;
# UINT32 SizeOfImage;
# UINT32 SizeOfHeaders;
# UINT32 CheckSum;
# UINT16 Subsystem;
# UINT16 DllCharacteristics;
# UINT64 SizeOfStackReserve;
# UINT64 SizeOfStackCommit;
# UINT64 SizeOfHeapReserve;
# UINT64 SizeOfHeapCommit;
# UINT32 LoaderFlags;
# UINT32 NumberOfRvaAndSizes;
# The offset fo MinorLinkerVersion: $opthdr_offset + 2 + 1
$packed = pack("C", $minor_linker_version);
substr($pe_image, $opthdr_offset + 3, 1, $packed);
# The offset of CheckSum: $opthdr_offset + 2 + 1*2 + 4*5 + 8 + 4*2 + 2*6 + 4*3
$packed = pack("V", $checksum);
substr($pe_image, $opthdr_offset + 64, 4, $packed);
&write_file($input, $pe_image);