示例#1
0
    def resolveCallingAddressBackwards(self, func, target, start, end):
        '''
        start is callingAddr
        end is curFun.start
        '''
        
        pc = start
        pc = idc.prev_head(pc, 0)
        while pc > end:
            opcode = idc.GetMnem(pc)
            opTarget = idc.print_operand(pc, 0)
            # print hex(pc)
            # print opcode
            # print target
            # print '\n'

            value = None
            if opcode in self.collectRegMnem and opTarget == target:
                return None

            if opcode in self.assignRegMnem and opTarget == target:
                if opcode == 'MOV':
                    nextTarget = idc.print_operand(pc, 1)
                    return self.resolveCallingAddressBackwards(func, nextTarget, pc, end)
                    
                elif opcode == 'LDR':
                    dataref = list(idautils.DataRefsFrom(pc))[0]
                    value = idc.print_operand(dataref, 0)

                    return value
                    
            pc = idc.prev_head(pc, 0)
        return None
def find_all_ioctls():
    """
    From the currently selected address attempts to traverse all blocks inside the current function to find all immediate values which
    are used for a comparison/sub immediately before a jz. Returns a list of address, second operand pairs.
    """

    ioctls = []
    # Find the currently selected function and get a list of all of it's basic blocks
    addr = idc.get_screen_ea()
    f = idaapi.get_func(addr)
    fc = idaapi.FlowChart(f, flags=idaapi.FC_PREDS)
    for block in fc:
        # grab the last two instructions in the block
        last_inst = idc.prev_head(block.end_ea)
        penultimate_inst = idc.prev_head(last_inst)
        # If the penultimate instruction is cmp or sub against an immediate value immediately preceding a 'jz'
        # then it's a decent guess that it's an IOCTL code (if this is a dispatch function)
        if idc.print_insn_mnem(penultimate_inst) in [
                'cmp', 'sub'
        ] and idc.get_operand_type(penultimate_inst, 1) == 5:
            if idc.print_insn_mnem(last_inst) == 'jz':
                value = get_operand_value(penultimate_inst)
                ioctls.append((penultimate_inst, value))
                ioctl_tracker.add_ioctl(penultimate_inst, value)
    return ioctls
示例#3
0
 def get_protocols(self):
     """found UEFI protocols information in idb"""
     for service_name in self.gBServices:
         for address in self.gBServices[service_name]:
             ea, found = address, False
             if self.arch == 'x86':
                 for _ in range(1, 25):
                     ea = idc.prev_head(ea)
                     if (idc.get_operand_value(ea, 0) > self.base
                             and idc.print_insn_mnem(ea) == 'push'):
                         found = True
                         break
             if self.arch == 'x64':
                 for _ in range(1, 16):
                     ea = idc.prev_head(ea)
                     if (idc.get_operand_value(ea, 1) > self.base
                             and idc.print_insn_mnem(ea) == 'lea'):
                         found = True
                         break
             if not found:
                 continue
             for xref in idautils.DataRefsFrom(ea):
                 if idc.print_insn_mnem(xref):
                     continue
                 if not check_guid(xref):
                     continue
                 cur_guid = get_guid(xref)
                 record = {
                     'address': xref,
                     'service': service_name,
                     'guid': cur_guid,
                 }
                 if not self.Protocols['all'].count(record):
                     self.Protocols['all'].append(record)
示例#4
0
文件: findcrypt.py 项目: you0708/ida
def main():
    print("[*] loading crypto constants")
    for const in non_sparse_consts:
        const["byte_array"] = convert_to_byte_array(const)

    for start in idautils.Segments():
        print("[*] searching for crypto constants in %s" % idc.get_segm_name(start))
        ea = start
        while ea < idc.get_segm_end(start):
            bbbb = list(struct.unpack("BBBB", idc.get_bytes(ea, 4)))
            for const in non_sparse_consts:
                if bbbb != const["byte_array"][:4]:
                    continue
                if map(lambda x:ord(x), idc.get_bytes(ea, len(const["byte_array"]))) == const["byte_array"]:
                    print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"]))
                    idc.set_name(ea, const["name"])
                    if const["size"] == "B":
                        idc.create_byte(ea)
                    elif const["size"] == "L":
                        idc.create_dword(ea)
                    elif const["size"] == "Q":
                        idc.create_qword(ea)
                    idc.make_array(ea, len(const["array"]))
                    ea += len(const["byte_array"]) - 4
                    break
            ea += 4

        ea = start
        if idc.get_segm_attr(ea, idc.SEGATTR_TYPE) == 2:
            while ea < idc.get_segm_end(start):
                d = ida_bytes.get_dword(ea)
                for const in sparse_consts:
                    if d != const["array"][0]:
                        continue
                    tmp = ea + 4
                    for val in const["array"][1:]:
                        for i in range(8):
                            if ida_bytes.get_dword(tmp + i) == val:
                                tmp = tmp + i + 4
                                break
                        else:
                            break
                    else:
                        print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"]))
                        cmt = idc.get_cmt(idc.prev_head(ea), 0)
                        if cmt:
                            idc.set_cmt(idc.prev_head(ea), cmt + ' ' + const["name"], 0)
                        else:
                            idc.set_cmt(idc.prev_head(ea), const["name"], 0)
                        ea = tmp
                        break
                ea += 1
    print("[*] finished")
示例#5
0
def trace_rep_mov(stack_var, loc, func_ea, state):
    """
    Helper function to trace back a rep mov
    """
    loc = idc.prev_head(loc)
    while loc != func_ea:
        mnem = idc.print_insn_mnem(loc)
        if mnem == 'lea' and idc.print_operand(loc, 0) == 'edi':
            if stack_var == get_operand_value_replacement(loc, 1, state):
                return trace_register('esi', loc, func_ea, state)
            return None
        loc = idc.prev_head(loc)
    return None
示例#6
0
def get_stacked_bytes(dec_func_addr):
    func_stacked_bytes_addr_dict = {}
    xrefs = idautils.CodeRefsTo(dec_func_addr, 0)

    for xref in xrefs:
        prev_addr = idc.prev_head(xref)
        prev_addr_2 = idc.prev_head(prev_addr)

        if idc.print_insn_mnem(prev_addr_2) == "call":
            func_name = idc.print_operand(prev_addr_2, 0)
            func_addr = idc.get_name_ea_simple(func_name)
            func_stacked_bytes_addr_dict[xref] = func_addr

    # enc_mod_addr = list(set(enc_mod_addr)) # [Debug] Get unique functions only

    for xref, stacked_bytes_addr in func_stacked_bytes_addr_dict.items():
        print(f"Address: {hex(stacked_bytes_addr)}")
        func_ea = idc.get_func_attr(stacked_bytes_addr, idc.FUNCATTR_START)
        bytes_collected = bytearray()  # Collected stack string store here

        for ins in idautils.FuncItems(func_ea):
            if ida_bytes.is_code(ida_bytes.get_full_flags(ins)):
                if idc.print_insn_mnem(ins) == "mov":
                    if idc.get_operand_type(ins, 1) == idc.o_imm:
                        # disasm = idc.GetDisasm(ins) # [Debug]
                        hex_str_len = len(
                            idc.print_operand(ins, 1).lstrip("0").rstrip("h"))
                        const_hex_byte = idc.print_operand(
                            ins, 1).lstrip("0").rstrip("h")

                        if hex_str_len != 8:  # Skip if const hex byte less than 8
                            append_zero = "0" * (8 - hex_str_len)
                            const_hex_byte = append_zero + const_hex_byte
                            # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug]

                        # else:
                        # print(struct.pack("<I", int(const_hex_byte, 16))) # [Debug]
                        bytes_collected += struct.pack("<I",
                                                       int(const_hex_byte, 16))

        if len(bytes_collected) >= 1:
            cmt_str = ""
            if dec_func_addr == 0x10001253:  # fn_name_addr
                print(f"{decode_fnname(bytes_collected[4:])}")
                cmt_str = decode_fnname(bytes_collected[4:])
            elif dec_func_addr == 0x1000122B:  # mod_name_addr
                print(f"{decode_modname(bytes_collected[4:])}")
                cmt_str = decode_modname(bytes_collected[4:])
            idc.set_cmt(xref, cmt_str, 1)  # Comment near xref decoder function
        else:
            print(f"[-] {hex(stacked_bytes_addr)} addr error")
def ret_vals(bbl):
    iaddr = idc.prev_head(bbl.end_ea)
    while idc.next_head(iaddr) != bbl.start_ea:
        if is_eax_written(iaddr) and is_nothing_read(iaddr):
            return [idc.get_operand_value(iaddr, 1)]
        if is_eax_read(iaddr):
            return []
        iaddr = idc.prev_head(iaddr)

    ret = []
    for bb in bbl.preds():
        ret = ret + ret_vals(bb)

    return ret
示例#8
0
def get_con2_var_or_num(i_cnt, cur_addr):
    """
    :param i_cnt: the register of the virtual call
    :param cur_addr: the current address in the memory
    :return: "success" string and the address of the vtable's location. if it fails it sends the reason and -1
    """
    start_addr = idc.get_func_attr(cur_addr, idc.FUNCATTR_START)
    virt_call_addr = cur_addr
    cur_addr = idc.prev_head(cur_addr)
    dct_arch = get_arch_dct()
    if dct_arch == -1:
        return 'Wrong Architechture', "-1", cur_addr

    while cur_addr >= start_addr:
        if idc.print_insn_mnem(
                cur_addr)[:3] == dct_arch["opcode"] and idc.print_operand(
                    cur_addr, 0) == i_cnt:  # TODO lea ?
            opnd2 = idc.print_operand(cur_addr, 1)
            place = opnd2.find(dct_arch["separator"])
            if place != -1:  # if the function is not the first in the vtable
                register = opnd2[opnd2.find('[') + 1:place]
                if opnd2.find('*') == -1:
                    offset = opnd2[place +
                                   dct_arch["val_offset"]:opnd2.find(']')]
                else:
                    offset = "*"
                return register, offset, cur_addr
            else:
                offset = "0"
                if opnd2.find(']') != -1:
                    register = opnd2[opnd2.find('[') + 1:opnd2.find(']')]
                else:
                    register = opnd2
                return register, offset, cur_addr
        elif idc.print_insn_mnem(cur_addr)[:4] == "call":
            intr_func_name = idc.print_operand(cur_addr, 0)
            # In case the code has CFG -> ignores the function call before the virtual calls
            if "guard_check_icall_fptr" not in intr_func_name:
                if "nullsub" not in intr_func_name:
                    # intr_func_name = idc.Demangle(intr_func_name, idc.GetLongPrm(idc.INF_SHORT_DN))
                    print(
                        "Warning! At address 0x%08x: The vtable assignment might be in another function (Maybe %s),"
                        " could not place BP." %
                        (virt_call_addr, intr_func_name))
                cur_addr = start_addr
        cur_addr = idc.prev_head(cur_addr)
    return "out of the function", "-1", cur_addr

    return '', 0, cur_addr
    def get_branch_type(self):
        if self.bbl == None:
            return -1

        addr = self.addr
        while addr != self.bbl.end_ea:
            mnem = idc.print_insn_mnem(addr).lower()
            if mnem.startswith("call"):
                if op_type[idc.get_operand_type(addr,0)] != "o_near" and\
                    op_type[idc.get_operand_type(addr,0)] != "o_far":
                    return ICALL
                else:
                    return CALL
            addr = idc.next_head(addr)

        addr = idc.prev_head(self.bbl.end_ea)
        mnem = idc.print_insn_mnem(addr).lower()
        if mnem in u_jumps or mnem in c_jumps:
            if op_type[idc.get_operand_type(addr,0)] != "o_near" and\
                op_type[idc.get_operand_type(addr,0)] != "o_far":
                return IJMP
            else:
                if mnem in u_jumps:
                    return JMP
                else:
                    return CJMP
        elif self.bbl.type >= 2 and self.bbl.type <= 5:
            return RET

        return NA
示例#10
0
    def find_ehfuncinfo_addr(self):
        for eh_addr in self.frmhdlr_xref:
            addr_ = eh_addr
            for i in range(0, self.MAX_SEARCH):
                addr_ = idc.prev_head(addr_)
                mnem = idc.print_insn_mnem(addr_)

                ### locate the ehfuncInfo address
                if mnem == 'mov' and idc.get_operand_type(
                        addr_, 0) == o_reg and idc.get_operand_type(
                            addr_, 1) == o_imm:
                    op1 = idc.print_operand(addr_, 0)
                    op2 = idc.print_operand(addr_, 1)

                    ## eh function info address
                    eh_func_info_addr = get_operand_value(addr_, 1)

                    #print(hex(addr_), mnem, op1, op2,hex(eh_func_info_addr))

                    ### locate the ptryBlockMapAddr
                    for ad in idautils.XrefsTo(addr_, flags=0):
                        seh_init_addr = ad.frm
                    print(
                        "[+] seh_frame_addr: {} ehFuncInfo_struct_addr: {}\n------------------------------------------------------------------"
                        .format(hex(addr_), hex(eh_func_info_addr)))

                    ### locate the xref of the _cxxframehandler ehfuncinfo
                    self.parse_func_info_entry(seh_init_addr, addr_,
                                               eh_func_info_addr)
        return
示例#11
0
def getMinorDispatchTableAddress(ea):
    """find address of last lea in function"""
    start = idc.get_func_attr(ea, idc.FUNCATTR_START)
    end = idc.prev_head(idc.get_func_attr(ea, idc.FUNCATTR_END), start)
    res = prevMnemonic(end, 'lea', start)
    assert res != idc.BADADDR
    return idc.get_operand_value(res, 1)
示例#12
0
def is_eax_set(bbl):
    iaddr = idc.prev_head(bbl.end_ea)
    iaddr = idc.prev_head(bbl.end_ea)
    while idc.next_head(iaddr) != bbl.start_ea:
        if is_eax_written(iaddr):
            return True
        if is_eax_read(iaddr):
            return False
        iaddr = idc.prev_head(iaddr)

    ret = True
    for bb in bbl.preds():
        ret = ret & is_eax_set(bb)
        if ret == False:
            break
    return ret
def replace_sym_const(ea, api):
    for arg_n in api_list[api].keys():
        # Calling Convention: cdecl, stdcall
        push_cnt = 0
        ea_search = ea
        while push_cnt < arg_n:
            ea_search = idc.prev_head(ea_search)
            op = idc.print_insn_mnem(ea_search)
            if op == "push":
                push_cnt += 1

        operand = idc.print_operand(ea_search, 0)
        if operand.isdigit():
            operand = int(idc.print_operand(ea_search, 0))
        else:
            continue

        enum_name = api + "_" + str(arg_n)
        const = api_list[api][arg_n][operand]

        enum_id = ida_enum.get_enum(enum_name)
        if enum_id == BADADDR:
            # add new enum
            enum_qty = ida_enum.get_enum_qty()
            enum_id = ida_enum.add_enum(enum_qty, enum_name, 0)

        symbolic_id = ida_enum.get_enum_member_by_name(const)
        if symbolic_id == BADADDR:
            # add new enum member
            ida_enum.add_enum_member(enum_id, const, operand, 0xffffffff)

        ida_bytes.op_enum(ea_search, 0, enum_id, 0)
示例#14
0
    def track_register(self, ea, target_dest_reg):

        f_start = idc.get_func_attr(ea, idc.FUNCATTR_START)
        f_end = idc.get_func_attr(ea, idc.FUNCATTR_END)

        curr_ea = ea
        dst = None
        src = None

        target = target_dest_reg.lower()
        target_dest_reg = target_dest_reg.lower()

        target_value = None
        target_ea = idc.BADADDR
        target_type = None
        previous_call = None

        ret_dict = {}

        while curr_ea != idc.BADADDR:
            #instruction = idc.GetDisasm(curr_ea)

            # print "0x%08x %s" % (curr_ea, instruction)

            # looking for the previous place this register was assigned a value
            mnem = idc.print_insn_mnem(curr_ea).lower()
            dst = idc.print_operand(curr_ea, 0).lower()
            src = idc.print_operand(curr_ea, 1).lower()

            if dst == target and self.is_set_argument_instr(mnem):
                target = src
                target_value = src
                target_ea = curr_ea
                # print "            new target set %s (type=%d)" % (target, idc.get_operand_type(curr_ea, 1))
                if target.startswith("="):
                    break

            if dst == target == "r0" and self.is_call_instr(mnem):
                target_value = "<return from previous call>"
                previous_call = curr_ea
                break
            # step to previous instruction
            curr_ea = idc.prev_head(curr_ea - 1, f_start)

        if target_value:
            # print ">>> 0x%08x, %s is set to %s @ 0x%08x" % (ea, target_dest_reg, target_value, target_ea)
            ret_dict = {
                "target": target_dest_reg,
                "value": target_value,
                "target_ea": target_ea,
                "ea": ea
            }

            if previous_call:
                ret_dict["previous_call"] = previous_call

            return ret_dict

        # fall through if nothing is found
        return {}
def AEG_GuessArgs(addr):
    _iter_addr = addr
    ret = []
    while 1:
        _iter_addr = idc.prev_head(_iter_addr)
        _iter_instr = AEG_Instruction(_iter_addr)
        _op = _iter_instr.GetOperator()
        if _op in ('jmp', 'call', 'ret', 'retn', 'leave'):
            break
        elif 'j' in _op:
            break
        elif _op == 'mov':
            _opnd0 = _iter_instr.GetOperand(0)
            if INFO_BITS == 32:
                ## mov [esp+xx] , xxx
                if 'esp' in _opnd0 and ']' in _opnd0:
                    ret.append(_iter_addr)
            else:
                if 'di' in _opnd0 or 'si' in _opnd0 or 'dx' in _opnd0 or 'cx' in _opnd0:
                    ret.append(_iter_addr)
        elif _op == 'push':
            ret.append(_iter_addr)
        elif 'lea' == _op:
            ## lea rsi, xxx
            _opnd0 = _iter_instr.GetOperand(0)
            if 'si' in _opnd0 or 'di' in _opnd0:
                ret.append(_iter_addr)

    return ret
示例#16
0
def decrypt_all_strings(decrypt_string_func_ea):
    global STRING_DICTIONARY
    for ref in idautils.CodeRefsTo(decrypt_string_func_ea, 1):
        # this function can be better. I hate it rn but oh well

        prev_instruction_ea = 0x472DAC if ref == translate_ea(
            0x1db3) else idc.prev_head(ref)

        if idc.print_insn_mnem(
                prev_instruction_ea) == 'push' or idc.print_insn_mnem(
                    prev_instruction_ea) == 'lea':
            encrypted_blob_ea = idc.get_operand_value(
                prev_instruction_ea,
                1) if ref == translate_ea(0x1db3) else idc.get_operand_value(
                    prev_instruction_ea, 0)
            length = int.from_bytes(idaapi.get_bytes(encrypted_blob_ea - 4, 4),
                                    'little')
            #print(hex(prev_instruction_ea) + " and " + hex(encrypted_blob_ea) + " and " + hex(length))
            encrypted_blob = [
                x for x in idaapi.get_bytes(encrypted_blob_ea, length)
            ]
            encrypted_blob = decrypt_config(encrypted_blob, length)
            string = ''
            for each in encrypted_blob:
                if each != 0:
                    string += chr(each)
            STRING_DICTIONARY[translate_ea_to_offset(
                encrypted_blob_ea)] = string
    return
def resolve_all_APIs(resolve_ea, mode):
    if resolve_ea is None:
        print('resolve fails..')
        return

    for ref in idautils.CodeRefsTo(resolve_ea, 1):
        # only 1 ref

        curr_ea = ref
        while True:
            prev_instruction_ea = idc.prev_head(curr_ea)
            if mode == 1:
                if idc.print_insn_mnem(prev_instruction_ea) == 'push':
                    hash_val = idc.get_operand_value(prev_instruction_ea, 0)
                    if hash_val in export_hashes:
                        print(hex(ref) + ' : ' + export_hashes[hash_val])
                        idc.set_cmt(ref, export_hashes[hash_val], 0)
                    break
            else:
                if idc.print_insn_mnem(prev_instruction_ea) == 'mov':
                    hash_val = idc.get_operand_value(prev_instruction_ea, 1)
                    print(hex(hash_val))
                    if hash_val in export_hashes:
                        print(hex(ref) + ' : ' + export_hashes[hash_val])
                        idc.set_cmt(ref, export_hashes[hash_val], 0)
                    break
            curr_ea = prev_instruction_ea
示例#18
0
def trace_register_family(reg, loc, func_ea, state=None):
    """
    Trace a provided register to the location in which any member of its register family is set. If it is set using a
    mov operation, the value is either an o_imm type (return the immediate value) or an o_mem type, that means the
    referenced location MAY a pointer to the actual data, which we need to acquire. We validate this by ensuring the
    acquired value is within the loaded memory range of the application. Otherwise we return idc.BADADDR.

    If the register is set using an lea operation, it is likely done so using a stack variable (which we validate)
    and then trace back to determine how the stack variable is set.

    :param reg: The referenced register which a location is loaded into
    :param loc: The starting offset for tracing back from
    :param func_ea: Starting function offset
    :param state: the current TraceState (a new state will be created if one is not provided)

    :return: The acquired location, or idc.BADADDR
    """
    if state is None:
        state = TraceState()
    reg_fam = unsafe_get_reg_fam(reg)
    if reg_fam:
        loc = idc.prev_head(loc)
        while loc != func_ea:
            opnd = idc.print_operand(loc, 0)
            op_type_1 = idc.get_operand_type(loc, 1)
            opval_1 = idc.get_operand_value(loc, 1)
            mnem = idc.print_insn_mnem(loc)
            if 'mov' in mnem and opnd in reg_fam:
                if op_type_1 == idc.o_imm:
                    return opval_1
                elif op_type_1 == idc.o_mem:
                    poss_loc = idc.get_wide_dword(opval_1)
                    if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA:
                        return poss_loc
                    else:
                        return opval_1
                else:
                    return idc.BADADDR
            elif mnem == 'lea' and op_type_1 == idc.o_displ and opnd in reg_fam:
                stack_var = get_operand_value_replacement(loc, 1, state)
                return trace_stack_var(stack_var, loc, func_ea, state)
            elif is_64_bit() and mnem == 'lea' and opnd in reg_fam:
                if op_type_1 == idc.o_mem:
                    return opval_1
            loc = idc.prev_head(loc)
    return idc.BADADDR
示例#19
0
def trace_register_family_x64(reg, loc, func_ea, state=None):
    """
    Shouldn't be any different than trace_register_family except for continuing a trace if a register is loaded into
    the target register. However, using it in trace_register_family was not behaving properly, so keeping it separate
    for now. Also unsure of what the repercussions would be of adding that into the existing trace_register_family.

    :param reg: The referenced register which a location is loaded into
    :param loc: The starting offset for tracing back from
    :param func_ea: Starting function offset
    :param state: the current TraceState

    :return: The acquired location, or idc.BADADDR
    """
    if state is None:
        state = TraceState()
    reg_fam = unsafe_get_reg_fam(reg)
    if reg_fam:
        loc = idc.prev_head(loc)
        while loc != func_ea:
            opnd = idc.print_operand(loc, 0)
            op_type_1 = idc.get_operand_type(loc, 1)
            opval_1 = idc.get_operand_value(loc, 1)
            mnem = idc.print_insn_mnem(loc)
            if "mov" in mnem and opnd in reg_fam:
                if op_type_1 == idc.o_imm:
                    return opval_1
                elif op_type_1 == idc.o_mem:
                    poss_loc = idc.get_wide_dword(opval_1)
                    if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA:
                        return poss_loc
                    else:
                        return opval_1
                elif op_type_1 == idc.o_reg:
                    return trace_register_family_x64(idc.print_operand(loc, 1),
                                                     loc, func_ea, state)
                else:
                    return idc.BADADDR
            elif mnem == "lea" and op_type_1 == idc.o_displ and opnd in reg_fam:
                stack_var = get_operand_value_replacement(loc, 1, state)
                return trace_stack_var(stack_var, loc, func_ea, state)
            elif is_64_bit() and mnem == "lea" and opnd in reg_fam:
                if op_type_1 == idc.o_mem:
                    return opval_1
            loc = idc.prev_head(loc)
    return idc.BADADDR
示例#20
0
def get_bb_ends(address):
    """
    Get end addresses of all bbs in function containing address.
    :param address: address in function
    :return: list of bb end addresses
    """
    function = idaapi.get_func(address)
    flowchart = idaapi.FlowChart(function)
    return [idc.prev_head(bb.end_ea) for bb in flowchart]
示例#21
0
def get_bb_ends(address):
    """
    Get end addresses of all bbs in function containing address.
    :param address: address in function
    :return: list of bb end addresses
    """
    function = idaapi.get_func(address)
    flowchart = idaapi.FlowChart(function)
    return [idc.prev_head(bb.end_ea) for bb in flowchart]
示例#22
0
def trace_stack_var(stack_var, loc, func_ea, state=None):
    """
    Trace a provided stack variable to the location in which it is set. If it is set using a mov operation, the
    value may be set from a register, which we then need to call back to trace_register in order to acquire the
    value. Otherwise it is either an o_imm type (return the immediate value) or an o_mem type, that means the
    referenced location MAY a pointer to the actual data, which we need to acquire. We validate this by ensuring
    the acquired value is within the loaded memory range of the application. Otherwise we return idc.BADADDR.

    :param stack_var: The stack variable which a location is loaded into
    :param loc: The starting offset for tracing back from
    :param func_ea: Starting function offset
    :param state: the current TraceState

    :return: The acquired location, or idc.BADADDR
    """
    if state is None:
        state = TraceState()
    loc = idc.prev_head(loc)
    while loc != func_ea:
        op_type_1 = idc.get_operand_type(loc, 1)
        opval_1 = idc.get_operand_value(loc, 1)
        mnem = idc.print_insn_mnem(loc)
        dis = idc.GetDisasm(loc)
        if mnem == "mov" and stack_var == get_operand_value_replacement(
                loc, 0, state):
            if op_type_1 == idc.o_reg:
                return trace_register(idc.print_operand(loc, 1), loc, func_ea,
                                      state)
            elif op_type_1 == idc.o_imm:
                return opval_1
            elif op_type_1 == idc.o_mem:
                poss_loc = idc.get_wide_dword(opval_1)
                if idaapi.cvar.inf.minEA <= poss_loc < idaapi.cvar.inf.maxEA:
                    return poss_loc
                else:
                    return opval_1
            else:
                return idc.BADADDR
        elif any(x in dis for x in MOVS):
            result = trace_rep_mov(stack_var, loc, func_ea, state)
            if result:
                return result
        loc = idc.prev_head(loc)
    return idc.BADADDR
示例#23
0
def hand_register(line, start_ea, reg_target):
    current = line
    while (current >= start_ea):
        current = idc.prev_head(current)
        if (idc.print_insn_mnem(current) == 'jmp'):
            return hand_block(line, current, reg_target)
        if (idc.print_operand(current, 0)
                == reg_target) and (idc.print_insn_mnem(current)
                                    in ['mov', 'lea']):
            return idc.print_operand(current, 1)
示例#24
0
 def func_bound(self):
     if self.func == None:
         return (IDA_ERROR, IDA_ERROR)
     fend = idc.prev_head(self.func.end_ea)
     if self.addr == fend:
         if idc.print_insn_mnem(self.addr) in u_jumps:
             return (RESOLVE_NAME, RESOLVE_NAME)
         else:
             return (IDA_ERROR, IDA_ERROR)
     return (self.func.start_ea, fend)
示例#25
0
 def set_types(self):
     '''
     handle (EFI_BOOT_SERVICES *) type
     and (EFI_SYSTEM_TABLE *) for x64 images
     '''
     RAX = 0
     O_REG = 1
     O_MEM = 2
     EFI_BOOT_SERVICES = 'EFI_BOOT_SERVICES *'
     EFI_SYSTEM_TABLE = 'EFI_SYSTEM_TABLE *'
     empty = True
     for service in self.gBServices:
         for address in self.gBServices[service]:
             ea = address
             num_of_attempts = 10
             for _ in range(num_of_attempts):
                 ea = idc.prev_head(ea)
                 if (idc.print_insn_mnem(ea) == 'mov'
                         and idc.get_operand_type(ea, 1) == O_MEM):
                     if (idc.get_operand_type(ea, 0) == O_REG
                             and idc.get_operand_value(ea, 0) == RAX):
                         gvar = idc.get_operand_value(ea, 1)
                         gvar_type = idc.get_type(gvar)
                         '''
                         if (EFI_SYSTEM_TABLE *)
                         '''
                         if ((gvar_type != 'EFI_SYSTEM_TABLE *') and \
                             (idc.print_operand(address, 0).find('rax') == 1)
                         ):
                             if self._find_est(gvar, ea, address):
                                 print(
                                     '[ {0} ] Type ({type}) successfully applied'
                                     .format(
                                         '{addr:#010x}'.format(addr=gvar),
                                         type=EFI_SYSTEM_TABLE))
                                 empty = False
                                 break
                         '''
                         otherwise it (EFI_BOOT_SERVICES *)
                         '''
                         if (gvar_type != 'EFI_BOOT_SERVICES *'
                                 and gvar_type != 'EFI_SYSTEM_TABLE *'):
                             if idc.SetType(gvar, EFI_BOOT_SERVICES):
                                 empty = False
                                 idc.set_name(
                                     gvar,
                                     'gBs_{addr:#x}'.format(addr=gvar))
                                 print(
                                     '[ {0} ] Type ({type}) successfully applied'
                                     .format(
                                         '{addr:#010x}'.format(addr=gvar),
                                         type=EFI_BOOT_SERVICES))
                         break
     if empty:
         print(' * list is empty')
示例#26
0
def find_function_starts(location, start_mnem_bytes=None):
    """
    Description:
        Identifies all possible function starts since the most recent function or Align.

    Input:
        location - The EA to search before
        start_mnem_bytes - Try to start functions on a particular instruction
                           Instructions are entered as space separated bytes (i.e. '55' for 'push ebp')
                           The specified pattern will be used first, then the defaults will be used
                           If no pattern is specified, the defaults will be used, which prefers 'push ebp'

    Output:
        starts - A list of function end EAs sorted: start_mnem_bytes, push ebp, (push esp, push esi, push edi)
    """
    # foreach target bytes:
    #  step instructions up
    #  if instruction matches the target bytes, add to the corresponding output list
    #  if we hit a function or an align, quit
    # return starts in the order:
    #  start_nmem_bytes
    #  push ebp
    #  others, sorted ascending

    min_location = None
    ea = location
    while min_location is None:
        ea = idc.prev_head(ea)
        if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)):
            min_location = ea
        elif ea == idc.BADADDR:
            min_location = idaapi.getseg(location).start_ea
    min_location = max(min_location, idaapi.getseg(location).start_ea)

    targets = ['55', '54', '56', '57']
    if start_mnem_bytes:
        targets.insert(0, start_mnem_bytes)

    starts = {}
    for target in targets:
        function_starts = []
        ea = find_binary_instruction_start(location - 1, idc.SEARCH_UP, target,
                                           min_location)
        while ea != idc.BADADDR:
            if ea < min_location:
                break
            else:
                function_starts.append(ea)
            ea = find_binary_instruction_start(ea - 1, idc.SEARCH_UP, target,
                                               min_location)
        starts[target] = function_starts

    return (starts[start_mnem_bytes] if start_mnem_bytes else []) + starts['55'] + \
           sorted(itertools.chain.from_iterable(starts[target] for target in targets[-3:]))
示例#27
0
 def imp_cb(ea, name, ord):
     if name in funcs:
         for xref in idautils.XrefsTo(ea):
             call_addr = xref.frm
             caller_name = idc.get_func_name(call_addr)
             prev = idc.prev_head(call_addr)
             for _ in range(10):
                 if idc.get_cmt(prev, 0) == 'Tag' and idc.get_operand_type(
                         prev, 1) == 5:
                     tag_raw = idc.get_operand_value(prev, 1)
                     tag = ''
                     for i in range(3, -1, -1):
                         tag += chr((tag_raw >> 8 * i) & 0xFF)
                     if tag in tags.keys():
                         tags[tag].add(caller_name)
                     else:
                         tags[tag] = set([caller_name])
                     break
                 prev = idc.prev_head(prev)
     return True
示例#28
0
def find_function_starts_near(location, start_mnem_bytes=None):
    """
    Description:
        Identifies the nearest possible function starts since the most recent function or Align.

    Input:
        location - The EA to search before
        start_mnem_bytes - Try to start functions on a particular instruction
                           Instructions are entered as space separated bytes (i.e. '55' for 'push ebp')
                           The specified pattern will be used first, then the defaults will be used
                           If no pattern is specified, the defaults will be used, which prefers 'push ebp'

    Output:
        starts - A list of function end EAs sorted: start_mnem_bytes, push ebp, (push esp, push esi, push edi)
    """
    # foreach target bytes:
    #  step instructions up
    #  if instruction matches the target bytes, add to output list
    #   then move on to the next target bytes
    #  if we hit a function or an align, quit
    # return starts in the order
    #  start_nmem_bytes
    #  push ebp
    #  others, sorted descending

    min_location = None
    ea = location
    while min_location is None:
        ea = idc.prev_head(ea)
        if idaapi.get_func(ea) or idc.is_align(idc.get_full_flags(ea)):
            min_location = ea
        elif ea == idc.BADADDR:
            min_location = idaapi.getseg(location).start_ea
    min_location = max(min_location, idaapi.getseg(location).start_ea)

    targets = ['55', '54', '56', '57']
    if start_mnem_bytes:
        targets.insert(0, start_mnem_bytes)

    starts = {}
    for target in targets:
        ea = find_binary_instruction_start(location - 1, idc.SEARCH_UP, target,
                                           min_location)
        if ea != idc.BADADDR:
            starts[target] = ea

    return [
        start for start in (
            [starts.get(start_mnem_bytes, None),
             starts.get('55', None)] +
            sorted([starts.get(target, None) for target in targets[-3:]],
                   reverse=True)) if start
    ]
示例#29
0
def find_arg_ea(ea_call, arg_name):
    """ Return ea of argument by looking backwards from library function
    call.

    Arguments:
    ea_call -- effective address of call
    arg_name -- the argument name to look for
    """
    # the search for previous instruction/data will stop at the specified
    # address (inclusive)
    prev_instr = idc.prev_head(ea_call, ea_call - PREVIOUS_INSTR_DELTA)
    while prev_instr > (ea_call - ARG_SEARCH_THRESHOLD) and \
            prev_instr != idaapi.BADADDR:
        # False indicates not to look for repeatable comments
        comment = idc.get_cmt(prev_instr, False)
        if comment == arg_name:
            return prev_instr
        prev_instr = idc.prev_head(prev_instr,
                                   prev_instr - PREVIOUS_INSTR_DELTA)
    raise ArgumentNotFoundException(
        '  Argument {} not found within threshold'.format(arg_name))
示例#30
0
 def set_types(self):
     """
     handle (EFI_BOOT_SERVICES *) type
     """
     RAX = 0
     O_REG = 1
     O_MEM = 2
     EFI_BOOT_SERVICES = "EFI_BOOT_SERVICES *"
     empty = True
     for service in self.gBServices:
         for address in self.gBServices[service]:
             ea = address
             num_of_attempts = 10
             for _ in range(num_of_attempts):
                 ea = idc.prev_head(ea)
                 if (idc.GetMnem(ea) == "mov"
                         and idc.get_operand_type(ea, 1) == O_MEM):
                     if (idc.get_operand_type(ea, 0) == O_REG
                             and idc.get_operand_value(ea, 0) == RAX):
                         gBs_var = idc.get_operand_value(ea, 1)
                         gBs_var_type = idc.get_type(gBs_var)
                         if (gBs_var_type == "EFI_BOOT_SERVICES *"):
                             empty = False
                             print("[{0}] EFI_BOOT_SERVICES->{1}".format(
                                 "{addr:#010x}".format(addr=address),
                                 service))
                             print("\t [address] {0}".format(
                                 "{addr:#010x}".format(addr=gBs_var)))
                             print("\t [message] type already applied")
                             break
                         if idc.SetType(gBs_var, EFI_BOOT_SERVICES):
                             empty = False
                             idc.MakeName(
                                 gBs_var,
                                 "gBs_{addr:#x}".format(addr=gBs_var))
                             print("[{0}] EFI_BOOT_SERVICES->{1}".format(
                                 "{addr:#010x}".format(addr=address),
                                 service))
                             print("\t [address] {0}".format(
                                 "{addr:#010x}".format(addr=gBs_var)))
                             print("\t [message] type successfully applied")
                         else:
                             empty = False
                             print("[{0}] EFI_BOOT_SERVICES->{1}".format(
                                 "{addr:#010x}".format(addr=address),
                                 service))
                             print("\t [address] {0}".format(
                                 "{addr:#010x}".format(addr=gBs_var)))
                             print("\t [message] type not applied")
                         break
     if empty:
         print(" * list is empty")
示例#31
0
def find_function_arg_with_operand_value(addr, mnemonic, register, value,
                                         idx_operand):
    """
    00000000000167FC mov     [rsp+20h], rax
    idc.get_operand_value(0x167FC, 0) ==> 0x20
    """

    for _ in range(20):  # looks up to 20 instructions behind
        addr = idc.prev_head(addr)
        if idc.print_insn_mnem(addr) == mnemonic and register in idc.print_operand(addr, idx_operand)\
                and idc.get_operand_value(addr, idx_operand) == value:
            return addr
    return None
示例#32
0
 def get_protocols(self):
     """
     found UEFI protocols information in idb
     """
     for service_name in self.gBServices:
         for address in self.gBServices[service_name]:
             ea, found = address, False
             if self.arch == "x86":
                 for i in range(1, 25):
                     ea = idc.prev_head(ea)
                     if (idc.get_operand_value(ea, 0) > self.base
                             and idc.GetMnem(ea) == "push"):
                         found = True
                         break
             if self.arch == "x64":
                 for i in range(1, 16):
                     ea = idc.prev_head(ea)
                     if (idc.get_operand_value(ea, 1) > self.base
                             and idc.GetMnem(ea) == "lea"):
                         found = True
                         break
             if not found:
                 continue
             for xref in idautils.DataRefsFrom(ea):
                 if (idc.GetMnem(xref) == ""):
                     cur_guid = utils.get_guid(xref)
                     if cur_guid != [0] * 11:
                         record = {
                             "address": xref,
                             "service": service_name,
                             "guid": cur_guid,
                         }
                         record["address"] = xref
                         record["service"] = service_name
                         record["guid"] = cur_guid
                         if not self.Protocols["All"].count(record):
                             self.Protocols["All"].append(record)
示例#33
0
def symbolic_exec():
    from miasm2.ir.symbexec import SymbolicExecutionEngine
    from miasm2.core.bin_stream_ida import bin_stream_ida

    from utils import guess_machine

    start, end = idc.SelStart(), idc.SelEnd()

    bs = bin_stream_ida()
    machine = guess_machine(addr=start)

    mdis = machine.dis_engine(bs)

    if start == idc.BADADDR and end == idc.BADADDR:
        start = idc.ScreenEA()
        end = idc.next_head(start) # Get next instruction address

    mdis.dont_dis = [end]
    asmcfg = mdis.dis_multiblock(start)
    ira = machine.ira(loc_db=mdis.loc_db)
    ircfg = ira.new_ircfg_from_asmcfg(asmcfg)

    print "Run symbolic execution..."
    sb = SymbolicExecutionEngine(ira, machine.mn.regs.regs_init)
    sb.run_at(ircfg, start)
    modified = {}

    for dst, src in sb.modified(init_state=machine.mn.regs.regs_init):
        modified[dst] = src

    view = symbolicexec_t()
    all_views.append(view)
    if not view.Create(modified, machine, mdis.loc_db,
                       "Symbolic Execution - 0x%x to 0x%x"
                       % (start, idc.prev_head(end))):
        return

    view.Show()