Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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