extract names from sections

This commit is contained in:
Trammell hudson 2018-01-26 13:51:17 -05:00
parent d07129b7f7
commit e8c0acaff7
Failed to extract signature
2 changed files with 113 additions and 64 deletions

View File

@ -12,9 +12,11 @@ use lib "$FindBin::Bin/../lib";
use EFI;
use Getopt::Long;
use File::Basename;
use Data::Dumper;
my $start_offset = 0; # 0x02c00000;
my $verbose = 0;
local $/;
while(<>)
@ -95,6 +97,12 @@ sub process_fv
$guid,
;
if ($guid ne '8c8ce578-8a3d-4f1c-9935-896185c32dd3')
{
# we can only process normal firmware volumes
return;
}
while($offset < $fv_length - 0x20)
{
my $len = EFI::read24($fv, $offset + 0x14);
@ -109,7 +117,7 @@ sub process_fv
# the start of free space
return 1 if ~$len == 0;
# Looks good, adjust the starting offset
## Looks good, adjust the starting offset
$data_offset += 0x8;
}
@ -133,7 +141,7 @@ sub process_fv
my $data = substr($fv, $offset, $len);
process_ffs($base, $data);
process_ffs($base, $data, $data_offset);
$offset += $len;
@ -149,6 +157,7 @@ sub process_ffs
{
my $base = shift;
my $ffs = shift;
my $data_offset = shift; # might be 0x18 or 0x20
my $len = length($ffs);
my $guid = EFI::read_guid($ffs, 0x00);
@ -160,15 +169,85 @@ sub process_ffs
return;
}
warn sprintf "%s/%s: len %x\n",
$base,
$guid,
$len,
;
output("$base/$guid.ffs", $ffs);
# TODO: recursively expand embedded, compressed fv
my @sections = ffs_sections("$base/$guid", $ffs, $data_offset);
# if this file has a UI section, extract its name
my $name = '';
for my $sec (@sections)
{
next unless $sec->[0] eq 'USER_INTERFACE';
#$name = Dumper($sec->[1]); # EFI::read_ucs16($sec->[1], 2);
$name = EFI::read_ucs16($sec->[1], 0);
}
warn sprintf "%s/%s: %s\n", $base, $guid, $name;
# if ($guid eq '8c8ce578-8a3d-4f1c-9935-896185c32dd3')
# {
# # recursively expand embedded, compressed fv
# process_ffs_fv($base, $ffs, $data_offset);
# } else {
# # todo: Look for a UI section to produce a nice table
# }
}
sub ffs_sections
{
my $base = shift;
my $ffs = shift;
my $offset = shift;
my $ffs_len = length($ffs);
my @sections;
# find each section inside
while($offset < $ffs_len - 8)
{
my $len = EFI::read24($ffs, $offset);
my $data_offset = 0x4;
if ($len == 0xFFFFFF)
{
# FFSv3 section
$len = EFI::read32($ffs, $offset + $data_offset);
$data_offset += 4;
}
if ($len < $data_offset)
{
die sprintf "%s: 0x%x Section length %x invalid\n", $base, $offset, $len;
}
if ($offset + $len > $ffs_len)
{
die sprintf "%s: Section length %x exceeds FFS len %x\n",
$base,
$len,
$ffs_len,
;
}
my $sec = substr($ffs, $offset, $len);
# move to the next section, keeping a 4-byte alignment
$offset = ($offset + $len + 3) & ~3;
my $sec_type = ord(substr($sec, 3, 1));
my $sec_data = substr($sec, $data_offset, $len - $data_offset);
my $sec_type_name = $EFI::section_types_lookup{$sec_type};
$sec_type_name ||= sprintf "0x%02x", $sec_type;
warn sprintf "%s: %s len %x\n", $base, $sec_type_name, $len
if $verbose;
push @sections, [ $sec_type_name, $sec_data ];
}
return @sections;
}
@ -185,58 +264,3 @@ sub output
print FILE $data;
close FILE;
}
__END__
sub read16
{
my $data = shift;
my $offset = shift;
return unpack("v", substr($data, $offset, 2));
}
sub read24
{
my $data = shift;
my $offset = shift;
return 0
| ord(substr($data, $offset+2, 1)) << 16
| ord(substr($data, $offset+1, 1)) << 8
| ord(substr($data, $offset+0, 1)) << 0
;
}
sub read32
{
my $data = shift;
my $offset = shift;
return unpack("V", substr($data, $offset, 4));
}
sub read64
{
my $data = shift;
my $offset = shift;
return read32($data, $offset+4) << 32 | read32($data, $offset+0);
}
sub read_guid
{
my $data = shift;
my $offset = shift;
my ($g1,$g2,$g3,$g4,@g5) = unpack("VvvnCCCCCC", substr($data, $offset, 16));
return sprintf "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
$g1,
$g2,
$g3,
$g4,
$g5[0],
$g5[1],
$g5[2],
$g5[3],
$g5[4],
$g5[5],
;
}

View File

@ -66,6 +66,7 @@ our %file_types = qw/
FFS_PAD 0xf0
/;
our %section_types = qw/
GUID_DEFINED 0x02
PE32 0x10
@ -82,6 +83,7 @@ our %section_types = qw/
SMM_DEPEX 0x1C
/;
# Some special cases for non-PE32 sections
our %section_type_map = qw/
FREEFORM RAW
@ -95,6 +97,9 @@ our %depex_type_map = qw/
SMM SMM_DEPEX
/;
# Invert the file type and section type maps
our %file_types_lookup = map { hex $file_types{$_} => $_ } keys %file_types;
our %section_types_lookup = map { hex $section_types{$_} => $_ } keys %section_types;
# convert text GUID to hex
sub guid
@ -142,6 +147,26 @@ sub ucs16
return $rc;
}
# Convert from UCS-16 back to a normal string
sub read_ucs16
{
my $val = shift;
my $offset = shift;
my $len = length($val);
my $rc = '';
while($offset < $len-1)
{
my $word = unpack("n", substr($val, $offset, 2));
last if $word == 0x0000;
$rc .= chr(($word >> 8) & 0xFF);
$offset += 2;
}
return $rc;
}
# output an EFI Common Section Header
# Since we might be dealing with ones larger than 16 MB, we should use extended