Align UEFI structures with all other OS

This commit is contained in:
elicn
2024-08-01 13:36:10 +03:00
parent 334fe70c58
commit b5477ec10e
12 changed files with 65 additions and 125 deletions
+1 -1
View File
@@ -161,7 +161,7 @@ class QlLoaderPE_UEFI(QlLoader):
for handle in context.loaded_image_protocol_modules:
struct_addr = context.protocols[handle][self.loaded_image_protocol_guid]
loaded_image_protocol = EfiLoadedImageProtocol.EFI_LOADED_IMAGE_PROTOCOL.loadFrom(self.ql, struct_addr)
loaded_image_protocol = EfiLoadedImageProtocol.EFI_LOADED_IMAGE_PROTOCOL.load_from(self.ql.mem, struct_addr)
unload_ptr = loaded_image_protocol.Unload.value
+3 -60
View File
@@ -10,6 +10,8 @@ from contextlib import contextmanager
from functools import lru_cache
from typing import TYPE_CHECKING, Mapping, Sequence, Union, Optional
from qiling.os.struct import BaseStructEL
if TYPE_CHECKING:
from qiling import Qiling
@@ -51,72 +53,13 @@ BOOLEAN = UINT8
CHAR8 = UINT8
CHAR16 = UINT16
STRUCT = BaseStructEL
UNION = ctypes.Union
CPU_STACK_ALIGNMENT = 16
PAGE_SIZE = 0x1000
class STRUCT(ctypes.LittleEndianStructure):
"""An abstract class for C structures.
"""
# Structures are packed by default; when needed, padding should be added
# manually through placeholder fields
_pack_ = 1
def __init__(self):
pass
def saveTo(self, ql: Qiling, address: int) -> None:
"""Store self contents to a specified memory address.
"""
data = bytes(self)
ql.mem.write(address, data)
@classmethod
def loadFrom(cls, ql: Qiling, address: int) -> 'STRUCT':
"""Construct an instance of the structure from saved contents.
"""
data = bytes(ql.mem.read(address, cls.sizeof()))
return cls.from_buffer_copy(data)
@classmethod
@contextmanager
def bindTo(cls, ql: Qiling, address: int):
instance = cls.loadFrom(ql, address)
try:
yield instance
finally:
instance.saveTo(ql, address)
@classmethod
def sizeof(cls) -> int:
"""Get the C structure size in bytes.
"""
return ctypes.sizeof(cls)
@classmethod
def offsetof(cls, fname: str) -> int:
"""Get the offset of a field in the C structure.
"""
return getattr(cls, fname).offset
@classmethod
def memberat(cls, offset: int) -> Optional[str]:
"""Get the member name at a given offset.
"""
return next((fname for fname, *_ in cls._fields_ if cls.offsetof(fname) == offset), None)
class EnumMeta(type(ctypes.c_int)):
def __getattr__(self, key):
return self._members_.index(key)
+2 -2
View File
@@ -594,8 +594,8 @@ def initialize(ql: Qiling, gBS: int):
ql.os.monotonic_count = 0
instance = init_struct(ql, gBS, descriptor)
instance.saveTo(ql, gBS)
instance.save_to(ql.mem, gBS)
__all__ = [
'initialize'
]
]
+8 -8
View File
@@ -53,7 +53,7 @@ class UefiContext(ABC):
address = self.heap.alloc(struct_class.sizeof())
instance = utils.init_struct(self.ql, address, proto_desc)
instance.saveTo(self.ql, address)
instance.save_to(self.ql.mem, address)
self.protocols[handle][guid] = address
return self.notify_protocol(handle, guid, address, from_hook)
@@ -66,7 +66,7 @@ class UefiContext(ABC):
# and update it here.
guid = utils.str_to_guid(protocol)
guid_ptr = self.heap.alloc(guid.sizeof())
guid.saveTo(self.ql, guid_ptr)
guid.save_to(self.ql.mem, guid_ptr)
event_dic['CallbackArgs'] = [guid_ptr, interface, handle]
@@ -135,10 +135,10 @@ class UefiConfTable:
ptr = self.baseptr + self.nitems * EFI_CONFIGURATION_TABLE.sizeof()
append = True
instance = EFI_CONFIGURATION_TABLE()
instance.VendorGuid = utils.str_to_guid(guid)
instance.VendorTable = table
instance.saveTo(self.ql, ptr)
EFI_CONFIGURATION_TABLE(
VendorGuid = utils.str_to_guid(guid),
VendorTable = table
).save_to(self.ql.mem, ptr)
if append:
self.nitems += 1
@@ -149,7 +149,7 @@ class UefiConfTable:
efi_guid = utils.str_to_guid(guid)
for _ in range(nitems):
entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr)
entry = EFI_CONFIGURATION_TABLE.load_from(self.ql.mem, ptr)
if utils.CompareGuid(entry.VendorGuid, efi_guid):
return ptr
@@ -162,7 +162,7 @@ class UefiConfTable:
ptr = self.find(guid)
if ptr is not None:
entry = EFI_CONFIGURATION_TABLE.loadFrom(self.ql, ptr)
entry = EFI_CONFIGURATION_TABLE.load_from(self.ql.mem, ptr)
return entry.VendorTable.value
+1 -1
View File
@@ -275,7 +275,7 @@ def initialize(ql: Qiling, gDS: int):
}
instance = init_struct(ql, gDS, descriptor)
instance.saveTo(ql, gDS)
instance.save_to(ql.mem, gDS)
__all__ = [
'EFI_DXE_SERVICES',
+9 -9
View File
@@ -36,7 +36,7 @@ def GetHobList(ql: Qiling, context: UefiContext) -> int:
return hoblist_vend
def CreateHob(ql: Qiling, context: UefiContext, hob) -> int:
def CreateHob(ql: Qiling, context: UefiContext, hob: STRUCT) -> int:
"""Add a HOB to the end of the HOB list.
"""
@@ -48,15 +48,15 @@ def CreateHob(ql: Qiling, context: UefiContext, hob) -> int:
# overwrite end marker with the hob
pHob = hoblist
hob.saveTo(ql, pHob)
hob.save_to(ql.mem, pHob)
hoblist += hob.sizeof()
# create a new end marker istead, following the hob
marker = EFI_HOB_GENERIC_HEADER()
marker.HobType = EFI_HOB_TYPE_END_OF_HOB_LIST
marker.HobLength = 0x0000
marker.Reserved = 0x00000000
marker.saveTo(ql, hoblist)
EFI_HOB_GENERIC_HEADER(
HobType = EFI_HOB_TYPE_END_OF_HOB_LIST,
HobLength = 0x0000,
Reserved = 0x00000000
).save_to(ql.mem, hoblist)
# return the address the hob was written to; it might be useful
return pHob
@@ -68,7 +68,7 @@ def GetNextHob(ql: Qiling, hobtype: int, hoblist: int) -> int:
hobaddr = hoblist
while True:
header = EFI_HOB_GENERIC_HEADER.loadFrom(ql, hobaddr)
header = EFI_HOB_GENERIC_HEADER.load_from(ql.mem, hobaddr)
# found the hob?
if header.HobType == hobtype:
@@ -95,7 +95,7 @@ def GetNextGuidHob(ql: Qiling, guid: str, hoblist: int) -> int:
if not hobaddr:
return 0
hob = EFI_HOB_GUID_TYPE.loadFrom(ql, hobaddr)
hob = EFI_HOB_GUID_TYPE.load_from(ql.mem, hobaddr)
if CompareGuid(hob.Name, hobguid):
break
@@ -47,7 +47,7 @@ class EFI_SMM_ACCESS2_PROTOCOL(STRUCT):
def hook_Open(ql: Qiling, address: int, params):
this = params["This"]
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
struct.OpenState = True
return EFI_SUCCESS
@@ -58,7 +58,7 @@ def hook_Open(ql: Qiling, address: int, params):
def hook_Close(ql: Qiling, address: int, params):
this = params["This"]
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
struct.OpenState = False
return EFI_SUCCESS
@@ -69,7 +69,7 @@ def hook_Close(ql: Qiling, address: int, params):
def hook_Lock(ql: Qiling, address: int, params):
this = params["This"]
with EFI_SMM_ACCESS2_PROTOCOL.bindTo(ql, this) as struct:
with EFI_SMM_ACCESS2_PROTOCOL.ref(ql.mem, this) as struct:
struct.LockState = True
return EFI_SUCCESS
@@ -143,7 +143,7 @@ def hook_GetCapabilities(ql: Qiling, address: int, params):
return EFI_BUFFER_TOO_SMALL
this = params["This"]
struct = EFI_SMM_ACCESS2_PROTOCOL.loadFrom(ql, this)
struct = EFI_SMM_ACCESS2_PROTOCOL.load_from(ql.mem, this)
state = EFI_CACHEABLE
state |= EFI_SMRAM_OPEN if struct.OpenState else EFI_SMRAM_CLOSED
@@ -152,13 +152,12 @@ def hook_GetCapabilities(ql: Qiling, address: int, params):
MmramMap = params["MmramMap"]
for i, ch in enumerate(chunks):
desc = EFI_SMRAM_DESCRIPTOR()
desc.PhysicalStart = ch[0]
desc.CpuStart = ch[0]
desc.PhysicalSize = ch[1] - ch[0]
desc.RegionState = state | (EFI_ALLOCATED if ch[2] else 0)
desc.saveTo(ql, MmramMap + (i * desc.sizeof()))
EFI_SMRAM_DESCRIPTOR(
PhysicalStart = ch[0],
CpuStart = ch[0],
PhysicalSize = ch[1] - ch[0],
RegionState = state | (EFI_ALLOCATED if ch[2] else 0)
).save_to(ql.mem, MmramMap + (i * EFI_SMRAM_DESCRIPTOR.sizeof()))
return EFI_SUCCESS
@@ -55,7 +55,7 @@ def hook_Register(ql: Qiling, address: int, params):
handlers = ql.loader.smm_context.swsmi_handlers
SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.loadFrom(ql, RegisterContext)
SwRegisterContext = EFI_SMM_SW_REGISTER_CONTEXT.load_from(ql.mem, RegisterContext)
idx = SwRegisterContext.SwSmiInputValue
# a value of -1 indicates that the swsmi index for this handler is flexible and
@@ -67,10 +67,10 @@ def hook_Register(ql: Qiling, address: int, params):
return EFI_OUT_OF_RESOURCES
SwRegisterContext.SwSmiInputValue = idx
SwRegisterContext.saveTo(ql, RegisterContext)
SwRegisterContext.save_to(ql.mem, RegisterContext)
else:
This = EFI_SMM_SW_DISPATCH2_PROTOCOL.loadFrom(ql, params['This'])
This = EFI_SMM_SW_DISPATCH2_PROTOCOL.load_from(ql.mem, params['This'])
if idx in handlers:
return EFI_INVALID_PARAMETER
+14 -15
View File
@@ -34,21 +34,20 @@ def hook_GetTime(ql: Qiling, address: int, params):
localtime = time.localtime()
efitime = EFI_TIME()
efitime.Year = localtime.tm_year
efitime.Month = localtime.tm_mon
efitime.Day = localtime.tm_mday
efitime.Hour = localtime.tm_hour
efitime.Minute = localtime.tm_min
efitime.Second = localtime.tm_sec
efitime.Nanosecond = 0
EFI_TIME(
Year = localtime.tm_year,
Month = localtime.tm_mon,
Day = localtime.tm_mday,
Hour = localtime.tm_hour,
Minute = localtime.tm_min,
Second = localtime.tm_sec,
Nanosecond = 0,
# tz and dst settings are stored in the "RtcTimeSettings" nvram variable.
# we just use the default settings instead
efitime.TimeZone = EFI_UNSPECIFIED_TIMEZONE
efitime.Daylight = 0
efitime.saveTo(ql, Time)
# tz and dst settings are stored in the "RtcTimeSettings" nvram variable.
# we just use the default settings instead
TimeZone = EFI_UNSPECIFIED_TIMEZONE,
Daylight = 0
).save_to(ql.mem, Time)
return EFI_SUCCESS
@@ -296,7 +295,7 @@ def initialize(ql: Qiling, gRT: int):
}
instance = init_struct(ql, gRT, descriptor)
instance.saveTo(ql, gRT)
instance.save_to(ql.mem, gRT)
__all__ = [
'initialize'
+7 -7
View File
@@ -219,17 +219,17 @@ class SmmEnv:
CommBufferSize = heap.alloc(ql.arch.pointersize)
# setup Context
args['RegisterContext'].saveTo(ql, Context)
args['RegisterContext'].save_to(ql.mem, Context)
# setup CommBuffer
SmmSwContext = EFI_SMM_SW_CONTEXT()
SmmSwContext.SwSmiCpuIndex = cpu
SmmSwContext.CommandPort = idx
SmmSwContext.DataPort = 0
SmmSwContext.saveTo(ql, CommBuffer)
EFI_SMM_SW_CONTEXT(
SwSmiCpuIndex = cpu,
CommandPort = idx,
DataPort = 0
).save_to(ql.mem, CommBuffer)
# setup CommBufferSize
ql.mem.write_ptr(CommBufferSize, SmmSwContext.sizeof(), 8)
ql.mem.write_ptr(CommBufferSize, EFI_SMM_SW_CONTEXT.sizeof(), 8)
# clean up handler resources
def __cleanup(ql: Qiling):
+1 -1
View File
@@ -278,7 +278,7 @@ def initialize(ql: Qiling, context, gSmst: int):
}
instance = init_struct(ql, gSmst, descriptor)
instance.saveTo(ql, gSmst)
instance.save_to(ql.mem, gSmst)
install_configuration_table(context, "HOB_LIST", None)
install_configuration_table(context, "SMM_RUNTIME_SERVICES_TABLE", gSmmRT)
+6 -7
View File
@@ -67,13 +67,12 @@ def initialize(ql: Qiling, context: UefiContext, gST: int):
rt.initialize(ql, gRT)
ds.initialize(ql, gDS)
instance = EFI_SYSTEM_TABLE()
instance.RuntimeServices = gRT
instance.BootServices = gBS
instance.NumberOfTableEntries = 0
instance.ConfigurationTable = cfg
instance.saveTo(ql, gST)
EFI_SYSTEM_TABLE(
RuntimeServices = gRT,
BootServices = gBS,
NumberOfTableEntries = 0,
ConfigurationTable = cfg
).save_to(ql.mem, gST)
install_configuration_table(context, "HOB_LIST", None)
install_configuration_table(context, "DXE_SERVICE_TABLE", gDS)