def _find_system_calls(self, start_ea, end_ea): system_calls = [] system_load = MIPSInstruction("la", "$t9", "system") stack_arg_zero = MIPSInstruction("addiu", "$a0", "$sp") for xref in idautils.XrefsTo(ida_shims.get_name_ea_simple('system')): ea = xref.frm mnem = ida_shims.print_insn_mnem(ea) if mnem and ea >= start_ea and \ ea <= end_ea and mnem[0] in ['j', 'b']: a0_ea = self._find_next_instruction_ea( ea+self.INSIZE, stack_arg_zero, ea+self.INSIZE) if a0_ea == idc.BADADDR: a0_ea = self._find_prev_instruction_ea( ea, stack_arg_zero, ea-(self.SEARCH_DEPTH*self.INSIZE)) if a0_ea != idc.BADADDR: control_ea = self._find_prev_instruction_ea( ea-self.INSIZE, system_load, ea-(self.SEARCH_DEPTH*self.INSIZE)) if control_ea != idc.BADADDR: system_calls.append( ROPGadget( self._get_instruction(control_ea), self._get_instruction(ea), self._get_instruction(a0_ea), description="System call", base=self.base)) ea += self.INSIZE else: break return system_calls
def _is_bad_instruction(self, ea, bad_instructions=['j', 'b'], no_clobber=[]): bad = False mnem = ida_shims.print_insn_mnem(ea) if mnem and mnem[0] in bad_instructions: bad = True else: insn = ida_shims.decode_insn(ea) feature = ida_shims.get_canon_feature(insn) for register in no_clobber: if (feature & idaapi.CF_CHG1) == idaapi.CF_CHG1: if ida_shims.print_operand(ea, 0) == register: bad = True return bad
def __init__(self): print "Naming saved register locations...", for ea in idautils.Functions(): mea = ea named_regs = [] last_iteration = False while mea < (ea + (self.INSIZE * self.SEARCH_DEPTH)): mnem = ida_shims.print_insn_mnem(mea) if mnem in ['sw', 'sd']: reg = ida_shims.print_operand(mea, 0) dst = ida_shims.print_operand(mea, 1) if reg in self.ARCH['savedregs'] and \ reg not in named_regs and \ dst.endswith('($sp)') and 'var_' in dst: split_string = 'var_' stack_position = "[sp-%d]" if '_s' in dst: split_string += 's' stack_position = "[sp+%d]" offset = int( dst.split(split_string)[1].split('(')[0], 16) ida_shims.define_local_var(ea, ida_shims.find_func_end(ea), stack_position % offset, "saved_%s" % reg[1:]) named_regs.append(reg) if last_iteration: break elif mnem.startswith('j') or mnem.startswith('b'): last_iteration = True mea += self.INSIZE print "done."
def _does_instruction_match(self, ea, instruction, regex=False): i = 0 op_cnt = 0 op_ok_cnt = 0 match = False insn = ida_shims.decode_insn(ea) mnem = ida_shims.print_insn_mnem(ea) if (not instruction.mnem) or (instruction.mnem == mnem) or \ (regex and re.match(instruction.mnem, mnem)): for operand in instruction.operands: if operand: op_cnt += 1 op = ida_shims.print_operand(ea, i) if regex: if re.match(operand, op): op_ok_cnt += 1 elif operand == op: op_ok_cnt += 1 i += 1 if op_cnt == op_ok_cnt: match = True return match
def block(self, block): ''' Returns a tuple: ([formal, block, signatures], [fuzzy, block, signatures], set([unique, immediate, values]), [called, function, names]) ''' formal = [] fuzzy = [] functions = [] immediates = [] ea = ida_shims.start_ea(block) while ea < ida_shims.end_ea(block): insn = ida_shims.decode_insn(ea) # Get a list of all data/code refs from the current instruction drefs = [x for x in idautils.DataRefsFrom(ea)] crefs = [x for x in idautils.CodeRefsFrom(ea, False)] # Add all instruction mnemonics to the formal block hash formal.append(ida_shims.print_insn_mnem(ea)) # If this is a call instruction, be sure to note the name of the # function being called. This is used to apply call-based # signatures to functions. # # For fuzzy signatures, we can't use the actual name or EA of the # function, but rather just want to note that a function call was # made. # # Formal signatures already have the call instruction mnemonic, # which is more specific than just saying that a call was made. if idaapi.is_call_insn(ea): for cref in crefs: func_name = ida_shims.get_name(cref) if func_name: functions.append(func_name) fuzzy.append("funcref") # If there are data references from the instruction, check to see # if any of them are strings. These are looked up in the # pre-generated strings dictionary. # # String values are easily identifiable, and are used as part of # both the fuzzy and the formal signatures. # # It is more difficult to determine if non-string values are # constants or not; for both fuzzy and formal signatures, just use # "data" to indicate that some data was referenced. elif drefs: for dref in drefs: if self.strings.has_key(dref): formal.append(self.strings[dref].value) fuzzy.append(self.strings[dref].value) else: formal.append("dataref") fuzzy.append("dataref") # If there are no data or code references from the instruction, use # every operand as part of the formal signature. # # Fuzzy signatures are only concerned with interesting immediate # values, that is, values that are greater than 65,535, are not # memory addresses, and are not displayed as negative values. elif not drefs and not crefs: ops = ida_shims.get_operands(insn) for n in range(0, len(ops)): opnd_text = ida_shims.print_operand(ea, n) formal.append(opnd_text) if ops[n].type == idaapi.o_imm and \ not opnd_text.startswith('-'): if ops[n].value >= 0xFFFF: if ida_shims.get_full_flags(ops[n].value) == 0: fuzzy.append(str(ops[n].value)) immediates.append(ops[n].value) ea = ida_shims.next_head(ea) return (self.sighash(''.join(formal)), self.sighash(''.join(fuzzy)), immediates, functions)
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)
def summary(self): ''' Prints a summary of your currently marked ROP gadgets, in alphabetical order by the marked name. To mark a location as a ROP gadget, simply mark the position in IDA (Alt+M) with any name that starts with "ROP". ''' rop_gadgets = self._get_marked_gadgets() summaries = [] delim_char = "-" headings = { 'name': "Gadget Name", 'offset': "Gadget Offset", 'summary': "Gadget Summary" } if self.base != 0: headings['offset'] = "Gadget Base + Offset = Address " lengths = { 'name': len(headings['name']), 'offset': len(headings['offset']), 'summary': len(headings['summary']), } total_length = (3 * len(headings)) + 1 if rop_gadgets: gadget_keys = list(rop_gadgets.keys()) gadget_keys.sort() for marked_comment in gadget_keys: if len(marked_comment) > lengths['name']: lengths['name'] = len(marked_comment) summary = [] ea = rop_gadgets[marked_comment] end_ea = ea + (self.SEARCH_DEPTH * self.INSIZE) while ea <= end_ea: summary.append(idc.GetDisasm(ea)) mnem = ida_shims.print_insn_mnem(ea) if len(mnem) > 0 and mnem[0].lower() in ['j', 'b']: summary.append(idc.GetDisasm(ea + self.INSIZE)) break ea += self.INSIZE if len(summary) == 0: summary.append('') for line in summary: if len(line) > lengths['summary']: lengths['summary'] = len(line) summaries.append(summary) for (heading, size) in lengths.items(): total_length += size delim = delim_char * total_length line_fmt = "| %%-%ds | %%-%ds | %%-%ds |" % \ (lengths['name'], lengths['offset'], lengths['summary']) print(delim) print(line_fmt % \ (headings['name'], headings['offset'], headings['summary'])) print(delim) for i in range(0, len(gadget_keys)): line_count = 0 marked_comment = gadget_keys[i] if self.base != 0: offset = "0x%.8X + 0x%.8X = 0x%.8X" % \ (self.base, rop_gadgets[marked_comment], self.base + rop_gadgets[marked_comment]) else: offset = "0x%.8X" % rop_gadgets[marked_comment] summary = summaries[i] for line in summary: if line_count == 0: print(line_fmt % (marked_comment, offset, line)) else: print(line_fmt % ('', '', line)) line_count += 1 print(delim)
def _get_instruction(self, ea): return MIPSInstruction(ida_shims.print_insn_mnem(ea), ida_shims.print_operand(ea, 0), ida_shims.print_operand(ea, 1), ida_shims.print_operand(ea, 2), ea)