def _color_var(self, vu, item): global COLOR_VARS if not item: return pc = vu.cfunc.get_pseudocode() if item in COLOR_VARS: for sl in pc: sl.line = sl.line.replace( ida_lines.COLSTR(item, ida_lines.SCOLOR_ERROR), item) COLOR_VARS.remove(item) else: for sl in pc: pos = 0 while True: pos = sl.line.find(item, pos) if pos < 0: break if not sl.line[pos + len(item)].isalnum(): sl.line = sl.line[:pos] + ida_lines.COLSTR( item, ida_lines.SCOLOR_ERROR) + sl.line[pos + len(item):] pos += len( ida_lines.COLSTR(item, ida_lines.SCOLOR_ERROR)) else: pos += 1 # sl.line = sl.line.replace(item, ida_lines.COLSTR(item, ida_lines.SCOLOR_ERROR)) COLOR_VARS.append(item) refresh_idaview_anyway()
def disasm(self, inst): """A simple local disassembler. In reality one can use a full-blown disassembler to render the text""" opbyte = ord(inst[0]) if sys.version_info.major < 3 else inst[0] op = opbyte >> 4 if not (1 <= op <= 5): return None r1 = (opbyte & 0xf) >> 2 r2 = opbyte & 3 sz = 0 if r2 == 0: if len(inst) != 5: return None imm = struct.unpack_from('L', inst, 1)[0] sz = 5 else: imm = None sz = 1 text = "%s %s, %s" % ( ida_lines.COLSTR(simplevm_data_format.INST[op], ida_lines.SCOLOR_INSN), ida_lines.COLSTR(simplevm_data_format.REGS[r1], ida_lines.SCOLOR_REG), ida_lines.COLSTR("0x%08X" % imm, ida_lines.SCOLOR_NUMBER) if imm is not None else ida_lines.COLSTR( simplevm_data_format.REGS[r2], ida_lines.SCOLOR_REG)) return (sz, text)
def as_id(self, s): t = s.lower() if t in self.register_list: return ida_lines.COLSTR(s, ida_lines.SCOLOR_REG) elif t in self.instruction_list: return ida_lines.COLSTR(s, ida_lines.SCOLOR_INSN) else: return s
def render_function_hint(fva): ''' create a textual report for the call and string references in the given function. eg. 3 calls, 4 strings calls: - call new - call gethostbyname - call delete strings: - www.google.com - www.bing.com - www.yahoo.com - www.cnn.com Args: fva (int): the starting address of a function Returns: str: the report ''' ret = [] # use `uniq` here (vs using a set) cause we want to maintain *some* semblance of order. calls = list(uniq(d for f, d in enum_calls_in_function(fva))) strings = list(uniq(s for o, r, s in enum_string_refs_in_function(fva))) # this would be a good place to use Jinja2 templating, # but lets not require that external dependency title = ida_lines.COLSTR('%d calls, ' % len(calls), ida_lines.SCOLOR_CODNAME) title += ida_lines.COLSTR('%s strings' % len(strings), ida_lines.SCOLOR_DSTR) ret.append(title) ret.append('') if calls: ret.append(ida_lines.COLSTR('calls:', ida_lines.SCOLOR_CODNAME)) for call in calls: ret.append(' - ' + call) ret.append('') if strings: ret.append(ida_lines.COLSTR('strings:', ida_lines.SCOLOR_DSTR)) for s in strings: ret.append(' - ' + ida_lines.COLSTR(s, ida_lines.SCOLOR_DSTR)) return '\n'.join(ret)
def _contains_item(self, pc, items, remove=False): for sl in pc: line = self._strip_line(sl.line) s = ''.join(items) count = line.count(s) if count <= 0: continue #print(count, line) start = 0 fact = 0 for i in range(13): # max 13 times to try to match if fact == count: continue # find all arguments pos = len(sl.line) found = True pos = sl.line.find(items[-1], start, pos) old_start = start start = pos + 1 if pos < 0 or (pos+len(items[-1])<len(sl.line) and sl.line[pos+len(items[-1])].isalnum()) or \ ((pos-1) >= 0 and sl.line[pos-1].isalnum()): continue for item in items[-2::-1]: pos = sl.line.rfind(item, old_start, pos) if pos < 0 or (pos+len(item)<len(sl.line) and sl.line[pos+len(item)].isalnum()) or \ ((pos-1) >= 0 and sl.line[pos-1].isalnum()): found = False break if found: fact += 1 for item in items: pos = sl.line.find(item, pos, start) if pos + len(item) == len( sl.line ) or not sl.line[pos + len(item)].isalnum( ) or pos - 1 < 0 or not sl.line[pos - 1].isalnum(): if remove: sl.line = sl.line[:pos - 2] + item + sl.line[ pos + len(item) + 2:] start -= 4 else: sl.line = sl.line[:pos] + ida_lines.COLSTR( item, ida_lines.SCOLOR_ERROR ) + sl.line[pos + len(item):] pos += len( ida_lines.COLSTR(item, ida_lines.SCOLOR_ERROR)) start += 4 elif pos < 0: continue else: pos += 1
def Create(self, sn=None, use_colors=True): # Form the title title = "Simple custom view test" if sn: title += " %d" % sn self.use_colors = use_colors # Create the customviewer if not ida_kernwin.simplecustviewer_t.Create(self, title): return False for i in range(0, 100): prefix, bg = ida_lines.COLOR_DEFAULT, None # make every 10th line a bit special if i % 10 == 0: prefix = ida_lines.COLOR_DNAME # i.e., dark yellow... bg = 0xFFFF00 # ...on cyan pfx = ida_lines.COLSTR("%3d" % i, ida_lines.SCOLOR_PREFIX) if self.use_colors: self.AddLine("%s: Line %d" % (pfx, i), fgcolor=prefix, bgcolor=bg) else: self.AddLine("%s: Line %d" % (pfx, i)) return True
def ResetOutput(self): self.ClearLines() self.AddLine( ida_lines.COLSTR( "Please press INS to enter command; X to clear output", ida_lines.SCOLOR_AUTOCMT)) self.Refresh()
def OnKeydown(self, vkey, shift): """ User pressed a key @param vkey: Virtual key code @param shift: Shift flag @return: Boolean. True if you handled the event """ print("OnKeydown, vk=%d shift=%d" % (vkey, shift)) # ESCAPE? if vkey == 27: self.Close() # VK_DELETE elif vkey == 46: n = self.GetLineNo() if n is not None: self.DelLine(n) self.Refresh() print("Deleted line %d" % n) # Goto? elif vkey == ord('G'): n = self.GetLineNo() if n is not None: v = ida_kernwin.ask_long(self.GetLineNo(), "Where to go?") if v: self.Jump(v, 0, 5) elif vkey == ord('R'): print("refreshing....") self.Refresh() elif vkey == ord('C'): print("refreshing current line...") self.RefreshCurrent() elif vkey == ord('A'): s = ida_kernwin.ask_str("NewLine%d" % self.Count(), 0, "Append new line") self.AddLine(s) self.Refresh() elif vkey == ord('X'): print("Clearing all lines") self.ClearLines() self.Refresh() elif vkey == ord('I'): n = self.GetLineNo() s = ida_kernwin.ask_str("InsertedLine%d" % n, 0, "Insert new line") self.InsertLine(n, s) self.Refresh() elif vkey == ord('E'): l = self.GetCurrentLine(notags=1) if not l: return False n = self.GetLineNo() print("curline=<%s>" % l) l = l + ida_lines.COLSTR("*", ida_lines.SCOLOR_VOIDOP) self.EditLine(n, l) self.RefreshCurrent() print("Edited line %d" % n) else: return False return True
def replace_addr_tags(s): tag = "%c%c" % (il.COLOR_ON, il.COLOR_ADDR) tag_size = len(tag) ti = {} p = s.find(tag) while p != -1: ti[s[p+tag_size:p+tag_size+il.COLOR_ADDR_SIZE]] = 0 p = s.find(tag, p+tag_size+il.COLOR_ADDR_SIZE) for addr in ti.keys(): s = s.replace(tag+addr, il.COLSTR("<%s>" % addr, il.SCOLOR_AUTOCMT)+tag+addr) return s
def maturity_ev(self, cfunc, new_maturity): if new_maturity == ida_hexrays.CMAT_FINAL: lvars = cfunc.get_lvars() for lvar in lvars: if lvar.has_nice_name and not lvar.has_user_name: vtype = "s" if lvar.is_stk_var( ) else "r" if lvar.is_reg_var() else "u" suffix = "_%s%d" % (vtype, lvar.width) lvar.name += ida_lines.COLSTR(suffix, ida_lines.SCOLOR_AUTOCMT) lvar.set_user_name() return 0
def IssueCommand(self): s = ida_kernwin.ask_str(self.last_cmd, 0, "Please enter a debugger command") if not s: return # Save last command self.last_cmd = s # Add it using a different color self.AddLine("debugger>" + ida_lines.COLSTR(s, ida_lines.SCOLOR_VOIDOP)) ok, out = ida_dbg.send_dbg_command(s) if ok: for line in out.split("\n"): self.AddLine(ida_lines.COLSTR(line, ida_lines.SCOLOR_LIBNAME)) else: self.AddLine( ida_lines.COLSTR( "Debugger is not active or does not export ida_dbg.send_dbg_command() (%s)" % out, ida_lines.SCOLOR_ERROR)) self.Refresh()
def printf(self, value, current_ea, operand_num, dtid): # Is it already cached? val = self.cache_node.supval(current_ea) # Not cached? if val == None: # Retrieve it num = ida_idaapi.struct_unpack(value) val = self.get_rsrc_string(ida_nalt.get_input_file_path(), num) # Cache it self.cache_node.supset(current_ea, val) # Failed to retrieve? if val == "" or val == "\x00": return None # Return the format return "RSRC_STR(\"%s\")" % ida_lines.COLSTR(val, ida_lines.SCOLOR_IMPNAME)
def tag_signed_ops(self, cf, item_codes): ci = hr.ctree_item_t() ccode = cf.get_pseudocode() for line_idx in range(cf.hdrlines, len(ccode)): items = [] sl = ccode[line_idx] for char_idx in range(len(sl.line)): if cf.get_line_item(sl.line, char_idx, True, None, ci, None): if ci.it.is_expr() and ci.e.op in item_codes: #print("%s: unsigned op. line %d, pos %d" % (__file__, line_idx+1, char_idx)) items.append(ci.it.index) for item in list(dict.fromkeys(items)): tag = FMT % (ida_lines.COLOR_ON, ida_lines.COLOR_ADDR, item) sample = "/*signed*/" sl.line = sl.line.replace( tag, tag + ida_lines.COLSTR(sample, ida_lines.SCOLOR_ERROR))
def replace_addr_tags(cfunc, s): tag = "%c%c" % (il.COLOR_ON, il.COLOR_ADDR) tag_size = len(tag) ti = {} p = s.find(tag) while p != -1: ti[s[p+tag_size:p+tag_size+il.COLOR_ADDR_SIZE]] = 0 p = s.find(tag, p+tag_size+il.COLOR_ADDR_SIZE) for addr in ti.keys(): idx = int(addr, 16) a = ida_hexrays.ctree_anchor_t() a.value = idx if a.is_valid_anchor() and a.is_citem_anchor(): item = cfunc.treeitems.at(a.get_index()) if item: ctype_name = ida_hexrays.get_ctype_name(item.op) s = s.replace(tag+addr, il.COLSTR("<%s>" % ctype_name, il.SCOLOR_AUTOCMT)+tag+addr) return s
def get_node_label(self, n, highlight_node=False): item = self.items[n] op = item.op insn = item.cinsn expr = item.cexpr type_name = ida_hexrays.get_ctype_name(op) parts = [] if op == ida_hexrays.cot_ptr: parts.append("%s.%d" % (type_name, expr.ptrsize)) elif op == ida_hexrays.cot_memptr: parts.append("%s.%d (m=%d)" % (type_name, expr.ptrsize, expr.m)) elif op == ida_hexrays.cot_memref: parts.append("%s (m=%d)" % ( type_name, expr.m, )) elif op in [ida_hexrays.cot_obj, ida_hexrays.cot_var]: name = self.get_expr_name(expr) parts.append("%s.%d %s" % (type_name, expr.refwidth, name)) elif op in [ ida_hexrays.cot_num, ida_hexrays.cot_helper, ida_hexrays.cot_str ]: name = self.get_expr_name(expr) parts.append("%s %s" % ( type_name, name, )) elif op == ida_hexrays.cit_goto: parts.append("%s LABEL_%d" % (type_name, insn.cgoto.label_num)) elif op == ida_hexrays.cit_asm: parts.append("%s <asm statements; unsupported ATM>" % type_name) # parts.append(" %a.%d" % ()) else: parts.append("%s" % type_name) parts.append("ea: %08X" % item.ea) if item.is_expr() and not expr.type.empty(): tstr = expr.type._print() parts.append(tstr if tstr else "?") scolor = ida_lines.SCOLOR_EXTRA if highlight_node else ida_lines.SCOLOR_DEFAULT parts = [ida_lines.COLSTR("%s" % part, scolor) for part in parts] return "\n".join(parts)
def func_printed_ev(self, cfunc): pc = cfunc.get_pseudocode() for sl in pc: for token in FUNC_NAMES: sl.line = sl.line.replace(token, ida_lines.COLSTR(token, ida_lines.SCOLOR_ERROR)) return 0
def _get_node_label(self, n, highlight_node=False): item = self.items[n] op = item.op insn = item.cinsn expr = item.cexpr type_name = ida_hexrays.get_ctype_name(op) parts = [] if op == ida_hexrays.cot_ptr: parts.append("%s.%d" % (type_name, expr.ptrsize)) elif op == ida_hexrays.cot_memptr: parts.append("%s.%d (m=%d)" % (type_name, expr.ptrsize, expr.m)) elif op == ida_hexrays.cot_memref: parts.append("%s (m=%d)" % ( type_name, expr.m, )) elif op in [ida_hexrays.cot_obj, ida_hexrays.cot_var]: name = self._get_expr_name(expr) parts.append("%s.%d %s" % (type_name, expr.refwidth, name)) elif op in [ ida_hexrays.cot_num, ida_hexrays.cot_helper, ida_hexrays.cot_str ]: name = self._get_expr_name(expr) parts.append("%s %s" % ( type_name, name, )) elif op == ida_hexrays.cit_goto: parts.append("%s LABEL_%d" % (type_name, insn.cgoto.label_num)) elif op == ida_hexrays.cit_asm: parts.append("%s <asm statements; unsupported ATM>" % type_name) # parts.append(" %a.%d" % ()) else: parts.append("%s" % type_name) parts.append("ea: %x" % item.ea) # add type if item.is_expr() and not expr.type.empty(): tstr = expr.type._print() parts.append(tstr if tstr else "?") if self.debug: parts.append("-" * 20) parts.append("obj_id: %x" % item.obj_id) if op is ida_hexrays.cot_var: parts.append("idx: %d" % expr.v.idx) lv = expr.v.getv() if lv: parts.append("width: %d" % lv.width) parts.append("defblk: %d" % lv.defblk) parts.append("cmt: %s" % lv.cmt) parts.append("arg_var: %r" % lv.is_arg_var) parts.append("thisarg: %r" % lv.is_thisarg()) parts.append("result_var: %r" % lv.is_result_var) parts.append("used_byref: %r" % lv.is_used_byref()) parts.append("mapdst_var: %r" % lv.is_mapdst_var) parts.append("overlapped_var: %r" % lv.is_overlapped_var) parts.append("floating_var: %r" % lv.is_floating_var) parts.append("typed: %r" % lv.typed) if self.debug > 1: parts.append("divisor: %d" % lv.divisor) parts.append("automapped: %r" % lv.is_automapped()) parts.append("fake_var: %r" % lv.is_fake_var) parts.append("spoiled_var: %r" % lv.is_spoiled_var) parts.append("noptr_var: %r" % lv.is_noptr_var()) parts.append("forced_var: %r" % lv.is_forced_var()) parts.append("dummy_arg: %r" % lv.is_dummy_arg()) parts.append("used: %r" % lv.used) parts.append("user_info: %r" % lv.has_user_info) parts.append("user_name: %r" % lv.has_user_name) parts.append("user_type: %r" % lv.has_user_type) parts.append("regname: %r" % lv.has_regname()) parts.append("mreg_done: %r" % lv.mreg_done) parts.append("nice_name: %r" % lv.has_nice_name) parts.append("unknown_width: %r" % lv.is_unknown_width) parts.append("in_asm: %r" % lv.in_asm()) parts.append("notarg: %r" % lv.is_notarg()) parts.append("decl_unused: %r" % lv.is_decl_unused()) elif op is ida_hexrays.cot_obj: parts.append("obj_ea: %x" % expr.obj_ea) # disable hightlight color for now -> requires labels to be re-generated/graph to be redrawn #scolor = self.COLOR_TEXT_HIGHLIGHT if highlight_node else self.COLOR_TEXT_DEFAULT scolor = self.COLOR_TEXT_DEFAULT parts = [ida_lines.COLSTR("%s" % part, scolor) for part in parts] return "\n".join(parts)
def process_text(self, vu): pc = vu.cfunc.get_pseudocode() for sl in pc: for token in FUNC_NAMES: sl.line = sl.line.replace(token, ida_lines.COLSTR(token, ida_lines.SCOLOR_ERROR)) return 0
def as_comment(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_RPTCMT)
def as_directive(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_KEYWORD)
def as_num(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_NUMBER)
def as_string(self, s): return ida_lines.COLSTR(s, ida_lines.SCOLOR_STRING)