def get_smst_func(rz: rzpipe.open, code_addr: int, interface: int) -> List[int]: res: List[int] = list() func = rz.cmdj(f"pdfj @ {code_addr:#x}") insns = func.get("ops", None) if insns is None: return res index = get_current_insn_index(insns, code_addr) if index is None: return res # check all instructions from index to end of function for i in range(index + 1, len(insns), 1): insn = insns[i] if "esil" not in insn: continue esil = insn["esil"].split(",") if esil[-1] == "=" and esil[-2] == "rax" and esil[-3] == "[8]": # check both for global variable and local variable if insn.get("ptr", None) == interface or get_int( esil[0]) == interface: offset = insn.get("offset", None) if offset is None: continue bb = rz.cmdj(f"pdbj @ {offset:#x}") smst = get_smst_bb(bb) if smst is not None: res.append(smst) return res
def get_xrefs_to_guids(rz: rzpipe.open, guids: List[UefiGuid]) -> List[int]: code_addrs = list() # xrefs from code for guid in guids: guid_bytes = binascii.hexlify(guid.bytes).decode() json_addrs = rz.cmdj(f"/xj {guid_bytes}") for element in json_addrs: if "offset" not in element: continue offset = element["offset"] # xrefs = rz.cmd(f"axtj @ {offset:x}") # this doesn't work in rizin, so needs to be split into two separate steps (seek + axtj) # seek to GUID location in .data segment rz.cmd(f"s {offset:#x}") # get xrefs xrefs = rz.cmdj(f"axtj") for xref in xrefs: if "from" not in xref: continue # get code address addr = xref["from"] code_addrs.append(addr) return code_addrs
def get_sw_smi_handlers(rz: rzpipe.open) -> List[SwSmiHandler]: """Find Software SMI Handlers""" res: List[SwSmiHandler] = list() guids = [ UefiGuid( "18A3C6DC-5EEA-48C8-A1C1B53389F98999", name="EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID", ), UefiGuid( "E541B773-DD11-420C-B026DF993653F8BF", name="EFI_SMM_SW_DISPATCH_PROTOCOL_GUID", ), ] code_addrs = get_xrefs_to_guids(rz, guids) for code_addr in code_addrs: # get basic block information bb = rz.cmdj(f"pdbj @ {code_addr:#x}") interface = get_interface_from_bb(bb, code_addr) if interface is None: continue # need to check the use of this interface below code_addr res += get_handlers(rz, code_addr, interface) return res
def get_child_sw_smi_handlers(rz: rzpipe.open, smst_list: List[int]) -> List[ChildSwSmiHandler]: res: List[ChildSwSmiHandler] = list() haddrs = list() # addresses for smst in smst_list: code_addrs = get_xrefs_to_data(rz, smst) for addr in code_addrs: # analyze instructions and found gSmst->SmiHandlerRegister call result = rz.cmd(f"pdj 24 @ {addr:#x}") # prevent error messages to sys.stderr from rizin: # https://github.com/rizinorg/rz-pipe/blob/0f7ac66e6d679ebb03be26bf61a33f9ccf199f27/python/rzpipe/open_base.py#L261 try: bb = json.loads(result) except (ValueError, KeyError, TypeError) as _: continue handler = get_child_sw_smi_handler_bb(rz, bb) if handler is not None: if handler.address not in haddrs: res.append(handler) haddrs.append(handler.address) return res
def get_xrefs_to_data(rz: rzpipe.open, addr: int) -> List[int]: code_addrs = list() # xrefs from code rz.cmd(f"s {addr:#x}") # get xrefs xrefs = rz.cmdj(f"axtj") for xref in xrefs: if "from" not in xref: continue # get code address addr = xref["from"] if addr not in code_addrs: code_addrs.append(addr) return code_addrs
def get_handlers(rz: rzpipe.open, code_addr: int, interface: int) -> List[SwSmiHandler]: res: List[SwSmiHandler] = list() res_addrs: List[int] = list() func = rz.cmdj(f"pdfj @ {code_addr:#x}") insns = func.get("ops", None) if insns is None: return res index = get_current_insn_index(insns, code_addr) if index is None: return res # check all instructions from index to end of function for i in range(index + 1, len(insns), 1): insn = insns[i] if "esil" not in insn: continue esil = insn["esil"].split(",") # find `mov rax, [rbp+EfiSmmSwDispatch2Protocol]` instruction if not (esil[-1] == "=" and esil[-2] == "rax"): continue value = get_int(esil[0]) if value is None: continue if value == interface: offset = insn.get("offset", None) if offset is None: continue bb = rz.cmdj(f"pdbj @ {offset:#x}") handler = get_handler(bb) if handler is not None: if handler.address not in res_addrs: res.append(handler) # prevent duplicates res_addrs.append(handler.address) return res
def get_child_sw_smi_handler_bb( rz: rzpipe.open, insns: List[Dict[str, Any]]) -> Optional[ChildSwSmiHandler]: handler_address = None handler_guid = None end_index = find_handler_register_service(insns) if end_index is None: return None for insn in insns[:end_index][::-1]: if "esil" not in insn: continue esil = insn["esil"].split(",") # try to get handler address (Handler parameter) if esil[-1] == "=" and esil[-2] == "rcx": handler_address = insn.get("ptr", None) # try to get handler guid value (HandlerType parameter) if esil[-1] == "=" and esil[-2] == "rdx": guid_addr = insn.get("ptr", None) if guid_addr is not None: rz.cmd(f"s {guid_addr:#x}") guid_b = bytes(rz.cmdj("xj 16")) handler_guid = str(uuid.UUID(bytes_le=guid_b)).upper() if handler_address is not None and handler_guid is not None: return ChildSwSmiHandler(address=handler_address, handler_guid=handler_guid) if handler_address is not None: # handler_guid is Optional return ChildSwSmiHandler(address=handler_address, handler_guid=handler_guid) return None
def get_smst_list(rz: rzpipe.open) -> List[int]: """Find SMST addresses""" res: List[int] = list() guids = [ UefiGuid("F4CCBFB7-F6E0-47FD-9DD410A8F150C191", name="EFI_SMM_BASE2_PROTOCOL_GUID") ] code_addrs = get_xrefs_to_guids(rz, guids) for code_addr in code_addrs: bb = rz.cmdj(f"pdbj @ {code_addr:#x}") interface = get_interface_global(bb, code_addr) if interface is None: continue res += get_smst_func(rz, code_addr, interface) return res