Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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()