def get_asm_comments(self): cmts = [] for seg in idautils.Segments(): seg_name = idc.SegName(seg) ea = idc.SegStart(seg) end = idc.SegEnd(seg) while ea < end: if ea != idc.BADADDR: cmt = idc.GetCommentEx(ea, True) # repeatable comments if cmt: if not self.check_isin_filter(cmt): current_cmt = [ "%s:%-16X" % (seg_name, ea), 'R', idc.GetDisasm(ea), cmt ] cmts.append(current_cmt) self.n += 1 cmt2 = idc.GetCommentEx(ea, False) # usual comments if cmt2: if not self.check_isin_filter(cmt2): current_cmt = [ "%s:%-16X" % (seg_name, ea), 'N', idc.GetDisasm(ea), cmt2 ] cmts.append(current_cmt) self.n += 1 ea = idc.next_head(ea, end) return cmts
def find_exported_eas(): """Find the address of all exported functions. Exported functions are entrypoints into this program that external code can execute.""" exported_eas = set() for index, ordinal, ea, name in idautils.Entries(): # Not sure how this happens, but IDA seemed to treat # `obstack_alloc_failed_handler` in `call cs:[obstack_alloc_failed_handler]` # as an entrypoint. num_data_refs = len(tuple(idautils.DataRefsTo(ea))) num_code_refs = len(tuple(idautils.CodeRefsTo(ea, True))) num_code_refs += len(tuple(idautils.CodeRefsTo(ea, True))) if num_data_refs and not num_code_refs: log.warning( "Ignoring entrypoint {:08x}, it's only referenced by data". format(ea)) continue if not has_segment_type(ea, idc.SEG_CODE): log.warning( "Ignoring entrypoint {:08x}, it is not in a code segment". format(ea)) continue if not idc.hasName(ea): old_name = name if name.startswith("."): name = idc.GetCommentEx(ea, 0) log.info("Renaming `{}` at {:08x} to `{}`".format( old_name, ea, name)) idc.MakeName(ea, name) return exported_eas
def get_alternative_symnbol_name(ea): comment = idc.GetCommentEx(ea, 0) or "" for comment_line in comment.split("\n"): comment_line = comment_line.replace(";", "").strip() mstr = comment_line.split("'") return mstr[1] + "'" + mstr[2] return None
def report_strings(self, strs, stack, stack_min_value=None, stack_max_value=None): ''' Parses and returns Stack strings as Strings ''' for char_width in xrange(1, MAX_CHARACTER_WIDTH + 1): parsed_strs = self.parse_strings(stack, stack_min_value, stack_max_value, char_width) for string, eas, length in parsed_strs: startEA, endEA = self.find_start_and_end(eas) for string_obj in strs: if string_obj[2] == string and string_obj[ 0] == startEA and string_obj[1] == endEA: break else: # if we didn't break strs.add((startEA, endEA, string)) old_cmt = idc.GetCommentEx(eas[0], 0) old_cmt = '' if not old_cmt else old_cmt if not is_string_ascii(string): new_cmt = string.encode('hex') new_cmt = old_cmt + '\nStack String (hex): ' + new_cmt else: new_cmt = string.encode('string-escape').replace( '\\x00', '\nStack String: ') new_cmt = old_cmt + '\nStack String: ' + new_cmt new_cmt += '\nSize: ' + str(length) new_cmt = '\n'.join(list(set( new_cmt.split('\n')))) # Remove duplicates. idc.MakeComm(eas[0], str(new_cmt).strip('\r\n'))
def common_cmt(ea, funclist, prefix=None, offset=0, override=False): if not funclist: return cmt = set() for func in funclist: name = idc.get_func_off_str(func + offset) cmt.add(name) try: scmt = ' '.join(cmt) except Exception as e: print(e) return if prefix: scmt = prefix + scmt if not override: socmt = idc.GetCommentEx(ea, 0) if socmt: ocmt = [] if prefix and socmt.startswith(prefix): socmt = socmt[len(prefix):] oldcmt = socmt.strip().split("\n") for _cmt in oldcmt: ocmt.extend(_cmt.split(' ')) ocmt = set(ocmt) ocmt -= cmt else: ocmt = None if ocmt: scmt += "\n" + ' '.join(ocmt) idc.MakeComm(ea, scmt)
def _extract_cmnts(self, repeatable): commdict = {} for func_item in self._func_items: i = int(func_item) - int(self._first_addr) comm = idc.GetCommentEx(func_item, repeatable) if (comm != None): commdict[i] = comm return commdict
def cmt_changed(self, ea, rep): cmt = idc.GetCommentEx(ea, rep) self.ctrl._handle_action({ 'action': 'cmt_changed', 'ea': ea, 'rep': rep, 'cmt': cmt }) return 0
def get_jlocs(self, sw): jlocs = [] ncases = sw.ncases if sw.jcases == 0 else sw.jcases for i in range(ncases): addr = idc.Dword(sw.jumps+i*4) name = idaapi.get_name(idc.BADADDR, addr) comm = idc.GetCommentEx(idc.LocByName(name), 1) comm = comm[comm.find('case'):] if comm is not None and comm.startswith('jumptable') else comm jlocs.append((name, idc.LocByName(name), comm)) return jlocs
def get_alternative_symbol_name(ea): comment = idc.GetCommentEx(ea, 0) or "" for comment_line in comment.split("\n"): comment_line = comment_line.replace(";", "").strip() if not comment_line: continue mstr = comment_line.split("'") if 3 <= len(mstr): return mstr[1] + "'" + mstr[2] return None
def yacheck_data_comments(self): eas = yaunit.load('data_comments') i = 0 for offset in range(0, 3): for cmt, rpt, post, ant in tests_data: ea = eas[i] logger.debug( "checking data comment at 0x%08X : %r, %r, %r, %r" % (ea, cmt, rpt, post, ant)) i += 1 if cmt != None: self.assertEqual(idc.GetCommentEx(ea, False), cmt) if rpt != None: self.assertEqual(idc.GetCommentEx(ea, True), rpt) if post != None: for j, txt in enumerate(post.split('\n')): self.assertEqual(idc.LineB(ea, j), txt) if ant != None: for j, txt in enumerate(ant.split('\n')): self.assertEqual(idc.LineA(ea, j), txt)
def _merge_cmnts(self, comments, repeatable): for ea_rel in comments: ea = int(ea_rel) + self._first_addr comment = comments[ea_rel] current_comment = idc.GetCommentEx(ea, repeatable) if current_comment is None: current_comment = "" final_comment = current_comment + "; REDB: " + comment self._embed_comment(ea, final_comment, repeatable) idaapi.refresh_idaview_anyway()
def push_comms(): global skel_conn commBL = [ "size_t", "int", "LPSTR", "char", "char *", "lpString", "unsigned int", "void *", "indirect table for switch statement", "this", "jump table for switch statement", "switch jump" ] for i in range(idc.MinEA(), idc.MaxEA()): if idc.GetCommentEx( i, 0) is not None and not idc.GetCommentEx(i, 0) in commBL: if not skel_conn.push_comment(i, idc.GetCommentEx(i, 0)): return -1 elif idc.GetCommentEx( i, 1) is not None and not idc.GetCommentEx(i, 1) in commBL: if not skel_conn.push_comment(i, idc.GetCommentEx(i, 1)): return -1 for function_ea in idautils.Functions(idc.MinEA(), idc.MaxEA()): fName = idc.GetFunctionName(function_ea) if hasSubNoppedPrefix(fName) is False: if not skel_conn.push_name(function_ea, fName): g_logger.error("Error sending function name %s" % (fName)) # if idc.GetFunctionCmt(function_ea,0) != "": # push_change("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(i,0)) # elif idc.GetFunctionCmt(function_ea,1) != "": # push_change("idc.SetFunctionCmt",shex(function_ea),idc.GetFunctionCmt(function_ea,1)) return
def is_runtime_external_data_reference(ea): """This can happen in ELF binaries, where you'll have somehting like `stdout@@GLIBC_2.2.5` in the `.bss` section, where at runtime the linker will fill in the slot with a pointer to the real `stdout`. IDA discovers this type of reference, but it has no real way to cross-reference it to anything, because the target address will only exist at runtime.""" comment = idc.GetCommentEx(ea, 0) if comment and "Copy of shared data" in comment: return True else: return False
def parse_ivar(self, ea): cmt = idc.GetCommentEx(ea, True) if cmt: type = cmt.split()[0] self._ivars[ea] = type if type in self._ivars_2: self._ivars_2[type].append(ea) else: self._ivars_2[type] = [ ea, ] else: print 'CANNOT GET CMT OF IVAR: '.format(hex(ea))
def postprocess(self): try: if "MakeComment" in self.cmdname: if idc.Comment(self.addr) is not None: self.skel_conn.push_comment(self.addr, idc.Comment(self.addr)) if idc.GetFunctionCmt(self.addr, 0) != "": self.skel_conn.push_comment( self.addr, idc.GetFunctionCmt((self.addr), 0)) elif "MakeRptCmt" in self.cmdname: if idc.GetCommentEx(self.addr, 1) != "": self.skel_conn.push_comment( self.addr, idc.GetCommentEx(self.addr, 1)) if idc.GetFunctionCmt(self.addr, 1) != "": self.skel_conn.push_comment( self.addr, idc.GetFunctionCmt(self.addr, 1)) elif self.cmdname == "MakeFunction": if idc.GetFunctionAttr(self.addr, 0) is not None: pass #push_change("idc.MakeFunction", shex(idc.GetFunctionAttr( # self.addr, 0)), shex(idc.GetFunctionAttr(self.addr, 4))) elif self.cmdname == "DeclareStructVar": print "Fixme : declare Struct variable" elif self.cmdname == "SetType": newtype = idc.GetType(self.addr) if newtype is None: newtype = "" else: newtype = SkelUtils.prepare_parse_type( newtype, self.addr) self.skel_conn.push_type(int(self.addr), newtype) # XXX IMPLEMENT elif self.cmdname == "OpStructOffset": print "Fixme, used when typing a struct member/stack var/data pointer to a struct offset " except KeyError: pass return 0
def is_external_vtable_reference(ea): """ It checks the references of external vtable in the .bss section, where it is referred as the `Copy of shared data`. There is no way to resolve the cross references for these vtable as the target address will only appear during runtime. It is introduced to avoid lazy initilization of runtime typeinfo variables which gets referred by the user-defined exception types. """ if not is_runtime_external_data_reference(ea): return False comment = idc.GetCommentEx(ea, 0) if comment and "Alternative name is '`vtable" in comment: return True else: return
def is_tls(ea): if is_invalid_ea(ea): return False if is_tls_segment(ea): return True # Something references `ea`, and that something is commented as being a # `TLS-reference`. This comes up if you have an thread-local extern variable # declared/used in a binary, and defined in a shared lib. There will be an # offset variable. for source_ea in _drefs_to(ea): comment = idc.GetCommentEx(source_ea, 0) if isinstance(comment, str) and "TLS-reference" in comment: return True return False
def get_segment_end_ea(ea): """ Return address where next MSDN info can be written to in added segment. Argument: ea -- effective address within added segment where search starts """ addr = ea while idc.GetCommentEx(addr, 0) is not None: addr = addr + 1 if addr > idc.get_segm_end(ea): g_logger.debug('Address {} out of segment bounds. Expanding segment.' .format(hex(addr))) try: expand_segment(ea) except FailedToExpandSegmentException as e: g_logger.warning(e.message) raise e else: return addr
def find_arg_ea(ea_call, arg_name): """ Return ea of argument by looking backwards from library function call. Arguments: ea_call -- effective address of call arg_name -- the argument name to look for """ # the search for previous instruction/data will stop at the specified # address (inclusive) prev_instr = idc.PrevHead(ea_call, ea_call - PREVIOUS_INSTR_DELTA) while prev_instr > (ea_call - ARG_SEARCH_THRESHOLD) and \ prev_instr != idaapi.BADADDR: # False indicates not to look for repeatable comments comment = idc.GetCommentEx(prev_instr, False) if comment == arg_name: return prev_instr prev_instr = idc.PrevHead(prev_instr, prev_instr - PREVIOUS_INSTR_DELTA) raise ArgumentNotFoundException( ' Argument {} not found within threshold'.format(arg_name))
def export(self, vtables): """ @vtables: List of tuples with vtable information [(ins_addr, vtable), ... ] There is a small mistake. Some .data references will be tagged as being vtables. This is due to the way we detect them on pin. In IDA pro it should be easy to mark just only the ones that refer to .text but I could not find a way to get that information from idapython. """ # We build a dictionary with the ins addr referencing the vtable as the key dict_ = {} for vtable in vtables: # Add all the vtable references found while tracing to the set dict_.setdefault(vtable[0], set()).add(vtable[1]) for (key, val) in dict_.iteritems(): prev_comment = idc.GetCommentEx(vtable[0], False) # Check if we already have commented this line. This will avoid duplicating info. if not prev_comment or "VTables found:" in prev_comment: prev_comment = "VTables found:\n" prev_comment += "\n".join(map(lambda x: "0x%.8x" % x, val)) # vtable[0] == instruction address idc.MakeComm(key, prev_comment) # Check if we already have a cross reference for v in val: if key in [ref.frm for ref in XrefsTo(v, 0)]: continue # Add a data reference if add_dref(key, v, dr_R) != True: idaapi.msg( "Could not create cross reference from %x to %x\n" % (key, v))
def db_read(cls, address, key=None, repeatable=0): result = comment.toDict( idc.GetCommentEx(address, repeatable) ) name = idc.NameEx(address, address) if name: result['__name__'] = name # defaults if '__color__' not in result: c = cls.color(address) if c is not None: result['__color__'] = c if '__address__' not in result: result['__address__'] = address if '__context__' not in result: result['__context__'] = idc.GetFunctionAttr(address, idc.FUNCATTR_START) if '__sp__' not in result: result['__sp__'] = idc.GetSpd(address) if key is not None: return result[key] return result
def export(self, resolved_branches): dict_ = {} for r in resolved_branches: dict_.setdefault(r[0], set()).add(r[1]) for key, val in dict_.iteritems(): prev_comment = idc.GetCommentEx(key, False) if not prev_comment or "Resolved:" in prev_comment: prev_comment = "Resolved:\n" for v in val: prev_comment += "%s : %.8x\n" % (GetAddressName(v), v) # Check if we already have a cross reference if key in [ref.frm for ref in XrefsTo(v, 0)]: continue if AddCodeXref(key, v, fl_CN) != True: idaapi.msg( "Could not create cross reference from %x to %x\n" % (key, v)) idc.MakeComm(key, prev_comment)
def getComment(self, ea): return idc.GetCommentEx(ea, False)
def getComment(self, ea): res = idc.GetCommentEx(ea, False) if not res: return "" else: return res
flow_insns = [] while cur_addr <= end: next_instr = idc.NextHead(cur_addr, end) #get size instr if next_instr > end: size = end - cur_addr else: size = next_instr - cur_addr #get assembly and comments curr_asm = hex(cur_addr).rstrip("L") + " " + idc.GetDisasm( cur_addr).split(';')[0] try: curr_asm += ' ;' + idc.GetCommentEx(cur_addr, True).replace( '\n', ' ') except: pass curr_asm += '\n' asm += curr_asm #get first byte of instruction opc = hex(ord(idc.GetManyBytes(cur_addr, 1)))[2:] if len(opc) < 2: opc = '0' + opc ops += opc #get instruction bytes insns_list.append( (cur_addr, base64.b64encode(idc.GetManyBytes(cur_addr, size))))
def postprocess(self): global skel_conn try: if self.cmdname == "MakeComment": if idc.GetCommentEx(self.addr, 0) is not None: skel_conn.push_comment(self.addr, idc.GetCommentEx((self.addr), 0)) elif idc.GetCommentEx(self.addr, 1) is not None: skel_conn.push_comment(self.addr, idc.GetCommentEx((self.addr), 1)) elif idc.GetFunctionCmt(self.addr, 0) != "": skel_conn.push_comment(self.addr, idc.GetCommentEx((self.addr), 0)) elif idc.GetFunctionCmt(self.addr, 1) != "": skel_conn.push_comment( self.addr, idc.GetFunctionCmt(self.addr, 1).replace("\n", "\\n").replace( "\"", "\\\"")) if self.cmdname == "MakeRptCmt": if idc.GetCommentEx(self.addr, 0) is not None: skel_conn.push_comment( self.addr, idc.GetCommentEx(self.addr, 0).replace("\n", "\\n").replace( "\"", "\\\"")) elif idc.GetCommentEx(self.addr, 1) is not None: skel_conn.push_comment( self.addr, idc.GetCommentEx(self.addr, 1).replace("\n", "\\n").replace( "\"", "\\\"")) elif idc.GetFunctionCmt(self.addr, 0) != "": skel_conn.push_comment( self.addr, idc.GetFunctionCmt(self.addr, 0).replace("\n", "\\n").replace( "\"", "\\\"")) elif idc.GetFunctionCmt(self.addr, 1) != "": skel_conn.push_comment( self.addr, idc.GetFunctionCmt(self.addr, 1).replace("\n", "\\n").replace( "\"", "\\\"")) elif self.cmdname == "MakeName": # idc.Jump(self.addr) if (idc.GetFunctionAttr(self.addr, 0) == self.addr): fname = GetFunctionName(self.addr) if fname != "": if not CheckDefaultValue(fname): skel_conn.push_name(self.addr, fname) else: fname = idc.GetTrueName(self.addr) if fname != "" and not CheckDefaultValue(fname): skel_conn.push_name( self.addr, fname.replace("\n", "\\n").replace("\"", "\\\"")) else: # ok, on regarde ce qui est pointe if GetOpType(self.addr, 0) in [o_near, o_imm, o_mem]: if GetOpType(self.addr, 1) in [o_near, o_imm, o_mem]: print "[P] You must be on the top of function or at the global address to set the name in log file" else: add = idc.GetOperandValue(self.addr, 0) fname = idc.GetTrueName(add) if fname != "" and not CheckDefaultValue( fname): skel_conn.push_name( add, fname.replace("\n", "\\n").replace( "\"", "\\\"")) else: print "[P] You must be on the top of function or at the global address to set the name in log file" elif GetOpType(self.addr, 1) in [o_near, o_imm, o_mem]: add = idc.GetOperandValue(self.addr, 1) fname = idc.GetTrueName(add) if fname != "" and not CheckDefaultValue(fname): skel_conn.push_name( add, fname.replace("\n", "\\n").replace("\"", "\\\"")) else: print "[P] You must be on the top of function or at the global address to set the name in log file" elif self.cmdname == "MakeFunction": if idc.GetFunctionAttr(self.addr, 0) is not None: pass #push_change("idc.MakeFunction", shex(idc.GetFunctionAttr( # self.addr, 0)), shex(idc.GetFunctionAttr(self.addr, 4))) elif self.cmdname == "DeclareStructVar": print "Fixme : declare Struct variable" elif self.cmdname == "AddStruct": print "Fixme : adding structure" elif self.cmdname == "SetType": newtype = idc.GetType(self.addr) if newtype is None: newtype = "" else: newtype = prepare_parse_type(newtype, self.addr) push_change("idc.SetType", shex(self.addr), newtype) elif self.cmdname == "OpStructOffset": print "Fixme, used when typing a struct member/stack var/data pointer to a struct offset " except KeyError: pass return 0
def getRptComment(self, ea): return idc.GetCommentEx(ea, True)
def _profile_function(self): current_ea = idc.ScreenEA() current_function = idc.GetFunctionName(current_ea) current_function_ea = idc.LocByName(current_function) if current_function: self.function = current_function ea = start_ea = idc.GetFunctionAttr(current_function_ea, idc.FUNCATTR_START) end_ea = idc.GetFunctionAttr(current_function_ea, idc.FUNCATTR_END) self.highlighted = idaapi.get_highlighted_identifier() while ea < end_ea and ea != idc.BADADDR and self.highlighted: i = 0 match = False optype = self.READ comment = None idaapi.decode_insn(ea) mnem = idc.GetMnem(ea) if self.highlighted in mnem: match = True elif idaapi.is_call_insn(ea): for xref in idautils.XrefsFrom(ea): if xref.type != 21: name = idc.Name(xref.to) if name and self.highlighted in name: match = True break else: while True: opnd = idc.GetOpnd(ea, i) if opnd: if self.highlighted in opnd: try: canon_feature = idaapi.insn_t_get_canon_feature( idaapi.cmd.ityp) except AttributeError: insn_t = idaapi.insn_t() canon_feature = insn_t.get_canon_feature() match = True if canon_feature & self.OPND_WRITE_FLAGS[i]: optype = self.WRITE i += 1 else: break if not match: comment = idc.GetCommentEx(ea, 0) if comment and self.highlighted in comment: match = True else: comment = idc.GetCommentEx(ea, 1) if comment and self.highlighted in comment: match = True else: comment = None if match: if ea > current_ea: direction = self.DOWN elif ea < current_ea: direction = self.UP else: direction = self.THIS self.xrefs[ea] = { 'offset': idc.GetFuncOffset(ea), 'mnem': mnem, 'type': optype, 'direction': direction, 'text': idc.GetDisasm(ea), } ea += idaapi.cmd.size
def main(): print("[*] loading crypto constants") for const in non_sparse_consts: const["byte_array"] = convert_to_byte_array(const) for start in idautils.Segments(): print("[*] searching for crypto constants in %s" % idc.SegName(start)) ea = start while ea < idc.SegEnd(start): bbbb = list( struct.unpack("BBBB", idc.GetManyBytes(ea, 4) or "AAAA")) for const in non_sparse_consts: if bbbb != const["byte_array"][:4]: continue if map( lambda x: ord(x), idc.GetManyBytes(ea, len(const["byte_array"])) or list()) == const["byte_array"]: print(("0x%0" + str(digits) + "X: found const array %s (used in %s)") % (ea, const["name"], const["algorithm"])) idc.MakeName(ea, const["name"]) if const["size"] == "B": idc.MakeByte(ea) elif const["size"] == "L": idc.MakeDword(ea) elif const["size"] == "Q": idc.MakeQword(ea) MakeArray(ea, len(const["array"])) ea += len(const["byte_array"]) - 4 break ea += 4 #print "ea: 0x%x " % ea ea = start if idc.GetSegmentAttr(ea, SEGATTR_TYPE) == 2: while ea < idc.SegEnd(start): d = idc.Dword(ea) for const in sparse_consts: if d != const["array"][0]: continue tmp = ea + 4 for val in const["array"][1:]: for i in range(8): if idc.Dword(tmp + i) == val: tmp = tmp + i + 4 break else: break else: print(("0x%0" + str(digits) + "X: found sparse constants for %s") % (ea, const["algorithm"])) cmt = idc.GetCommentEx(idc.prev_head(ea), 0) if cmt: idc.CommentEx(idc.prev_head(ea), cmt + ' ' + const["name"], 0) else: idc.CommentEx(idc.prev_head(ea), const["name"], 0) ea = tmp break ea += 1 print("[*] finished")
def _profile_function(self): current_ea = ida_shims.get_screen_ea() current_function = ida_shims.get_func_name(current_ea) current_function_ea = ida_shims.get_name_ea_simple(current_function) if current_function: self.function = current_function ea = ida_shims.get_func_attr(current_function_ea, idc.FUNCATTR_START) end_ea = ida_shims.get_func_attr(current_function_ea, idc.FUNCATTR_END) self.highlighted = ida_shims.get_highlighted_identifier() while ea < end_ea and ea != idc.BADADDR and self.highlighted: i = 0 match = False optype = self.READ insn = ida_shims.decode_insn(ea) mnem = ida_shims.print_insn_mnem(ea) if self.highlighted in mnem: match = True elif idaapi.is_call_insn(ea): for xref in idautils.XrefsFrom(ea): if xref.type != 21: name = ida_shims.get_name(xref.to) if name and self.highlighted in name: match = True break else: while True: opnd = ida_shims.print_operand(ea, i) if opnd: if self.highlighted in opnd: canon_feature = ida_shims.get_canon_feature(insn) match = True if canon_feature & self.OPND_WRITE_FLAGS[i]: optype = self.WRITE i += 1 else: break if not match: comment = idc.GetCommentEx(ea, 0) if comment and self.highlighted in comment: match = True else: comment = idc.GetCommentEx(ea, 1) if comment and self.highlighted in comment: match = True else: comment = None if match: if ea > current_ea: direction = self.DOWN elif ea < current_ea: direction = self.UP else: direction = self.THIS self.xrefs[ea] = { 'offset': ida_shims.get_func_off_str(ea), 'mnem': mnem, 'type': optype, 'direction': direction, 'text': idc.GetDisasm(ea), } ea = ida_shims.next_head(ea)