#!/usr/bin/env python # ragdiff2 - Copyright 2010-2011 # nibble import sys import os import gtk import gtk.gdk import xdot import time import tempfile from r2.r_core import * class ViewWidget(gtk.VBox): ui = ''' ''' def __init__(self): gtk.VBox.__init__(self) # XDotWidget xdotwidget = self.xdotwidget = xdot.DotWidget() # Toolbar uimanager = gtk.UIManager() actiongroup = gtk.ActionGroup('Actions') actiongroup.add_actions(( ('ZoomIn', gtk.STOCK_ZOOM_IN, None, None, None, self.xdotwidget.on_zoom_in), ('ZoomOut', gtk.STOCK_ZOOM_OUT, None, None, None, self.xdotwidget.on_zoom_out), ('ZoomFit', gtk.STOCK_ZOOM_FIT, None, None, None, self.xdotwidget.on_zoom_fit), ('Zoom100', gtk.STOCK_ZOOM_100, None, None, None, self.xdotwidget.on_zoom_100), )) uimanager.insert_action_group(actiongroup, 0) uimanager.add_ui_from_string(self.ui) toolbar = uimanager.get_widget('/ToolBar') toolbar.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR) toolbar.set_style(gtk.TOOLBAR_ICONS) toolbar.set_show_arrow(False) label = self.label = gtk.Label() hbox = gtk.HBox(False, 5) hbox.pack_start(toolbar, False) hbox.pack_start(label, False) self.pack_start(hbox, False) self.pack_start(xdotwidget) def set_filename(self, name): self.label.set_text(name) def set_code(self, code, fit): self.xdotwidget.set_dotcode(code) if (fit): self.xdotwidget.zoom_to_fit() class DiffWidget(gtk.VPaned): def __init__(self): gtk.VPaned.__init__(self) self.set_position (500) # Graph viewers hbox = gtk.HBox(True, 5) dw = self.dw = ViewWidget() dw2 = self.dw2 = ViewWidget() hbox.pack_start(dw) hbox.pack_start(dw2) self.add(hbox) # Function list scrolledwin = gtk.ScrolledWindow() scrolledwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) liststore = self.liststore = gtk.ListStore(str, str, str, str, str) treeview = gtk.TreeView(liststore) # Column Address L tvcolumn0 = gtk.TreeViewColumn('Function L') treeview.append_column(tvcolumn0) cell0 = gtk.CellRendererText() tvcolumn0.pack_start(cell0, True) tvcolumn0.add_attribute(cell0, 'text', 0) tvcolumn0.set_sort_column_id(0) # Column Function L tvcolumn1 = gtk.TreeViewColumn('Address L') treeview.append_column(tvcolumn1) cell1 = gtk.CellRendererText() tvcolumn1.pack_start(cell1, True) tvcolumn1.add_attribute(cell1, 'text', 1) tvcolumn1.set_sort_column_id(1) # Column Address R tvcolumn2 = gtk.TreeViewColumn('Function R') treeview.append_column(tvcolumn2) cell2 = gtk.CellRendererText() tvcolumn2.pack_start(cell2, True) tvcolumn2.add_attribute(cell2, 'text', 2) tvcolumn2.set_sort_column_id(2) # Column Function R tvcolumn3 = gtk.TreeViewColumn('Address R') treeview.append_column(tvcolumn3) cell3 = gtk.CellRendererText() tvcolumn3.pack_start(cell3, True) tvcolumn3.add_attribute(cell3, 'text', 3) tvcolumn3.set_sort_column_id(3) # Column Diff tvcolumn4 = gtk.TreeViewColumn('Diff') treeview.append_column(tvcolumn4) cell4 = gtk.CellRendererText() tvcolumn4.pack_start(cell4, True) tvcolumn4.add_attribute(cell4, 'text', 4) tvcolumn4.set_sort_column_id(4) # Set treeview options and add it to scrolledwin treeview.set_reorderable(True) scrolledwin.add(treeview) self.add2(scrolledwin) treeview.connect('row-activated', self.on_row_activated) def on_row_activated(self, treeview, row, col): model = treeview.get_model() self.row_handler(self, model[row][1], model[row][3]) def set_row_handler(self, handler): self.row_handler = handler def set_filename_l(self, name): self.dw.set_filename(name) def set_filename_r(self, name): self.dw2.set_filename(name) def set_code_l(self, code, fit): self.dw.set_code(code, fit) def set_code_r(self, code, fit): self.dw2.set_code(code, fit) def add_function(self, row): self.liststore.append(row) def clear_functions(self): self.liststore.clear() class RagDiff2(gtk.Window): def __init__(self): gtk.Window.__init__(self) self.c = RCore() self.c2 = RCore() # Main window self.set_title('ragdiff2') self.set_default_size(512, 512) dw = self.dw = DiffWidget() dw.set_row_handler(self.update_graphs) self.add(dw) self.connect('destroy', gtk.main_quit) def update_graphs(self, dw, addr_l, addr_r): if addr_l != '': file_l = tempfile.gettempdir()+os.sep+'ragdiff2_l' self.c.cmd0('agd %s > %s' % (addr_l, file_l)) fp = file(file_l) dw.set_code_l (fp.read(), True) fp.close() os.unlink(file_l) else: dw.set_code_l ('digraph code { }', False) if addr_r != '': file_r = tempfile.gettempdir()+os.sep+'ragdiff2_r' self.c2.cmd0('agd %s > %s' % (addr_r, file_r)) fp = file(file_r) dw.set_code_r (fp.read(), True) fp.close() os.unlink(file_r) else: dw.set_code_r ('digraph code { }', False) def set_files(self, file_l, file_r): # Init cores self.c.config.set_i("io.va", 1) self.c.config.set_i("anal.split", 1) self.c.file_open(file_l, 0, 0) self.c.bin_load(None) self.c2.config.set_i("io.va", 1) self.c2.config.set_i("anal.split", 1) self.c2.file_open(file_r, 0, 0) self.c2.bin_load(None) # Configure bindiffing self.c.anal.diff_setup_i (False, -1, -1) self.c2.anal.diff_setup_i (False, -1, -1) # Clear treeview self.dw.clear_functions() self.dw.set_filename_l(file_l) self.dw.set_filename_r(file_r) def diff(self): # Diff self.c.gdiff(self.c2) # Fill treeview for fcn in self.c.anal.get_fcns(): if (fcn.type == FcnType_FCN or fcn.type == FcnType_SYM): diffaddr = '0x%08x' % fcn.diff.addr if (fcn.diff.type == BlockDiff_MATCH): difftype = "MATCH" elif (fcn.diff.type == BlockDiff_UNMATCH): difftype = "UNMATCH" else: difftype = "NEW" diffaddr = '' self.dw.add_function([fcn.name, '0x%08x' % fcn.addr, fcn.diff.name, diffaddr, difftype]) for fcn in self.c2.anal.get_fcns(): if ((fcn.type == FcnType_FCN or fcn.type == FcnType_SYM) and fcn.diff.type == BlockDiff_NULL): self.dw.add_function(['', '', fcn.name, '0x%08x' % fcn.addr, "NEW"]) def main(): # Check args if (len (sys.argv) != 3): sys.exit(' usage: %s ' % sys.argv[0]) # Create ragdiff2 win rd = RagDiff2() rd.show_all() # Set and Diff files rd.set_files(sys.argv[1], sys.argv[2]) rd.diff() # Gtk main gtk.main() if __name__ == '__main__': main()