Ejemplo n.º 1
1
    def __init__(self, ea):
        self.ea = ea
        self.funcname_or_segname = ""
        self.text = ""
        if not ida_bytes.is_code(ida_bytes.get_flags(ea)):
            ida_ua.create_insn(ea)

        # text
        t = ida_lines.generate_disasm_line(ea)
        if t:
            self.text = ida_lines.tag_remove(t)

        # funcname_or_segname
        n = ida_funcs.get_func_name(ea) \
            or ida_segment.get_segm_name(ida_segment.getseg(ea))
        if n:
            self.funcname_or_segname = n
Ejemplo n.º 2
0
    def handle_operand(self, insn, op, isRead):
      flags     = ida_bytes.get_flags(insn.ea)
      is_offs   = ida_bytes.is_off(flags, op.n)
      dref_flag = ida_xref.dr_R if isRead else ida_xref.dr_W
      def_arg   = ida_bytes.is_defarg(flags, op.n)
      optype    = op.type

      itype = insn.itype
      # create code xrefs
      if optype == ida_ua.o_imm:        
        makeoff = False
        if itype in [self.itype_ncall, self.itype_call]:
          insn.add_cref(op.value, op.offb, ida_xref.fl_CN)
          makeoff = True
        #elif itype == self.itype_mov: # e.g., mov #addr, PC
        #  insn.add_cref(op.value, op.offb, ida_xref.fl_JN)
        #  makeoff = True        
        if makeoff and not def_arg:
          otype = ida_offset.get_default_reftype(insn.ea)
          ida_offset.op_offset(insn.ea, op.n, otype, ida_idaapi.BADADDR, insn.cs)
          is_offs = True
        if is_offs:
          insn.add_off_drefs(op, ida_xref.dr_O, 0)
      elif optype == ida_ua.o_near:
        if insn.itype in [self.itype_ncall, self.itype_call]:
            fl = ida_xref.fl_CN
        else:
            fl = ida_xref.fl_JN
        insn.add_cref(op.addr, op.offb, fl)
      # create data xrefs
      elif optype == ida_ua.o_mem:
        insn.create_op_data(op.addr, op.offb, op.dtype)
        insn.add_dref(op.addr, op.offb, dref_flag)
        '''
Ejemplo n.º 3
0
 def activate(self, ctx):
     cur_ea = ida_kernwin.get_screen_ea()
     pfn = ida_funcs.get_func(cur_ea)
     if pfn:
         v = ida_kernwin.get_current_viewer()
         result = ida_kernwin.get_highlight(v)
         if result:
             stkvar_name, _ = result
             frame = ida_frame.get_frame(cur_ea)
             sptr = ida_struct.get_struc(frame.id)
             mptr = ida_struct.get_member_by_name(sptr, stkvar_name)
             if mptr:
                 fii = ida_funcs.func_item_iterator_t()
                 ok = fii.set(pfn)
                 while ok:
                     ea = fii.current()
                     F = ida_bytes.get_flags(ea)
                     for n in range(ida_ida.UA_MAXOP):
                         if not ida_bytes.is_stkvar(F, n):
                             continue
                         insn = ida_ua.insn_t()
                         if not ida_ua.decode_insn(insn, ea):
                             continue
                         v = ida_frame.calc_stkvar_struc_offset(
                             pfn, insn, n)
                         if v >= mptr.soff and v < mptr.eoff:
                             print("Found xref at 0x%08x, operand #%d" %
                                   (ea, n))
                     ok = fii.next_code()
             else:
                 print("No stack variable named \"%s\"" % stkvar_name)
     else:
         print("Please position the cursor within a function")
Ejemplo n.º 4
0
 def _data_type_enum(self) -> int:
     """The data type as a IDA enum"""
     if self.is_stack:
         flags = self._member.flag
     else:
         flags = ida_bytes.get_flags(self.addr)
     return flags & idc.DT_TYPE
Ejemplo n.º 5
0
    def dump():
        ret = []
        for addr, name in idautils.Names():
            flags = ida_bytes.get_flags(addr)
            # The 'a' heuristic is fairly bad but we need to filter out IDA's default
            # naming for strings
            if ida_bytes.has_dummy_name(flags) or ida_bytes.has_auto_name(flags) or not ida_bytes.is_data(flags) or name[0] == 'a':
                continue

            # Sometimes the auto-generated names don't actually usually have the
            # right flags set, so skip these auto-looking names.
            if any(name.startswith(s) for s in ['byte_', 'word_', 'dword_', 'unk_', 'jpt_']):
                continue

            sz = ida_bytes.get_item_size(addr)

            if ida_bytes.is_struct(flags):
                ti = ida_nalt.opinfo_t()
                ida_bytes.get_opinfo(ti, addr, 0, flags)
                typ = ida_struct.get_struc_name(ti.tid)
            else:
                typ = None
			
            ret.append(filter_none({
                'address': addr,
                'name': name,
                'type': typ,
                'sz': sz,
                'flags': flags,
            }))

        return ret
Ejemplo n.º 6
0
def restore_x(unique_name=None, start=None):
    ea = ida_kernwin.get_screen_ea()

    # signature
    if not unique_name:
        if not start:
            seg = ida_segment.getseg(ea)
            start = seg.start_ea
        sig_bytes = ida_bytes.get_bytes(start, SIGNATURE_SIZE)
        sig_hash = hashlib.md5(sig_bytes).hexdigest()
        unique_name = sig_hash

    if not start:
        seg = ida_segment.getseg(ea)
        start = seg.start_ea

    if MD5_hash_data_file and os.path.isfile(MD5_hash_data_file):
        with open(MD5_hash_data_file, "rb") as ifile:
            received_data = pickle.loads(ifile.read())
            saved_data = received_data

            print("dumpDyn::restore\n\
            Name: {}\n\
            Restore address: {}\n".format(unique_name, hex(start)))

            # (start_addr, end_addr, names, comms, bpts, funcs)
            if unique_name in saved_data:
                current_data = saved_data[unique_name]

                # restore names
                names = current_data[2]

                for name in names:
                    # names: (rel_addr, name, is_code)
                    ida_name.set_name(start + name[0], name[1])
                    flags = ida_bytes.get_flags(start + name[0])
                    if name[2] and not ida_bytes.is_code(flags):
                        ida_auto.auto_make_code(start + name[0])

                # restore comments
                # comms: (rel_addr, TYPE, comment)
                comms = current_data[3]
                for comm in comms:
                    # 0:MakeComm and 1:MakeRptCmt
                    ida_bytes.set_cmt(start + comm[0], comm[2], comm[1])

                # restore breakpoints
                # bpts: (rel_addr, size, type)
                bpts = current_data[4]
                for bpt in bpts:
                    ida_dbg.add_bpt(start + bpt[0], bpt[1], bpt[2])

                # restore functions
                funcs_addr = current_data[5]
                for addr in funcs_addr:
                    ida_auto.auto_make_proc(start + addr)  # make code & func
Ejemplo n.º 7
0
 def getBlocks(self, function_offset):
     blocks = []
     function_chart = ida_gdl.FlowChart(ida_funcs.get_func(function_offset))
     for block in function_chart:
         extracted_block = []
         for instruction in idautils.Heads(block.start_ea, block.end_ea):
             if ida_bytes.is_code(ida_bytes.get_flags(instruction)):
                 extracted_block.append(instruction)
         if extracted_block:
             blocks.append(extracted_block)
     return sorted(blocks)
Ejemplo n.º 8
0
def Callees(ea):
    pfn = ida_funcs.get_func(ea)
    callees = []
    if pfn:
        for item in pfn:
            F = ida_bytes.get_flags(item)
            if ida_bytes.is_code(F):
                insn = ida_ua.insn_t()
                if ida_ua.decode_insn(insn, item):
                    if ida_idp.is_call_insn(insn):
                        if insn.ops[0].type in [ida_ua.o_near, ida_ua.o_far]:
                            callees.append(insn.ops[0].addr)
    return list(dict.fromkeys(callees))
Ejemplo n.º 9
0
    def op_type_changed(self, ea, n):
        flags = ida_bytes.get_flags(ea)
        self.log("op_type_changed(ea=0x%08X, n=%d). Flags now: 0x%08X" % (ea, n, flags))

        buf = ida_nalt.opinfo_t()
        opi = ida_bytes.get_opinfo(buf, ea, n, flags)
        if opi:
            if ida_bytes.is_struct(flags):
                self.log("New struct: 0x%08X (name=%s)" % (
                    opi.tid,
                    ida_struct.get_struc_name(opi.tid)))
            elif ida_bytes.is_strlit(flags):
                encidx = ida_nalt.get_str_encoding_idx(opi.strtype)
                if encidx == ida_nalt.STRENC_DEFAULT:
                    encidx = ida_nalt.get_default_encoding_idx(ida_nalt.get_strtype_bpu(opi.strtype))
                encname = ida_nalt.get_encoding_name(encidx)
                strlen = ida_bytes.get_max_strlit_length(
                    ea,
                    opi.strtype,
                    ida_bytes.ALOPT_IGNHEADS | ida_bytes.ALOPT_IGNCLT)
                raw = ida_bytes.get_strlit_contents(ea, strlen, opi.strtype) or b""
                self.log("New strlit: 0x%08X, raw hex=%s (encoding=%s)" % (
                    opi.strtype,
                    binascii.hexlify(raw),
                    encname))
            elif ida_bytes.is_off(flags, n):
                self.log("New offset: refinfo={target=0x%08X, base=0x%08X, tdelta=0x%08X, flags=0x%X}" % (
                    opi.ri.target,
                    opi.ri.base,
                    opi.ri.tdelta,
                    opi.ri.flags))
            elif ida_bytes.is_enum(flags, n):
                self.log("New enum: 0x%08X (enum=%s), serial=%d" % (
                    opi.ec.tid,
                    ida_enum.get_enum_name(opi.ec.tid),
                    opi.ec.serial))
                pass
            elif ida_bytes.is_stroff(flags, n):
                parts = []
                for i in range(opi.path.len):
                    tid = opi.path.ids[i]
                    parts.append("0x%08X (name=%s)" % (tid, ida_struct.get_struc_name(tid)))
                self.log("New stroff: path=[%s] (len=%d, delta=0x%08X)" % (
                    ", ".join(parts),
                    opi.path.len,
                    opi.path.delta))
            elif ida_bytes.is_custom(flags) or ida_bytes.is_custfmt(flags, n):
                self.log("New custom data type") # unimplemented
        else:
            print("Cannot retrieve opinfo_t")
Ejemplo n.º 10
0
def iter_dynamic_functions() -> Iterable[Tuple[int, str]]:
    """
    Iterates the dynamically resolved function signatures.

    :yield: (ea, name)
    """
    # Look for data elements in the .data segment in which IDA has placed
    # a function signature element on.
    data_segment = ida_segment.get_segm_by_name(".data")
    for ea in idautils.Heads(start=data_segment.start_ea,
                             end=data_segment.end_ea):
        flags = ida_bytes.get_flags(ea)
        if idc.is_data(flags) and not idc.is_strlit(flags) and _is_func_type(
                ea):
            yield ea, ida_name.get_name(ea)
Ejemplo n.º 11
0
def show_microcode():
    """Generates and displays microcode for an address range.
    An address range can be a selection of code or that of
    the current function."""
    sel, sea, eea = kw.read_range_selection(None)
    pfn = ida_funcs.get_func(kw.get_screen_ea())
    if not sel and not pfn:
        return (False, "Position cursor within a function or select range")

    if not sel and pfn:
        sea = pfn.start_ea
        eea = pfn.end_ea

    addr_fmt = "%016x" if ida_ida.inf_is_64bit() else "%08x"
    fn_name = (ida_funcs.get_func_name(pfn.start_ea) if pfn else "0x%s-0x%s" %
               (addr_fmt % sea, addr_fmt % eea))
    F = ida_bytes.get_flags(sea)
    if not ida_bytes.is_code(F):
        return (False, "The selected range must start with an instruction")

    text, mmat, mba_flags = ask_desired_maturity()
    if text is None and mmat is None:
        return (True, "Cancelled")

    if not sel and pfn:
        mbr = hr.mba_ranges_t(pfn)
    else:
        mbr = hr.mba_ranges_t()
        mbr.ranges.push_back(ida_range.range_t(sea, eea))

    hf = hr.hexrays_failure_t()
    ml = hr.mlist_t()
    mba = hr.gen_microcode(mbr, hf, ml, hr.DECOMP_WARNINGS, mmat)
    if not mba:
        return (False, "0x%s: %s" % (addr_fmt % hf.errea, hf.desc()))
    vp = printer_t()
    mba.set_mba_flags(mba_flags)
    mba._print(vp)
    mcv = microcode_viewer_t()
    if not mcv.Create(
            mba, "0x%s-0x%s (%s)" %
        (addr_fmt % sea, addr_fmt % eea, text), text, fn_name, vp.get_mc()):
        return (False, "Error creating viewer")

    mcv.Show()
    return (True, "Successfully generated microcode for 0x%s..0x%s" %
            (addr_fmt % sea, addr_fmt % eea))
Ejemplo n.º 12
0
    def __init__(self, ea):
        self.ea = ea
        self.funcname_or_segname = ""
        self.text = ""
        if not ida_bytes.is_code(ida_bytes.get_flags(ea)):
            ida_ua.create_insn(ea)

        # text
        t = ida_lines.generate_disasm_line(ea)
        if t:
            self.text = ida_lines.tag_remove(t)

        # funcname_or_segname
        n = ida_funcs.get_func_name(ea) \
            or ida_segment.get_segm_name(ida_segment.getseg(ea))
        if n:
            self.funcname_or_segname = n
Ejemplo n.º 13
0
    def get_custom_viewer_hint(self, view, place):
        try:
            widget = ida_kernwin.get_current_widget()
            if ida_kernwin.get_widget_type(widget) != ida_kernwin.BWN_DISASM:
                return None

            curline = ida_kernwin.get_custom_viewer_curline(view, True)

            # sometimes get_custom_viewer_place() returns [x, y] and sometimes [place_t, x, y].
            # we want the place_t.
            viewer_place = ida_kernwin.get_custom_viewer_place(view, True)
            if len(viewer_place) != 3:
                return None

            _, x, y = viewer_place
            ea = place.toea()

            # "color" is a bit of misnomer: its the type of the symbol currently hinted
            color = get_color_at_char(curline, x)
            if color != ida_lines.COLOR_ADDR:
                return None

            # grab the FAR references to code (not necessarilty a branch/call/jump by itself)
            far_code_references = [
                xref.to for xref in idautils.XrefsFrom(ea, ida_xref.XREF_FAR)
                if ida_bytes.is_code(ida_bytes.get_flags(xref.to))
            ]
            if len(far_code_references) != 1:
                return None

            fva = far_code_references[0]

            # ensure its actually a function
            if not idaapi.get_func(fva):
                return None

            # this magic constant is the number of "important lines" to display by default.
            # the remaining lines get shown if you scroll down while the hint is displayed, revealing more lines.
            return render_function_hint(fva), DEFAULT_IMPORTANT_LINES_NUM
        except Exception as e:
            logger.warning(
                'unexpected exception: %s. Get in touch with @williballenthin.',
                e,
                exc_info=True)
            return None
Ejemplo n.º 14
0
def Heads(start=None, end=None):
    """
    Get a list of heads (instructions or data)

    @param start: start address (default: inf.min_ea)
    @param end:   end address (default: inf.max_ea)

    @return: list of heads between start and end
    """
    if not start: start = ida_ida.cvar.inf.min_ea
    if not end:   end = ida_ida.cvar.inf.max_ea

    ea = start
    if not idc.is_head(ida_bytes.get_flags(ea)):
        ea = ida_bytes.next_head(ea, end)
    while ea != ida_idaapi.BADADDR:
        yield ea
        ea = ida_bytes.next_head(ea, end)
Ejemplo n.º 15
0
    def get_custom_viewer_hint(self, viewer, place):
        widget_type = ida_kernwin.get_widget_type(viewer)
        if widget_type != ida_kernwin.BWN_DISASM:
            return

        flags = ida_bytes.get_flags(place.toea()) if place else 0
        if not ida_bytes.is_code(flags):
            return

        item = AMIE.extract_item(viewer)
        if not item:
            return
        tag, val = item

        hint = self.arch.hint(place.toea(), tag, val)
        if not hint:
            return

        return AMIE.format_hint(*hint)
Ejemplo n.º 16
0
def main():

    typelib = None
    for typelib_name in DEFAULT_TYPELIBS:
        typelib = ida_typeinf.load_til(typelib_name)
        if typelib:
            break
    if not typelib:
        print(f"Unable to load mssdk")
        return
    # print(f"Loaded mssdk type library: {typelib.name}")

    status_enum = ida_typeinf.import_type(typelib, -1, "MACRO_STATUS")
    if status_enum == ida_netnode.BADNODE:
        print(f"Unable to load type MACRO_STATUS")
    # print(f"Loaded MACRO_STATUS")

    # Grab the enum members
    enum_map = get_enum_map(status_enum)
    cur_member_id = ida_enum.get_first_enum_member(status_enum)
    while cur_member_id:
        cur_value = idaapi.get_const_value(cur_member_id)
        enum_map[cur_value] = cur_member_id
        cur_member_id = ida_enum.get_next_enum_member(cur_member_id)

    # Iterate over all untyped immediates
    imm_ea = ida_ida.cvar.inf.min_ea
    while (imm_ea != idaapi.BADADDR):
        imm_ea = ida_search.find_notype(
            imm_ea, ida_search.SEARCH_NEXT | ida_search.SEARCH_DOWN)[0]
        if ida_bytes.is_code(ida_bytes.get_flags(imm_ea)):
            enum_value = idc.get_operand_value(imm_ea, 1)
            # Only handle likely error types right now..
            if (enum_value & DWORD_MASK) > 0xC0000000:
                try:
                    cid = enum_map[enum_value]
                    # print(f"Applying {hex(enum_value & DWORD_MASK)} at {hex(imm_ea)}")
                    # We don't need the member, we can just apply the enum type to the address
                    ida_bytes.op_enum(imm_ea, 1, status_enum, 0)
                except KeyError:
                    continue
Ejemplo n.º 17
0
 def dbg_trace(self, tid, ip):
     if ip in self._visited_addrs:
         return 1
     self._visited_addrs.add(ip)
     if idc.is_unknown(ida_bytes.get_flags(ip)):
         ida_ua.create_insn(ip)
     else:
         idc.msg(
             'Skipping explored EA at address 0x{0:X}\n'.format(ip)
         )
     # print idc.generate_disasm_line(ip, 0)
     if ida_ua.decode_insn(ip) > 0:
         if 'ret' in ida_ua.cmd.get_canon_mnem().lower():
             idc.msg('Found ret instruction, suspending execution\n')
             ida_dbg.suspend_process()
     else:
         idc.msg(
             'Unable to decode instruction at address 0x{0:X}\n'.format(ip)
         )
         ida_dbg.suspend_process()
     return 0
Ejemplo n.º 18
0
    def dump():
        ret = []
        for addr, name in idautils.Names():
            flags = ida_bytes.get_flags(addr)
            if ida_bytes.has_dummy_name(flags) or ida_bytes.has_auto_name(
                    flags) or not ida_bytes.is_data(flags):
                print('skip auto:', name)
                continue

            # Sometimes the auto-generated names don't actually usually have the
            # right flags set, so skip these auto-looking names.
            if any(
                    name.startswith(s)
                    for s in ['byte_', 'word_', 'dword_', 'unk_', 'jpt_']):
                continue

            # print('%08x' % addr, '%08x' % flags, name,
            # ida_bytes.is_data(flags))

            sz = ida_bytes.get_item_size(addr)

            if ida_bytes.is_struct(flags):
                ti = ida_nalt.opinfo_t()
                ida_bytes.get_opinfo(ti, addr, 0, flags)
                # itemsize = ida_bytes.get_data_elsize(addr, flags, ti)
                typ = ida_struct.get_struc_name(ti.tid)
            else:
                # itemsize = ida_bytes.get_item_size(addr)
                typ = None

            ret.append({
                'address': addr,
                'name': name,
                'type': typ,
                'sz': sz,
                'flags': flags,
            })

        return ret
Ejemplo n.º 19
0
def color_head(ea):
    flags = ida_bytes.get_flags(ea)
    if not ida_bytes.is_code(flags):
        return

    mnem = ida_ua.print_insn_mnem(ea)
    if mnem == 'call':
        logger.debug('call: 0x%x', ea)
        idc.set_color(ea, idc.CIC_ITEM, CALL_COLOR)
    elif mnem == 'xor':
        if idc.get_operand_value(ea, 0) != idc.get_operand_value(ea, 1):
            logger.debug('non-zero xor: 0x%x', ea)
            idc.set_color(ea, idc.CIC_ITEM, ENCRYPT_COLOR)
    elif mnem in ('sdit', 'sgdt', 'sldt', 'smsw', 'str', 'in', 'cpuid'):
        logger.debug('anti-vm: 0x%x', ea)
        idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
    elif mnem == 'in':
        if idc.get_operand_value(ea, 0) in ("3", "2D"):
            logger.debug('anti-debug: 0x%x', ea)
            idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
    elif mnem in ('rdtsc', 'icebp'):
        logger.debug('anti-debug: 0x%x', ea)
        idc.set_color(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
Ejemplo n.º 20
0
    def apply_signatures(self, start_addr: int, end_addr: int) -> None:
        total_objs = len(self._signatures)

        idaapi.msg('Applying obj symbols...\n')

        objs_list = dict()

        for sig in self._signatures:
            bytes_data = sig.get_sig()

            low_entropy = (not bytes_data.is_bios_call()) and (sig.get_entropy() < self.min_entropy)

            labels = sig.get_labels()

            search_addr = start_addr

            while search_addr < end_addr:
                addr, _ = masked_search(search_addr, end_addr, bytes_data.get_bytes(), bytes_data.get_masks())

                if addr == idaapi.BADADDR:
                    break

                if not sig.is_applied():
                    objs_list[sig.get_name()] = (addr, sig.get_entropy())

                for lb in labels:
                    lb_name = lb[0]
                    lb_offs = lb[1]

                    if lb_name == '':  # removed label
                        continue

                    lb_addr = addr + lb_offs

                    if ida_bytes.is_unknown(ida_bytes.get_flags(lb_addr) and not low_entropy and not (sig.is_applied() and self.only_first)):
                        ida_auto.auto_make_code(lb_addr)

                    is_func = not lb_name.startswith('loc_')
                    new_name = '%s_' % sig.get_name().replace('.', '_')
                    new_lb_name = lb_name.replace('text_', new_name).replace('loc_', new_name)
                    new_lb_name = ('_%s' % new_lb_name) if ('0' <= new_lb_name[0] <= '9') else new_lb_name

                    if not low_entropy and not (sig.is_applied() and self.only_first) and not self.has_non_default_name(lb_addr, new_lb_name):
                        SigApplier.set_function(lb_addr, new_lb_name, is_func, False)
                        idaapi.msg('Symbol %s at 0x%08X\n' % (new_lb_name, lb_addr))
                    else:
                        prev_comment = ida_bytes.get_cmt(lb_addr, False)

                        prev_comment = ('%s\n' % prev_comment) if prev_comment else ''

                        new_comment = 'Possible %s/%s' % (sig.get_name(), new_lb_name)

                        if prev_comment.find(new_comment) == -1:
                            ida_bytes.set_cmt(lb_addr, '%s%s' % (prev_comment, new_comment), False)
                            idaapi.msg('Possible symbol %s at 0x%08X\n' % (new_lb_name, lb_addr))

                sig.set_applied(True)

                search_addr = addr + 4

        idaapi.msg('Applied OBJs for %s: %d/%d:\n' % (self.short_lib_name, len(objs_list), total_objs))

        for k, v in objs_list.items():
            idaapi.msg('\t0x%08X: %s, %.02f entropy\n' % (v[0], k, v[1]))
Ejemplo n.º 21
0

def show_xrefs(ea, gco, xrefs, ndefs):
    title = "xrefs to %s at %08x" % (gco.name, ea)
    xc = xref_chooser_t(xrefs, title, ndefs, ea, gco)
    i = xc.Show(True)
    if i >= 0:
        ida_kernwin.jumpto(xrefs[i])


if ida_hexrays.init_hexrays_plugin():
    ea = ida_kernwin.get_screen_ea()
    pfn = ida_funcs.get_func(ea)
    w = ida_kernwin.warning
    if pfn:
        F = ida_bytes.get_flags(ea)
        if ida_bytes.is_code(F):
            gco = ida_hexrays.gco_info_t()
            if ida_hexrays.get_current_operand(gco):
                # generate microcode
                hf = ida_hexrays.hexrays_failure_t()
                mbr = ida_hexrays.mba_ranges_t(pfn)
                mba = ida_hexrays.gen_microcode(mbr, hf, None,
                                                ida_hexrays.DECOMP_WARNINGS,
                                                ida_hexrays.MMAT_PREOPTIMIZED)
                if mba:
                    merr = mba.build_graph()
                    if merr == ida_hexrays.MERR_OK:
                        ncalls = mba.analyze_calls(ida_hexrays.ACFL_GUESS)
                        if ncalls < 0:
                            print(
Ejemplo n.º 22
0
movs = ["mov", "xchg"]

ida_api_is_new = False
try:
    import ida_auto
    ida_api_is_new = True
except ImportError:
    pass

user_pos = ida_kernwin.get_screen_ea()
after_function_before_user_pos = ida_funcs.get_prev_func(user_pos).end_ea + 1
before_function_after_user_pos = ida_funcs.get_next_func(user_pos).start_ea - 1
hopefully_a_sane_start_of_function = (after_function_before_user_pos
                                      & ~0x0F) + 0x10
make_fun_pos = None
if ida_bytes.is_code(ida_bytes.get_flags(hopefully_a_sane_start_of_function)):
    make_fun_pos = hopefully_a_sane_start_of_function


def re_analyze_relevant_range():
    ida_bytes.del_items(
        after_function_before_user_pos, 0,
        before_function_after_user_pos - after_function_before_user_pos)
    if not make_fun_pos is None:
        assume_code_at(make_fun_pos)
    else:
        run_autoanalysis(after_function_before_user_pos,
                         before_function_after_user_pos)


def run_autoanalysis(start, end=None):
Ejemplo n.º 23
0
def CallStackWalk(nn):
    class Result:
        """
        Class holding the result of one call stack item
        Each call stack item instance has the following attributes:
            caller = ea of caller
            displ  = display string
            sp     = stack pointer
        """
        def __init__(self, caller, sp):
            self.caller = caller
            self.sp     = sp
            f = ida_funcs.get_func(caller)
            self.displ = "%08x: " % caller
            if f:
                self.displ += ida_funcs.get_func_name(caller)
                t = caller - f.start_ea
                if t > 0: self.displ += "+" + hex(t)
            else:
                self.displ += hex(caller)
            self.displ += " [" + hex(sp) + "]"

        def __str__(self):
            return self.displ

    # get stack pointer
    sp = idautils.cpu.Esp
    seg = ida_segment.getseg(sp)
    if not seg:
        return (False, "Could not locate stack segment!")

    stack_seg = Seg(seg)
    word_size = 2 ** (seg.bitness + 1)
    callers = []
    sp = idautils.cpu.Esp - word_size
    while sp < stack_seg.end_ea:
        sp += word_size
        ptr = next(idautils.GetDataList(sp, 1, word_size))
        seg = ida_segment.getseg(ptr)
        # only accept executable segments
        if (not seg) or ((seg.perm & ida_segment.SEGPERM_EXEC) == 0):
            continue
        # try to find caller
        caller = IsPrevInsnCall(ptr)
        # we have no recognized caller, skip!
        if caller is None:
            continue

        # do we have a debug name that is near?
        if nn:
            ret = nn.find(caller)
            if ret:
                ea = ret[0]
                # function exists?
                f = ida_funcs.get_func(ea)
                if not f:
                    # create function
                    ida_funcs.add_func(ea)

        # get the flags
        f = ida_bytes.get_flags(caller)
        # no code there?
        if not ida_bytes.is_code(f):
            ida_ua.create_insn(caller)

        callers.append(Result(caller, sp))
    #
    return (True, callers)
Ejemplo n.º 24
0
def load_file(fd, neflags, format):
    global prologues
    size = 0
    base_addr = 0
    ea = 0
    nfunc = 0
    idaapi.set_processor_type("arm", idaapi.SETPROC_LOADER)
    idaapi.get_inf_structure().lflags |= idaapi.LFLG_64BIT
    if (neflags & idaapi.NEF_RELOAD) != 0:
        return 1
    fd.seek(0, idaapi.SEEK_END)
    size = fd.tell()
    segm = idaapi.segment_t()
    segm.bitness = 2  # 64-bit
    segm.start_ea = 0
    segm.end_ea = size
    idaapi.add_segm_ex(segm, "iBoot", "CODE", idaapi.ADDSEG_OR_DIE)
    fd.seek(0)
    fd.file2base(0, 0, size, False)
    idaapi.add_entry(0, 0, "start", 1)
    idaapi.add_func(ea, idaapi.BADADDR)
    print("[+] Marked as code")
    # heuristic
    while (True):
        mnemonic = idaapi.ua_mnem(ea)
        if mnemonic == None:
            mnemonic = ''
        if "LDR" in mnemonic:
            base_str = idc.print_operand(ea, 1)
            base_addr = int(base_str.split("=")[1], 16)
            break
        ea += 4
    print("[+] Rebasing to address 0x%x" % (base_addr))
    idaapi.rebase_program(base_addr, idc.MSF_NOFIX)
    ida_auto.auto_wait()

    segment_start = base_addr
    segment_end = idc.get_segm_attr(segment_start, idc.SEGATTR_END)
    ea = segment_start

    print("[+] Searching and defining functions")

    for prologue in prologues:
        while ea != idc.BADADDR:
            ea = ida_search.find_binary(ea, idc.ida_search.SEARCH_DOWN,
                                        prologue, 16, ida_search.SEARCH_DOWN)
            if ea != idc.BADADDR:
                ea = ea - 2
                if (ea % 4) == 0 and ida_bytes.get_flags(ea) < 0x200:
                    print("[+] Defining a function at 0x%x" % (ea))
                    idaapi.add_func(ea, idaapi.BADADDR)
                    nfunc = nfunc + 1
                ea = ea + 4

    ida_auto.plan_and_wait(segment_start, segment_end)
    print("[+] Identified %d new functions" % (nfunc))
    print("[+] Looking for interesting functions")
    find_interesting(segment_start)
    return 1


# EOF
Ejemplo n.º 25
0
def CallStackWalk(nn):
    class Result:
        """
        Class holding the result of one call stack item
        Each call stack item instance has the following attributes:
            caller = ea of caller
            displ  = display string
            sp     = stack pointer
        """
        def __init__(self, caller, sp):
            self.caller = caller
            self.sp     = sp
            f = ida_funcs.get_func(caller)
            self.displ = "%08x: " % caller
            if f:
                self.displ += ida_funcs.get_func_name(caller)
                t = caller - f.start_ea
                if t > 0: self.displ += "+" + hex(t)
            else:
                self.displ += hex(caller)
            self.displ += " [" + hex(sp) + "]"

        def __str__(self):
            return self.displ

    # get stack pointer
    sp = idautils.cpu.Esp
    seg = ida_segment.getseg(sp)
    if not seg:
        return (False, "Could not locate stack segment!")

    stack_seg = Seg(seg)
    word_size = 2 ** (seg.bitness + 1)
    callers = []
    sp = idautils.cpu.Esp - word_size
    while sp < stack_seg.end_ea:
        sp += word_size
        ptr = next(idautils.GetDataList(sp, 1, word_size))
        seg = ida_segment.getseg(ptr)
        # only accept executable segments
        if (not seg) or ((seg.perm & ida_segment.SEGPERM_EXEC) == 0):
            continue
        # try to find caller
        caller = IsPrevInsnCall(ptr)
        # we have no recognized caller, skip!
        if caller is None:
            continue

        # do we have a debug name that is near?
        if nn:
            ret = nn.find(caller)
            if ret:
                ea = ret[0]
                # function exists?
                f = ida_funcs.get_func(ea)
                if not f:
                    # create function
                    ida_funcs.add_func(ea)

        # get the flags
        f = ida_bytes.get_flags(caller)
        # no code there?
        if not ida_bytes.is_code(f):
            ida_ua.create_insn(caller)

        callers.append(Result(caller, sp))
    #
    return (True, callers)
Ejemplo n.º 26
0
def is_str_literal(addr):
    return ida_bytes.is_strlit(ida_bytes.get_flags(addr))
Ejemplo n.º 27
0
def save_x(unique_name=None, start=None, size=None):
    ea = ida_kernwin.get_screen_ea()

    # signature
    if not unique_name:
        if not start:
            seg = ida_segment.getseg(ea)
            start = seg.start_ea
        sig_bytes = ida_bytes.get_bytes(start, SIGNATURE_SIZE)
        sig_hash = hashlib.md5(sig_bytes).hexdigest()
        unique_name = sig_hash

    if not start or not size:
        seg = ida_segment.getseg(ea)
        start = seg.start_ea
        size = seg.size()

    # (start_addr, end_addr, names, comms)
    saved_data = {}
    if MD5_hash_data_file and os.path.isfile(MD5_hash_data_file):
        with open(MD5_hash_data_file, "rb") as ifile:
            received_data = pickle.loads(ifile.read())
            if received_data:
                saved_data = received_data

    # save names (func_names, labels, etc)
    # (addr, name, is_code)
    names_addr_name = []
    names = idautils.Names()
    for addr, name in names:
        if start <= addr <= start + size:
            flags = ida_bytes.get_flags(addr)
            names_addr_name.append(
                (addr - start, name, ida_bytes.is_code(flags)))

    # save comments
    comms_addr_type_comm = []
    # (addr, TYPE, comment)
    # type 0:comment 1:rpt_comment
    end = start + size
    for i in range(start, end + 1):
        if ida_bytes.get_cmt(i, 0):  # 0 Comment
            comms_addr_type_comm.append((i - start, 0, ida_bytes.get_cmt(i,
                                                                         0)))
        if ida_bytes.get_cmt(i, 1):  # 1 RptCmt
            comms_addr_type_comm.append((i - start, 1, ida_bytes.get_cmt(i,
                                                                         1)))

    # breakpoints
    bpts_addr_size_type = []
    bpt = ida_dbg.bpt_t()
    global remove_on_exit_bpts
    for i in range(start, end + 1):
        if ida_dbg.get_bpt(i, bpt):
            bpts_addr_size_type.append((i - start, bpt.size, bpt.type))
            remove_on_exit_bpts.append(i)

    # functions
    funcs_addr = []
    flag = ida_bytes.get_flags(start)
    if ida_bytes.is_func(flag):
        funcs_addr.append(0)  # start addr
    next_func = ida_funcs.get_next_func(start)
    while next_func:
        funcs_addr.append(next_func.start_ea - start)
        next_func = ida_funcs.get_next_func(next_func.start_ea)

    # SAVE
    saved_data[unique_name] = (start, start + end, names_addr_name,
                               comms_addr_type_comm, bpts_addr_size_type,
                               funcs_addr)

    if MD5_hash_data_file:
        with open(MD5_hash_data_file, "wb") as ifile:
            serial_data = pickle.dumps(saved_data)
            ifile.write(serial_data)
            print("dumpDyn::save:\n\
            Name: {}\n\
            Start address: {}".format(unique_name, hex(start)))
import idautils
import ida_bytes
import idaapi

for ea in idautils.Heads():
    if ida_bytes.is_code(ida_bytes.get_flags(ea)) and idaapi.is_call_insn(ea):
        idaapi.set_item_color(ea, 0xFFFFFFA0)
Ejemplo n.º 29
0
 def _is_string(self, ea):
     head = get_item_head(ea)
     flags = get_flags(head)
     return is_strlit(flags)
Ejemplo n.º 30
0
def main():
    global til

    til = ida_typeinf.get_idati()

    capstone_init()
    unicorn_init()

    all_names = list(idautils.Names())

    # First, get inheritance tree for all classes
    # We do this in two passes:
    #   First pass: for each class, gather class name, parent class name,
    #               and superclass name, and connect them
    #   Second pass: for each inheritance hierarchy object, we check
    #                   if the parent pointer is None (signaling a top-level
    #                   class), and add that to the `ihs` list
    # We can do this whole thing by processing xrefs to OSMetaClass::OSMetaClass
    OSMetaClass_ctor = get_OSMetaClass_ctor()

    if OSMetaClass_ctor == 0:
        print("Could not find OSMetaClass::OSMetaClass")
        return

    print("Got OSMetaClass::OSMetaClass at {}".format(hex(OSMetaClass_ctor)))

    # key,value pairs of all inheritance hierarchy objects
    ih_dict = {}

    # only those inheritance hierarchy objects which represent
    # a top-level parent class (aka inheriting from OSObject)
    ihs = []

    xrefs = list(idautils.XrefsTo(OSMetaClass_ctor))

    num = 0

    for xref in xrefs:
        frm = xref.frm
        # test
        # frm = 0x63920
        # print("xref from {}".format(hex(frm)))
        args = get_OSMetaClass_ctor_args(frm)

        pname = args[0]
        cname = args[1]

        if cname == "OSMetaClassBase":
            print("xref from {}".format(hex(frm)))
            print(args)

        if pname == cname:
            continue

        csz = args[2]

        # if pname == "AUAUnitDictionary" and cname == "AUAMixerUnitDictionary":
        #     print(args)
        # return

        new_parent = pname is not None and pname not in ih_dict
        new_child = cname not in ih_dict

        if new_parent:
            ih_dict[pname] = InheritanceHierarchy(None, pname, csz, csz)

        if new_child:
            ih_dict[cname] = InheritanceHierarchy(None, cname, csz)
        else:
            # Update class size for only child classes
            ih_dict[cname].sz = csz

        if pname == None:
            # If this class has no superclass, it must be parent class,
            # so make its InheritanceHierarchy object
            ih_dict[cname] = InheritanceHierarchy(None, cname, csz)
        else:
            child_ih = ih_dict[cname]
            parent_ih = ih_dict[pname]
            parent_ih.add_child(child_ih)
            child_ih.parent = parent_ih
            child_ih.totsz = child_ih.sz + parent_ih.totsz

        # if cname == "AUAUnitDictionary":
        #     print("AUAUnitDictionary sz: {}".format(ih_dict[pname].sz))
        #     print(args)
        #     return
        # if cname == "AUAMixerUnitDictionary":
        #     print("AUAMixerUnitDictionary sz: {}".format(ih_dict[cname].sz))
        #     print(args)
        #     return

        num += 1
        # if num == 10:
        #     break

    print("First pass: {} classes processed".format(num))
    num = 0

    # Second pass
    for ih in ih_dict.values():
        if ih.parent == None:
            # print("Adding {} to the ihs list".format(ih.name))
            num += 1
            ihs.append(ih)

    print("Second pass: {} classes added to ihs list".format(num))
    num = 0

    wants_class_hierarchy = ida_kernwin.ask_yn(0, "Dump class hierarchy?")

    if wants_class_hierarchy:
        hierch_file = open(
            "{}/iOS/Scripts/iokit_hier.txt".format(str(Path.home())), "w")
        for ih in ihs:
            dump_hierarchy_to_file(hierch_file, ih, 0)
        print("File written to {}".format(hierch_file.name))
        hierch_file.close()
        return

    vtables = []

    for cur_name in all_names:
        ea = cur_name[0]
        name = cur_name[1]

        if "ZTV" in name:
            vtables.append(cur_name)

    struct_file = open(
        "{}/iOS/Scripts/structs_from_vtabs.h".format(str(Path.home())), "w")

    is_standalone_kext = ida_kernwin.ask_yn(0, "Standalone kext?")

    if is_standalone_kext:
        # If this is from a standalone kext, I need to write some
        # definitions for common objects that follow my struct format,
        # otherwise, things get really screwed
        struct_file.write(
            "struct __cppobj ExpansionData {};\n\n"
            "struct __cppobj OSMetaClassBase_vtbl;\n\n"
            "struct __cppobj OSMetaClassBase_mbrs {};\n\n"
            "struct __cppobj OSMetaClassBase {\n"
            "\tOSMetaClassBase_vtbl *__vftable /*VFT*/;\n"
            "\tOSMetaClassBase_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSObject_mbrs : OSMetaClassBase_mbrs {\n"
            "\tint retainCount;\n"
            "};\n\n"
            "struct __cppobj OSObject_vtbl : OSMetaClassBase_vtbl {};\n\n"
            "struct __cppobj OSObject {\n"
            "\tOSObject_vtbl *__vftable;\n"
            "\tOSObject_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSMetaClass_mbrs : OSMetaClassBase_mbrs {\n"
            "\tExpansionData *reserved;\n"
            "\tconst OSMetaClass *superClassLink;\n"
            "\tconst OSSymbol *className;\n"
            "\tunsigned int classSize;\n"
            "\tunsigned int instanceCount;\n"
            "};\n\n"
            "struct __cppobj OSMetaClass {\n"
            "\tOSMetaClassBase_vtbl *__vftable;\n"
            "\tOSMetaClass_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSCollection_vtbl;\n"
            "struct __cppobj OSCollection_mbrs : OSObject_mbrs {\n"
            "\tunsigned int updateStamp;\n"
            "\tunsigned int fOptions;\n"
            "};\n\n"
            "struct __cppobj OSCollection {\n"
            "\tOSCollection_vtbl *__vftable;\n"
            "\tOSCollection_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSArray_vtbl;\n"
            "struct __cppobj OSArray_mbrs : OSCollection_mbrs {\n"
            "\tunsigned int count;\n"
            "\tunsigned int capacity;\n"
            "\tunsigned int capacityIncrement;\n"
            "\tvoid *array;\n"
            "};\n\n"
            "struct __cppobj OSArray {\n"
            "\tOSArray_vtbl *__vftable;\n"
            "\tOSArray_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSDictionary::dictEntry {\n"
            "\tconst OSSymbol *key;\n"
            "\tconst OSMetaClassBase *value;\n"
            "};\n\n"
            "struct __cppobj OSDictionary_vtbl;\n"
            "struct __cppobj OSDictionary_mbrs : OSCollection_mbrs {\n"
            "\tunsigned int count;\n"
            "\tunsigned int capacity;\n"
            "\tunsigned int capacityIncrement;\n"
            "\tOSDictionary::dictEntry *dict;\n"
            "};\n\n"
            "struct __cppobj OSDictionary {\n"
            "\tOSDictionary_vtbl *__vftable;\n"
            "\tOSDictionary_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSSet_vtbl;\n"
            "struct __cppobj OSSet_mbrs : OSCollection_mbrs {\n"
            "\tOSArray *members;\n"
            "};\n\n"
            "struct __cppobj OSSet {\n"
            "\tOSSet_vtbl *__vftable;\n"
            "\tOSSet_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSString_mbrs : OSObject_mbrs {\n"
            "\tunsigned __int32 flags : 14;\n"
            "\tunsigned __int32 length : 18;\n"
            "\tchar *string;\n"
            "};\n\n"
            "struct __cppobj OSString {\n"
            "\tOSObject_vtbl *__vftable;\n"
            "\tOSString_mbrs m;\n"
            "};\n\n"
            "struct __cppobj OSSymbol : OSString {};\n\n")

    num_failed_get_type = 0
    cnt = 0

    for vtable in vtables:
        demangled_name = idc.demangle_name(vtable[1],
                                           get_inf_attr(idc.INF_LONG_DN))

        # unless this is a vtable for OSMetaClassBase, OSMetaClassMeta,
        # or OSMetaClass, skip anything metaclass related
        if "::MetaClass" in demangled_name:
            continue

        class_name = ida_name.extract_name(demangled_name, len("`vtable for'"))

        if class_name in BLACKLIST:
            continue

        ea = vtable[0]  #+ 8;

        while ida_bytes.get_qword(ea) == 0:
            ea += 8

        # print("EA: {}".format(hex(ea)))
        if is_unknown(ida_bytes.get_flags(ea)):
            continue

        # if class_name != "IOSkywalkPacket":
        #     continue
        # if class_name != "AHTHSBufferStatic":
        #     continue
        # if class_name != "HSMSPITest":
        #     continue
        # if class_name != "AppleMesa":
        #     continue
        # if class_name != "AppleUSBHostController":
        #     continue
        # if class_name != "AppleEmbeddedPCIE":
        #     continue
        # if class_name != "SimpleEval":
        #     continue
        # if class_name != "AppleUSBCDCControl":
        #     continue
        # if class_name != "IOHDCP2TransmitterAuthSession":
        #     continue
        # if class_name != "IOAVService::DisplayIDParser::readDisplayID":
        #     continue
        # if class_name != "IOMFB::TypedProp":
        #     continue
        # if class_name != "IOMFB::UPBlock_GenPipe_v2":
        #     continue
        # if class_name != "AppleMesaSEPDriver":
        #     continue
        # if class_name != "IOAVController":
        #     continue
        # if class_name != "AppleConvergedIPCICEBBBTIInterface":
        #     continue
        # if class_name != "ApplePPM":
        #     continue

        cnt += 1

        # print("{}".format(class_name))

        # skip NULL pointers until we hit a function
        while ida_bytes.get_qword(ea) == 0:
            ea += 8

        num_virts = 0
        num_dtors = 0
        num_untyped = 0
        num_noname = 0

        fxn_name_list = []
        fxn_name_dict = {}

        struct_fields = []

        fwd_decls = set()
        fwd_decls.add(class_name)

        svt = SymbolicatedVtable(class_name)
        ioc = IOKitClass(svt)
        ioc.svt = svt

        # vtables seem to be NULL terminated
        while True:
            fxn_ea = ida_bytes.get_qword(ea)

            # end of vtable for this class
            if fxn_ea == 0:
                break

            # print("Type for {}/{} @ {}: {}".format(hex(fxn_ea), fxn_name, hex(ea), fxn_type))

            # if fxn_type == None:
            #     num_failed_get_type += 1
            #     ea += 8
            #     continue

            # default to this for ___cxa_pure_virtual
            fxn_args = "void"
            fxn_call_conv = ""
            fxn_mangled_name = ida_name.get_ea_name(fxn_ea)
            fxn_name = ida_name.demangle_name(fxn_mangled_name,
                                              get_inf_attr(idc.INF_LONG_DN))

            if fxn_name == None:
                # ___cxa_pure_virtual
                fxn_name = ida_name.get_ea_name(fxn_ea)

                # some other thing?
                if len(fxn_name) == 0:
                    fxn_name = "noname{}".format(num_noname)
            else:
                fxn_type = idc.get_type(fxn_ea)

                if fxn_type == None:
                    # sometimes this happens, don't know why
                    # the only thing fxn_type would have provided was
                    # the calling convention, so we need to manually
                    # reconstruct parameter list, and assume calling
                    # convention is __fastcall

                    # if mangled_fxn_name == "__ZN25IOGeneralMemoryDescriptor7doUnmapEP7_vm_mapyy":
                    #     exit(0)
                    fxn_return_type = "__int64"
                    fxn_call_conv = "__fastcall"

                    fxn_args_string = fxn_name[fxn_name.find("(") +
                                               1:fxn_name.rfind(")")]

                    # if fxn_args_string == "IOService *, unsigned int, void *, void (*)(OSObject *, AppleUSBCDCControl*, void *, USBCDCNotification *)":
                    #     # print("Hello")
                    #     fxn_args_string = "IOService *, unsigned int, void *, void (*)(OSObject *, void (*)(TestType *, AppleUSBCDCControl*, void *, USBCDCNotification *), AppleUSBCDCControl*, void *, USBCDCNotification *)"

                    # print("fxn args: {}".format(fxn_args_string))

                    # if fxn_args_string == "OSObject *, void (*)(OSObject *, IOHDCPAuthSession *), IOHDCPMessageTransport *, IOHDCPInterface *":
                    #     fxn_args_string = "OSObject *, void (*)(OSObject *, IOHDCPAuthSession *), IOHDCPMessageTransport *, IOHDCPInterface *, unsigned long long"

                    fxn_args_string = fxn_args_string.replace(
                        "{block_pointer}", "*")

                    if fxn_args_string.find(",") != -1:
                        # print("More than one arg: {}".format(fxn_args_list))

                        # extra comma makes the parser happy
                        fxn_args_types_list = get_arg_type_list(
                            fxn_args_string + ",")

                        # print("More than one arg for {}: {}".format(fxn_name, fxn_args_types_list))
                        # print()

                        fxn_args = ""
                        argnum = 0

                        # print(type(fxn_args_types_list))
                        to_fwd_decl = get_fwd_decls(fxn_args_types_list)

                        if len(to_fwd_decl) > 0:
                            fwd_decls.update(to_fwd_decl)

                        for arg_type in fxn_args_types_list:
                            if argnum == 0:
                                fxn_args += "{} *__hidden this, ".format(
                                    class_name)
                            else:
                                fxn_args += "{}, ".format(fix_type(arg_type))

                            argnum += 1

                        fxn_args = fxn_args[:-2]
                    else:
                        fxn_args = "{} *__hidden this".format(class_name)

                        arg_type = fxn_name[fxn_name.find("(") +
                                            1:fxn_name.rfind(")")]

                        # print("Only one arg for {}: {}".format(fxn_name, arg_type))
                        arg_type_list = [arg_type]
                        # print("Only one arg: {}".format(arg_type_list))
                        to_fwd_decl = get_fwd_decls(arg_type_list)

                        if len(to_fwd_decl) > 0:
                            fwd_decls.update(to_fwd_decl)

                        if arg_type != "void" and len(arg_type) > 0:
                            fxn_args += ", {}".format(fix_type(arg_type))
                else:
                    all_except_args = fxn_type[:fxn_type.find("(")]

                    # first, if there's no spaces, there's no calling
                    # convention specifed
                    if all_except_args.find(" ") == -1:
                        fxn_return_type = all_except_args

                        # Also, this having no spaces could mean IDA messed
                        # up, so we should use the demangled name instead
                        # and parse that
                        fxn_type = "(" + fxn_name[fxn_name.find("(") + 1:]
                        # print("No spaces in args, using {} as fxn_type".format(fxn_type))
                    else:
                        double_underscore = all_except_args.rfind("__")

                        if double_underscore != -1:
                            fxn_return_type = all_except_args[:
                                                              double_underscore]
                            fxn_call_conv = all_except_args[double_underscore:]
                        else:
                            fxn_return_type = all_except_args

                    # get args
                    # print("fxn_type: {}".format(fxn_type))
                    fxn_args = fxn_type[fxn_type.find("(") +
                                        1:fxn_type.rfind(")")]
                    fxn_args_type_list = get_arg_type_list(fxn_args + ",")
                    fixed_fxn_args_type_list = []

                    # Fix up args
                    for arg_type in fxn_args_type_list:
                        # Remove __hidden
                        arg_type = arg_type.replace("__hidden", "")

                        # Check for a pointer. This is an easy case, we
                        # just delete everything from the first *
                        star = arg_type.find("*")

                        if star != -1:
                            arg_type = arg_type[0:star]
                        else:
                            # Otherwise, find the last space, and delete
                            # from there
                            # But in case there was no name for this
                            # parameter, check if the token after the last
                            # space is not an IDA type or primitive type
                            lspace = arg_type.rfind(" ")

                            if lspace != -1:
                                token = arg_type[lspace:].replace(" ", "")

                                if not is_primitive_type(
                                        token) and not is_ida_type(token):
                                    arg_type = arg_type[0:lspace]

                        # print("arg_type: {}".format(arg_type))

                        fixed_fxn_args_type_list.append(arg_type)

                    # to_fwd_decl = get_fwd_decls(fxn_args_type_list)
                    to_fwd_decl = get_fwd_decls(fixed_fxn_args_type_list)

                    if len(to_fwd_decl) > 0:
                        fwd_decls.update(to_fwd_decl)

                    # print("fxn_type is not None for {}: fxn args: {}".format(fxn_name, fxn_args_type_list))
                    # print("fxn_type is not None: will fwd declare: {}".format(to_fwd_decl))

                # get function name
                # remove 'classname::' and params
                fxn_name = fxn_name[fxn_name.find("::") +
                                    2:fxn_name.find("(") + 1]
                fxn_name = fxn_name[:fxn_name.find("(")]
                # replace any '~'
                fxn_name = fxn_name.replace("~", "DTOR{}_".format(num_dtors))
                # remove any < and >
                fxn_name = fxn_name.replace("<", "")
                fxn_name = fxn_name.replace(">", "")

                if fxn_name in list(fxn_name_dict.keys()):
                    fxn_name_dict[fxn_name] += 1
                    fxn_name += "_{}".format(fxn_name_dict[fxn_name])
                else:
                    fxn_name_dict[fxn_name] = -1

                if "DTOR" in fxn_name:
                    num_dtors += 1

            curfield = ""

            if fxn_name == "___cxa_pure_virtual":
                # struct_fields.append("\tvoid __noreturn (__cdecl *___cxa_pure_virtual{})({});".format(num_virts,
                #     fxn_args))
                curfield = "\tvoid __noreturn (__cdecl *___cxa_pure_virtual{})({});".format(
                    num_virts, fxn_args)
                num_virts += 1
            else:
                # struct_fields.append("\t{} ({} *{})({});".format(fxn_return_type,
                #     fxn_call_conv, fxn_name, fxn_args))
                curfield = "\t{} ({} *{})({});".format(fxn_return_type,
                                                       fxn_call_conv, fxn_name,
                                                       fxn_args)

            svt.add(curfield)

            ea += 8

        # return
        # Some classes won't have xrefs to OSMetaClass::OSMetaClass,
        # like OSMetaClassBase
        if class_name in ih_dict:
            ih_dict[class_name].ioc = ioc

        # Just write forward decls for now
        for decl in fwd_decls:
            struct_file.write("struct __cppobj {};\n".format(decl))

        struct_file.write("\n")

        # cnt += 1

        # if cnt == 5:
        #     break

    print("{} IOKit vtables".format(len(vtables)))

    # Now create the header file to import into IDA
    # for ih in ihs:
    #     dump_ih(ih, 0)

    generate_header_file(struct_file, ihs)
    # fixup_header_file(struct_file)

    struct_file.close()
Ejemplo n.º 31
0
def dump_heads(out):
    # out is a file like object, sys.stdout or an acual file object

    # There doesn't seem to a good way to determine what function a
    # particular address is in.  Almost everyone recommends iterating
    # of the functions, and then getting the bytes out of each, but
    # that's not really what we want because it skips non function
    # bytes and reports them in the wrong order. It appears that the
    # best we can do is to build a map in advance. :-(
    a2fmap = build_a2fmap()

    min_ea = idaapi.cvar.inf.minEA
    max_ea = idaapi.cvar.inf.maxEA
    ea = min_ea
    while ea != ida_idaapi.BADADDR:
        ida_auto.show_addr(ea)
        isize = ida_bytes.get_item_size(ea)
        ibytes = ida_bytes.get_bytes(ea, isize)
        ihexbytes = binascii.b2a_hex(ibytes).upper()
        iflags = ida_bytes.get_flags(ea)

        # Skip the PE header?
        if not ida_bytes.is_head(iflags):
            ea = ida_bytes.next_head(ea, max_ea)
            continue

        # Loop up this address in the address-to-function map.
        if ea in a2fmap:
            faddrs = a2fmap[ea]
        else:
            faddrs = [ea]

        tcode = "ERROR"
        imnem = "???"
        iops = "???"

        if ida_bytes.is_code(iflags):
            tcode = "INSN"
            imnem = "???"
            iops = "???"

            insn = idautils.DecodeInstruction(ea)
            if insn == None:
                imnem = "BAD"
                iops = ""
            elif not insn.is_canon_insn():
                imnem = "NCAN"
                iops = ""
            else:
                imnem = insn.get_canon_mnem()

                sops = []
                for n in range(8):
                    ostr = ida_ua.print_operand(ea, n)
                    if ostr is not None:
                        ostrnt = ida_lines.tag_remove(ostr)
                        if ostrnt != '':
                            sops.append(ostrnt)
                iops = ', '.join(sops)

        elif ida_bytes.is_data(iflags):
            tcode = "DATA"
            imnem = "db"
            iops = "???"
            if ida_bytes.is_align(iflags):
                tcode += "_ALIGN"
            #elif ida_bytes.is_struct(iflags):
            #    tcode += "_STRUCT"
            #elif ida_bytes.is_char(iflags):
            #    tcode += "_STR"
            # There are other types that IDA recognizes.
        elif ida_bytes.is_unknown(iflags):
            tcode = "UNK-%08X" % iflags
            imnem = "???"
            iops = "???"

        for faddr in sorted(faddrs):
            out.write('"PART",0x%08X,"%s",0x%08X,"%s","%s","%s"\n' %
                      (ea, tcode, faddr, ihexbytes, imnem, iops))
        ea = ida_bytes.next_head(ea, max_ea)
    print "Analysis complete!"