#!/usr/bin/python ######################################################################## # Copyright (c) 2015-2016 # Jason Jones <jason<at>jasonjon<dot>es> # All rights reserved. ######################################################################## # # This file is part of IDA TACO # # IDATACO is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # <http://www.gnu.org/licenses/>. # ######################################################################## """ original code by Aaron Portnoy / Zef Cekaj, Exodus Intelligence Updated and modified by Jason Jones """ import idaapi import idc import idataco.util.qt as qt from . import TacoTabWidget from collections import defaultdict import logging print __name__ log = logging.getLogger(__name__) class TacoSwitchJumps(TacoTabWidget): name = "Switch Jumps" short_name = "switch_jumps" description = """ Attempt to locate all known Switch Jumps (case statements) and display detailed information on each """ def initVars(self): self.byte_strings = {} self._switch_tree = qt.qtreewidget()() self._switch_tree.setHeaderLabels(("Names", "# Cases")) self._switch_tree.setColumnWidth(0, 100) def initLayout(self): layout = qt.qvboxlayout()() layout.addWidget(self._switch_tree) self.setLayout(layout) def click_tree(self): i = self._switch_tree.currentItem() addr = i.text(0).strip() if not addr.startswith("0x"): addr = idaapi.get_name_ea(idc.BADADDR, str(addr)) else: addr = addr[2:10] addr = int(addr, 16) idc.Jump(addr) return def load(self): """ title = "Switch Jumps" #root = QtGui.QTreeWidgetItem(self, title) comment = COLSTR("; Double-click to follow", SCOLOR_BINPREF) #self.AddLine(comment) comment = COLSTR("; Hover for preview", idc.SCOLOR_BINPREF) #self.AddLine(comment) """ self._switch_tree.clear() self._switch_tree.setColumnCount(2) self._switch_tree.clicked.connect(self.click_tree) self.find_all_switch_jumps() for func in sorted(self._switch_dict.keys()): func_node = qt.qtreewidgetitem()(self._switch_tree) func_node.setText(0, func) func_node.setText(1, "") for item in self._switch_dict[func]: node = qt.qtreewidgetitem()(func_node) addr = item[0] cases = item[1] address_element = "0x%08x" % addr node.setText(0, address_element) node.setText(1, "%04s" % cases) for c in item[2]: cnode = qt.qtreewidgetitem()(node) cnode.setText(0, c[0]) cnode.setText(1, c[2]) return True def get_jlocs(self, sw): jlocs = [] ncases = sw.ncases if sw.jcases == 0 else sw.jcases for i in range(ncases): addr = idc.Dword(sw.jumps+i*4) name = idaapi.get_name(idc.BADADDR, addr) comm = idc.GetCommentEx(idc.LocByName(name), 1) comm = comm[comm.find('case'):] if comm is not None and comm.startswith('jumptable') else comm jlocs.append((name, idc.LocByName(name), comm)) return jlocs def find_all_switch_jumps(self): self._switch_dict = defaultdict(list) next_switch = idc.FindBinary(idc.MinEA(), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24") while next_switch != idc.BADADDR: sw = idaapi.get_switch_info_ex(next_switch) if idc.GetMnem(next_switch).startswith("jmp") and sw: ic = self.get_jlocs(sw) self._switch_dict[idaapi.get_func_name(next_switch)].append((next_switch, sw.ncases, ic)) next_switch = idc.FindBinary(idc.NextHead(next_switch), idc.SEARCH_DOWN|idc.SEARCH_NEXT, "ff 24") def getTacoTab(self): taco_tab = qt.qwidget()() layout = qt.qvboxlayout()() layout.addWidget(self) taco_tab.setLayout(layout) return taco_tab, self.name