mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
d924645ea1
Signed-off-by: Evgeny Zinoviev <me@ch1p.io>
1337 lines
57 KiB
Python
1337 lines
57 KiB
Python
#!/usr/bin/python
|
|
#CHIPSEC: Platform Security Assessment Framework
|
|
#Copyright (c) 2010-2019, Intel Corporation
|
|
#
|
|
#This program is free software; you can redistribute it and/or
|
|
#modify it under the terms of the GNU General Public License
|
|
#as published by the Free Software Foundation; Version 2.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU General Public License
|
|
#along with this program; if not, write to the Free Software
|
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
#Contact information:
|
|
#chipsec@intel.com
|
|
#
|
|
|
|
|
|
|
|
# -------------------------------------------------------------------------------
|
|
#
|
|
# CHIPSEC: Platform Hardware Security Assessment Framework
|
|
# (c) 2010-2019 Intel Corporation
|
|
#
|
|
# -------------------------------------------------------------------------------
|
|
|
|
"""
|
|
Platform specific UEFI functionality (parsing platform specific EFI NVRAM, capsules, etc.)
|
|
"""
|
|
|
|
import struct
|
|
import string
|
|
from collections import namedtuple
|
|
from uuid import UUID
|
|
|
|
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)
|
|
#################################################################################################3
|
|
|
|
class FWType:
|
|
EFI_FW_TYPE_UEFI = 'uefi'
|
|
EFI_FW_TYPE_UEFI_AUTH = 'uefi_auth'
|
|
# EFI_FW_TYPE_WIN = 'win' # Windows 8 GetFirmwareEnvironmentVariable format
|
|
EFI_FW_TYPE_VSS = 'vss' # NVRAM using format with '$VSS' signature
|
|
EFI_FW_TYPE_VSS_AUTH = 'vss_auth' # NVRAM using format with '$VSS' signature with extra fields
|
|
# See "A Tour Beyond BIOS Implementing UEFI Authenticated
|
|
# Variables in SMM with EDKII"
|
|
EFI_FW_TYPE_VSS2 = 'vss2'
|
|
EFI_FW_TYPE_VSS2_AUTH = 'vss2_auth'
|
|
EFI_FW_TYPE_VSS_APPLE = 'vss_apple'
|
|
EFI_FW_TYPE_NVAR = 'nvar' # 'NVAR' NVRAM format
|
|
EFI_FW_TYPE_EVSA = 'evsa' # 'EVSA' NVRAM format
|
|
|
|
|
|
fw_types = []
|
|
for i in [t for t in dir(FWType) if not callable(getattr(FWType, t))]:
|
|
if not i.startswith('__'):
|
|
fw_types.append( getattr(FWType, i) )
|
|
|
|
|
|
NVRAM_ATTR_RT = 1
|
|
NVRAM_ATTR_DESC_ASCII = 2
|
|
NVRAM_ATTR_GUID = 4
|
|
NVRAM_ATTR_DATA = 8
|
|
NVRAM_ATTR_EXTHDR = 0x10
|
|
NVRAM_ATTR_AUTHWR = 0x40
|
|
NVRAM_ATTR_HER = 0x20
|
|
NVRAM_ATTR_VLD = 0x80
|
|
|
|
#
|
|
# Known GUIDs of NVRAM stored in EFI firmware volumes, FS files etc. of various firmware implementations
|
|
#
|
|
ADDITIONAL_NV_STORE_GUID = '00504624-8A59-4EEB-BD0F-6B36E96128E0'
|
|
NVAR_NVRAM_FS_FILE = "CEF5B9A3-476D-497F-9FDC-E98143E0422C"
|
|
|
|
LENOVO_FS1_GUID = "16B45DA2-7D70-4AEA-A58D-760E9ECB841D"
|
|
LENOVO_FS2_GUID = "E360BDBA-C3CE-46BE-8F37-B231E5CB9F35"
|
|
|
|
EFI_PLATFORM_FS_GUIDS = [LENOVO_FS1_GUID, LENOVO_FS2_GUID]
|
|
EFI_NVRAM_GUIDS = [VARIABLE_STORE_FV_GUID, ADDITIONAL_NV_STORE_GUID, NVAR_NVRAM_FS_FILE]
|
|
|
|
#################################################################################################3
|
|
# This Variable header is defined by UEFI
|
|
#################################################################################################3
|
|
|
|
#
|
|
# Variable Store Status
|
|
#
|
|
#typedef enum {
|
|
# EfiRaw,
|
|
# EfiValid,
|
|
# EfiInvalid,
|
|
# EfiUnknown
|
|
# } VARIABLE_STORE_STATUS;
|
|
VARIABLE_STORE_STATUS_RAW = 0
|
|
VARIABLE_STORE_STATUS_VALID = 1
|
|
VARIABLE_STORE_STATUS_INVALID = 2
|
|
VARIABLE_STORE_STATUS_UNKNOWN = 3
|
|
|
|
#
|
|
# Variable State flags
|
|
#
|
|
VAR_IN_DELETED_TRANSITION = 0xfe # Variable is in obsolete transistion
|
|
VAR_DELETED = 0xfd # Variable is obsolete
|
|
VAR_ADDED = 0x7f # Variable has been completely added
|
|
#IS_VARIABLE_STATE(_c, _Mask) (BOOLEAN) (((~_c) & (~_Mask)) != 0)
|
|
def IS_VARIABLE_STATE(_c, _Mask):
|
|
return ( ( ((~_c)&0xFF) & ((~_Mask)&0xFF) ) != 0 )
|
|
|
|
#
|
|
#typedef struct {
|
|
# UINT16 StartId;
|
|
# UINT8 State;
|
|
# UINT8 Reserved;
|
|
# UINT32 Attributes;
|
|
# UINT32 NameSize;
|
|
# UINT32 DataSize;
|
|
# EFI_GUID VendorGuid;
|
|
#} VARIABLE_HEADER;
|
|
#
|
|
#typedef struct {
|
|
# UINT32 Data1;
|
|
# UINT16 Data2;
|
|
# UINT16 Data3;
|
|
# UINT8 Data4[8];
|
|
#} EFI_GUID;
|
|
#
|
|
UEFI_VARIABLE_HEADER_SIZE = 28
|
|
class UEFI_VARIABLE_HEADER( namedtuple('UEFI_VARIABLE_HEADER', 'StartId State Reserved Attributes NameSize DataSize VendorGuid0 VendorGuid1 VendorGuid2 VendorGuid3') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
Header (UEFI)
|
|
-------------
|
|
StartId : 0x{:04X}
|
|
State : 0x{:02X}
|
|
Reserved : 0x{:02X}
|
|
Attributes : 0x{:08X}
|
|
NameSize : 0x{:08X}
|
|
DataSize : 0x{:08X}
|
|
VendorGuid : {0x{:08X}-0x{:04X}-0x{:04X}-0x{:08X}}
|
|
""".format( self.StartId, self.State, self.Reserved, self.Attributes, self.NameSize, self.DataSize, self.VendorGuid0, self.VendorGuid1, self.VendorGuid2, self.VendorGuid3 )
|
|
|
|
|
|
UEFI_VARIABLE_STORE_HEADER = "<IHH8sIBBHI"
|
|
UEFI_VARIABLE_STORE_HEADER_SIZE = struct.calcsize(UEFI_VARIABLE_STORE_HEADER)
|
|
'''
|
|
EFI_VARIABLE_HEADER_AUTH = "<HBBI28sIIIHH8s"
|
|
EFI_VARIABLE_HEADER_AUTH_SIZE = struct.calcsize(EFI_VARIABLE_HEADER_AUTH)
|
|
|
|
EFI_VARIABLE_HEADER = "<HBBIIIIHH8s"
|
|
EFI_VARIABLE_HEADER_SIZE = struct.calcsize(EFI_VARIABLE_HEADER)
|
|
'''
|
|
VARIABLE_STORE_FORMATTED = 0x5a
|
|
VARIABLE_STORE_HEALTHY = 0xfe
|
|
|
|
def _getNVstore_EFI( nvram_buf, efi_type ):
|
|
l = (-1, -1, None)
|
|
FvOffset = 0
|
|
FvLength = 0
|
|
while True:
|
|
FvOffset, FsGuid, FvLength, Attributes, HeaderLength, Checksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf, FvOffset+FvLength)
|
|
if (FvOffset is None): break
|
|
if (FsGuid != VARIABLE_STORE_FV_GUID): continue
|
|
nvram_start = HeaderLength
|
|
StoreGuid0, StoreGuid1, StoreGuid2, StoreGuid03, Size, Format, State, R0, R1 = \
|
|
struct.unpack(UEFI_VARIABLE_STORE_HEADER, FvImage[nvram_start:nvram_start + UEFI_VARIABLE_STORE_HEADER_SIZE])
|
|
if ((Format == VARIABLE_STORE_FORMATTED) and (State == VARIABLE_STORE_HEALTHY)):
|
|
if (isCorrectVSStype(FvImage[nvram_start:], efi_type)):
|
|
l = (FvOffset + nvram_start, FvLength - nvram_start, None)
|
|
break
|
|
return l
|
|
|
|
def getNVstore_EFI( nvram_buf ):
|
|
return _getNVstore_EFI( nvram_buf, FWType.EFI_FW_TYPE_VSS )
|
|
|
|
def getNVstore_EFI_AUTH( nvram_buf ):
|
|
return _getNVstore_EFI( nvram_buf, FWType.EFI_FW_TYPE_VSS_AUTH )
|
|
|
|
def getEFIvariables_UEFI( nvram_buf ):
|
|
return _getEFIvariables_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS)
|
|
|
|
def getEFIvariables_UEFI_AUTH( nvram_buf ):
|
|
return _getEFIvariables_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS_AUTH)
|
|
|
|
|
|
'''
|
|
def getEFIvariables_UEFI_Ex( nvram_buf, auth = False ):
|
|
dof = 0
|
|
length = len(nvram_buf)
|
|
storen = 0
|
|
variables = dict()
|
|
while ((dof+UEFI_VARIABLE_STORE_HEADER_SIZE) < length):
|
|
store_start = dof
|
|
StoreGuid0, StoreGuid1, StoreGuid2, StoreGuid03, Size, Format, State, R0, R1 = \
|
|
struct.unpack(UEFI_VARIABLE_STORE_HEADER, nvram_buf[dof:dof + UEFI_VARIABLE_STORE_HEADER_SIZE])
|
|
dof = align(dof + UEFI_VARIABLE_STORE_HEADER_SIZE, 4)
|
|
if ((Format != VARIABLE_STORE_FORMATTED) or (State != VARIABLE_STORE_HEALTHY)):
|
|
break
|
|
if ((store_start + Size) >= length): break
|
|
while ((dof + EFI_VARIABLE_HEADER_SIZE) <= (store_start + Size)):
|
|
StartId, State, R0, Attributes, Auth, NameSize, DataSize, VendorGuid0, VendorGuid1, VendorGuid2, VendorGuid3 = \
|
|
struct.unpack(EFI_VARIABLE_HEADER, nvram_buf[dof:dof+EFI_VARIABLE_HEADER_SIZE]);
|
|
if (StartId != VARIABLE_DATA): break
|
|
dof += EFI_VARIABLE_HEADER_SIZE
|
|
if ((State == 0xff) and (DataSize == 0xffffffff) and (NameSize == 0xffffffff) and (Attributes == 0xffffffff)):
|
|
NameSize = 0
|
|
DataSize = 0
|
|
# just skip variable with empty name and data for now
|
|
else:
|
|
guid = guid_str(VendorGuid0, VendorGuid1, VendorGuid2, VendorGuid3)
|
|
Name = nvram_buf[dof:dof+NameSize]
|
|
NameStr = unicode(Name, "utf-16-le").split('\x00')[0]
|
|
VarData = nvram_buf[dof+NameSize:dof+NameSize+DataSize]
|
|
if NameStr not in variables.keys():
|
|
variables[NameStr] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[NameStr].append((dof, None, None, VarData, guid, Attributes))
|
|
dof = align(dof+NameSize+DataSize, 4)
|
|
dof = store_start + Size
|
|
storen += 1
|
|
return variables
|
|
'''
|
|
##################################################################################################
|
|
#
|
|
# Platform/Vendor Specific EFI NVRAM Parsing Functions
|
|
#
|
|
# For each platform, EFI NVRAM parsing functionality includes:
|
|
# 1. Function to parse EFI variable within NVRAM binary (func_getefivariables)
|
|
# May define/use platform specific EFI Variable Header
|
|
# Function arguments:
|
|
# In : binary buffer (as a string)
|
|
# Out:
|
|
# start - offset in the buffer to the current EFI variable
|
|
# next_var_offset - offset in the buffer to the next EFI variable
|
|
# efi_var_buf - full EFI variable buffer
|
|
# efi_var_hdr - EFI variable header object
|
|
# efi_var_name - EFI variable name
|
|
# efi_var_data - EFI variable data contents
|
|
# efi_var_guid - EFI variable GUID
|
|
# efi_var_attr - EFI variable attributes
|
|
# 2. [Optional] Function to find EFI NVRAM within arbitrary binary (func_getnvstore)
|
|
# If this function is not defined, 'chipsec_util uefi' searches EFI variables from the beginning of the binary
|
|
# Function arguments:
|
|
# In : NVRAM binary buffer (as a string)
|
|
# Out:
|
|
# start - offset of NVRAM (-1 means NVRAM not found)
|
|
# size - size of NVRAM (-1 means NVRAM is entire binary)
|
|
# nvram_header - NVRAM header object
|
|
#
|
|
##################################################################################################
|
|
|
|
##################################################################################################
|
|
# NVAR format of NVRAM
|
|
#
|
|
|
|
from chipsec.logger import *
|
|
class EFI_HDR_NVAR1( namedtuple('EFI_HDR_NVAR1', 'StartId TotalSize Reserved1 Reserved2 Reserved3 Attributes State') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
Header (NVAR)
|
|
------------
|
|
StartId : 0x{:04X}
|
|
TotalSize : 0x{:04X}
|
|
Reserved1 : 0x{:02X}
|
|
Reserved2 : 0x{:02X}
|
|
Reserved3 : 0x{:02X}
|
|
Attributes : 0x{:02X}
|
|
State : 0x{:02X}
|
|
""".format( self.StartId, self.TotalSize, self.Reserved1, self.Reserved2, self.Reserved3, self.Attributes, self.State )
|
|
|
|
NVAR_EFIvar_signature = b'NVAR'
|
|
|
|
def getNVstore_NVAR( nvram_buf ):
|
|
l = (-1, -1, None)
|
|
FvOffset, FsGuid, FvLength, FvAttributes, FvHeaderLength, FvChecksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf)
|
|
if (FvOffset is None):
|
|
return l
|
|
if (FvOffset >= len(nvram_buf)):
|
|
return l
|
|
if (FvOffset + FvLength) > len(nvram_buf):
|
|
FvLength = len(nvram_buf) - FvOffset
|
|
while FvOffset is not None:
|
|
polarity = bit_set(FvAttributes, EFI_FVB2_ERASE_POLARITY)
|
|
cur_offset, next_offset, Name, Type, Attributes, State, Checksum, Size, FileImage, HeaderSize, UD, fCalcSum = NextFwFile(FvImage, FvLength, FvHeaderLength, polarity)
|
|
while next_offset is not None:
|
|
if (Type == EFI_FV_FILETYPE_RAW) and (Name == NVAR_NVRAM_FS_FILE):
|
|
l = ((FvOffset + cur_offset + HeaderSize), Size - HeaderSize, None)
|
|
if (not UD):
|
|
return l
|
|
cur_offset, next_offset, Name, Type, Attributes, State, Checksum, Size, FileImage, HeaderSize, UD, fCalcSum = NextFwFile(FvImage, FvLength, next_offset, polarity)
|
|
FvOffset, FsGuid, FvLength, Attributes, HeaderLength, Checksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf, FvOffset+FvLength)
|
|
return l
|
|
|
|
def _ord(c):
|
|
return ord(c) if isinstance(c, str) else c
|
|
|
|
def getEFIvariables_NVAR( nvram_buf ):
|
|
start = nvram_buf.find( NVAR_EFIvar_signature )
|
|
nvram_size = len(nvram_buf)
|
|
EFI_HDR_NVAR = "<4sH3sB"
|
|
nvar_size = struct.calcsize(EFI_HDR_NVAR)
|
|
variables = dict()
|
|
nof = 0 #start
|
|
# EMPTY = 0
|
|
EMPTY = 0xffffffff
|
|
while (nof+nvar_size) < nvram_size:
|
|
start_id, size, next, attributes = struct.unpack(EFI_HDR_NVAR, nvram_buf[nof:nof+nvar_size])
|
|
next = get_3b_size(next)
|
|
valid = (bit_set(attributes, NVRAM_ATTR_VLD) and (not bit_set(attributes, NVRAM_ATTR_DATA)))
|
|
if not valid:
|
|
nof = nof + size
|
|
continue
|
|
isvar = (start_id == NVAR_EFIvar_signature)
|
|
if (not isvar) or (size == (EMPTY & 0xffff)): break
|
|
var_name_off = 1
|
|
if bit_set(attributes, NVRAM_ATTR_GUID):
|
|
guid = UUID(bytes_le=nvram_buf[nof + nvar_size: nof + nvar_size + guid_size])
|
|
guid = str(guid).upper()
|
|
var_name_off = guid_size
|
|
else:
|
|
guid_idx = _ord(nvram_buf[nof+nvar_size])
|
|
guid_off = (nvram_size - guid_size) - guid_idx * guid_size
|
|
guid = UUID(bytes_le=nvram_buf[guid_off: guid_off + guid_size])
|
|
guid = str(guid).upper()
|
|
name_size = 0
|
|
name_offset = nof+nvar_size+var_name_off
|
|
if not bit_set(attributes, NVRAM_ATTR_DATA):
|
|
name, name_size = get_nvar_name(nvram_buf, name_offset, bit_set(attributes, NVRAM_ATTR_DESC_ASCII))
|
|
esize = 0
|
|
eattrs = 0
|
|
if bit_set(attributes, NVRAM_ATTR_EXTHDR):
|
|
esize, = struct.unpack("<H", nvram_buf[nof+size-2:nof+size])
|
|
eattrs = _ord(nvram_buf[nof+size-esize])
|
|
attribs = EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
attribs = attribs | EFI_VARIABLE_NON_VOLATILE
|
|
if bit_set(attributes, NVRAM_ATTR_RT): attribs = attribs | EFI_VARIABLE_RUNTIME_ACCESS
|
|
if bit_set(attributes, NVRAM_ATTR_HER): attribs = attribs | EFI_VARIABLE_HARDWARE_ERROR_RECORD
|
|
if bit_set(attributes, NVRAM_ATTR_AUTHWR):
|
|
if bit_set(eattrs, EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS):
|
|
attribs = attribs | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
|
|
if bit_set(eattrs, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS):
|
|
attribs = attribs | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
|
|
# Get variable data
|
|
lof = nof
|
|
lnext = next
|
|
lattributes = attributes
|
|
lsize = size
|
|
lesize = esize
|
|
while lnext != (0xFFFFFF & EMPTY):
|
|
lof = lof + lnext
|
|
lstart_id, lsize, lnext, lattributes = struct.unpack(EFI_HDR_NVAR, nvram_buf[lof:lof+nvar_size])
|
|
lnext = get_3b_size(lnext)
|
|
dataof = lof + nvar_size
|
|
if not bit_set(lattributes, NVRAM_ATTR_DATA):
|
|
lnameof = 1
|
|
if bit_set(lattributes, NVRAM_ATTR_GUID): lnameof = guid_size
|
|
name_offset = lof+nvar_size+lnameof
|
|
name, name_size = get_nvar_name(nvram_buf, name_offset, bit_set(attributes, NVRAM_ATTR_DESC_ASCII))
|
|
dataof = name_offset + name_size
|
|
if bit_set(lattributes, NVRAM_ATTR_EXTHDR):
|
|
lesize, = struct.unpack("<H", nvram_buf[lof+lsize-2:lof+lsize])
|
|
data = nvram_buf[dataof:lof+lsize-lesize]
|
|
if name not in variables.keys():
|
|
variables[name] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[name].append((nof, None, None, data, guid, attribs))
|
|
nof = nof + size
|
|
return variables
|
|
|
|
NVAR_HDR_FMT = '=IHBBBBB'
|
|
NVAR_HDR_SIZE = struct.calcsize( NVAR_HDR_FMT )
|
|
|
|
|
|
#
|
|
# Linear/simple NVAR format parsing
|
|
#
|
|
def getNVstore_NVAR_simple( nvram_buf ):
|
|
return (nvram_buf.find( NVAR_EFIvar_signature ), -1, None)
|
|
|
|
def getEFIvariables_NVAR_simple( nvram_buf ):
|
|
nvsize = len(nvram_buf)
|
|
hdr_fmt = NVAR_HDR_FMT
|
|
hdr_size = struct.calcsize( hdr_fmt )
|
|
variables = dict()
|
|
start = nvram_buf.find( NVAR_EFIvar_signature )
|
|
if -1 == start: return variables
|
|
|
|
while (start + hdr_size) < nvsize:
|
|
efi_var_hdr = EFI_HDR_NVAR1( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
name_size = 0
|
|
efi_var_name = "NA"
|
|
if not IS_VARIABLE_ATTRIBUTE( efi_var_hdr.Attributes, EFI_VARIABLE_HARDWARE_ERROR_RECORD ):
|
|
name_size = nvram_buf[ start + hdr_size : ].find( '\0' )
|
|
efi_var_name = "".join( nvram_buf[ start + hdr_size : start + hdr_size + name_size ] )
|
|
|
|
next_var_offset = start + efi_var_hdr.TotalSize
|
|
data_size = efi_var_hdr.TotalSize - name_size - hdr_size
|
|
efi_var_buf = nvram_buf[ start : next_var_offset ]
|
|
efi_var_data = nvram_buf[ start + hdr_size + name_size : next_var_offset ]
|
|
|
|
if efi_var_name not in variables.keys(): variables[efi_var_name] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[efi_var_name].append((start, efi_var_buf, efi_var_hdr, efi_var_data, '', efi_var_hdr.Attributes))
|
|
|
|
if start >= next_var_offset: break
|
|
start = next_var_offset
|
|
|
|
return variables
|
|
|
|
|
|
#######################################################################
|
|
#
|
|
# VSS NVRAM (signature = '$VSS')
|
|
#
|
|
#
|
|
|
|
#define VARIABLE_STORE_SIGNATURE EFI_SIGNATURE_32 ('$', 'V', 'S', 'S')
|
|
VARIABLE_STORE_SIGNATURE_VSS = b'$VSS'
|
|
VARIABLE_STORE_HEADER_FMT_VSS = '=IIBBHI' # Signature is '$VSS'
|
|
class VARIABLE_STORE_HEADER_VSS( namedtuple('VARIABLE_STORE_HEADER_VSS', 'Signature Size Format State Reserved Reserved1') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
EFI Variable Store
|
|
-----------------------------
|
|
Signature : {} (0x{:08X})
|
|
Size : 0x{:08X} bytes
|
|
Format : 0x{:02X}
|
|
State : 0x{:02X}
|
|
Reserved : 0x{:04X}
|
|
Reserved1 : 0x{:08X}
|
|
""".format( struct.pack('=I',self.Signature), self.Signature, self.Size, self.Format, self.State, self.Reserved, self.Reserved1 )
|
|
|
|
VARIABLE_STORE_SIGNATURE_VSS2 = UUID('DDCF3617-3275-4164-98B6-FE85707FFE7D').bytes_le
|
|
VARIABLE_STORE_SIGNATURE_VSS2_AUTH = UUID('AAF32C78-947B-439A-A180-2E144EC37792').bytes_le
|
|
|
|
VARIABLE_STORE_HEADER_FMT_VSS2 = '=16sIBBHI'
|
|
class VARIABLE_STORE_HEADER_VSS2( namedtuple('VARIABLE_STORE_HEADER_VSS2', 'Signature Size Format State Reserved Reserved1') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
EFI Variable Store
|
|
-----------------------------
|
|
Signature : %s
|
|
Size : 0x%08X bytes
|
|
Format : 0x%02X
|
|
State : 0x%02X
|
|
Reserved : 0x%04X
|
|
Reserved1 : 0x%08X
|
|
""" % ( UUID(bytes_le=self.Signature), self.Size, self.Format, self.State, self.Reserved, self.Reserved1 )
|
|
|
|
VARIABLE_STORE_SIGNATURE_VSS2 = UUID('DDCF3617-3275-4164-98B6-FE85707FFE7D').bytes_le
|
|
VARIABLE_STORE_SIGNATURE_VSS2_AUTH = UUID('AAF32C78-947B-439A-A180-2E144EC37792').bytes_le
|
|
|
|
VARIABLE_STORE_HEADER_FMT_VSS2 = '=16sIBBHI'
|
|
class VARIABLE_STORE_HEADER_VSS2( namedtuple('VARIABLE_STORE_HEADER_VSS2', 'Signature Size Format State Reserved Reserved1') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
EFI Variable Store
|
|
-----------------------------
|
|
Signature : %s
|
|
Size : 0x%08X bytes
|
|
Format : 0x%02X
|
|
State : 0x%02X
|
|
Reserved : 0x%04X
|
|
Reserved1 : 0x%08X
|
|
""" % ( UUID(bytes_le=self.Signature), self.Size, self.Format, self.State, self.Reserved, self.Reserved1 )
|
|
|
|
|
|
HDR_FMT_VSS = '<HBBIII4s2s2s8s'
|
|
#HDR_SIZE_VSS = struct.calcsize( HDR_FMT_VSS )
|
|
#NAME_OFFSET_IN_VAR_VSS = HDR_SIZE_VSS
|
|
class EFI_HDR_VSS( namedtuple('EFI_HDR_VSS', 'StartId State Reserved Attributes NameSize DataSize guid0 guid1 guid2 guid3') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
Header (VSS)
|
|
------------
|
|
VendorGuid : {{{}}}
|
|
StartId : 0x{:04X}
|
|
State : 0x{:02X}
|
|
Reserved : 0x{:02X}
|
|
Attributes : 0x{:08X}
|
|
NameSize : 0x{:08X}
|
|
DataSize : 0x{:08X}
|
|
""".format( guid_str(self.guid0, self.guid1, self.guid2, self.guid3), self.StartId, self.State, self.Reserved, self.Attributes, self.NameSize, self.DataSize)
|
|
|
|
|
|
HDR_FMT_VSS_AUTH = '<HBBIQQQIII4s2s2s8s'
|
|
class EFI_HDR_VSS_AUTH( namedtuple('EFI_HDR_VSS_AUTH', 'StartId State Reserved Attributes MonotonicCount TimeStamp1 TimeStamp2 PubKeyIndex NameSize DataSize guid0 guid1 guid2 guid3') ):
|
|
__slots__ = ()
|
|
# if you don't re-define __str__ method, initialize is to None
|
|
#__str__ = None
|
|
def __str__(self):
|
|
return """
|
|
Header (VSS_AUTH)
|
|
----------------
|
|
VendorGuid : {{{}}}
|
|
StartId : 0x{:04X}
|
|
State : 0x{:02X}
|
|
Reserved : 0x{:02X}
|
|
Attributes : 0x{:08X}
|
|
MonotonicCount : 0x{:016X}
|
|
TimeStamp1 : 0x{:016X}
|
|
TimeStamp2 : 0x{:016X}
|
|
PubKeyIndex : 0x{:08X}
|
|
NameSize : 0x{:08X}
|
|
DataSize : 0x{:08X}
|
|
""".format( guid_str(self.guid0, self.guid1, self.guid2, self.guid3), self.StartId, self.State, self.Reserved, self.Attributes, self.MonotonicCount, self.TimeStamp1, self.TimeStamp2, self.PubKeyIndex, self.NameSize, self.DataSize )
|
|
|
|
HDR_FMT_VSS_APPLE = '<HBBIII4s2s2s8sI'
|
|
class EFI_HDR_VSS_APPLE( namedtuple('EFI_HDR_VSS_APPLE', 'StartId State Reserved Attributes NameSize DataSize guid0 guid1 guid2 guid3 unknown') ):
|
|
__slots__ = ()
|
|
def __str__(self):
|
|
return """
|
|
Header (VSS_APPLE)
|
|
------------
|
|
VendorGuid : {{{}}}
|
|
StartId : 0x{:04X}
|
|
State : 0x{:02X}
|
|
Reserved : 0x{:02X}
|
|
Attributes : 0x{:08X}
|
|
NameSize : 0x{:08X}
|
|
DataSize : 0x{:08X}
|
|
Unknown : 0x{:08X}
|
|
""".format( guid_str(self.guid0, self.guid1, self.guid2, self.guid3), self.StartId, self.State, self.Reserved, self.Attributes, self.NameSize, self.DataSize, self.unknown)
|
|
|
|
|
|
def _getNVstore_VSS( nvram_buf, vss_type ):
|
|
if vss_type == FWType.EFI_FW_TYPE_VSS2:
|
|
sign = VARIABLE_STORE_SIGNATURE_VSS2
|
|
elif vss_type == FWType.EFI_FW_TYPE_VSS2_AUTH:
|
|
sign = VARIABLE_STORE_SIGNATURE_VSS2_AUTH
|
|
else:
|
|
sign = VARIABLE_STORE_SIGNATURE_VSS
|
|
|
|
nvram_start = nvram_buf.find( sign )
|
|
if -1 == nvram_start:
|
|
return (-1, 0, None)
|
|
buf = nvram_buf[nvram_start:]
|
|
if (not isCorrectVSStype(buf, vss_type)):
|
|
return (-1, 0, None)
|
|
if vss_type in (FWType.EFI_FW_TYPE_VSS2, FWType.EFI_FW_TYPE_VSS2_AUTH):
|
|
nvram_hdr = VARIABLE_STORE_HEADER_VSS2( *struct.unpack_from( VARIABLE_STORE_HEADER_FMT_VSS2, buf ) )
|
|
else:
|
|
nvram_hdr = VARIABLE_STORE_HEADER_VSS( *struct.unpack_from( VARIABLE_STORE_HEADER_FMT_VSS, buf ) )
|
|
return (nvram_start, nvram_hdr.Size, nvram_hdr)
|
|
|
|
def getNVstore_VSS( nvram_buf ):
|
|
return _getNVstore_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS)
|
|
|
|
def getNVstore_VSS_AUTH( nvram_buf ):
|
|
return _getNVstore_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS_AUTH)
|
|
|
|
def getNVstore_VSS2( nvram_buf ):
|
|
return _getNVstore_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS2)
|
|
|
|
def getNVstore_VSS2_AUTH( nvram_buf ):
|
|
return _getNVstore_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS2_AUTH)
|
|
|
|
def getNVstore_VSS_APPLE( nvram_buf):
|
|
return _getNVstore_VSS(nvram_buf, FWType.EFI_FW_TYPE_VSS_APPLE)
|
|
|
|
VSS_TYPES = (FWType.EFI_FW_TYPE_VSS, FWType.EFI_FW_TYPE_VSS_AUTH, FWType.EFI_FW_TYPE_VSS2, FWType.EFI_FW_TYPE_VSS2_AUTH, FWType.EFI_FW_TYPE_VSS_APPLE)
|
|
MAX_VSS_VAR_ALIGNMENT = 8
|
|
|
|
def isCorrectVSStype(nvram_buf, vss_type):
|
|
if (vss_type not in VSS_TYPES):
|
|
return False
|
|
|
|
buf_size = len(nvram_buf)
|
|
start = nvram_buf.find( VARIABLE_SIGNATURE_VSS )
|
|
if (-1 == start):
|
|
return False
|
|
|
|
next_var = nvram_buf.find( VARIABLE_SIGNATURE_VSS, start+struct.calcsize( HDR_FMT_VSS ) ) # skip the minimun bytes required for the header
|
|
if (-1 == next_var):
|
|
next_var = buf_size
|
|
|
|
buf_size -= start
|
|
|
|
if (vss_type in (FWType.EFI_FW_TYPE_VSS, FWType.EFI_FW_TYPE_VSS2)):
|
|
hdr_fmt = HDR_FMT_VSS
|
|
efi_var_hdr = EFI_HDR_VSS( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
elif (vss_type in (FWType.EFI_FW_TYPE_VSS_AUTH, FWType.EFI_FW_TYPE_VSS2_AUTH)):
|
|
hdr_fmt = HDR_FMT_VSS_AUTH
|
|
efi_var_hdr = EFI_HDR_VSS_AUTH( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
elif (vss_type == FWType.EFI_FW_TYPE_VSS_APPLE):
|
|
hdr_fmt = HDR_FMT_VSS_APPLE
|
|
efi_var_hdr = EFI_HDR_VSS_APPLE( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
|
|
hdr_size = struct.calcsize( hdr_fmt )
|
|
# check NameSize and DataSize
|
|
name_offset = start + hdr_size
|
|
if ((name_offset < next_var) and ((name_offset + efi_var_hdr.NameSize) < next_var)):
|
|
valid_name = False
|
|
if (efi_var_hdr.NameSize > 0):
|
|
name = nvram_buf[name_offset: name_offset + efi_var_hdr.NameSize]
|
|
try:
|
|
name = name.decode("utf-16-le").split('\x00')[0]
|
|
valid_name = defines.is_printable(name)
|
|
except Exception as e:
|
|
pass
|
|
if (valid_name):
|
|
end_var_offset = name_offset + efi_var_hdr.NameSize + efi_var_hdr.DataSize
|
|
off_diff = next_var - end_var_offset
|
|
if (off_diff == 0):
|
|
return True
|
|
elif (off_diff > 0):
|
|
if (next_var == len(nvram_buf)) or (off_diff <= (MAX_VSS_VAR_ALIGNMENT - 1)):
|
|
return True
|
|
else:
|
|
if (next_var < len(nvram_buf)):
|
|
new_nex_var = nvram_buf.find(VARIABLE_SIGNATURE_VSS, next_var, next_var + len(VARIABLE_SIGNATURE_VSS) + (MAX_VSS_VAR_ALIGNMENT - 1))
|
|
if (new_nex_var != -1):
|
|
return True
|
|
|
|
return False
|
|
|
|
def _getEFIvariables_VSS( nvram_buf, _fwtype):
|
|
variables = dict()
|
|
nvsize = len(nvram_buf)
|
|
if _fwtype in (FWType.EFI_FW_TYPE_VSS, FWType.EFI_FW_TYPE_VSS2):
|
|
hdr_fmt = HDR_FMT_VSS
|
|
elif _fwtype in (FWType.EFI_FW_TYPE_VSS_AUTH, FWType.EFI_FW_TYPE_VSS2_AUTH):
|
|
hdr_fmt = HDR_FMT_VSS_AUTH
|
|
elif (FWType.EFI_FW_TYPE_VSS_APPLE == _fwtype):
|
|
hdr_fmt = HDR_FMT_VSS_APPLE
|
|
else:
|
|
return variables
|
|
hdr_size = struct.calcsize( hdr_fmt )
|
|
start = nvram_buf.find( VARIABLE_SIGNATURE_VSS )
|
|
if -1 == start:
|
|
return variables
|
|
|
|
while (start + hdr_size) < nvsize:
|
|
if _fwtype in (FWType.EFI_FW_TYPE_VSS, FWType.EFI_FW_TYPE_VSS2):
|
|
efi_var_hdr = EFI_HDR_VSS( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
elif _fwtype in (FWType.EFI_FW_TYPE_VSS_AUTH, FWType.EFI_FW_TYPE_VSS2_AUTH):
|
|
efi_var_hdr = EFI_HDR_VSS_AUTH( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
elif (FWType.EFI_FW_TYPE_VSS_APPLE == _fwtype):
|
|
efi_var_hdr = EFI_HDR_VSS_APPLE( *struct.unpack_from( hdr_fmt, nvram_buf[start:] ) )
|
|
|
|
if (efi_var_hdr.StartId != VARIABLE_DATA): break
|
|
|
|
if ((efi_var_hdr.State == 0xff) and (efi_var_hdr.DataSize == 0xffffffff) and (efi_var_hdr.NameSize == 0xffffffff) and (efi_var_hdr.Attributes == 0xffffffff)):
|
|
name_size = 0
|
|
data_size = 0
|
|
# just skip variable with empty name and data for now
|
|
next_var_offset = nvram_buf.find( VARIABLE_SIGNATURE_VSS, start + hdr_size, start + hdr_size + len(VARIABLE_SIGNATURE_VSS) + (MAX_VSS_VAR_ALIGNMENT - 1))
|
|
if (next_var_offset == -1) or (next_var_offset > nvsize):
|
|
break
|
|
else:
|
|
name_size = efi_var_hdr.NameSize
|
|
data_size = efi_var_hdr.DataSize
|
|
efi_var_name = "<not defined>"
|
|
|
|
end_var_offset = start + hdr_size + name_size + data_size
|
|
efi_var_buf = nvram_buf[ start : end_var_offset ]
|
|
|
|
name_offset = hdr_size
|
|
#if not IS_VARIABLE_ATTRIBUTE( efi_var_hdr.Attributes, EFI_VARIABLE_HARDWARE_ERROR_RECORD ):
|
|
#efi_var_name = "".join( efi_var_buf[ NAME_OFFSET_IN_VAR_VSS : NAME_OFFSET_IN_VAR_VSS + name_size ] )
|
|
Name = efi_var_buf[ name_offset : name_offset + name_size ]
|
|
efi_var_name = Name.decode("utf-16-le").split('\x00')[0]
|
|
|
|
efi_var_data = efi_var_buf[ name_offset + name_size : name_offset + name_size + data_size ]
|
|
guid = guid_str(efi_var_hdr.guid0, efi_var_hdr.guid1, efi_var_hdr.guid2, efi_var_hdr.guid3)
|
|
if efi_var_name not in variables.keys():
|
|
variables[efi_var_name] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[efi_var_name].append( (start, efi_var_buf, efi_var_hdr, efi_var_data, guid, efi_var_hdr.Attributes) )
|
|
|
|
# deal with different alignments (1-8)
|
|
next_var_offset = nvram_buf.find( VARIABLE_SIGNATURE_VSS, end_var_offset, end_var_offset + len(VARIABLE_SIGNATURE_VSS) + (MAX_VSS_VAR_ALIGNMENT - 1))
|
|
if (next_var_offset == -1) or (next_var_offset > nvsize):
|
|
break
|
|
|
|
if start >= next_var_offset: break
|
|
start = next_var_offset
|
|
|
|
return variables
|
|
|
|
|
|
def getEFIvariables_VSS( nvram_buf ):
|
|
return _getEFIvariables_VSS( nvram_buf, FWType.EFI_FW_TYPE_VSS )
|
|
|
|
def getEFIvariables_VSS_AUTH( nvram_buf ):
|
|
return _getEFIvariables_VSS( nvram_buf, FWType.EFI_FW_TYPE_VSS_AUTH )
|
|
|
|
def getEFIvariables_VSS2( nvram_buf ):
|
|
return _getEFIvariables_VSS( nvram_buf, FWType.EFI_FW_TYPE_VSS2 )
|
|
|
|
def getEFIvariables_VSS2_AUTH( nvram_buf ):
|
|
return _getEFIvariables_VSS( nvram_buf, FWType.EFI_FW_TYPE_VSS2_AUTH )
|
|
|
|
def getEFIvariables_VSS_APPLE( nvram_buf ):
|
|
return _getEFIvariables_VSS( nvram_buf, FWType.EFI_FW_TYPE_VSS_APPLE )
|
|
|
|
#######################################################################
|
|
#
|
|
# EVSA NVRAM (signature = 'EVSA')
|
|
#
|
|
#
|
|
VARIABLE_STORE_SIGNATURE_EVSA = b'EVSA'
|
|
|
|
TLV_HEADER = "<BBH"
|
|
tlv_h_size = struct.calcsize(TLV_HEADER)
|
|
|
|
def getNVstore_EVSA( nvram_buf ):
|
|
l = (-1, -1, None)
|
|
FvOffset, FsGuid, FvLength, FvAttributes, FvHeaderLength, FvChecksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf)
|
|
while FvOffset is not None:
|
|
if (FsGuid == VARIABLE_STORE_FV_GUID):
|
|
nvram_start = FvImage.find( VARIABLE_STORE_SIGNATURE_EVSA )
|
|
if (nvram_start != -1) and (nvram_start >= tlv_h_size):
|
|
nvram_start = nvram_start - tlv_h_size
|
|
l = (FvOffset + nvram_start, FvLength - nvram_start, None)
|
|
break
|
|
if (FsGuid == ADDITIONAL_NV_STORE_GUID):
|
|
nvram_start = FvImage.find( VARIABLE_STORE_SIGNATURE_EVSA )
|
|
if (nvram_start != -1) and (nvram_start >= tlv_h_size):
|
|
nvram_start = nvram_start - tlv_h_size
|
|
l = (FvOffset + nvram_start, FvLength - nvram_start, None)
|
|
FvOffset, FsGuid, FvLength, Attributes, HeaderLength, Checksum, ExtHeaderOffset, FvImage, CalcSum = NextFwVolume(nvram_buf, FvOffset+FvLength)
|
|
return l
|
|
|
|
def EFIvar_EVSA(nvram_buf):
|
|
image_size = len(nvram_buf)
|
|
sn = 0
|
|
EVSA_RECORD = "<IIII"
|
|
evsa_rec_size = struct.calcsize(EVSA_RECORD)
|
|
GUID_RECORD = "<H4s2s2s8s"
|
|
guid_rc_size = struct.calcsize(GUID_RECORD)
|
|
fof = 0
|
|
variables = dict()
|
|
while fof < image_size:
|
|
fof = nvram_buf.find(VARIABLE_STORE_SIGNATURE_EVSA, fof)
|
|
if fof == -1: break
|
|
if fof < tlv_h_size:
|
|
fof = fof + 4
|
|
continue
|
|
start = fof - tlv_h_size
|
|
Tag0, Tag1, Size = struct.unpack(TLV_HEADER, nvram_buf[start: start + tlv_h_size])
|
|
if Tag0 != 0xEC: # Wrong EVSA block
|
|
fof = fof + 4
|
|
continue
|
|
value = nvram_buf[start + tlv_h_size:start + Size]
|
|
Signature, Unkwn0, Length, Unkwn1 = struct.unpack(EVSA_RECORD, value)
|
|
if start + Length > image_size: # Wrong EVSA record
|
|
fof = fof + 4
|
|
continue
|
|
# NV storage EVSA found
|
|
bof = 0
|
|
guid_map = dict()
|
|
var_list = list()
|
|
value_list = dict()
|
|
while (bof + tlv_h_size) < Length:
|
|
Tag0, Tag1, Size = struct.unpack(TLV_HEADER, nvram_buf[start + bof: start + bof + tlv_h_size])
|
|
if (Size < tlv_h_size):
|
|
break
|
|
value = nvram_buf[start + bof + tlv_h_size:start + bof + Size]
|
|
bof = bof + Size
|
|
if (Tag0 == 0xED) or (Tag0 == 0xE1): # guid
|
|
GuidId, guid0, guid1, guid2, guid3 = struct.unpack(GUID_RECORD, value)
|
|
g = guid_str(guid0, guid1, guid2, guid3)
|
|
guid_map[GuidId] = g
|
|
elif (Tag0 == 0xEE) or (Tag0 == 0xE2): # var name
|
|
VAR_NAME_RECORD = "<H{:d}s".format(Size - tlv_h_size - 2)
|
|
VarId, Name = struct.unpack(VAR_NAME_RECORD, value)
|
|
Name = Name.decode("utf-16-le")[:-1]
|
|
var_list.append((Name, VarId, Tag0, Tag1))
|
|
elif (Tag0 == 0xEF) or (Tag0 == 0xE3) or (Tag0 == 0x83): # values
|
|
VAR_VALUE_RECORD = "<HHI{:d}s".format(Size - tlv_h_size - 8)
|
|
GuidId, VarId, Attributes, Data = struct.unpack(VAR_VALUE_RECORD, value)
|
|
value_list[VarId] = (GuidId, Attributes, Data, Tag0, Tag1)
|
|
elif not ((Tag0 == 0xff) and (Tag1 == 0xff) and (Size == 0xffff)):
|
|
pass
|
|
var_count = len(var_list)
|
|
var_list.sort()
|
|
var1 = {}
|
|
for i in var_list:
|
|
name = i[0]
|
|
VarId = i[1]
|
|
#NameTag0 = i[2]
|
|
#NameTag1 = i[3]
|
|
if VarId in value_list:
|
|
var_value = value_list[VarId]
|
|
else:
|
|
# Value not found for VarId
|
|
continue
|
|
GuidId = var_value[0]
|
|
guid = "NONE"
|
|
if GuidId not in guid_map:
|
|
# Guid not found for GuidId
|
|
pass
|
|
else:
|
|
guid = guid_map[GuidId]
|
|
if name not in variables.keys():
|
|
variables[name] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[name].append((start, None, None, var_value[2], guid, var_value[1]))
|
|
fof = fof + Length
|
|
return variables
|
|
|
|
|
|
|
|
#
|
|
# Uncomment if you want to parse output buffer returned by NtEnumerateSystemEnvironmentValuesEx
|
|
# using 'chipsec_util uefi nvram' command
|
|
#
|
|
#
|
|
# Windows 8 NtEnumerateSystemEnvironmentValuesEx (infcls = 2)
|
|
#
|
|
#def guid_str(guid0, guid1, guid2, guid3):
|
|
# return ( "{:08X}-{:04X}-{:04X}-{:4}-{:6}".format(guid0, guid1, guid2, guid3[:2].encode('hex').upper(), guid3[-6::].encode('hex').upper()) )
|
|
#
|
|
#class EFI_HDR_WIN( namedtuple('EFI_HDR_WIN', 'Size DataOffset DataSize Attributes guid0 guid1 guid2 guid3') ):
|
|
# __slots__ = ()
|
|
# def __str__(self):
|
|
# return """
|
|
#Header (Windows)
|
|
#----------------
|
|
#VendorGuid= {{:08X}-{:04X}-{:04X}-{:4}-{:6}}
|
|
#Size = 0x{:08X}
|
|
#DataOffset= 0x{:08X}
|
|
#DataSize = 0x{:08X}
|
|
#Attributes= 0x{:08X}
|
|
#""".format( self.guid0, self.guid1, self.guid2, self.guid3[:2].encode('hex').upper(), self.guid3[-6::].encode('hex').upper(), self.Size, self.DataOffset, self.DataSize, self.Attributes )
|
|
"""
|
|
def getEFIvariables_NtEnumerateSystemEnvironmentValuesEx2( nvram_buf ):
|
|
start = 0
|
|
buffer = nvram_buf
|
|
bsize = len(buffer)
|
|
header_fmt = "<IIIIIHH8s"
|
|
header_size = struct.calcsize( header_fmt )
|
|
variables = dict()
|
|
off = 0
|
|
while (off + header_size) < bsize:
|
|
efi_var_hdr = EFI_HDR_WIN( *struct.unpack_from( header_fmt, buffer[ off : off + header_size ] ) )
|
|
|
|
next_var_offset = off + efi_var_hdr.Size
|
|
efi_var_buf = buffer[ off : next_var_offset ]
|
|
efi_var_data = buffer[ off + efi_var_hdr.DataOffset : off + efi_var_hdr.DataOffset + efi_var_hdr.DataSize ]
|
|
|
|
#efi_var_name = "".join( buffer[ start + header_size : start + efi_var_hdr.DataOffset ] ).decode('utf-16-le')
|
|
str_fmt = "{:d}s".format(efi_var_hdr.DataOffset - header_size)
|
|
s, = struct.unpack( str_fmt, buffer[ off + header_size : off + efi_var_hdr.DataOffset ] )
|
|
efi_var_name = unicode(s, "utf-16-le", errors="replace").split(u'\u0000')[0]
|
|
|
|
if efi_var_name not in variables.keys():
|
|
variables[efi_var_name] = []
|
|
# off, buf, hdr, data, guid, attrs
|
|
variables[efi_var_name].append( (off, efi_var_buf, efi_var_hdr, efi_var_data, guid_str(efi_var_hdr.guid0, efi_var_hdr.guid1, efi_var_hdr.guid2, efi_var_hdr.guid3), efi_var_hdr.Attributes) )
|
|
|
|
if 0 == efi_var_hdr.Size: break
|
|
off = next_var_offset
|
|
|
|
return variables
|
|
# return ( start, next_var_offset, efi_var_buf, efi_var_hdr, efi_var_name, efi_var_data, guid_str(efi_var_hdr.guid0, efi_var_hdr.guid1, efi_var_hdr.guid2, efi_var_hdr.guid3), efi_var_hdr.Attributes )
|
|
"""
|
|
|
|
|
|
#################################################################################################3
|
|
# Decoding S3 Resume Boot Script
|
|
#################################################################################################3
|
|
|
|
class S3BootScriptType:
|
|
EFI_BOOT_SCRIPT_TYPE_DEFAULT = 0x00
|
|
EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT = 0xAA
|
|
|
|
|
|
def decode_s3bs_opcode( s3bootscript_type, script_data ):
|
|
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == s3bootscript_type:
|
|
return decode_s3bs_opcode_edkcompat( script_data )
|
|
else:
|
|
return decode_s3bs_opcode_def( script_data )
|
|
|
|
def encode_s3bs_opcode( s3bootscript_type, op ):
|
|
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == s3bootscript_type:
|
|
return encode_s3bs_opcode_edkcompat( op )
|
|
else:
|
|
return encode_s3bs_opcode_def( op )
|
|
|
|
|
|
def decode_s3bs_opcode_def( data ):
|
|
opcode = None
|
|
size = None
|
|
width = None
|
|
unknown = None
|
|
count = None
|
|
value = None
|
|
mask = None
|
|
|
|
op = None
|
|
opcode, = struct.unpack( '<B', data[ : 1 ] )
|
|
try:
|
|
if logger().HAL: logger().log( script_opcodes[opcode] )
|
|
except:
|
|
pass
|
|
if S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_IO_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, address, alignment, count = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, data[ size : ], value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, address, alignment, value, mask = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, None, value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, unknown, alignment, address, count = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, data[ size : ], value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, unknown, alignment, address, value, mask = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, None, value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, unknown, alignment, address, count = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, data[ size : ], value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE == opcode:
|
|
frmt = '<BBHIQQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, width, unknown, alignment, address, value, mask = struct.unpack( frmt, data[ : size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, unknown, count, None, value, mask )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE == opcode:
|
|
frmt = '<BBQBB'
|
|
size = struct.calcsize( frmt )
|
|
opcode, slave_address, command, operation, peccheck = struct.unpack( frmt, data[ : size ] )
|
|
op = op_smbus_execute( opcode, size, slave_address, command, operation, peccheck )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_STALL_OPCODE == opcode:
|
|
frmt = '<BBQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, dummy, duration = struct.unpack( frmt, data[ : size ] )
|
|
op = op_stall( opcode, size, duration )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_DISPATCH_OPCODE == opcode:
|
|
frmt = '<BBHIQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, dummy1, dummy2, dummy3, entrypoint = struct.unpack( frmt, data[ : size ] )
|
|
op = op_dispatch( opcode, size, entrypoint )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE == opcode:
|
|
frmt = '<BBHIQQ'
|
|
size = struct.calcsize( frmt )
|
|
opcode, dummy1, dummy2, dummy3, entrypoint, context = struct.unpack( frmt, data[ : size ] )
|
|
op = op_dispatch( opcode, size, entrypoint, context )
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
|
|
frmt = '<B'
|
|
size = struct.calcsize( frmt )
|
|
opcode, = struct.unpack( frmt, data[ : size ] )
|
|
op = op_terminate( opcode, size )
|
|
else:
|
|
op = op_unknown( opcode, 1 )
|
|
if logger().HAL: logger().warn( 'Unrecognized opcode {:X}'.format(opcode) )
|
|
|
|
return op
|
|
|
|
#
|
|
# @TODO: encode functions are not fully implemented
|
|
#
|
|
def encode_s3bs_opcode_def( op ):
|
|
encoded_opcode = None
|
|
|
|
if S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_IO_WRITE_OPCODE == op.opcode:
|
|
encoded_hdr = struct.pack( '<BBHIQ', op.opcode, op.width, op.address, 0x0, op.count )
|
|
if op.values is None: encoded_opcode = encoded_hdr + op.buffer
|
|
else: encoded_opcode = encoded_hdr + struct.pack( script_width_formats[op.width] * op.count, *op.values )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<BBHIQQ', op.opcode, op.width, op.address, 0x0, op.value, op.mask )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE == op.opcode or \
|
|
S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE == op.opcode:
|
|
encoded_hdr = struct.pack( '<BBHIQQ', op.opcode, op.width, op.unknown, 0x0, op.address, op.count )
|
|
if op.values is None: encoded_opcode = encoded_hdr + op.buffer
|
|
else: encoded_opcode = encoded_hdr + struct.pack( script_width_formats[op.width] * op.count, *op.values )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE == op.opcode:
|
|
frmt = '<BBHIQQQ'
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<BBHIQQQ', op.opcode, op.width, op.unknown, 0x0, op.address, op.value, op.mask )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE == op.opcode:
|
|
frmt = '<BBQBB'
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_STALL_OPCODE == op.opcode:
|
|
frmt = '<BBQ'
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_DISPATCH_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<BBHIQ', op.opcode, 0x0, 0x0, 0x0, op.entrypoint )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<BBHIQQ', op.opcode, 0x0, 0x0, 0x0, op.entrypoint, op.context )
|
|
|
|
elif S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == op.opcode:
|
|
frmt = '<B'
|
|
|
|
else:
|
|
if logger().HAL: logger().warn( 'Unrecognized opcode {:X}'.format(op.opcode) )
|
|
|
|
return encoded_opcode
|
|
|
|
|
|
def decode_s3bs_opcode_edkcompat( data ):
|
|
opcode = None
|
|
width = None
|
|
count = None
|
|
value = None
|
|
mask = None
|
|
|
|
op = None
|
|
|
|
hdr_frmt = '<HB'
|
|
header_size = struct.calcsize( hdr_frmt )
|
|
opcode, size = struct.unpack( hdr_frmt, data[ : header_size ] )
|
|
opcode_data = data[ header_size : ]
|
|
try:
|
|
if logger().HAL: logger().log( script_opcodes[opcode] )
|
|
except:
|
|
pass
|
|
|
|
if S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_IO_WRITE_OPCODE == opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE == opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE == opcode:
|
|
|
|
frmt = '<IIQ'
|
|
op_size = struct.calcsize( frmt )
|
|
width, count, address = struct.unpack( frmt, opcode_data[ : op_size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, None, count, opcode_data[ op_size : ], value, mask )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE == opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE == opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE == opcode:
|
|
frmt = '<IQ'
|
|
sz = struct.calcsize( frmt )
|
|
width, address = struct.unpack( frmt, opcode_data[ : sz ] )
|
|
frmt = 2*script_width_formats[width]
|
|
op_size = sz + struct.calcsize( frmt )
|
|
value, mask = struct.unpack( frmt, opcode_data[ sz : op_size ] )
|
|
op = op_io_pci_mem( opcode, size, width, address, None, count, None, value, mask )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE == opcode:
|
|
if logger().UTIL_TRACE or logger().HAL: logger().warn( 'Cannot parse opcode {:X} yet'.format(opcode) )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_STALL_OPCODE == opcode:
|
|
frmt = '<Q'
|
|
op_size = struct.calcsize( frmt )
|
|
duration, = struct.unpack( frmt, opcode_data[ : op_size ] )
|
|
op = op_stall( opcode, size, duration )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_DISPATCH_OPCODE == opcode:
|
|
frmt = '<Q'
|
|
op_size = struct.calcsize( frmt )
|
|
entrypoint, = struct.unpack( frmt, opcode_data[ : op_size ] )
|
|
op = op_dispatch( opcode, size, entrypoint )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_POLL_OPCODE == opcode:
|
|
frmt = '<IQQQ'
|
|
op_size = struct.calcsize( frmt )
|
|
width, address, duration, looptimes = struct.unpack( frmt, opcode_data[ : op_size ] )
|
|
op = op_mem_poll( opcode, size, width, address, duration, looptimes )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
|
|
op = op_terminate( opcode, size )
|
|
|
|
else:
|
|
op = op_unknown( opcode, size )
|
|
if logger().HAL: logger().warn( 'Unrecognized opcode {:X}'.format(opcode) )
|
|
|
|
return op
|
|
|
|
#
|
|
# @TODO: encode functions are not fully implemented
|
|
#
|
|
def encode_s3bs_opcode_edkcompat( op ):
|
|
encoded_opcode = None
|
|
|
|
if S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_IO_WRITE_OPCODE == op.opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_PCI_CONFIG_WRITE_OPCODE == op.opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_WRITE_OPCODE == op.opcode:
|
|
|
|
encoded_hdr = struct.pack( '<IIQ', op.width, op.count, op.address )
|
|
if op.values is None: encoded_opcode = encoded_hdr + op.buffer
|
|
else: encoded_opcode = encoded_hdr + struct.pack( script_width_formats[op.width] * op.count, *op.values )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE == op.opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE == op.opcode or \
|
|
S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_READ_WRITE_OPCODE == op.opcode:
|
|
|
|
frmt = '<IQ2{}'.format(script_width_formats[op.width])
|
|
encoded_opcode = struct.pack( frmt, op.width, op.address, op.value, op.mask )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_SMBUS_EXECUTE_OPCODE == op.opcode:
|
|
pass
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_STALL_OPCODE == op.opcode:
|
|
frmt = '<Q'
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_DISPATCH_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<Q', op.entrypoint )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_MEM_POLL_OPCODE == op.opcode:
|
|
encoded_opcode = struct.pack( '<IQQQ', op.width, op.address, op.duration, op.looptimes )
|
|
|
|
elif S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == op.opcode:
|
|
pass
|
|
|
|
return encoded_opcode
|
|
|
|
|
|
|
|
def parse_s3bootscript_entry( s3bootscript_type, script, off, log_script=False ):
|
|
entry_index = None
|
|
entry_length = 0
|
|
opcode = None
|
|
entry_data = None
|
|
|
|
remaining_len = len(script[off:])
|
|
|
|
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == s3bootscript_type:
|
|
fhdr = '<HB'
|
|
hdr_length = struct.calcsize(fhdr)
|
|
if remaining_len < hdr_length:
|
|
if logger().HAL: logger().warn( 'the script should have at least 0x{:X} bytes to parse next entry'.format(hdr_length) )
|
|
return (0,None)
|
|
|
|
opcode, entry_length = struct.unpack( fhdr, script[ off : off + hdr_length ] )
|
|
if S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
|
|
entry_length = hdr_length
|
|
entry_data = script[ off : off + entry_length ]
|
|
|
|
if entry_length > MAX_S3_BOOTSCRIPT_ENTRY_LENGTH:
|
|
logger().error( '[uefi] Unrecognized S3 boot script format (entry length = 0x{:X})'.format(entry_length) )
|
|
return (0,None)
|
|
|
|
s3script_entry = S3BOOTSCRIPT_ENTRY( s3bootscript_type, entry_index, off, entry_length, entry_data )
|
|
|
|
else: # S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_DEFAULT
|
|
|
|
fhdr = '<II'
|
|
hdr_length = struct.calcsize(fhdr)
|
|
f = fhdr + 'B'
|
|
if remaining_len < (hdr_length + 1):
|
|
if logger().HAL: logger().warn( 'the script should have at least 0x{:X} bytes to parse next entry'.format(hdr_length+1) )
|
|
return (0,None)
|
|
|
|
entry_index, entry_length, opcode = struct.unpack(f, script[ off : off + hdr_length + 1 ])
|
|
if S3BootScriptOpcode_MDE.EFI_BOOT_SCRIPT_TERMINATE_OPCODE == opcode:
|
|
entry_length = hdr_length + 1
|
|
entry_index = -1
|
|
entry_data = script[ off + hdr_length : off + entry_length ]
|
|
|
|
if entry_length > MAX_S3_BOOTSCRIPT_ENTRY_LENGTH:
|
|
logger().error( '[uefi] Unrecognized S3 boot script format (entry length = 0x{:X})'.format(entry_length) )
|
|
return (0,None)
|
|
|
|
s3script_entry = S3BOOTSCRIPT_ENTRY( s3bootscript_type, entry_index, off, entry_length, entry_data )
|
|
s3script_entry.header_length = hdr_length
|
|
|
|
s3script_entry.decoded_opcode = decode_s3bs_opcode( s3bootscript_type, s3script_entry.data )
|
|
|
|
if log_script: logger().log( s3script_entry )
|
|
return (opcode,s3script_entry)
|
|
|
|
|
|
def encode_s3bootscript_entry( entry ):
|
|
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == entry.script_type:
|
|
entry_hdr_buf = struct.pack( '<HB', entry.decoded_opcode.opcode, entry.length )
|
|
else: # S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_DEFAULT
|
|
entry_hdr_buf = struct.pack( '<II', entry.index, entry.length )
|
|
|
|
entry_val_buf = encode_s3bs_opcode( entry.script_type, entry.decoded_opcode )
|
|
entry_buf = None
|
|
if entry_val_buf is not None:
|
|
entry_buf = entry_hdr_buf + entry_val_buf
|
|
else:
|
|
logger().warn( 'Could not encode opcode of boot script entry (type 0x{:X})'.format(entry.script_type) )
|
|
|
|
return entry_buf
|
|
|
|
|
|
def create_s3bootscript_entry_buffer( script_type, op, index = None ):
|
|
entry_val_buf = encode_s3bs_opcode( script_type, op )
|
|
length = len(entry_val_buf);
|
|
if S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT == script_type:
|
|
length += struct.calcsize('<HB')
|
|
entry_hdr_buf = struct.pack( '<HB', op.opcode, length )
|
|
else: # S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_DEFAULT
|
|
length += struct.calcsize('<II')
|
|
entry_hdr_buf = struct.pack( '<II', index, length )
|
|
|
|
return (entry_hdr_buf + entry_val_buf)
|
|
|
|
|
|
def id_s3bootscript_type( script, log_script=False ):
|
|
script_header_length = 0
|
|
|
|
start_op, = struct.unpack('<B', script[ : 1 ])
|
|
if S3BootScriptOpcode_EdkCompat.EFI_BOOT_SCRIPT_TABLE_OPCODE == start_op:
|
|
if logger().HAL: logger().log('S3 Boot Script AA Parser')
|
|
script_type = S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_EDKCOMPAT
|
|
if log_script: logger().log( '[uefi] Start opcode 0x{:X}'.format(start_op) )
|
|
script_header_length = 1 # skip start opcode
|
|
script_header_length += 0x34
|
|
else:
|
|
if logger().HAL: logger().log('S3 Boot Script DEFAULT Parser')
|
|
script_type = S3BootScriptType.EFI_BOOT_SCRIPT_TYPE_DEFAULT
|
|
|
|
return (script_type,script_header_length)
|
|
|
|
|
|
|
|
#################################################################################################3
|
|
# EFI Variable Header Dictionary
|
|
#################################################################################################3
|
|
|
|
#
|
|
# Add your EFI variable details to the dictionary
|
|
#
|
|
# Fields:
|
|
# name func_getefivariables func_getnvstore
|
|
#
|
|
EFI_VAR_DICT = {
|
|
# UEFI
|
|
FWType.EFI_FW_TYPE_UEFI : {'name' : 'UEFI', 'func_getefivariables' : getEFIvariables_UEFI, 'func_getnvstore' : getNVstore_EFI },
|
|
FWType.EFI_FW_TYPE_UEFI_AUTH : {'name' : 'UEFI_AUTH', 'func_getefivariables' : getEFIvariables_UEFI_AUTH, 'func_getnvstore' : getNVstore_EFI_AUTH },
|
|
# Windows 8 NtEnumerateSystemEnvironmentValuesEx (infcls = 2)
|
|
#FWType.EFI_FW_TYPE_WIN : {'name' : 'WIN', 'func_getefivariables' : getEFIvariables_NtEnumerateSystemEnvironmentValuesEx2, 'func_getnvstore' : None },
|
|
# NVAR format
|
|
FWType.EFI_FW_TYPE_NVAR : {'name' : 'NVAR', 'func_getefivariables' : getEFIvariables_NVAR, 'func_getnvstore' : getNVstore_NVAR },
|
|
# $VSS NVRAM format
|
|
FWType.EFI_FW_TYPE_VSS : {'name' : 'VSS', 'func_getefivariables' : getEFIvariables_VSS, 'func_getnvstore' : getNVstore_VSS },
|
|
# $VSS Authenticated NVRAM format
|
|
FWType.EFI_FW_TYPE_VSS_AUTH : {'name' : 'VSS_AUTH', 'func_getefivariables' : getEFIvariables_VSS_AUTH, 'func_getnvstore' : getNVstore_VSS_AUTH },
|
|
# VSS2 NVRAM format
|
|
FWType.EFI_FW_TYPE_VSS2 : {'name' : 'VSS2', 'func_getefivariables' : getEFIvariables_VSS2, 'func_getnvstore' : getNVstore_VSS2 },
|
|
# VSS2 Authenticated NVRAM format
|
|
FWType.EFI_FW_TYPE_VSS2_AUTH : {'name' : 'VSS2_AUTH', 'func_getefivariables' : getEFIvariables_VSS2_AUTH, 'func_getnvstore' : getNVstore_VSS2_AUTH },
|
|
# Apple $VSS formart
|
|
FWType.EFI_FW_TYPE_VSS_APPLE : {'name' : 'VSS_APPLE', 'func_getefivariables' : getEFIvariables_VSS_APPLE, 'func_getnvstore' : getNVstore_VSS_APPLE },
|
|
# EVSA
|
|
FWType.EFI_FW_TYPE_EVSA : {'name' : 'EVSA', 'func_getefivariables' : EFIvar_EVSA, 'func_getnvstore' : getNVstore_EVSA },
|
|
}
|