class FakefastWidget(CustomWidget): def __init__(self, parent=None): super(FakefastWidget, self).__init__(parent) self._create_gui() def _create_gui(self): self.t_fakefast_addr = QtWidgets.QLineEdit() self.t_fakefast_addr.setFixedWidth(150) self.tbl_fakefast = TTable( ['fast_id', 'fast_size', 'bytes to target', 'chunk address']) self.tbl_fakefast.customContextMenuRequested.connect(self.context_menu) self.t_fakefast_info = QtWidgets.QTextEdit() self.t_fakefast_info.setReadOnly(True) self.btn_find_fakefast = QtWidgets.QPushButton("Find") self.btn_find_fakefast.clicked.connect(self.find_fakefast_on_click) hbox_fakefast = QtWidgets.QHBoxLayout() hbox_fakefast.addWidget(QtWidgets.QLabel('Target address')) hbox_fakefast.addWidget(self.t_fakefast_addr) hbox_fakefast.addWidget(self.btn_find_fakefast) hbox_fakefast.addStretch(1) vbox_fakefast = QtWidgets.QVBoxLayout() vbox_fakefast.addLayout(hbox_fakefast) vbox_fakefast.addWidget(self.tbl_fakefast) vbox_fakefast.addStretch(1) vbox_fakefast.setContentsMargins(0, 0, 0, 0) self.setLayout(vbox_fakefast) def context_menu(self, position): sender = self.sender() menu = QtWidgets.QMenu() copy_action = menu.addAction("Copy value") copy_row = menu.addAction("Copy row") view_chunk = menu.addAction("View chunk") jump_to = menu.addAction("Jump to chunk") chunk_addr = int(sender.item(sender.currentRow(), 3).text(), 16) action = menu.exec_(sender.mapToGlobal(position)) if action == copy_action: sender.copy_selected_value() if action == copy_row: sender.copy_selected_row() elif action == jump_to: idc.jumpto(chunk_addr) elif action == view_chunk: self.parent.parent.show_chunk_info(chunk_addr) def find_fakefast_on_click(self): start_addr = int(self.t_fakefast_addr.text(), 16) fake_chunks = self.heap.find_fakefast(start_addr) if len(fake_chunks) == 0: idaapi.info("Fakefast: 0 results") return self.tbl_fakefast.clearContents() self.tbl_fakefast.setRowCount(0) self.tbl_fakefast.setSortingEnabled(False) for idx, chunk in enumerate(fake_chunks): self.tbl_fakefast.insertRow(idx) self.tbl_fakefast.setItem( idx, 0, QtWidgets.QTableWidgetItem("%d" % chunk['fast_id'])) self.tbl_fakefast.setItem( idx, 1, QtWidgets.QTableWidgetItem("0x%x" % chunk['size'])) self.tbl_fakefast.setItem( idx, 2, QtWidgets.QTableWidgetItem("%d" % chunk['bytes_to'])) self.tbl_fakefast.setItem( idx, 3, QtWidgets.QTableWidgetItem("0x%x" % chunk['address'])) self.tbl_fakefast.resizeRowsToContents() self.tbl_fakefast.resizeColumnsToContents() self.tbl_fakefast.setSortingEnabled(True)
class LibcOffsetsWidget(CustomWidget): def __init__(self, parent=None): super(LibcOffsetsWidget, self).__init__(parent) self.libc_base = None self._create_gui() self.populate_table() def _create_gui(self): self.tbl_offsets_vars = TTable(['name', 'offset']) self.tbl_offsets_vars.resize_columns([150, 100]) self.tbl_offsets_vars.cellDoubleClicked.connect( self.tbl_offsets_double_clicked) self.tbl_offsets_vars.customContextMenuRequested.connect( self.context_menu) self.tbl_offsets_funcs = TTable(['name', 'offset']) self.tbl_offsets_funcs.resize_columns([150, 100]) self.tbl_offsets_funcs.cellDoubleClicked.connect( self.tbl_offsets_double_clicked) self.tbl_offsets_funcs.customContextMenuRequested.connect( self.context_menu) vbox_offsets_vars = QtWidgets.QVBoxLayout() vbox_offsets_vars.addWidget(QtWidgets.QLabel('Variables')) vbox_offsets_vars.addWidget(self.tbl_offsets_vars) vbox_offsets_funcs = QtWidgets.QVBoxLayout() vbox_offsets_funcs.addWidget(QtWidgets.QLabel('Functions')) vbox_offsets_funcs.addWidget(self.tbl_offsets_funcs) hbox_libc_offsets = QtWidgets.QHBoxLayout() hbox_libc_offsets.addLayout(vbox_offsets_vars) hbox_libc_offsets.addLayout(vbox_offsets_funcs) hbox_libc_offsets.setContentsMargins(0, 0, 0, 0) self.setLayout(hbox_libc_offsets) def context_menu(self, position): sender = self.sender() menu = QtWidgets.QMenu() action_copy = menu.addAction("Copy value") action_copy_row = menu.addAction("Copy row") action_jump_to = menu.addAction("Jump to address") action = menu.exec_(sender.mapToGlobal(position)) if action == action_copy: sender.copy_selected_value() elif action == action_copy_row: sender.copy_selected_row() elif action == action_jump_to: offset = int(sender.item(sender.currentRow(), 1).text(), 16) address = self.libc_base + offset idc.jumpto(address) def tbl_offsets_double_clicked(self): sender = self.sender() offset = int(sender.item(sender.currentRow(), 1).text(), 16) address = self.libc_base + offset idc.jumpto(address) def populate_table(self): self.tbl_offsets_vars.clearContents() self.tbl_offsets_funcs.clearContents() self.tbl_offsets_vars.setRowCount(0) self.tbl_offsets_funcs.setRowCount(0) self.tbl_offsets_vars.setSortingEnabled(False) self.tbl_offsets_funcs.setSortingEnabled(False) offsets = self.get_libc_offsets() variables = offsets['variables'] functions = offsets['functions'] for idx, (name, offset) in enumerate(variables.items()): self.tbl_offsets_vars.insertRow(idx) self.tbl_offsets_vars.setItem(idx, 0, QtWidgets.QTableWidgetItem(name)) self.tbl_offsets_vars.setItem( idx, 1, QtWidgets.QTableWidgetItem("0x%x" % offset)) for idx, (name, offset) in enumerate(functions.items()): self.tbl_offsets_funcs.insertRow(idx) self.tbl_offsets_funcs.setItem(idx, 0, QtWidgets.QTableWidgetItem(name)) self.tbl_offsets_funcs.setItem( idx, 1, QtWidgets.QTableWidgetItem("0x%x" % offset)) self.tbl_offsets_vars.resizeRowsToContents() self.tbl_offsets_funcs.resizeRowsToContents() self.tbl_offsets_vars.setSortingEnabled(True) self.tbl_offsets_funcs.setSortingEnabled(True) def get_libc_offsets(self): libc_symbols = { 'variables': [ 'environ', '__environ', '__free_hook', '__malloc_hook', '__realloc_hook', '_IO_list_all', '_IO_2_1_stdin_', '_IO_2_1_stdout_', '_IO_2_1_stderr_', ], 'functions': [ 'system', '__libc_system', 'execve', 'open', '__open64', 'read', 'write', '__write', '_IO_gets', 'gets', 'setcontext+0x35', ] } result = { 'variables': OrderedDict(), 'functions': OrderedDict(), } self.libc_base = get_libc_base() if not self.libc_base: return result libc_names = get_libc_names() if not libc_names: idaapi.warning("Unable to get glibc symbols") return result for s_type, symbols in libc_symbols.items(): for sym in symbols: name_expr = parse_name_expr(sym) if not name_expr: continue name, offset = name_expr addr = libc_names.get(name) if addr: addr += offset offset = addr - self.libc_base result[s_type][sym] = offset return result
class BinsWidget(CustomWidget): def __init__(self, parent=None): super(BinsWidget, self).__init__(parent) self.show_bases = False self._create_gui() def _create_gui(self): self._create_tables() vbox_fastbins = QtWidgets.QVBoxLayout() vbox_fastbins.addWidget(QtWidgets.QLabel("Fastbins")) vbox_fastbins.addWidget(self.tbl_fastbins) vbox_unsortedbin = QtWidgets.QVBoxLayout() vbox_unsortedbin.addWidget(QtWidgets.QLabel("Unsorted")) vbox_unsortedbin.addWidget(self.tbl_unsortedbin) vbox_smallbins = QtWidgets.QVBoxLayout() vbox_smallbins.addWidget(QtWidgets.QLabel("Small bins")) vbox_smallbins.addWidget(self.tbl_smallbins) vbox_largebins = QtWidgets.QVBoxLayout() vbox_largebins.addWidget(QtWidgets.QLabel("Large bins")) vbox_largebins.addWidget(self.tbl_largebins) self.te_chain_info = QtWidgets.QTextEdit() self.te_chain_info.setReadOnly(True) vbox_chain = QtWidgets.QVBoxLayout() vbox_chain.addWidget(QtWidgets.QLabel("Chain info")) vbox_chain.addWidget(self.te_chain_info) grid_bins = QtWidgets.QGridLayout() grid_bins.addLayout(vbox_fastbins, 0, 0) grid_bins.addLayout(vbox_unsortedbin, 0, 1) grid_bins.addLayout(vbox_smallbins, 1, 0) grid_bins.addLayout(vbox_largebins, 1, 1) grid_bins.addLayout(vbox_chain, 2, 0, 2, 2) self.setLayout(grid_bins) def _create_tables(self): # --- Fastbins table self.tbl_fastbins = TTable(['#', 'size', 'fd']) self.tbl_fastbins.resize_columns([50, 100, 155]) self.tbl_fastbins.customContextMenuRequested.connect(self.context_menu) self.tbl_fastbins.cellDoubleClicked.connect(self.table_on_change) self.tbl_fastbins.itemSelectionChanged.connect(self.table_on_change) # --- Unsortedbin self.tbl_unsortedbin = TTable(['#', 'fd', 'bk', 'base']) self.tbl_unsortedbin.resize_columns([50, 155, 155, 155]) self.tbl_unsortedbin.customContextMenuRequested.connect( self.context_menu) self.tbl_unsortedbin.cellDoubleClicked.connect(self.table_on_change) self.tbl_unsortedbin.itemClicked.connect(self.table_on_change) # --- Smallbins self.tbl_smallbins = TTable(['#', 'size', 'fd', 'bk', 'base']) self.tbl_smallbins.resize_columns([50, 100, 155, 155, 155]) self.tbl_smallbins.customContextMenuRequested.connect( self.context_menu) self.tbl_smallbins.cellDoubleClicked.connect(self.table_on_change) self.tbl_smallbins.itemSelectionChanged.connect(self.table_on_change) # --- Largebins self.tbl_largebins = TTable(['#', 'size', 'fd', 'bk', 'base']) self.tbl_largebins.resize_columns([50, 100, 155, 155, 155]) self.tbl_largebins.customContextMenuRequested.connect( self.context_menu) self.tbl_largebins.cellDoubleClicked.connect(self.table_on_change) self.tbl_largebins.itemSelectionChanged.connect(self.table_on_change) self.bin_tables = { self.tbl_fastbins: { 'title': 'fastbins', 'address': 2, 'size': 1, 'base': None }, self.tbl_unsortedbin: { 'title': 'unsortedbin', 'address': 1, 'size': None, 'base': 3 }, self.tbl_smallbins: { 'title': 'smallbins', 'address': 2, 'size': 1, 'base': 4 }, self.tbl_largebins: { 'title': 'largebins', 'address': 2, 'size': 1, 'base': 4 } } def context_menu(self, position): sender = self.sender() menu = QtWidgets.QMenu() copy_action = menu.addAction("Copy value") copy_row = menu.addAction("Copy row") view_chunk = menu.addAction("View chunk") jump_to = menu.addAction("Jump to") graphview_action = menu.addAction("GraphView") self.show_uninit = menu.addAction("Show uninitialized bins (bases)") self.show_uninit.setCheckable(True) self.show_uninit.setChecked(self.show_bases) action = menu.exec_(sender.mapToGlobal(position)) if action == copy_action: sender.copy_selected_value() if action == copy_row: sender.copy_selected_row() elif action == jump_to: self.jmp_to_selected_chunk() elif action == view_chunk: self.show_selected_chunk() elif action == self.show_uninit: self.show_bases = self.show_uninit.isChecked() self.populate_tables() elif action == graphview_action: if sender is self.tbl_fastbins: idx = int(sender.item(sender.currentRow(), 0).text()) size = int(sender.item(sender.currentRow(), 1).text(), 16) graph = BinGraph(self, info={ 'type': 'fastbin', 'fastbin_id': idx, 'size': size }) graph.Show() elif sender is self.tbl_unsortedbin: idx = sender.item(sender.currentRow(), 0).text() base = int(sender.item(sender.currentRow(), 3).text(), 16) graph = BinGraph(self, info={ 'type': 'unsortedbin', 'bin_id': idx, 'bin_base': base }) graph.Show() elif sender is self.tbl_smallbins: idx = sender.item(sender.currentRow(), 0).text() size = int(sender.item(sender.currentRow(), 1).text(), 16) base = int(sender.item(sender.currentRow(), 4).text(), 16) graph = BinGraph(self, info={ 'type': 'smallbin', 'bin_id': idx, 'size': size, 'bin_base': base }) graph.Show() elif sender is self.tbl_largebins: idx = sender.item(sender.currentRow(), 0).text() size = int(sender.item(sender.currentRow(), 1).text(), 16) base = int(sender.item(sender.currentRow(), 4).text(), 16) graph = BinGraph(self, info={ 'type': 'largebin', 'bin_id': idx, 'size': size, 'bin_base': base }) graph.Show() def show_bin_chain(self): sender = self.sender() stop = 0 size = None row = sender.selectedItems() if not len(row): return bin_cols = self.bin_tables[sender] address = int(row[bin_cols['address']].text(), 16) if bin_cols['size']: size = int(row[bin_cols['size']].text(), 16) if bin_cols['base']: stop = int(row[bin_cols['base']].text(), 16) self.show_chain(bin_cols['title'], address, size, stop) def show_selected_chunk(self): chunk_addr = self.get_selected_chunk_addr() if chunk_addr: self.parent.show_chunk_info(chunk_addr) def jmp_to_selected_chunk(self): chunk_addr = self.get_selected_chunk_addr() if chunk_addr: idc.Jump(chunk_addr) def get_selected_chunk_addr(self): sender = self.sender() items = sender.selectedItems() if len(items): col_id = self.bin_tables[sender]['address'] address = int(items[col_id].text(), 16) return address return None def table_on_change(self): self.show_selected_chunk() self.show_bin_chain() def show_chain(self, title, address, size, stop=0): if size: title = '%s[0x%02x]' % (title, size) if address != 0 and address != idc.BADADDR: chain, b_error = self.heap.chunk_chain(address, stop) html_chain = make_html_chain(title, chain, b_error) self.te_chain_info.clear() self.te_chain_info.insertHtml(html_chain) def populate_tbl_fastbins(self): self.tbl_fastbins.clearContents() self.tbl_fastbins.setRowCount(0) self.tbl_fastbins.setSortingEnabled(False) idx = 0 fastbins = self.heap.get_fastbins(self.cur_arena) for id_fast, (size, fast_chunk) in enumerate(fastbins.iteritems()): if not self.show_bases and fast_chunk == 0: continue self.tbl_fastbins.insertRow(idx) it_bin_num = QtWidgets.QTableWidgetItem("%d" % id_fast) it_size = QtWidgets.QTableWidgetItem("%#x" % size) it_fastchunk = QtWidgets.QTableWidgetItem("%#x" % fast_chunk) self.tbl_fastbins.setItem(idx, 0, it_bin_num) self.tbl_fastbins.setItem(idx, 1, it_size) self.tbl_fastbins.setItem(idx, 2, it_fastchunk) idx += 1 if idx: self.tbl_fastbins.resize_to_contents() self.tbl_fastbins.setSortingEnabled(True) def populate_tbl_unsortedbin(self): base, fd, bk = self.heap.get_unsortedbin(self.cur_arena) self.tbl_unsortedbin.clearContents() self.tbl_unsortedbin.setRowCount(0) # points to current base if not self.show_bases and fd == base: return self.tbl_unsortedbin.setSortingEnabled(False) self.tbl_unsortedbin.insertRow(0) it_bin_num = QtWidgets.QTableWidgetItem("1") it_fd = QtWidgets.QTableWidgetItem("%#x" % fd) it_bk = QtWidgets.QTableWidgetItem("%#x" % bk) it_base = QtWidgets.QTableWidgetItem("%#x" % base) self.tbl_unsortedbin.setItem(0, 0, it_bin_num) self.tbl_unsortedbin.setItem(0, 1, it_fd) self.tbl_unsortedbin.setItem(0, 2, it_bk) self.tbl_unsortedbin.setItem(0, 3, it_base) self.tbl_unsortedbin.resizeRowsToContents() self.tbl_unsortedbin.resizeColumnsToContents() self.tbl_unsortedbin.setSortingEnabled(True) def populate_tbl_smallbins(self): self.tbl_smallbins.clearContents() self.tbl_smallbins.setRowCount(0) self.tbl_smallbins.setSortingEnabled(False) smallbins = self.heap.get_smallbins(self.cur_arena) idx = 0 for bin_id, smallbin in smallbins.iteritems(): # point to himself if not self.show_bases and smallbin['base'] == smallbin['fd']: continue self.tbl_smallbins.insertRow(idx) it_bin_num = QtWidgets.QTableWidgetItem("%d" % bin_id) it_size = QtWidgets.QTableWidgetItem("%#x" % smallbin['size']) it_fd = QtWidgets.QTableWidgetItem("%#x" % smallbin['fd']) it_bk = QtWidgets.QTableWidgetItem("%#x" % smallbin['bk']) it_base = QtWidgets.QTableWidgetItem("%#x" % smallbin['base']) self.tbl_smallbins.setItem(idx, 0, it_bin_num) self.tbl_smallbins.setItem(idx, 1, it_size) self.tbl_smallbins.setItem(idx, 2, it_fd) self.tbl_smallbins.setItem(idx, 3, it_bk) self.tbl_smallbins.setItem(idx, 4, it_base) idx += 1 self.tbl_smallbins.resizeRowsToContents() self.tbl_smallbins.resizeColumnsToContents() self.tbl_smallbins.setSortingEnabled(True) def populate_tbl_largebins(self): self.tbl_largebins.clearContents() self.tbl_largebins.setRowCount(0) self.tbl_largebins.setSortingEnabled(False) largebins = self.heap.get_largebins(self.cur_arena) idx = 0 for bin_id, largebin in largebins.iteritems(): # point to himself if not self.show_bases and largebin['base'] == largebin['fd']: continue self.tbl_largebins.insertRow(idx) it_bin_num = QtWidgets.QTableWidgetItem("%d" % bin_id) it_size = QtWidgets.QTableWidgetItem("%#x" % largebin['size']) it_fd = QtWidgets.QTableWidgetItem("%#x" % largebin['fd']) it_bk = QtWidgets.QTableWidgetItem("%#x" % largebin['bk']) it_base = QtWidgets.QTableWidgetItem("%#x" % largebin['base']) self.tbl_largebins.setItem(idx, 0, it_bin_num) self.tbl_largebins.setItem(idx, 1, it_size) self.tbl_largebins.setItem(idx, 2, it_fd) self.tbl_largebins.setItem(idx, 3, it_bk) self.tbl_largebins.setItem(idx, 4, it_base) idx += 1 self.tbl_largebins.resizeRowsToContents() self.tbl_largebins.resizeColumnsToContents() self.tbl_largebins.setSortingEnabled(True) def populate_tables(self): self.populate_tbl_fastbins() self.populate_tbl_unsortedbin() self.populate_tbl_smallbins() self.populate_tbl_largebins()
class TcacheWidget(CustomWidget): def __init__(self, parent=None): super(TcacheWidget, self).__init__(parent) self._create_gui() def _create_gui(self): self._create_table() self.te_tcache_chain = QtWidgets.QTextEdit() self.te_tcache_chain.setFixedHeight(100) self.te_tcache_chain.setReadOnly(True) vbox_tcache_chain = QtWidgets.QVBoxLayout() vbox_tcache_chain.addWidget(QtWidgets.QLabel('Chain info')) vbox_tcache_chain.addWidget(self.te_tcache_chain) vbox_tcache = QtWidgets.QVBoxLayout() vbox_tcache.addWidget(QtWidgets.QLabel('Tcache entries')) vbox_tcache.addWidget(self.tbl_tcache) vbox_tcache.addLayout(vbox_tcache_chain) vbox_tcache.addStretch(1) self.setLayout(vbox_tcache) def _create_table(self): # ----------------------------------------------------------------------- # Tcache table self.tbl_tcache = TTable(['#', 'size', 'counts', 'next']) self.tbl_tcache.resize_columns([50, 100, 50, 155]) self.tbl_tcache.customContextMenuRequested.connect(self.context_menu) self.tbl_tcache.cellDoubleClicked.connect(self.show_selected_chunk) self.tbl_tcache.itemSelectionChanged.connect( self.table_on_change_index) def context_menu(self, position): sender = self.sender() menu = QtWidgets.QMenu() copy_action = menu.addAction("Copy value") copy_row = menu.addAction("Copy row") view_chunk = menu.addAction("View chunk") jump_to = menu.addAction("Jump to") graphview_action = menu.addAction("GraphView") action = menu.exec_(sender.mapToGlobal(position)) fd_addr = int(sender.item(sender.currentRow(), 3).text(), 16) if action == copy_action: sender.copy_selected_value() if action == copy_row: sender.copy_selected_row() elif action == jump_to: idc.Jump(fd_addr) elif action == view_chunk: self.show_selected_chunk() elif action == graphview_action: idx = int(sender.item(sender.currentRow(), 0).text()) size = int(sender.item(sender.currentRow(), 1).text(), 16) fd = int(sender.item(sender.currentRow(), 3).text(), 16) graph = BinGraph(self, info={ 'type': 'tcache', 'bin_id': idx, 'size': size, }) graph.Show() def populate_table(self): self.tbl_tcache.clearContents() self.tbl_tcache.setRowCount(0) self.tbl_tcache.setSortingEnabled(False) tcache = self.heap.get_tcache(self.cur_arena) if not tcache: return idx = 0 for i, (size, entry) in enumerate(tcache.iteritems()): if entry['counts'] == 0 and entry['next'] == 0: continue self.tbl_tcache.insertRow(idx) it_entry_id = QtWidgets.QTableWidgetItem("%d" % i) it_size = QtWidgets.QTableWidgetItem("%#x" % size) it_counts = QtWidgets.QTableWidgetItem("%d" % entry['counts']) it_address = QtWidgets.QTableWidgetItem("%#x" % entry['next']) self.tbl_tcache.setItem(idx, 0, it_entry_id) self.tbl_tcache.setItem(idx, 1, it_size) self.tbl_tcache.setItem(idx, 2, it_counts) self.tbl_tcache.setItem(idx, 3, it_address) idx += 1 self.tbl_tcache.resizeRowsToContents() self.tbl_tcache.resizeColumnsToContents() self.tbl_tcache.setSortingEnabled(True) def table_on_change_index(self): sender = self.sender() items = sender.selectedItems() if items and len(items): entry_addr = int(items[3].text(), 16) entry_size = int(items[1].text(), 16) self.show_chain(entry_addr, entry_size) def show_selected_chunk(self): items = self.sender().selectedItems() entry_addr = int(items[3].text(), 16) norm_address = "0x%x-0x%x" % (entry_addr, config.ptr_size * 2) self.parent.show_chunk_info(norm_address) def show_chain(self, address, size): title = 'Tcache[0x%02x]' % size chain, b_error = self.heap.tcache_chain(address) html_chain = make_html_chain(title, chain, b_error) self.te_tcache_chain.clear() self.te_tcache_chain.insertHtml(html_chain)
class ArenaWidget(CustomWidget): def __init__(self, parent=None): super(ArenaWidget, self).__init__(parent) self._create_gui() def _create_gui(self): self._create_table() self._create_menu() def _create_menu(self): self.t_top_addr = QtWidgets.QLineEdit() self.t_top_addr.setFixedWidth(130) self.t_top_addr.setReadOnly(True) self.t_last_remainder = QtWidgets.QLineEdit() self.t_last_remainder.setFixedWidth(150) self.t_last_remainder.setReadOnly(True) self.lbl_top_warning = QtWidgets.QLabel() self.lbl_top_warning.setStyleSheet('color: red') self.lbl_top_warning.setVisible(False) self.t_attached_threads = QtWidgets.QLineEdit() self.t_attached_threads.setFixedWidth(130) self.t_attached_threads.setReadOnly(True) hbox_arena_top = QtWidgets.QHBoxLayout() hbox_arena_top.addWidget(QtWidgets.QLabel('Top:')) hbox_arena_top.addWidget(self.t_top_addr) hbox_arena_top.addWidget(QtWidgets.QLabel('Last remainder:')) hbox_arena_top.addWidget(self.t_last_remainder) btn_malloc_par = QtWidgets.QPushButton("Struct") btn_malloc_par.clicked.connect(self.btn_struct_on_click) hbox_arena_top.addWidget(btn_malloc_par) hbox_arena_top.addStretch(1) hbox_arena_others = QtWidgets.QHBoxLayout() hbox_arena_others.addWidget(self.lbl_top_warning) self.bold_font = QtGui.QFont() self.bold_font.setBold(True) grid_arenas = QtWidgets.QGridLayout() grid_arenas.addLayout(hbox_arena_top, 0, 0) grid_arenas.addLayout(hbox_arena_others, 1, 0) grid_arenas.addWidget(self.tbl_parsed_heap, 2, 0) self.setLayout(grid_arenas) def _create_table(self): self.tbl_parsed_heap = TTable( ['address', 'prev', 'size', 'status', 'fd', 'bk']) self.tbl_parsed_heap.resize_columns([155, 40, 100, 120, 155, 155]) self.tbl_parsed_heap.customContextMenuRequested.connect( self.context_menu) self.tbl_parsed_heap.itemSelectionChanged.connect( self.view_selected_chunk) def context_menu(self, position): sender = self.sender() menu = QtWidgets.QMenu() copy_action = menu.addAction("Copy value") copy_row = menu.addAction("Copy row") view_chunk = menu.addAction("View chunk") jump_to = menu.addAction("Jump to chunk") jump_to_u = menu.addAction("Jump to user-data") check_freaable = menu.addAction("Check freeable") chunk_addr = int(sender.item(sender.currentRow(), 0).text(), 16) action = menu.exec_(sender.mapToGlobal(position)) if action == copy_action: sender.copy_selected_value() if action == copy_row: sender.copy_selected_row() elif action == jump_to: idc.jumpto(chunk_addr) elif action == jump_to_u: idc.jumpto(chunk_addr + (config.ptr_size * 2)) elif action == view_chunk: self.view_selected_chunk() elif action == check_freaable: self.parent.check_freeable(chunk_addr) def view_selected_chunk(self): items = self.tbl_parsed_heap.selectedItems() if len(items) > 0: chunk_addr = int(items[0].text(), 16) self.parent.show_chunk_info(chunk_addr) def populate_table(self): cur_arena = self.cur_arena arena = self.heap.get_arena(cur_arena) self.t_top_addr.setText("%#x" % arena.top) self.t_last_remainder.setText("%#x" % arena.last_remainder) self.t_attached_threads.setText("%d" % arena.attached_threads) top_segname = idc.get_segm_name(arena.top) if not any(s in top_segname for s in ['heap', 'debug']): self.lbl_top_warning.setVisible(True) self.lbl_top_warning.setText("Top points to '%s' segment" % top_segname) else: self.lbl_top_warning.setVisible(False) self.tbl_parsed_heap.clearContents() self.tbl_parsed_heap.setRowCount(0) self.tbl_parsed_heap.setSortingEnabled(False) parsed_heap = self.heap.parse_heap(cur_arena) for idx, chunk in enumerate(parsed_heap): self.tbl_parsed_heap.insertRow(idx) it_address = QtWidgets.QTableWidgetItem("%#x" % chunk['address']) it_prev = QtWidgets.QTableWidgetItem("%#x" % chunk['prev']) it_size = QtWidgets.QTableWidgetItem("%#x" % chunk['size']) it_status = QtWidgets.QTableWidgetItem("%s" % chunk['status']) it_fd = QtWidgets.QTableWidgetItem("%#x" % chunk['fd']) it_bk = QtWidgets.QTableWidgetItem("%#x" % chunk['bk']) if 'Freed' in chunk['status']: it_status.setForeground(QtGui.QColor('red')) elif chunk['status'] == 'Corrupt': it_status.setForeground(QtGui.QColor.fromRgb(213, 94, 0)) it_status.setFont(self.bold_font) else: it_status.setForeground(QtGui.QColor('blue')) self.tbl_parsed_heap.setItem(idx, 0, it_address) self.tbl_parsed_heap.setItem(idx, 1, it_prev) self.tbl_parsed_heap.setItem(idx, 2, it_size) self.tbl_parsed_heap.setItem(idx, 3, it_status) self.tbl_parsed_heap.setItem(idx, 4, it_fd) self.tbl_parsed_heap.setItem(idx, 5, it_bk) self.tbl_parsed_heap.resizeRowsToContents() self.tbl_parsed_heap.resizeColumnsToContents() self.tbl_parsed_heap.setSortingEnabled(True) self.tbl_parsed_heap.sortByColumn(0, QtCore.Qt.DescendingOrder) def btn_struct_on_click(self): self.parent.show_malloc_state()