def __PltResolver(jmprel, strtab, symtab):
     idx = 0
     while True:
         r_off = idc.get_qword(jmprel + 0x18 * idx)
         r_info1 = idc.get_wide_dword(jmprel + 0x18 * idx + 0x8)
         r_info2 = idc.get_wide_dword(jmprel + 0x18 * idx + 0xc)
         r_addend = idc.get_qword(jmprel + 0x18 * idx + 0x10)
         if r_off > 0x7fffffff:
             return
         if r_info1 == 7:
             st_name = idc.get_wide_dword(symtab + r_info2 * 0x18)
             name = idc.get_strlit_contents(strtab + st_name)
             # rename got
             idc.set_name(r_off, name.decode("ascii") + '_ptr')
             plt_func = idc.get_qword(r_off)
             if debug_mode:
                 print(hex(plt_func.start_ea), name)
             # rename plt
             idc.set_name(plt_func, 'j_' + name.decode("ascii"))
             SetFuncFlags(plt_func)
             # rename plt.sec
             for addr in idautils.DataRefsTo(r_off):
                 plt_sec_func = idaapi.get_func(addr)
                 if plt_sec_func:
                     plt_sec_func_addr = plt_sec_func.start_ea
                     idc.set_name(plt_sec_func_addr,
                                  '_' + name.decode("ascii"))
                     SetFuncFlags(plt_sec_func_addr)
                 else:
                     print("[!] idaapi.get_func({}) failed".format(
                         hex(addr)))
         idx += 1
示例#2
0
    def __init__(self, objc_class_va, segment_map, arch=ARCH_X86_64):
        """Create a new ObjcClass instance
                
        Arguments:
            objc_class_va {number} -- Virtual address of the Objective-C class to parse
            segment_map {dictionary} -- A dictionary mapping segment names to a start/end virtual address tuple
        
        Keyword Arguments:
            arch {number} -- CPU architecture. Either ARCH_X86_64 or ARM64 (default: {ARCH_X86_64})
        """
        self.arch = arch
        self.segment_map = segment_map
        class_ro_va = get_qword(objc_class_va + self.OBJC2_CLASS_RO_OFFSET)
        self.name_pointer = get_qword(class_ro_va +
                                      self.OBJC2_CLASS_RO_NAME_OFFSET)
        self.method_list = []
        if class_ro_va == BADADDR or class_ro_va == 0:
            self.class_ro_va = None
            return
        self.class_ro_va = class_ro_va

        class_methods_va = get_qword(class_ro_va +
                                     self.OBJC2_CLASS_RO_BASE_METHODS_OFFSET)

        if class_methods_va == BADADDR or class_methods_va == 0:
            self.class_methods_va = None
            return
        self.class_methods_va = class_methods_va
        msg("Class found at virtual address: 0x%x\n" % objc_class_va)
        msg("Class name: %s\n" % get_strlit_contents(self.name_pointer))
        #Parse the method_list_t struct and build a list of methods
        self.method_list = ObjcMethodList(class_methods_va,
                                          segment_map,
                                          arch=arch)
示例#3
0
    def resolve(self, alphabet, nids, symbols, libraries):

        if self.INFO > Relocation.R_X86_64_ORBIS_GOTPCREL_LOAD:
            self.INDEX = self.INFO >> 32
            self.INFO &= 0xFF
            symbol = next(value for key, value in enumerate(symbols)
                          if key + 2 == self.INDEX)[1]
        else:
            self.INDEX = 0

        # Library
        try:
            lid1 = alphabet[symbol[12:13]]

            # [base64]#
            if symbol[13:14] == '#':
                library = libraries[lid1]

            # [base64][base64]#
            elif symbol[14:15] == '#':
                lid2 = alphabet[symbol[13:14]]
                library = libraries[lid1 + lid2]

            else:
                raise

        # Not a NID
        except:
            library = ''

        # Function Name (Offset) == Symbol Value + AddEnd (S + A)
        # Library Name  (Offset) == Symbol Value (S)
        # Resolve the NID...
        idc.set_cmt(idc.get_qword(self.OFFSET) - 0x6, 'NID: ' + symbol, False)
        function = nids.get(symbol[:11], symbol)

        # Rename the Jump Function...
        idc.set_name(self.OFFSET, '__imp_' + function,
                     SN_NOCHECK | SN_NOWARN | SN_FORCE)

        # Rename the Real Function...
        idc.add_func(idc.get_qword(self.OFFSET) - 0x6)
        idc.set_name(
            idc.get_qword(self.OFFSET) - 0x6, function, SN_NOCHECK | SN_NOWARN)

        try:
            import_node = idaapi.netnode(library, 0, True)
            import_node.supset(ea2node(self.OFFSET), function)

            # Requires customized loader.i / ida_loader.py(d)
            idaapi.import_module(library, None, import_node.index(), None,
                                 'linux')

        except:
            pass

        return self.type()
 def GetDyn():
     phoff = idc.get_qword(ida_ida.inf_get_min_ea() +
                           0x20) + ida_ida.inf_get_min_ea()
     phnum = idc.get_wide_word(ida_ida.inf_get_min_ea() + 0x38)
     phentsize = idc.get_wide_word(ida_ida.inf_get_min_ea() + 0x36)
     for i in range(phnum):
         p_type = idc.get_wide_dword(phoff + phentsize * i)
         if p_type == 2:  # PY_DYNAMIC
             dyn_addr = idc.get_qword(phoff + phentsize * i + 0x10)
             return dyn_addr
 def ParseDyn(dyn, tag):
     idx = 0
     while True:
         v1, v2 = idc.get_qword(dyn +
                                idx * 0x10), idc.get_qword(dyn +
                                                           idx * 0x10 + 8)
         if v1 == 0 and v2 == 0:
             return
         if v1 == tag:
             return v2
         idx += 1
示例#6
0
    def __init__(self, method_va, segment_map):
        """Do not instantiate directly
        
        Arguments:
            method_va
            segment_map
        """
        msg("Found method at virtual address: 0x%x\n" % method_va)

        self.method_va = method_va
        self.segment_map = segment_map

        self.name_pointer = get_qword(method_va)
        self.method_type = get_qword(method_va + self.OBJC_METHOD_TYPE_OFFSET)
        self.method_pointer_va = method_va + self.OBJC_METHOD_IMP_OFFSET
        self.method_pointer = get_qword(self.method_pointer_va)
        self.patched_xrefs = []
        objc_selrefs = segment_map["__objc_selrefs"]
        objc_msgrefs = segment_map["__objc_msgrefs"]
        objc_const = segment_map["__objc_const"]
        msg("Method name: %s\n" % get_func_name(self.method_pointer))
        is_msg_ref, selector_ref, const_ref_count = self.get_xref(
            objc_selrefs, objc_msgrefs, objc_const)
        self.is_msg_ref = is_msg_ref
        self.const_ref_count = const_ref_count
        if not selector_ref:
            msg("No selref found.\n")
            self.selector_ref = None
            return
        if const_ref_count == 1:
            #We can only work with unambiguous situations where there is exactly one const reference
            #to the selector.
            self.selector_ref = selector_ref
        else:
            msg("Selector ref count not exactly 1. Potentially ambiguous: %d" %
                const_ref_count)
            # Otherwise this same selector is used by more than one class. (Or none at all)
            self.selector_ref = None
            return

        self.sel_ref_va = self.selector_ref.frm
        if is_msg_ref:
            # adjust pointer to beginning of message ref struct to get xrefs
            self.sel_ref_va -= POINTER_SIZE

        msg("selref VA: 0x%X - function VA: 0x%X\n" %
            (self.sel_ref_va, self.method_pointer))
        #Find all the references to this *selref* (note: not the string itself but the selref)
        #These should precede calls to the method
        #Patch the references to the selref with a reference to the method implementation
        self.walk_selector_refs()
示例#7
0
def assign_kmdf_structure_types(address):
    # Get the jmp to de import
    jmp_import_ea = next(idautils.XrefsTo(address)).frm
    # There is only one XREF to WdfVersionBind
    call_wdfVersionBind = next(idautils.XrefsTo(jmp_import_ea)).frm
    print(hex(call_wdfVersionBind))
    argument_WdfBindInfo = find_function_arg(call_wdfVersionBind, "lea", "r8",
                                             0)
    if argument_WdfBindInfo is None:
        print("Error: Argument WdfBindInfo wasn't found!")
        return
    wdfBindInfo = idc.get_operand_value(argument_WdfBindInfo, 1)
    idc.set_name(wdfBindInfo, '_WdfBindInfo')
    print("WdfBindInfo Struct: ", hex(wdfBindInfo))
    if not assign_struct_to_address(wdfBindInfo, "_WDF_BIND_INFO"):
        print("The _WDF_BIND_INFO struct wasn't found in the database")
        return
    g_vars["_WDF_BIND_INFO"] = wdfBindInfo

    # Assign ComponentGlobals Name
    argument_WdfComponentGlobals = find_function_arg(call_wdfVersionBind,
                                                     "lea", "r9", 0)
    wdfComponentGlobals = idc.get_operand_value(argument_WdfComponentGlobals,
                                                1)
    g_vars["_WDF_COMPONENT_GLOBALS"] = wdfComponentGlobals
    idc.set_name(wdfComponentGlobals, '_WdfComponentGlobals')

    # Now assign the WDFFUNCTIONS to FuncTable
    wdfFunctions = idc.get_qword(wdfBindInfo + 0x20)
    g_vars["_WDFFUNCTIONS"] = wdfFunctions
    assign_struct_to_address(wdfFunctions, "_WDFFUNCTIONS")
    idc.set_name(wdfFunctions, 'g_WdfF_Functions')
示例#8
0
    def extract_info_from_IDA(self):
        prots = ida_bytes.get_qword(self.ea + 0x10)
        if prots:
            count = ida_bytes.get_qword(prots)
            entrysize = 0x8
            p_ea = prots + 8
            for i in range(count):
                proto_ea = idc.get_qword(p_ea)
                self.prots.append(proto_ea)
                p_ea += entrysize

        type_info = ida_bytes.get_qword(self.ea + 0x48)
        for idx in range(0, 4):
            # 0: inst_meths
            # 1: class_meths
            # 2: opt_inst_meths
            # 3: opt_class_meths
            meth_list = ida_bytes.get_qword(self.ea + 0x18 + idx * 8)
            if meth_list:
                entrysize = ida_bytes.get_dword(meth_list)
                count = ida_bytes.get_dword(meth_list + 4)
                ea = meth_list + 8
                for i in range(0, count):
                    sel = idc.get_bytes(idc.Qword(ea), idc.get_item_size(idc.Qword(ea)) - 1)
                    meth_type = idc.get_bytes(idc.Qword(type_info), idc.get_item_size(idc.Qword(type_info)) - 1)
                    self.meths[sel] = meth_type
                    ea += entrysize
                    type_info += 8
示例#9
0
    def req_patch(self, hash):
        addr, value, length = hash['addr'], hash['value'], hash['len']

        if length == 4:
            prev_value = idc.get_wide_dword(addr)
            if not ida_bytes.create_data(ea, FF_DWORD, 4, ida_idaapi.BADADDR):
                rs_log('[x] ida_bytes.create_data FF_DWORD failed')
            if not ida_bytes.patch_dword(addr, value):
                rs_log('[x] patch_dword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                rs_log('[x] op_plain_offset failed')

        elif length == 8:
            prev_value = idc.get_qword(addr)
            if not ida_bytes.create_data(addr, FF_QWORD, 8,
                                         ida_idaapi.BADADDR):
                rs_log('[x] ida_bytes.create_data FF_QWORD failed')
            if not ida_bytes.patch_qword(addr, value):
                rs_log('[x] patch_qword failed')
            if not idc.op_plain_offset(addr, 0, 0):
                rs_log('[x] op_plain_offset failed')

        else:
            rs_log("[x] unsupported length: %d" % length)
            return

        rs_log("patched 0x%x = 0x%x (previous was 0x%x)" %
               (addr, value, prev_value))
示例#10
0
    def getDbgMem(ea, size):
        b = b''
        for i in range(0, (size & (~7)), 8):
            b += struct.pack("<Q", idc.get_qword(ea + i))

        for i in range(size & 7):
            b += struct.pack("<B", idc.Byte(ea + (size & (~7)) + i))

        return b
示例#11
0
 def _getOriginData(self, address, size):
     res = []
     for offset in range(0, size, 64):
         tmp = get_bytes(address + offset, 64)
         if tmp == None:
             res.extend([pack("<Q", get_qword(address + offset + i)) for i in range(0, 64, 8)])
         else:
             res.append(tmp)
     res = b"".join(res)
     return res[:size]
示例#12
0
    def extract_info_from_IDA(self):
        for xref in idautils.XrefsTo(self.ea):
            frm = xref.frm
            if idc.SegName(frm) == '__objc_classrefs':
                self.classref = frm
            if idc.SegName(frm) == '__objc_superrefs':
                self.superref = frm

        base_ivars = ida_bytes.get_qword(self.info + 0x30)
        if base_ivars and idc.SegName(base_ivars) == '__objc_const':
            entrysize = ida_bytes.get_dword(base_ivars)
            count = ida_bytes.get_dword(base_ivars + 4)
            ea = base_ivars + 8
            for i in range(count):
                offset = ida_bytes.get_dword(idc.get_qword(ea))
                _type = idc.get_bytes(idc.Qword(ea + 0X10), idc.get_item_size(idc.Qword(ea + 0X10)) - 1)
                _name = idc.get_bytes(idc.Qword(ea + 0X08), idc.get_item_size(idc.Qword(ea + 0X08)) - 1)
                # self.ivars[offset] = _type
                self.ivars[_name] = _type
                ea += entrysize

        base_props = ida_bytes.get_qword(self.info + 0x40)
        if base_props and idc.SegName(base_props) == '__objc_const':
            entrysize = ida_bytes.get_dword(base_props)
            count = ida_bytes.get_dword(base_props + 4)
            ea = base_props + 8
            for i in range(count):
                _type = idc.get_bytes(idc.Qword(ea + 0X08), idc.get_item_size(idc.Qword(ea + 0X08)) - 1)
                _name = idc.get_bytes(idc.Qword(ea), idc.get_item_size(idc.Qword(ea)) - 1)
                self.props[_name] = _type
                ea += entrysize

        base_prots = ida_bytes.get_qword(self.info + 0x28)
        if base_prots and idc.SegName(base_prots) == '__objc_const':
            count = ida_bytes.get_qword(base_prots)
            entrysize = 0x8
            p_ea = base_prots + 8
            for i in range(count):
                proto_ea = idc.get_qword(p_ea)
                self.prots.append(proto_ea)
                Protocol.add_implementing_class(proto_ea, self.ea)
                p_ea += entrysize
示例#13
0
def convert_pointer_to_offset(ea):
    # If this is code, skip it.
    flags = idc.get_full_flags(ea)
    if idc.is_code(flags):
        return
    # If the value at this address does not point into the kernelcache, skip it.
    value = idc.get_qword(ea)
    if not is_mapped(value, 8):
        return
    # Convert this value to a qword (in case it's unaligned) and then convert it into an
    # offset.
    idc.create_qword(ea)
    idc.op_plain_offset(ea, 0, 0)
示例#14
0
 def load(self, addr, dtyp):
     if addr is Unknown:
         return Unknown
     if not is_mapped_data(addr):
         return Unknown
     if dtyp == idaapi.dt_qword:
         return idc.get_qword(addr)
     elif dtyp == idaapi.dt_dword:
         return idc.get_wide_dword(addr)
     elif dtyp == idaapi.dt_word:
         return idc.get_wide_word(addr)
     elif dtyp == idaapi.dt_byte:
         return idc.get_wide_byte(addr)
     return Unknown
def read_word(ea, wordsize=WORD_SIZE):
    """Get the word at the given address.
    Words are read using Byte(), Word(), Dword(), or Qword(), as appropriate. Addresses are checked
    using is_mapped(). If the address isn't mapped, then None is returned.
    """
    if not is_mapped(ea, wordsize):
        return None
    if wordsize == 1:
        return idc.get_wide_byte(ea)
    if wordsize == 2:
        return idc.get_wide_word(ea)
    if wordsize == 4:
        return idc.get_wide_dword(ea)
    if wordsize == 8:
        return idc.get_qword(ea)
    raise ValueError('Invalid argument: wordsize={}'.format(wordsize))
示例#16
0
    def _defineImportThunk(self, start, thunk_val):
        """If the binary has the Import Thunk filled, define it as a data chunk of appropriate size.
        """

        info = idaapi.get_inf_structure()
        if info.is_64bit():
            curr_val = idc.get_qword(start)
            if (curr_val == thunk_val):
                return ida_bytes.create_data(start, idaapi.FF_QWORD, 8,
                                             idaapi.BADADDR)
        elif info.is_32bit():
            curr_val = ida_bytes.get_dword(start)
            if (curr_val == thunk_val):
                return ida_bytes.create_data(start, idaapi.FF_DWORD, 4,
                                             idaapi.BADADDR)
        return False
示例#17
0
def get_metaclass_for_vtable(vtable, length):
    # Get the address of the ::getMetaClass() method.
    OSObject_method_count = 12
    getMetaClass_index = 7
    if length <= OSObject_method_count:
        return None
    getMetaClass = idc.get_qword(vtable + 8 * getMetaClass_index)

    # Emulate the method to get the return value.
    class GetReturnEmulator(Arm64Emulator):
        def __init__(self):
            super(GetReturnEmulator, self).__init__()
            self.return_value = None

        def RET(self):
            self.return_value = self.regs['X0']

    emulator = GetReturnEmulator()
    getMetaClass_end = getMetaClass + 4 * 4
    emulator.run(getMetaClass, getMetaClass_end)
    return emulator.return_value
示例#18
0
def check_vtable(start, end=None):
    # We recognize a vtable by looking for an array of at least 2 pointers to code followed by a
    # NULL.
    # If no end was specified, go until the end of the segment.
    if end is None:
        end = idc.get_segm_end(start)
    # Check each address in the table. Stop once we've found something other than a pointer to
    # code.
    ended_with_zero = False
    ea = start
    while ea < end:
        method = idc.get_qword(ea)
        if method == 0:
            ended_with_zero = True
            break
        if not idc.is_code(idc.get_full_flags(method)):
            break
        ea += 8
    # Compute the length.
    length = (ea - start) / 8
    possible_vtable = ended_with_zero and length >= 2
    return possible_vtable, length
示例#19
0
    def reload_info(self):
        if not dbg.is_process_suspended():
            return False

        base_addr = None
        if self.base_expr is None:
            base_addr = idc.get_reg_value(dbg.registers.stack)
        else:
            base_addr = idaapi.str2ea(self.base_expr)
            if base_addr == idc.BADADDR:
                idaapi.warning("Invalid base expr: %s" % self.base_expr)
                return False

            if not idaapi.is_loaded(base_addr):
                idaapi.warning("Memory address is not loaded: $#x" % base_addr)
                return False

        self.ClearLines()
        dbg.set_thread_info()

        try:
            segm_end = idc.get_segm_end(base_addr)
            n_entries = config.n_stack_entries or ((segm_end-base_addr) // dbg.ptr_size)

            for i in range(n_entries):
                offset = i * dbg.ptr_size
                ptr = base_addr + offset

                if not idaapi.is_loaded(ptr):
                    break

                value = idc.get_qword(ptr)
                self.add_line("%02d:%04X  %s" % (i, offset, self.parse_value(ptr)))

        except Exception as e:
            idaapi.warning(str(e))
            return False
        return True
示例#20
0
def extract_vtable_pac_codes(vtable_ea):
    pac_codes = []
    # Open the file.
    path = idc.get_input_file_path()
    with open(path, "rb") as kernelcache_file:
        # Seek to the offset of the vtable.
        offset = idaapi.get_fileregion_offset(vtable_ea)
        kernelcache_file.seek(offset)
        # Loop over each entry in the vtable.
        ea = vtable_ea
        while True:
            # Break if we've reached the end of the vtable.
            vmethod = idc.get_qword(ea)
            if vmethod == 0:
                break
            # Get the original value from the original file.
            original = kernelcache_file.read(8)
            value, = struct.unpack("<Q", original)
            # Extract the type code and add it to the list.
            pac_code = (value & 0x0000ffff00000000) >> 32
            pac_codes.append(pac_code)
            # Advance.
            ea += 8
    return pac_codes
示例#21
0
def is_code_ptr(ea):
    return is_mapped_data(ea, 4) and idc.is_code(
        idc.get_full_flags(idc.get_qword(ea)))
示例#22
0
def process_mod_init_segment_for_metaclasses(start, end, found_metaclass):
    for ea in range(start, end, 8):
        func = idc.get_qword(ea)
        process_mod_init_func_for_metaclasses(func, found_metaclass)
示例#23
0
 def getQWordValue(self, addr):
     return idc.get_qword(addr)
示例#24
0
 def get_qword(self, ea):
     return idc.get_qword(ea)
示例#25
0
 def cmd_get_qword(self, addr):
     return str(idc.get_qword(int(addr, 0)))
示例#26
0
def calculate_caller_function_frame_info_x64(ea, sp, bp):
    PTR_SIZE = 8
    debug('ea: 0x{:X}'.format(ea))

    function_info = idaapi.get_func(ea)
    if function_info:
        function_start_ea = function_info.start_ea
        function_end_ea = function_info.end_ea
    else:
        debug('function_info is None')
        _, _, function_start_ea, function_end_ea = get_func_name_and_call_offset(
            ea)

    debug('function_start_ea: 0x{:X}, function_end_ea: 0x{:X}'.format(
        function_start_ea, function_end_ea))

    prev_ea = idaapi.decode_prev_insn(insn, function_end_ea)

    #often padding is present at the end of a function. Iterate by padding to the last function's instruction
    if prev_ea == idaapi.BADADDR:
        prev_ea = FunctionAssemblyCalculator.iterateByPaddingToTheLastInstruction(
            function_end_ea)

    #often ret is not at the end of the function but earlier. Find it
    prev_ea = FunctionAssemblyCalculator.findRetInstruction(prev_ea)

    #case 2: find a 'pop rbp' or 'add rsp, X'. Skip or pops

    #prev_ea point to 'ret' instruction. Get previous instrucion
    prev_ea = idaapi.decode_prev_insn(insn, prev_ea)

    #if at the end some values are popped from stack then we need remember that
    pop_instruction_number = 0
    while idc.print_insn_mnem(prev_ea) == "pop":
        debug(idc.get_operand_value(prev_ea, 0))

        if idc.get_operand_value(prev_ea, 0) == OperandValueRegister.RBP:
            #pop rbp found. Unfortunately I don't konw a value of current rbp so I need calculate.
            debug('CASE 2.1: calculate bp from function prolog')

            # there is a need to use rbp. Unfortunately we don't know a corelation between rsp and rbp, so we need use simple heuristic to deterimne it.
            # Script will scan function from beginning looking for operation like: mov rbp, rsp or lea rbp, [rsp+0x00]
            difference = FunctionAssemblyCalculator.findRspRbpDifference(
                function_start_ea)

            #values for current funciton
            sp = bp + difference
            ret = idc.get_qword(sp)
            bp = sp - PTR_SIZE

            #Calculate registers for caller. ret takes a value from stack so I need change sp one more time
            sp += PTR_SIZE
            bp = idc.get_qword(bp)  #get bp value from stack

            debug('sp: 0x{:X}'.format(sp))
            debug('bp: 0x{:X}'.format(bp))
            return (ret, sp, bp)
        else:
            prev_ea = idaapi.decode_prev_insn(insn, prev_ea)
            pop_instruction_number += 1

    #CASE 2.2: get func base pointer from rbp
    debug('CASE 2.2: calclulate bp from function epilog')
    debug(idc.print_insn_mnem(prev_ea), idc.get_operand_value(prev_ea, 0))

    old_sp = sp
    function_stack_size = 0

    mnem = idc.print_insn_mnem(prev_ea)
    arg_0_type = idc.get_operand_type(prev_ea, 0)
    arg_0_value = idc.get_operand_value(prev_ea, 0)
    arg_1_type = idc.get_operand_type(prev_ea, 1)
    if mnem == "add" and arg_0_type == OperandType.GENERAL_REG and arg_0_value == OperandValueRegister.RSP and arg_1_type == OperandType.IMMEDIATE_VALUE:
        #this function has own place for stack. Count it
        function_stack_size = idc.get_operand_value(prev_ea, 1)
        sp += function_stack_size

    sp = sp + pop_instruction_number * PTR_SIZE
    ret = idc.get_qword(sp)

    #ret takes a value from stack so I need change sp one more time
    sp += PTR_SIZE

    #one more thing to do. Often previous instruction restoring rbp
    prev_ea = idaapi.decode_prev_insn(insn, prev_ea)
    mnem = idc.print_insn_mnem(prev_ea)
    arg_0_type = idc.get_operand_type(prev_ea, 0)
    arg_0_value = idc.get_operand_value(prev_ea, 0)
    arg_1_type = idc.get_operand_type(prev_ea, 1)

    if mnem == 'mov' and arg_0_type == OperandType.GENERAL_REG and arg_0_value == OperandValueRegister.RBP and arg_1_type == OperandType.MEMORY_REG:
        bp = idc.get_qword(old_sp + idc.get_operand_value(prev_ea, 1))

    debug(mnem, 'type0: ', arg_0_type, arg_0_value, 'type0: ', arg_1_type,
          idc.get_operand_value(prev_ea, 1))
    return (ret, sp, bp)