def _event(cls): while True: # cmt_changing event ea, rpt, new = (yield) old = utils.string.of(idaapi.get_cmt(ea, rpt)) f, o, n = idaapi.get_func(ea), internal.comment.decode(old), internal.comment.decode(new) # update references before we update the comment cls._update_refs(ea, o, n) # wait for cmt_changed event newea, nrpt, none = (yield) # now fix the comment the user typed if (newea, nrpt, none) == (ea, rpt, None): ncmt, repeatable = utils.string.of(idaapi.get_cmt(ea, rpt)), cls._is_repeatable(ea) if (ncmt or '') != new: logging.warn(u"{:s}.event() : Comment from event at address {:#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))) # delete it if it's the wrong type # if nrpt != repeatable: # idaapi.set_cmt(ea, '', nrpt) # # write the tag back to the address # if internal.comment.check(new): idaapi.set_cmt(ea, utils.string.to(internal.comment.encode(n)), repeatable) # # write the comment back if it's non-empty # elif new: idaapi.set_cmt(ea, utils.string.to(new), repeatable) # # otherwise, remove its reference since it's being deleted # else: cls._delete_refs(ea, n) if internal.comment.check(new): idaapi.set_cmt(ea, utils.string.to(internal.comment.encode(n)), rpt) elif new: idaapi.set_cmt(ea, utils.string.to(new), rpt) else: cls._delete_refs(ea, n) continue # if the changed event doesn't happen in the right order logging.fatal(u"{:s}.event() : Comment events are out of sync at address {:#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(ea, o) idaapi.set_cmt(ea, '', rpt) logging.warn(u"{:s}.event() : Deleted comment at address {:#x} was {!s}.".format('.'.join((__name__, cls.__name__)), ea, utils.string.repr(o))) # new comment new = utils.string.of(idaapi.get_cmt(newea, nrpt)) n = internal.comment.decode(new) cls._create_refs(newea, n) continue return
def _event(cls): while True: # cmt_changing event ea,rpt,new = (yield) old = idaapi.get_cmt(ea, rpt) f,o,n = idaapi.get_func(ea),internal.comment.decode(old),internal.comment.decode(new) # update references before we update the comment cls._update_refs(ea, o, n) # wait for cmt_changed event newea,nrpt,none = (yield) # now fix the comment the user typed if (newea,nrpt,none) == (ea,rpt,None): ncmt,repeatable = idaapi.get_cmt(ea, rpt), cls._is_repeatable(ea) if (ncmt or '') != new: logging.warn("internal.{:s}.event : Comment from event is different from database : {:x} : {!r} != {!r}".format('.'.join((__name__,cls.__name__)), ea, new, ncmt)) # delete it if it's the wrong type # if nrpt != repeatable: # idaapi.set_cmt(ea, '', nrpt) # # write the tag back to the address # if internal.comment.check(new): idaapi.set_cmt(ea, internal.comment.encode(n), repeatable) # # write the comment back if it's non-empty # elif new: idaapi.set_cmt(ea, new, repeatable) # # otherwise, remove it's reference since it's being deleted # else: cls._delete_refs(ea, n) if internal.comment.check(new): idaapi.set_cmt(ea, internal.comment.encode(n), rpt) elif new: idaapi.set_cmt(ea, new, rpt) else: cls._delete_refs(ea, n) continue # if the changed event doesn't happen in the right order logging.fatal("{:s}.event : Comment events are out of sync, updating tags from previous comment. : {!r} : {!r}".format('.'.join((__name__,cls.__name__)), o, n)) # delete the old comment cls._delete_refs(ea, o) idaapi.set_cmt(ea, '', rpt) logging.warn("{:s}.event : Previous comment at {:x} : {!r}".format('.'.join((__name__,cls.__name__)), o)) # new comment new = idaapi.get_cmt(newea, nrpt) n = internal.comment.decode(new) cls._create_refs(newea, n) continue return
def changed(cls, ea, repeatable_cmt): logging.debug(u"{:s}.changed({:#x}, {:d}) : Received comment.changed event for a {:s} comment at {:x}.".format('.'.join((__name__, cls.__name__)), ea, repeatable_cmt, 'repeatable' if repeatable_cmt else 'non-repeatable', ea)) newcmt = utils.string.of(idaapi.get_cmt(ea, repeatable_cmt)) try: cls.event.send((ea, bool(repeatable_cmt), None)) except StopIteration, e: logging.fatal(u"{:s}.changed({:#x}, {:d}) : Unexpected termination of event handler. Re-instantiating it.".format('.'.join((__name__, cls.__name__)), ea, repeatable_cmt)) cls.event = cls._event(); next(cls.event)
def changed(cls, ea, repeatable_cmt): logging.debug("{:s}.changing({:#x}, {:d}) : Received comment.changed at {:x} repeatable={:d}".format('.'.join((__name__, cls.__name__)), ea, repeatable_cmt, ea, repeatable_cmt)) newcmt = idaapi.get_cmt(ea, repeatable_cmt) try: cls.event.send((ea, bool(repeatable_cmt), None)) except StopIteration, e: logging.fatal("{:s}.changed({:#x}, {:d}) : Unexpected termination of event handler. Re-instantiating it.".format('.'.join((__name__, cls.__name__)), ea, repeatable_cmt)) cls.event = cls._event(); next(cls.event)
def add_to_comment(ea, key, value): """Add key:value to comm string at EA.""" from bap_comment import add_to_comment_string old_comm = idaapi.get_cmt(ea, 0) if old_comm is None: old_comm = '' new_comm = add_to_comment_string(old_comm, key, value) idaapi.set_cmt(ea, new_comm, 0)
def tag_read(ea, key=None, repeatable=0): res = idaapi.get_cmt(ea, int(bool(repeatable))) dict = _comment.toDict(res) name = idaapi.get_name(-1, ea) if name is not None: dict.setdefault('name', name) if key is None: return dict return dict[key]
def tag_read(ea, key=None, repeatable=0): res = idaapi.get_cmt(ea, int(bool(repeatable))) dict = internal.comment.toDict(res) name = idaapi.get_name(-1,ea) if name is not None: dict.setdefault('name', name) if key is None: return dict return dict[key]
def update(self, ea, key, value): """Add key=values to comm string at EA.""" cmt = idaapi.get_cmt(ea, 0) comm = cmt and bap_comment.parse(cmt) or {} values = comm.setdefault(key, []) if value and value != '()' and value not in values: values.append(value) idaapi.set_cmt(ea, bap_comment.dumps(comm), 0)
def handle_comments(delta, segs): for cmt_offset in get_all_comments(): for is_repeatable in (True, False): cmt = idaapi.get_cmt(cmt_offset, is_repeatable) if not cmt: continue new_cmt = rebase_comment(segs, delta, cmt) if not new_cmt: continue idaapi.set_cmt(cmt_offset, new_cmt, is_repeatable)
def get_override(ea): cmt = idaapi.get_cmt(ea, False) if (cmt == None): return None if (re.match(r'#override\s+.*', cmt)): return cmt[len("#override"):] else: return None
def get_override(ea): cmt = idaapi.get_cmt(ea, False) if(cmt == None): return None if(re.match(r'#override\s+.*', cmt)): return cmt[len("#override"):] else: return None
def clear_bap_comments(self): """Ask user for confirmation and then clear (BAP ..) comments.""" if idaapi.askyn_c(ASKBTN_YES, "Delete all `BAP: ..` comments?") != ASKBTN_YES: return for ea in ida.addresses(): # TODO: store actually commented addresses comm = idaapi.get_cmt(ea, 0) if comm and comm.startswith('BAP:'): idaapi.set_cmt(ea, '', 0)
def is_nzxor_stack_cookie(f, bb, insn): """ check if nzxor is related to stack cookie """ if contains_stack_cookie_keywords(idaapi.get_cmt(insn.ea, False)): # Example: # xor ecx, ebp ; StackCookie return True stack_cookie_regs = tuple(bb_stack_cookie_registers(bb)) if any(op_reg in stack_cookie_regs for op_reg in (insn.Op1.reg, insn.Op2.reg)): # Example: # mov eax, ___security_cookie # xor eax, ebp return True return False
def run(self, arg): comms = {} for addr in ida.addresses(): comm = idaapi.get_cmt(addr, 0) if comm: try: parsed = bap_comment.parse(comm) if parsed: for (name, data) in parsed.items(): comms[(addr, name)] = data except: idc.Message("BAP> failed to parse string {0}\n{1}".format( comm, str(sys.exc_info()[1]))) comms = [(name, addr, data) for ((addr, name), data) in comms.items()] attrs = Attributes(comms) choice = attrs.Show(modal=True) if choice >= 0: idc.Jump(comms[choice][1])
def run(self, arg): comms = {} for addr in ida.addresses(): comm = idaapi.get_cmt(addr, 0) if comm: try: parsed = bap_comment.parse(comm) if parsed: for (name, data) in parsed.items(): comms[(addr, name)] = data except: idc.Message("BAP> failed to parse string {0}\n{1}". format(comm, str(sys.exc_info()[1]))) comms = [(name, addr, data) for ((addr, name), data) in comms.items()] attrs = Attributes(comms) choice = attrs.Show(modal=True) if choice >= 0: idc.Jump(comms[choice][1])
def send_comments(self): start = idaapi.get_segm_base(idaapi.get_first_seg()) cur = start while True: if cur != idc.BADADDR: cmt = idaapi.get_cmt(cur, 0) if (cmt is not None) and (cmt != idc.BADADDR): self.cmd = "setcmt 0x%x %s" % (cur, cmt) # debugging if DEBUG: idaapi.msg( "[%s] send_comments: EA [0x%x], Comment [%s]\n" % (self.wanted_name, cur, cmt,)) self.ws_send(self.cmd) else: break cur = idc.NextAddr(cur) return True
def old_changed(cls, ea, repeatable_cmt): cmt = utils.string.of(idaapi.get_cmt(ea, repeatable_cmt)) fn = idaapi.get_func(ea) # if we're in a function, then clear our contents. if fn: internal.comment.contents.set_address(ea, 0) # otherwise, just clear the tags globally else: internal.comment.globals.set_address(ea, 0) # simply grab the comment and update its refs res = internal.comment.decode(cmt) if res: cls._create_refs(ea, res) # otherwise, there's nothing to do if its empty else: return # and then re-write it back to its address idaapi.set_cmt(ea, utils.string.to(internal.comment.encode(res)), repeatable_cmt)
def function_comments(self): """ Get all user comments from the function :raises TypeError: If no comments are found >>> saram.function_comments().send() """ self._comment = inspect.stack()[0][3] offset = self._SaramIDA__get_screen_ea() comments = [] for ea in range(offset.startEA, offset.endEA): comment = idaapi.get_cmt(ea, 1) if comment is not None: comments.append('{offset} {value}'.format(offset=hex(ea), value=comment)) if len(comments) > 0: self.command = 'Comments for: {name}'.format( name=idc.GetFunctionName(offset.startEA)) self.output = '\n'.join(comments) print(self.output) return self else: raise TypeError('No comments found')
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)
def comment(ea, comment=None, repeatable=0): if comment is None: return idaapi.get_cmt(ea, int(bool(repeatable))) return idaapi.set_cmt(ea, comment, int(bool(repeatable)))
def repeat(self): """Repeatable Comment""" return idaapi.get_cmt(self._ea, 1)
def regular(self): """Regular Comment""" return idaapi.get_cmt(self._ea, 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)
def activate(self, ctx): if self.menu_title == MenuAskEntryId: self.outer_self.mixto.entry_id = idaapi.ask_str( "", 1000, "Mixto Entry Id") else: if self.outer_self.mixto.entry_id is None: self.outer_self.mixto.entry_id = idaapi.ask_str( "", 1000, "Mixto Entry Id") if self.menu_title == MenuAllFunc: all_func = "" # Get count of all functions in the binary count = idaapi.get_func_qty() for i in range(count): fn = idaapi.getn_func(i) # Function should not have dummy name such as sub_* # and should not start with underscore (possible library functions) if not idaapi.has_dummy_name(get_flags_at( start_ea_of(fn))) and not idaapi.get_func_name( start_ea_of(fn)).startswith("_"): all_func += "{} @ 0x{:x}\n".format( idaapi.get_func_name(start_ea_of(fn)), start_ea_of(fn)) self.outer_self.mixto.AddCommit(all_func, self.outer_self.mixto.entry_id, "(IDA) All Functions") elif self.menu_title == MenuImports: global AllImports AllImports = "" # Get count of all import modules in the binary count = idaapi.get_import_module_qty() for i in range(count): module_name = idaapi.get_import_module_name(i) AllImports += "{}:\n".format(module_name) idaapi.enum_import_names(i, imports_cb) self.outer_self.mixto.AddCommit(AllImports, self.outer_self.mixto.entry_id, "(IDA) All Imports") elif self.menu_title == MenuDecFunc: addr_current = idc.get_screen_ea() addr_func = idaapi.get_func(addr_current) if not addr_func: idaapi.msg("Place cursor inside a function!") return False else: err = None out = str(idaapi.decompile(addr_func)) # print(out) self.outer_self.mixto.AddCommit( str(out), self.outer_self.mixto.entry_id, "(IDA) Function Decompilation {}".format( idc.GetFunctionName(addr_func.startEA)), ) elif self.menu_title == MenuExports: all_exports = "" for entry in idautils.Entries(): _, ord, ea, name = entry if not name: all_exports += "0x{:x}: ord#{}\n".format(ea, ord) else: all_exports += "0x{:x}: {} ord#{}\n".format( ea, name, ord) self.outer_self.mixto.AddCommit(all_exports, self.outer_self.mixto.entry_id, "(IDA) All Exports") elif self.menu_title == MenuAllComments: addr_current = idc.get_screen_ea() addr_func = idaapi.get_func(addr_current) uniq_comments = {} comments = [] for ea in range(addr_func.startEA, addr_func.endEA): comment = idaapi.get_cmt(ea, 0) if comment is not None: # hacky way to make sure only uniq comments are added if uniq_comments.get(comment) == 1: pass else: print(uniq_comments) comments.append("{offset} {value}".format( offset=hex(ea), value=comment)) print("here") uniq_comments[comment] = 1 if len(comments) > 0: out = "\n".join(comments) self.outer_self.mixto.AddCommit( str(out), self.outer_self.mixto.entry_id, "(IDA) Function Comments {}".format( idc.GetFunctionName(addr_func.startEA)), ) else: raise TypeError("No comments found") return True
def update_comment(addr, rpt): cmt = idaapi.get_cmt(addr, rpt) if cmt is not None: ws_send("setcmt 0x%x %s" % (addr, cmt))
def changed(cls, ea, repeatable_cmt): newcmt = idaapi.get_cmt(ea, repeatable_cmt) try: cls.event.send((ea, bool(repeatable_cmt), 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)