mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
PFS support and parsing fixes. (#196)
This commit is contained in:
+46
-29
@@ -253,40 +253,46 @@ def build_efi_modules_tree( _uefi, fwtype, data, Size, offset, polarity ):
|
||||
|
||||
_off, next_offset, _name, _type, _img, _hdrsz = NextFwFileSection( data, Size, offset, polarity )
|
||||
while next_offset is not None:
|
||||
sec = EFI_SECTION( _off, _name, _type, _img, _hdrsz )
|
||||
# pick random file name in case dumpall=False - we'll need it to decompress the section
|
||||
sec_fs_name = "sect%02d_%s" % (secn, ''.join(random.choice(string.ascii_lowercase) for _ in range(4)))
|
||||
if _name is not None:
|
||||
sec = EFI_SECTION( _off, _name, _type, _img, _hdrsz )
|
||||
# pick random file name in case dumpall=False - we'll need it to decompress the section
|
||||
sec_fs_name = "sect%02d_%s" % (secn, ''.join(random.choice(string.ascii_lowercase) for _ in range(4)))
|
||||
|
||||
if sec.Type in EFI_SECTIONS_EXE:
|
||||
# "leaf" executable section: update hashes and check against match criteria
|
||||
sec.calc_hashes( sec.HeaderSize )
|
||||
elif sec.Type == EFI_SECTION_USER_INTERFACE:
|
||||
# "leaf" UI section: update section's UI name
|
||||
sec.ui_string = unicode(sec.Image[sec.HeaderSize:], "utf-16-le", errors="ignore")[:-1]
|
||||
elif sec.Type == EFI_SECTION_GUID_DEFINED:
|
||||
guid0, guid1, guid2, guid3, sec.DataOffset, sec.Attributes = struct.unpack(EFI_GUID_DEFINED_SECTION, sec.Image[sec.HeaderSize:sec.HeaderSize+EFI_GUID_DEFINED_SECTION_size])
|
||||
sec.Guid = guid_str(guid0, guid1, guid2, guid3)
|
||||
|
||||
# "container" sections: keep parsing
|
||||
if sec.Type in (EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW):
|
||||
if sec.Type == EFI_SECTION_COMPRESSION:
|
||||
ul, ct = struct.unpack(EFI_COMPRESSION_SECTION, sec.Image[sec.HeaderSize:sec.HeaderSize+EFI_COMPRESSION_SECTION_size])
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.HeaderSize+EFI_COMPRESSION_SECTION_size:], ct, True )
|
||||
if d:
|
||||
sec.children = build_efi_modules_tree( _uefi, fwtype, d, len(d), 0, polarity )
|
||||
if sec.Type in EFI_SECTIONS_EXE:
|
||||
# "leaf" executable section: update hashes and check against match criteria
|
||||
sec.calc_hashes( sec.HeaderSize )
|
||||
elif sec.Type == EFI_SECTION_USER_INTERFACE:
|
||||
# "leaf" UI section: update section's UI name
|
||||
sec.ui_string = unicode(sec.Image[sec.HeaderSize:], "utf-16-le", errors="ignore")[:-1]
|
||||
elif sec.Type == EFI_SECTION_GUID_DEFINED:
|
||||
if sec.Guid == EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID:
|
||||
sec.children = build_efi_modules_tree( _uefi, fwtype, sec.Image[sec.DataOffset:], Size - sec.DataOffset, 0, polarity )
|
||||
elif sec.Guid == LZMA_CUSTOM_DECOMPRESS_GUID or sec.Guid == TIANO_DECOMPRESSED_GUID:
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.DataOffset:], 2, True )
|
||||
guid0, guid1, guid2, guid3, sec.DataOffset, sec.Attributes = struct.unpack(EFI_GUID_DEFINED_SECTION, sec.Image[sec.HeaderSize:sec.HeaderSize+EFI_GUID_DEFINED_SECTION_size])
|
||||
sec.Guid = guid_str(guid0, guid1, guid2, guid3)
|
||||
|
||||
# "container" sections: keep parsing
|
||||
if sec.Type in (EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW):
|
||||
if sec.Type == EFI_SECTION_COMPRESSION:
|
||||
ul, ct = struct.unpack(EFI_COMPRESSION_SECTION, sec.Image[sec.HeaderSize:sec.HeaderSize+EFI_COMPRESSION_SECTION_size])
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.HeaderSize+EFI_COMPRESSION_SECTION_size:], ct, True )
|
||||
if (d is None) and (ct == 2) and (len(sec.Image[sec.HeaderSize+EFI_COMPRESSION_SECTION_size:]) > 4):
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.HeaderSize+EFI_COMPRESSION_SECTION_size + 4:], ct, True )
|
||||
if d:
|
||||
sec.children = build_efi_modules_tree( _uefi, fwtype, d, len(d), 0, polarity )
|
||||
elif sec.Guid == FIRMWARE_VOLUME_GUID or sec.Guid == VOLUME_SECTION_GUID:
|
||||
elif sec.Type == EFI_SECTION_GUID_DEFINED:
|
||||
if sec.Guid == EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID:
|
||||
sec.children = build_efi_modules_tree( _uefi, fwtype, sec.Image[sec.DataOffset:], Size - sec.DataOffset, 0, polarity )
|
||||
elif sec.Guid == LZMA_CUSTOM_DECOMPRESS_GUID or sec.Guid == TIANO_DECOMPRESSED_GUID:
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.DataOffset:], 2, True )
|
||||
if d is None:
|
||||
d = decompress_section_data( _uefi, "", sec_fs_name, sec.Image[sec.HeaderSize+EFI_GUID_DEFINED_SECTION_size:], 2, True )
|
||||
if d:
|
||||
sec.children = build_efi_modules_tree( _uefi, fwtype, d, len(d), 0, polarity )
|
||||
#elif sec.Guid == FIRMWARE_VOLUME_GUID:
|
||||
else:
|
||||
sec.children = build_efi_model( _uefi, sec.Image[sec.HeaderSize:], fwtype )
|
||||
elif sec.Type in (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW):
|
||||
sec.children = build_efi_model( _uefi, sec.Image[sec.HeaderSize:], fwtype )
|
||||
elif sec.Type in (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW):
|
||||
sec.children = build_efi_model( _uefi, sec.Image[sec.HeaderSize:], fwtype )
|
||||
|
||||
sections.append(sec)
|
||||
sections.append(sec)
|
||||
_off, next_offset, _name, _type, _img, _hdrsz = NextFwFileSection( data, Size, next_offset, polarity )
|
||||
secn += 1
|
||||
return sections
|
||||
@@ -368,7 +374,18 @@ def update_efi_tree(modules, parent_guid=None):
|
||||
return ui_string
|
||||
|
||||
def build_efi_model( _uefi, data, fwtype ):
|
||||
model = build_efi_tree( _uefi, data, fwtype )
|
||||
# Try PFS first
|
||||
result = ParsePFS(data)
|
||||
if result is not None:
|
||||
model = []
|
||||
for d in result[0]:
|
||||
m = build_efi_tree( _uefi, d, fwtype )
|
||||
model.extend(m)
|
||||
if len(result[1]) > 0:
|
||||
m = build_efi_tree( _uefi, result[1], fwtype )
|
||||
model.extend(m)
|
||||
else:
|
||||
model = build_efi_tree( _uefi, data, fwtype )
|
||||
update_efi_tree(model)
|
||||
return model
|
||||
|
||||
|
||||
@@ -632,7 +632,7 @@ def NextFwFile(FvImage, FvLength, fof, polarity):
|
||||
next_offset = None
|
||||
res = None
|
||||
update_or_deleted = False
|
||||
if (fof + file_header_size) <= FvLength:
|
||||
if (fof + file_header_size) <= min(FvLength, len(FvImage)):
|
||||
if ('\xff\xff\xff\xff' == FvImage[fof+file_header_size-4:fof+file_header_size]):
|
||||
next_offset = fof + 8
|
||||
return (cur_offset, next_offset, None, None, None, None, None, None, None, None, update_or_deleted, None)
|
||||
|
||||
@@ -41,6 +41,83 @@ from collections import namedtuple
|
||||
from chipsec import defines
|
||||
from chipsec.hal.uefi_common import *
|
||||
|
||||
#################################################################################################
|
||||
# Dell PFS support,
|
||||
# relied heavily on uefi-firmware-parser (https://github.com/theopolis/uefi-firmware-parser)
|
||||
#################################################################################################
|
||||
|
||||
PFS_SEC_HDR = "<16sIIIIIIIIII16s"
|
||||
PFS_SEC_HDR_SIZE = struct.calcsize(PFS_SEC_HDR)
|
||||
U1_GUID = '\xf6\xe2\xb3YBN\xf3A\xb1\xf4Dj\x84\xbf\xc6\xd0'
|
||||
|
||||
class PfsFileSection:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.valid = (len(data) >= PFS_SEC_HDR_SIZE)
|
||||
data_offset = 0
|
||||
if (self.valid):
|
||||
gu1, u1, u2, u3, u4, u5, u6, sec_size, size1, size2, size3, gu2 = struct.unpack(PFS_SEC_HDR, data[:PFS_SEC_HDR_SIZE])
|
||||
self.valid = (len(data) >= (PFS_SEC_HDR_SIZE+sec_size+size1+size2+size3))
|
||||
if gu1 == U1_GUID: data_offset = 0x248
|
||||
if (self.valid):
|
||||
self.body = data[PFS_SEC_HDR_SIZE+data_offset:PFS_SEC_HDR_SIZE+sec_size]
|
||||
self.tail = data[PFS_SEC_HDR_SIZE+sec_size+size1+size2+size3:]
|
||||
|
||||
def parse(self):
|
||||
return self.body
|
||||
|
||||
PFS_HDR_SIG = "PFS.HDR."
|
||||
PFS_FTR_SIG = "PFS.FTR."
|
||||
PFS_HDR_STRUC = "<8sII"
|
||||
PFS_HDR_STRUC_SIZE = struct.calcsize(PFS_HDR_STRUC)
|
||||
PFS_FTR_STRUC = "<II8s"
|
||||
PFS_FTR_STRUC_SIZE = struct.calcsize(PFS_FTR_STRUC)
|
||||
|
||||
class PfsFile:
|
||||
|
||||
def __init__(self, data, concat = False):
|
||||
self.data = data
|
||||
self.concat = concat
|
||||
self.valid = (len(data) >= (PFS_HDR_STRUC_SIZE + PFS_FTR_STRUC_SIZE))
|
||||
self.size = 0
|
||||
hdr_sig = ""
|
||||
ver = 0
|
||||
if (self.valid):
|
||||
hdr_sig, ver, self.size = struct.unpack(PFS_HDR_STRUC, data[:PFS_HDR_STRUC_SIZE])
|
||||
self.valid = (PFS_FTR_STRUC_SIZE <= len(data[PFS_HDR_STRUC_SIZE+self.size:]))
|
||||
if (self.valid):
|
||||
ftr_size, u, ftr_sig = struct.unpack(PFS_FTR_STRUC, data[PFS_HDR_STRUC_SIZE+self.size:PFS_HDR_STRUC_SIZE+self.size+PFS_FTR_STRUC_SIZE])
|
||||
self.valid = (hdr_sig == PFS_HDR_SIG) and (ftr_sig == PFS_FTR_SIG) and (self.size == ftr_size) and ((self.size + PFS_HDR_STRUC_SIZE + PFS_FTR_STRUC_SIZE) <= len(data))
|
||||
if (self.valid):
|
||||
self.body = data[PFS_HDR_STRUC_SIZE:PFS_HDR_STRUC_SIZE + self.size + PFS_FTR_STRUC_SIZE]
|
||||
self.tail = data[PFS_HDR_STRUC_SIZE + self.size + PFS_FTR_STRUC_SIZE:]
|
||||
|
||||
def parse(self):
|
||||
pfs_sec = PfsFileSection(self.body)
|
||||
pfs_sec_data = []
|
||||
while pfs_sec.valid:
|
||||
sec_data = pfs_sec.parse()
|
||||
if sec_data[:len(PFS_HDR_SIG)] == PFS_HDR_SIG:
|
||||
sec_data = PfsFile(sec_data, True).parse()
|
||||
if sec_data is not None:
|
||||
pfs_sec_data.append(sec_data)
|
||||
pfs_sec = PfsFileSection(pfs_sec.tail)
|
||||
if self.concat:
|
||||
return ''.join(pfs_sec_data)
|
||||
else:
|
||||
return pfs_sec_data
|
||||
|
||||
def ParsePFS(data):
|
||||
pfs_file = PfsFile(data, True)
|
||||
if not pfs_file.valid:
|
||||
return None
|
||||
pfs_file_data = []
|
||||
while pfs_file.valid:
|
||||
pfs_data = pfs_file.parse()
|
||||
if pfs_data is not None:
|
||||
pfs_file_data.append(pfs_data)
|
||||
pfs_file = PfsFile(pfs_file.tail)
|
||||
return (pfs_file_data, pfs_file.data)
|
||||
|
||||
#################################################################################################3
|
||||
# List of supported types of EFI NVRAM format (platform/vendor specific)
|
||||
|
||||
Reference in New Issue
Block a user