Example #1
0
    def _event(cls):
        while True:
            # cmt_changing event
            ea, rpt, new = (yield)
            fn = idaapi.get_func(ea)
            old = utils.string.of(idaapi.get_func_cmt(fn, rpt))
            o, n = internal.comment.decode(old), internal.comment.decode(new)

            # update references before we update the comment
            cls._update_refs(fn, o, n)

            # wait for cmt_changed event
            newea, nrpt, none = (yield)

            # now we can fix the user's new coment
            if (newea, nrpt, none) == (ea, rpt, None):
                ncmt = utils.string.of(idaapi.get_func_cmt(fn, rpt))

                if (ncmt or '') != new:
                    logging.warn(u"{:s}.event() : Comment from event for function {:#x} is different from database. Expected comment ({!s}) is different from current comment ({!s}).".format('.'.join((__name__, cls.__name__)), ea, utils.string.repr(new), utils.string.repr(ncmt)))

                # if it's non-repeatable, then fix it.
#                if not nrpt:
#                    idaapi.set_func_cmt(fn, '', nrpt)

#                # write the tag back to the function
#                if internal.comment.check(new): idaapi.set_func_cmt(fn, utils.string.to(internal.comment.encode(n)), True)
#                # otherwise, write the comment back as long as it's valid
#                elif new: idaapi.set_func_cmt(fn, utils.string.to(new), True)
#                # otherwise, the user has deleted it..so update its refs.
#                else: cls._delete_refs(fn, n)

                # write the tag back to the function
                if internal.comment.check(new): idaapi.set_func_cmt(fn, utils.string.to(internal.comment.encode(n)), rpt)
                elif new: idaapi.set_func_cmt(fn, utils.string.to(new), rpt)
                else: cls._delete_refs(fn, n)
                continue

            # if the changed event doesn't happen in the right order
            logging.fatal(u"{:s}.event() : Comment events are out of sync for function {:#x}, updating tags from previous comment. Expected comment ({!s}) is different from current comment ({!s}).".format('.'.join((__name__, cls.__name__)), ea, utils.string.repr(o), utils.string.repr(n)))

            # delete the old comment
            cls._delete_refs(fn, o)
            idaapi.set_func_cmt(fn, '', rpt)
            logging.warn(u"{:s}.event() : Deleted comment for function {:#x} was ({!s}).".format('.'.join((__name__, cls.__name__)), ea, utils.string.repr(o)))

            # new comment
            newfn = idaapi.get_func(newea)
            new = utils.string.of(idaapi.get_func_cmt(newfn, nrpt))
            n = internal.comment.decode(new)
            cls._create_refs(newfn, n)

            continue
        return
Example #2
0
def export_func_names(fname):

    s = idautils.Strings(False)
    s.setup(strtypes=idautils.Strings.STR_UNICODE | idautils.Strings.STR_C)
    jsontable = []
    for v in s:
        if v is None:
            print("Failed to retrieve string index")
        else:
            xrefs = [x.frm for x in idautils.XrefsTo(v.ea)]
            if len(xrefs) != 1:
                continue
            print("%x: len=%d type=%d -> '%s'" % (v.ea, v.length, v.type, unicode(v)))
            d = {}
            d['string'] = unicode(v)
            d['str_type'] = v.type
            func = idaapi.get_func(xrefs[0])
            if func is None:
                continue
            d['func_name'] = idc.GetFunctionName(func.startEA)
            d['func_demangled'] = demangle(d['func_name'])
            d['func_c_decl'] = idc.GetType(func.startEA)
            d['func_comment'] = idaapi.get_func_cmt(func, 1)

            jsontable.append(d)
    f = open(fname,'w')
    json.dump(jsontable,f,indent=4)
    f.close()
Example #3
0
    def changing(cls, cb, a, cmt, repeatable):
        logging.debug(
            u"{:s}.changing({!s}, {:#x}, {!s}, {:d}) : Received comment.changing event for a {:s} comment at {:x}."
            .format('.'.join((__name__, cls.__name__)), utils.string.repr(cb),
                    interface.range.start(a), utils.string.repr(cmt),
                    repeatable,
                    'repeatable' if repeatable else 'non-repeatable',
                    interface.range.start(a)))
        fn = idaapi.get_func(interface.range.start(a))
        if fn is None and not cmt:
            return

        oldcmt = utils.string.of(idaapi.get_func_cmt(fn, repeatable))
        try:
            cls.event.send((interface.range.start(fn), bool(repeatable),
                            utils.string.of(cmt)))

        except StopIteration, e:
            logging.fatal(
                u"{:s}.changing({!s}, {:#x}, {!s}, {:d}) : Unexpected termination of event handler. Re-instantiating it."
                .format('.'.join((__name__, cls.__name__)),
                        utils.string.repr(cb), interface.range.start(a),
                        utils.string.repr(cmt), repeatable))
            cls.event = cls._event()
            next(cls.event)
Example #4
0
 def changed(cls, cb, a, cmt, repeatable):
     fn = idaapi.get_func(a.startEA)
     newcmt = idaapi.get_func_cmt(fn, repeatable)
     try: cls.event.send((fn.startEA, bool(repeatable), None))
     except StopIteration, e:
         logging.fatal("{:s}.changed : Unexpected termination of event handler. Re-instantiating it.".format('.'.join((__name__,cls.__name__))))
         cls.event = cls._event(); next(cls.event)
Example #5
0
    def _handle_tags(self, fn, fn_an, known_refs):
        if known_refs:
            known_refs = dict(known_refs)
            for k, names in known_refs.items():
                existing = set(fn_an['tags'][k])
                new = set(names) - existing
                if new:
                    fn_an['tags'][k] += list(new)

        tags = dict(fn_an['tags'])
        if not tags:
            return
        print 'fn: %#08x tags: %s' % (fn.startEA, tags)
        cmt = idaapi.get_func_cmt(fn, True)
        if cmt:
            cmt += '\n'
        s = str(tags.keys())
        name = idaapi.get_ea_name(fn.startEA)
        item = {'ea': fn.startEA, 'name': name, 'tags': tags}
        if not cmt or s not in cmt:
            idaapi.set_func_cmt(fn, '%sTAGS: %s' % (cmt or '', s), True)
        # self.mark_position(fn.startEA, 'TAGS: %s' % s)
        for tag in tags:
            if tag not in self._data:
                self._data[tag] = list()
            self._data[tag].append(item)
Example #6
0
 def changed(cls, cb, a, cmt, repeatable):
     logging.debug("{:s}.changing(...) : Received comment.changed at {:x} cb={!r} repeatable={:d} comment={!r}".format('.'.join((__name__, cls.__name__)), a.startEA, cb, repeatable, cmt))
     fn = idaapi.get_func(a.startEA)
     if fn is None and not cmt: return
     newcmt = idaapi.get_func_cmt(fn, repeatable)
     try: cls.event.send((fn.startEA, bool(repeatable), None))
     except StopIteration, e:
         logging.fatal("{:s}.changed(...) : Unexpected termination of event handler. Re-instantiating it.".format('.'.join((__name__, cls.__name__))))
         cls.event = cls._event(); next(cls.event)
Example #7
0
 def _handle_tags(self, fn, fn_an):
     tags = dict(fn_an['tags'])
     if not tags:
         return
     print 'fn: %#08x tags: %s' % (fn.startEA, tags)
     cmt = idaapi.get_func_cmt(fn, True)
     if cmt:
         cmt += '\n'
     s = str(tags.keys())
     name = idaapi.get_ea_name(fn.startEA)
     item = {'ea': fn.startEA, 'name': name, 'tags': tags}
     if not cmt or s not in cmt:
         idaapi.set_func_cmt(fn, '%sTAGS: %s' % (cmt or '', s), True)
     # self.mark_position(fn.startEA, 'TAGS: %s' % s)
     for tag in tags:
         if tag not in self._data:
             self._data[tag] = list()
         self._data[tag].append(item)
Example #8
0
def handle_function_comments(delta, segs):
    for f in get_all_funcs():
        for cmt_type in (True, False):
            cmt = idaapi.get_func_cmt(f, cmt_type)
            if cmt:
                new_cmt = rebase_comment(segs, delta, cmt)
                if new_cmt:
                    idaapi.set_func_cmt(f, cmt, cmt_type)
        cmts = idaapi.restore_user_cmts(f.start_ea)
        if not cmts:
            continue
        changed = False
        for (treeloc, citm) in cmts.items():
            if citm:
                citm = citm.c_str()
            new_cmt = rebase_comment(segs, delta, citm)
            if new_cmt:
                changed = True
                it = cmts.find(treeloc)
                cmts.erase(it)
                cmts.insert(treeloc, idaapi.citem_cmt_t(new_cmt))
        if changed:
            idaapi.save_user_cmts(f.start_ea, cmts)
Example #9
0
def process_function(arch, func_ea):

    func_end = idc.FindFuncEnd(func_ea)

    packet = DismantlerDataPacket()

    ida_chunks = get_chunks(func_ea)
    chunks = set()

    # Add to the chunks only the main block, containing the
    # function entry point
    #
    chunk = get_flow_code_from_address(func_ea)
    if chunk:
        chunks.add(chunk)

    # Make "ida_chunks" a set for faster searches  within
    ida_chunks = set(ida_chunks)
    ida_chunks_idx = dict(zip([c[0] for c in ida_chunks], ida_chunks))

    func = idaapi.get_func(func_ea)
    comments = [idaapi.get_func_cmt(func, 0), idaapi.get_func_cmt(func, 1)]

    # Copy the list of chunks into a queue to process
    #
    chunks_todo = [c for c in chunks]

    while True:

        # If no chunks left in the queue, exit
        if not chunks_todo:

            if ida_chunks:
                chunks_todo.extend(ida_chunks)
            else:
                break

        chunk_start, chunk_end = chunks_todo.pop()
        if ida_chunks_idx.has_key(chunk_start):
            ida_chunks.remove(ida_chunks_idx[chunk_start])
            del ida_chunks_idx[chunk_start]

        for head in idautils.Heads(chunk_start, chunk_end):

            comments.extend((idaapi.get_cmt(head, 0), idaapi.get_cmt(head, 1)))
            comment = '\n'.join([c for c in comments if c is not None])
            comment = comment.strip()
            if comment:
                packet.add_comment(head, comment)
            comments = list()

            if idc.isCode(idc.GetFlags(head)):

                instruction = arch.process_instruction(packet, head)

                # if there are other references than
                # flow add them all.
                if list(idautils.CodeRefsFrom(head, 0)):

                    # for each reference, including flow ones
                    for ref_idx, ref in enumerate(
                            idautils.CodeRefsFrom(head, 1)):

                        if arch.is_call(instruction):

                            # This two conditions must remain separated, it's
                            # necessary to enter the enclosing "if" whenever
                            # the instruction is a call, otherwise it will be
                            # added as an uncoditional jump in the last else
                            #
                            if ref in list(idautils.CodeRefsFrom(head, 0)):
                                packet.add_direct_call(head, ref)

                        elif ref_idx > 0 and arch.is_conditional_branch(
                                instruction):
                            # The ref_idx is > 0 in order to avoid processing the
                            # normal flow reference which would effectively imply
                            # that the conditional branch is processed twice.
                            # It's done this way instead of changing the loop's head
                            # from CodeRefsFrom(head, 1) to CodeRefsFrom(head, 0) in
                            # order to avoid altering the behavior of other conditions
                            # which rely on it being so.

                            # FIXME
                            # I don't seem to check for the reference here
                            # to point to valid, defined code. I suspect
                            # this could lead to a failure when exporting
                            # if such situation appears. I should test if
                            # it's a likely scenario and probably just add
                            # an isHead() or isCode() to address it.

                            packet.add_conditional_branch_true(head, ref)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))

                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)

                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, ref)

                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)

                        #skip = False

                for ref in idautils.DataRefsFrom(head):
                    packet.add_data_reference(head, ref)

                    # Get a data reference from the current reference's
                    # location. For instance, if 'ref' points to a valid
                    # address and such address contains a data reference
                    # to code.
                    target = list(idautils.DataRefsFrom(ref))
                    if target:
                        target = target[0]
                    else:
                        target = None

                    if target is None and arch.is_call(instruction):
                        imp_name = idc.Name(ref)

                        imp_module = get_import_module_name(ref)

                        imported_functions.add((ref, imp_name, imp_module))
                        packet.add_indirect_virtual_call(head, ref)

                    elif target is not None and idc.isHead(target):
                        # for calls "routed" through this reference
                        if arch.is_call(instruction):
                            packet.add_indirect_call(head, target)

                        # for unconditional jumps "routed" through this reference
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, target)

                        # for conditional "routed" through this reference
                        elif arch.is_conditional_branch(instruction):
                            packet.add_conditional_branch_true(head, target)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))

    f = FunctionAnalyzer(arch, func_ea, packet)

    instrumentation.new_packet(packet)
    instrumentation.new_function(f)
Example #10
0
 def getComment(ea, repeatable=1):
     fn = byAddress(ea)
     return idaapi.get_func_cmt(fn, repeatable)
Example #11
0
 def repeat(self):
     """Repeatable Function Comment"""
     return idaapi.get_func_cmt(self._function._func, True)
Example #12
0
 def regular(self):
     """Function Comment"""
     return idaapi.get_func_cmt(self._function._func, False)
Example #13
0
def process_function(arch, func_ea):
    
    func_end = idc.FindFuncEnd(func_ea)
    
    packet = DismantlerDataPacket()
    
    ida_chunks = get_chunks(func_ea)
    chunks = set()
    
    # Add to the chunks only the main block, containing the
    # function entry point
    #
    chunk = get_flow_code_from_address(func_ea)
    if chunk:
        chunks.add( chunk )
    
    # Make "ida_chunks" a set for faster searches  within
    ida_chunks = set(ida_chunks)
    ida_chunks_idx = dict(zip([c[0] for c in ida_chunks], ida_chunks))
    
    func = idaapi.get_func(func_ea)
    comments = [idaapi.get_func_cmt(func, 0), idaapi.get_func_cmt(func, 1)]
    
    # Copy the list of chunks into a queue to process
    #
    chunks_todo = [c for c in chunks]
    
    while True:
        
        # If no chunks left in the queue, exit
        if not chunks_todo:
        
            if ida_chunks:
                chunks_todo.extend(ida_chunks)
            else:   
               break
        
        chunk_start, chunk_end = chunks_todo.pop()
        if ida_chunks_idx.has_key(chunk_start):
            ida_chunks.remove(ida_chunks_idx[chunk_start])
            del ida_chunks_idx[chunk_start]
        
        for head in idautils.Heads(chunk_start, chunk_end):
        
            comments.extend( (idaapi.get_cmt(head, 0), idaapi.get_cmt(head, 1)) )
            comment = '\n'.join([c for c in comments if c is not None])
            comment = comment.strip()
            if comment:
                packet.add_comment(head, comment)
            comments = list()
            
            if idc.isCode(idc.GetFlags(head)):
                
                instruction = arch.process_instruction(packet, head)
                
                # if there are other references than
                # flow add them all.
                if list( idautils.CodeRefsFrom(head, 0) ):
                    
                    # for each reference, including flow ones
                    for ref_idx, ref in enumerate(idautils.CodeRefsFrom(head, 1)):
                        
                        if arch.is_call(instruction):
                            
                            # This two conditions must remain separated, it's
                            # necessary to enter the enclosing "if" whenever
                            # the instruction is a call, otherwise it will be
                            # added as an uncoditional jump in the last else
                            #
                            if ref in list( idautils.CodeRefsFrom(head, 0) ):
                                packet.add_direct_call(head, ref)
                        
                        elif ref_idx>0 and arch.is_conditional_branch(instruction):
                            # The ref_idx is > 0 in order to avoid processing the
                            # normal flow reference which would effectively imply
                            # that the conditional branch is processed twice.
                            # It's done this way instead of changing the loop's head
                            # from CodeRefsFrom(head, 1) to CodeRefsFrom(head, 0) in
                            # order to avoid altering the behavior of other conditions
                            # which rely on it being so.
                            
                            # FIXME
                            # I don't seem to check for the reference here
                            # to point to valid, defined code. I suspect
                            # this could lead to a failure when exporting
                            # if such situation appears. I should test if
                            # it's a likely scenario and probably just add
                            # an isHead() or isCode() to address it.
                            
                            packet.add_conditional_branch_true(head, ref)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))
                                
                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)
                                    
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, ref)
                            
                            # If the target is not in our chunk list
                            if not address_in_chunks(ref, chunks):
                                new_chunk = get_flow_code_from_address(ref)
                                # Add the chunk to the chunks to process
                                # and to the set containing all visited
                                # chunks
                                if new_chunk is not None:
                                    chunks_todo.append(new_chunk)
                                    chunks.add(new_chunk)
                                
                        #skip = False
                
                for ref in idautils.DataRefsFrom(head):
                    packet.add_data_reference(head, ref)
                    
                    # Get a data reference from the current reference's
                    # location. For instance, if 'ref' points to a valid
                    # address and such address contains a data reference
                    # to code.
                    target = list( idautils.DataRefsFrom(ref) )
                    if target:
                        target = target[0]
                    else:
                        target = None
                    
                    if target is None and arch.is_call(instruction):
                        imp_name = idc.Name(ref)

                        imp_module = get_import_module_name(ref)

                        imported_functions.add((ref, imp_name, imp_module))
                        packet.add_indirect_virtual_call(head, ref)
                    
                    elif target is not None and idc.isHead(target):
                        # for calls "routed" through this reference
                        if arch.is_call(instruction):
                            packet.add_indirect_call(head, target)
                            
                        # for unconditional jumps "routed" through this reference
                        elif arch.is_unconditional_branch(instruction):
                            packet.add_unconditional_branch(head, target)
                        
                        # for conditional "routed" through this reference
                        elif arch.is_conditional_branch(instruction):
                            packet.add_conditional_branch_true(head, target)
                            packet.add_conditional_branch_false(
                                head, idaapi.next_head(head, chunk_end))
    
    
    f = FunctionAnalyzer(arch, func_ea, packet)
    
    instrumentation.new_packet(packet)
    instrumentation.new_function(f)
Example #14
0
 def getComment(ea, repeatable=1):
     fn = byAddress(ea)
     return idaapi.get_func_cmt(fn, repeatable)
Example #15
0
def comment(fn, comment=None, repeatable=1):
    fn = by(fn)
    if comment is None:
        return idaapi.get_func_cmt(fn, repeatable)
    return idaapi.set_func_cmt(fn, comment, repeatable)
Example #16
0
 def repeat(self):
     """Repeatable Function Comment"""
     return idaapi.get_func_cmt(self._function._func, True)
Example #17
0
 def regular(self):
     """Function Comment"""
     return idaapi.get_func_cmt(self._function._func, False)
Example #18
0
def comment(fn, comment=None, repeatable=1):
    fn = by(fn)
    if comment is None:
        return idaapi.get_func_cmt(fn, repeatable)
    return idaapi.set_func_cmt(fn, comment, repeatable)