def render_img(self, buffers, addr, mouse_offs): colors = [] head = ida_idaapi.BADADDR tail = ida_idaapi.BADADDR goffs = 0 for mapped, buf in buffers: if mapped: if mouse_offs is not None: if self.switch == 0: # data head = get_item_head(addr + mouse_offs) tail = get_item_end(addr + mouse_offs) else: # code f = get_func(addr + mouse_offs) if f: head = f.startEA tail = f.endEA for pos in xrange(len(buf)): c = ord(buf[pos]) & 0xFF highlight = False if mouse_offs is not None: if addr + pos + goffs >= head and addr + pos + goffs < tail: highlight = True if highlight: colors.append((True, qRgb(c, 0xFF, self.hl_color))) else: colors.append((True, qRgb(c, 0, 0))) else: for pos in xrange(len(buf)): colors.append((False, 0)) goffs += len(buf) return colors
def on_process_buffer(self, buffers, addr, size, mouse_offs): colors = [] goffs = 0 if mouse_offs is not None: head = get_item_head(addr + mouse_offs) tail = get_item_end(addr + mouse_offs) for mapped, buf in buffers: if mapped: for i in range(len(buf)): c = buf[i] if addr + i + goffs >= head and addr + i + goffs < tail: col = self.red[1] else: col = self.colormap[int( c / (0xff / (len(self.colormap) - 1)))] colors.append((True, col)) else: for i in range(len(buf)): if addr + i + goffs >= head and addr + i + goffs < tail: colors.append((False, self.red[0])) else: colors.append((False, None)) goffs += len(buf) return colors
def on_get_annotations(self, address, size, mouse_offs): caption = " Mov instructions:" spaces = 40 * '-' cursor_ea = address + mouse_offs head = get_item_head(cursor_ea) ann = [ (head, self.ptrcol, "%X: %s" % (head, generate_disasm_line( head, GENDSM_FORCE_CODE | GENDSM_REMOVE_TAGS)), self.ptrcol), (None, None, "", None), (None, None, caption, self.colormap[0]) ] if len(self.annotations): i = 0 offs = self._get_selection_offs() ann_cnt = len(self.annotations) for x in xrange(offs, ann_cnt): _, acc, ea = self.annotations[x] textcol = self.txtcol ann.append((ea, self.insn_colors[acc], " %X: %s" % (ea, generate_disasm_line( ea, GENDSM_FORCE_CODE | GENDSM_REMOVE_TAGS)), self.insn_colors[acc])) i += 1 if i > self.threshold: ann.append((None, None, " <%d more not shown>" % (len(self.annotations) - i), self.colormap[0])) break return ann
def render_img(self, buffers, addr, mouse_offs): colors = [] cols = [qRgb(0xDC, 0xDC, 0xDC), qRgb(0x00, 0x00, 0x00)] colidx = 0 goffs = 0 for mapped, buf in buffers: if mapped: start = ea = addr + goffs end = start + len(buf) head = get_item_head(start) sz = get_item_size(head) if head < start: sz -= (start - head) while ea < end: for i in xrange(sz): colors.append((True, copy(cols[colidx]))) colidx = ((colidx + 1) & sz != 0) if ea + sz > end: sz = ea + sz - end ea += sz sz = get_item_size(ea) else: for i in xrange(len(buf)): colors.append((False, 0)) goffs += len(buf) return colors
def mouseMoveEvent(self, event): x = event.pos().x() y = event.pos().y() within_graph = (x >= self.rect_x and x < self.rect_x + self.rect_x_width) """(sx1, sy1), (sx2, sy2) = self.slider_coords on_slider = (x >= sx1 and x< sx2 and y>= sy1 and y < sy2)""" update_state = self.is_dragging_graph or within_graph if self.is_dragging_graph: # zoom if self.key == Qt.Key_Control: self.set_zoom_delta(-1 if y > self.prev_mouse_y else 1) # width elif self.key == Qt.Key_X: if not self.lock_width: self.set_width_delta(-1 if y > self.prev_mouse_y else 1) elif self.key == Qt.Key_H: if not self.lock_width: less = y > self.prev_mouse_y delta = -16 if less else 16 self.set_pixel_qty_per_line((self.get_pixel_qty_per_line() & 0xFFFFFFF0) + delta) # scrolling (offset) elif y != self.prev_mouse_y: # offset (fine) delta = y - self.prev_mouse_y # offset (coarse) if self.key != Qt.Key_Shift: delta *= self.get_pixel_qty_per_line() self.set_offset_delta(delta) elif within_graph: self._update_mouse_coords(event.pos()) self.mouseOffs = self._get_offs_by_pos(event.pos()) if self.link_pixel and self.highlight_cursor: highlight_item( ida_bytes.get_item_head(self.get_cursor_address())) elif self.highlight_cursor: unhighlight_item() self.setToolTip( self.fm.on_get_tooltip(self.get_address(), self.get_pixel_qty(), self.mouseOffs)) if update_state: self.prev_mouse_y = y self.x = x self.statechanged.emit() self.repaint() return
def get_tooltip(self, addr, mouse_offs): tooltip = '%X: ' % (addr + mouse_offs) if self.switch == 0: tooltip += '%s' % get_name(get_item_head(addr + mouse_offs)) else: f = get_func(addr + mouse_offs) if f: tooltip += '%s' % get_func_name(f.startEA) return tooltip
def mouseMoveEvent(self, event): x = event.pos().x() y = event.pos().y() within_graph = (x >= self.rect_x and x < self.rect_x + self.rect_x_width) if within_graph: if event.buttons() == Qt.NoButton: self._update_mouse_coords(event.pos()) self.mouseOffs = self._get_offs_by_pos(event.pos()) if self.link_pixel and self.highlight_cursor: highlight_item( ida_bytes.get_item_head(self.get_cursor_address())) elif self.highlight_cursor: unhighlight_item() self.setToolTip( self.fm.on_get_tooltip(self.get_address(), self.get_pixels_total(), self.mouseOffs)) # zoom elif self.key == Qt.Key_Control: self.set_zoom_delta(-1 if y > self.prev_mouse_y else 1) # width elif self.key == Qt.Key_X: if not self.lock_width: self.set_width_delta(-1 if y > self.prev_mouse_y else 1) elif self.key == Qt.Key_H: if not self.lock_width: less = y > self.prev_mouse_y delta = -16 if less else 16 self.set_width((self.get_width() & 0xFFFFFFF0) + delta) # scrolling (offset) elif y != self.prev_mouse_y: # offset (fine) delta = y - self.prev_mouse_y # offset (coarse) if self.key != Qt.Key_Shift: delta *= self.get_width() self.set_offset_delta(delta) self.prev_mouse_y = y self.x = x self.statechanged.emit() self.repaint() return
def _has_code(self): """ Checks if any address in the changed data area has code in it :return: (int) address of the code start, or None. """ for i in xrange(self.data): maybe_start_of_item = ida_bytes.get_item_head(self.address + i) if ida_bytes.is_code( ida_bytes.get_full_flags(maybe_start_of_item)): return self.address + i return None
def on_get_annotations(self, address, size, mouse_offs): item_ea = get_item_head(address + mouse_offs) cursor_ea = address + mouse_offs name = get_name(item_ea) if len(name): name = "(%s)" % name else: name = "" ann = [ (item_ea, self.red[0], "Item: %X" % (item_ea), self.colormap[-1]), (None, None, " Size: %d %s" % (get_item_size(get_item_head(cursor_ea)), name), self.colormap[-3]), (cursor_ea, self.colormap[-1], "Cursor: %X" % (cursor_ea), self.colormap[-1]), (None, None, " %s" % generate_disasm_line( cursor_ea, GENDSM_FORCE_CODE | GENDSM_REMOVE_TAGS), self.colormap[-3]), (None, None, " Value: %02X" % get_byte(cursor_ea), self.colormap[-3]), ] return ann
def _convert_address_to_function(func): """Convert an address that IDA has classified incorrectly into a proper function.""" # If everything goes wrong, we'll try to restore this function. orig = idc.first_func_chunk(func) # If the address is not code, let's undefine whatever it is. if not ida_bytes.is_code(ida_bytes.get_full_flags(func)): if not is_mapped(func): # Well, that's awkward. return False item = ida_bytes.get_item_head(func) itemend = ida_bytes.get_item_end(func) if item != idc.BADADDR: _log(1, 'Undefining item {:#x} - {:#x}', item, itemend) ida_bytes.del_items(item, ida_bytes.DELIT_EXPAND) idc.create_insn(func) # Give IDA a chance to analyze the new code or else we won't be able to create a # function. #ida_auto.auto_wait() autoanalyze() idc.plan_and_wait(item, itemend) else: # Just try removing the chunk from its current function. IDA can add it to another function # automatically, so make sure it's removed from all functions by doing it in loop until it # fails. for i in range(1024): if not idc.remove_fchunk(func, func): break # Now try making a function. if ida_funcs.add_func(func) != 0: return True # This is a stubborn chunk. Try recording the list of chunks, deleting the original function, # creating the new function, then re-creating the original function. if orig != idc.BADADDR: chunks = list(idautils.Chunks(orig)) if ida_funcs.del_func(orig) != 0: # Ok, now let's create the new function, and recreate the original. if ida_funcs.add_func(func) != 0: if ida_funcs.add_func(orig) != 0: # Ok, so we created the functions! Now, if any of the original chunks are not # contained in a function, we'll abort and undo. if all(idaapi.get_func(start) for start, end in chunks): return True # Try to undo the damage. for start, _ in chunks: ida_funcs.del_func(start) # Everything we've tried so far has failed. If there was originally a function, try to restore # it. if orig != idc.BADADDR: _log(0, 'Trying to restore original function {:#x}', orig) ida_funcs.add_func(orig) return False
def _ins2color(self, addr): col = _len = 0 acc = -1 head = get_item_head(addr) if can_decode(head): f = get_full_flags(head) if is_code(f): _len = decode_insn(self.insn, head) if _len: if self.insn.itype in [ida_allins.NN_mov ]: # TODO: add more instructions if self.insn.Op1.type in [o_mem, o_phrase, o_displ]: acc = ACC_WRITE col = self.insn_colors[acc] elif self.insn.Op2.type in [o_mem, o_phrase, o_displ]: acc = ACC_READ col = self.insn_colors[acc] else: acc = -1 return (col, _len, acc)
def get_conflict(self): """ :return: None if there's no conflict, empty string if there's no change, data if there's a change. """ # TODO: Fill docstring, plus, make the function return 0,1,2 and save the current data by itself. code_address = self._has_code() if code_address: return 'Code: 0x%x' % code_address num_of_elements = self._get_num_of_elements() data_undefined = True for i in xrange(self.data): ea_flags = ida_bytes.get_full_flags(self.address + i) if ea_flags & 0x400: # Data defined data_undefined = False if data_undefined: return None # No conflict # Iterate over all local data, and check if there's any conflict with the type conflict = '' for i in xrange(num_of_elements): current_address = self.address + ( i * self.TYPE_TO_SIZE[self.data_type]) current_address = ida_bytes.get_item_head(current_address) ea_flags = ida_bytes.get_full_flags(current_address) if not ida_bytes.is_data(ea_flags): conflict += 'unknown at 0x%x\n' % current_address continue current_data_type = ea_flags & ida_bytes.DT_TYPE if self.data_type != current_data_type: # Different data conflict += '%s at 0x%x\n' % ( self.TYPE_TO_NAME[current_data_type], current_address) if conflict: return conflict # TODO: Deal with the case it's just multiple type definitions in the area? return '' # No difference
def on_process_buffer(self, buffers, addr, size, mouse_offs): colors = [] head = BADADDR tail = BADADDR goffs = 0 for mapped, buf in buffers: if mapped: if mouse_offs is not None: if self.switch == 0: # data head = get_item_head(addr + mouse_offs) tail = get_item_end(addr + mouse_offs) else: # code f = get_func(addr + mouse_offs) if f: head = f.startEA tail = f.endEA for pos in xrange(len(buf)): c = ord(buf[pos]) & 0xFF highlight = False if mouse_offs is not None: if addr + pos + goffs >= head and addr + pos + goffs < tail: highlight = True if self.last_sel: lhead, lsize = self.last_sel if addr + pos + goffs >= lhead and addr + pos + goffs < lhead+lsize: highlight = True if highlight: colors.append((True, qRgb(c, 0xFF, self.hl_color))) else: colors.append((True, qRgb(c, 0, 0))) else: for pos in xrange(len(buf)): colors.append((False, None)) goffs += len(buf) return colors
def get_conflict(self): """ :return: None if there's no conflict, empty string if there's no change, data if there's a change. """ # TODO: Fill docstring, plus, make the function return 0,1,2 and save the current data by itself. conflicts = "" conflict_flag = False for i in xrange(self.data): current_address = self.address + i head_address = ida_bytes.get_item_head(current_address) if ida_bytes.is_code(ida_bytes.get_full_flags(head_address)): conflict_flag = True ea_flags = ida_bytes.get_full_flags(head_address) if not ida_bytes.is_data(ea_flags): continue conflict_flag = True conflicts += '%s at 0x%x\n' % ( self.TYPE_TO_NAME[ea_flags & ida_bytes.DT_TYPE], head_address) if conflict_flag: return conflicts return None
def _invent_var_type(ea, seg_ref, min_size=1): """Try to invent a variable type. This will basically be an array of bytes that spans what we need. We will, however, try to be slightly smarter and look for cross-references in the range, and when possible, use their types.""" seg = find_segment_containing_ea(ea, seg_ref) if not seg: return ea, None head_ea = ida_bytes.get_item_head(ea) if head_ea < ea: head_seg = find_segment_containing_ea(head_ea, seg_ref) if head_seg != seg: return ea, None return _invent_var_type(head_ea, seg_ref, ea - head_ea) min_size = max(min_size, ida_bytes.get_item_size(ea)) next_ea = ida_bytes.next_head(ea + 1, seg.end_ea) next_seg = find_segment_containing_ea(next_ea, seg_ref) arr = ArrayType() arr.set_element_type(IntegerType(1, False)) if not next_seg or next_seg != seg: arr.set_num_elements(min_size) return ea, arr min_size = min(min_size, next_ea - ea) # TODO(pag): Go and do a better job, e.g. find pointers inside of the global. # i = 0 # while i < min_size: # for ref_ea in xref_generator(ea + i, seg_ref): # break # i += 1 arr.set_num_elements(min_size) return ea, arr
def render_img(self, buf, addr, mouse_offs): colors = [] start = addr end = start + len(buf) ea = start col1 = qRgb(0xDC, 0xDC, 0xDC) col2 = qRgb(0x00, 0x00, 0x00) cols = [col1, col2] pos = 0 head = get_item_head(start) sz = get_item_size(start) if head < start: sz -= (start - head) while ea < end: for i in xrange(sz): colors.append(copy(cols[pos])) pos = (pos + 1) % len(cols) if ea + sz > end: sz = ea + sz - end ea += sz sz = get_item_size(ea) return colors
def lines(start=None, end=None, reverse=False, max_steps=None): """ Iterates through instructions within the start address and end addresses. :param start: Address of the starting instruction. (starts at beginning if not defined) :param end: Address of the end instruction. :param reverse: Iterates up if true. :param max_steps: Maximum number of steps to iterate. :yields: instructions addresses """ max_ea = idaapi.cvar.inf.maxEA min_ea = idaapi.cvar.inf.minEA # Normalize start and end addresses. if reverse: if start is None: start = max_ea - 1 if end is None: end = 0 start = max(start, end) else: if start is None: start = min_ea if end is None: end = max_ea + 1 start = min(start, end) steps = 0 func = ida_bytes.prev_head if reverse else ida_bytes.next_head ea = ida_bytes.get_item_head(start) while ea != idc.BADADDR: yield ea ea = func(ea, end) steps += 1 if max_steps and steps >= max_steps: break
def _get_item_info(self, ea): head = get_item_head(ea) name = get_name(head) size = get_item_size(head) return (head, name, size)
def _is_string(self, ea): head = get_item_head(ea) flags = get_flags(head) return is_strlit(flags)