Home | Trees | Indices | Help |
---|
|
1 #!/usr/bin/python 2 ######################################################################## 3 # Copyright (c) 2012 4 # Daniel Plohmann <daniel.plohmann<at>gmail<dot>com> 5 # Alexander Hanel <alexander.hanel<at>gmail<dot>com> 6 # All rights reserved. 7 ######################################################################## 8 # 9 # This file is part of IDAscope 10 # 11 # IDAscope is free software: you can redistribute it and/or modify it 12 # under the terms of the GNU General Public License as published by 13 # the Free Software Foundation, either version 3 of the License, or 14 # (at your option) any later version. 15 # 16 # This program is distributed in the hope that it will be useful, but 17 # WITHOUT ANY WARRANTY; without even the implied warranty of 18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 # General Public License for more details. 20 # 21 # You should have received a copy of the GNU General Public License 22 # along with this program. If not, see 23 # <http://www.gnu.org/licenses/>. 24 # 25 ######################################################################## 26 27 from PySide import QtGui, QtCore 28 from PySide.QtGui import QIcon 29 30 from NumberQTableWidgetItem import NumberQTableWidgetItem 31 3234 """ 35 This widget is the front-end for the semantic inspection. 36 """ 3738039 QtGui.QMainWindow.__init__(self) 40 print "Loading FunctionInspectionWidget" 41 # enable access to shared IDAscope modules 42 self.parent = parent 43 self.name = "Function Inspection" 44 self.icon = QIcon(self.parent.config.icon_file_path + "semantics.png") 45 # This widget relies on the semantic identifier and uses some functions via IDA proxy 46 self.si = self.parent.semantic_identifier 47 self.dh = self.parent.documentation_helper 48 self.ida_proxy = self.parent.ida_proxy 49 # references to Qt-specific modules 50 self.QtGui = QtGui 51 self.QtCore = QtCore 52 self.NumberQTableWidgetItem = NumberQTableWidgetItem 53 self.central_widget = self.QtGui.QWidget() 54 self.setCentralWidget(self.central_widget) 55 self.createGui()5658 """ 59 Create the main GUI with its components. 60 """ 61 self.funcs_label = QtGui.QLabel("Functions of Interest (0/0)") 62 self.calls_label = QtGui.QLabel("Selected function contains the following API references with parameters:") 63 64 self.create_toolbar() 65 66 self.create_functions_table() 67 self.create_calls_table() 68 self.create_parameter_table() 69 70 # layout and fill the widget 71 semantics_layout = QtGui.QVBoxLayout() 72 73 function_info_widget = QtGui.QWidget() 74 function_info_layout = QtGui.QHBoxLayout() 75 self.function_dummy_only_cb = QtGui.QCheckBox("Only dummy names") 76 self.function_dummy_only_cb.stateChanged.connect(self.populate_function_table) 77 function_info_layout.addWidget(self.funcs_label) 78 function_info_layout.addWidget(self.function_dummy_only_cb) 79 function_info_widget.setLayout(function_info_layout) 80 81 upper_table_widget = QtGui.QWidget() 82 upper_table_layout = QtGui.QVBoxLayout() 83 upper_table_layout.addWidget(function_info_widget) 84 upper_table_layout.addWidget(self.funcs_table) 85 upper_table_widget.setLayout(upper_table_layout) 86 87 calls_params_widget = QtGui.QWidget() 88 calls_params_layout = QtGui.QHBoxLayout() 89 calls_params_layout.addWidget(self.calls_table) 90 calls_params_layout.addWidget(self.parameter_table) 91 calls_params_widget.setLayout(calls_params_layout) 92 93 lower_tables_widget = QtGui.QWidget() 94 lower_tables_layout = QtGui.QVBoxLayout() 95 lower_tables_layout.addWidget(self.calls_label) 96 lower_tables_layout.addWidget(calls_params_widget) 97 lower_tables_widget.setLayout(lower_tables_layout) 98 99 splitter = self.QtGui.QSplitter(self.QtCore.Qt.Vertical) 100 q_clean_style = QtGui.QStyleFactory.create('Plastique') 101 splitter.setStyle(q_clean_style) 102 splitter.addWidget(upper_table_widget) 103 splitter.addWidget(lower_tables_widget) 104 semantics_layout.addWidget(splitter) 105 106 self.central_widget.setLayout(semantics_layout) 107 108 self.populate_function_table() 109 self.update_functions_label()110112 """ 113 Create the toolbar, containing some of the actions that can be performed with this widget. 114 """ 115 self.create_refresh_action() 116 self.create_rename_action() 117 self.create_coloring_action() 118 self.create_fix_unknown_code_action() 119 self.create_rename_wrappers_action() 120 121 self.toolbar = self.addToolBar('Function Inspection Toobar') 122 self.toolbar.addAction(self.refreshAction) 123 self.toolbar.addAction(self.annotateAction) 124 self.toolbar.addAction(self.toggleColorAction) 125 self.toolbar.addAction(self.fixUnknownCodeAction) 126 self.toolbar.addAction(self.renameWrappersAction)127129 """ 130 Create the refresh action for the toolbar. On activiation, it triggers a scan of I{SemanticIdentifier} and 131 updates the GUI. 132 """ 133 self.refreshAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "refresh.png"), "Refresh the " \ 134 + "view by scanning all named references again.", self) 135 self.refreshAction.triggered.connect(self.onRefreshButtonClicked)136138 """ 139 Create the action which performs renaming of the function names in the IDB that are covered by the scan of 140 the I{SemanticIdentifier}. 141 """ 142 self.annotateAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "tags.png"), "Rename functions " \ 143 + "according to the identified tags", self) 144 self.annotateAction.triggered.connect(self.onRenameButtonClicked)145147 """ 148 Create the action which cycles through the semantic code coloring modes via I{DocumentationHelper}. 149 """ 150 self.toggleColorAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "colors.png"), \ 151 "Toggle semantic coloring", self) 152 self.toggleColorAction.triggered.connect(self.onColoringButtonClicked)153155 """ 156 Create the action which fixes unknown code to functions via I{DocumentationHelper}. 157 """ 158 self.fixUnknownCodeAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "fix.png"), \ 159 "Fix unknown code to functions", self) 160 self.fixUnknownCodeAction.triggered.connect(self.onFixUnknownCodeButtonClicked)161163 """ 164 Create the action which fixes unknown code to functions via I{DocumentationHelper}. 165 """ 166 self.renameWrappersAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "unwrap.png"), \ 167 "Rename potential wrapper functions", self) 168 self.renameWrappersAction.triggered.connect(self.onRenameWrappersButtonClicked)169171 """ 172 Create the top table used for showing all functions covered by scanning for semantic information. 173 """ 174 self.funcs_table = QtGui.QTableWidget() 175 self.funcs_table.clicked.connect(self.onFunctionClicked) 176 self.funcs_table.doubleClicked.connect(self.onFunctionDoubleClicked)177179 """ 180 Create the bottom left table used for showing all identified API calls that are contained in the function 181 selected in the function table. 182 """ 183 self.calls_table = QtGui.QTableWidget() 184 self.calls_table.clicked.connect(self.onCallClicked) 185 self.calls_table.doubleClicked.connect(self.onCallDoubleClicked)186188 """ 189 Create the bottom right table used for showing all parameters for the API call selected in the calls table. 190 """ 191 self.parameter_table = QtGui.QTableWidget() 192 self.parameter_table.doubleClicked.connect(self.onParameterDoubleClicked)193195 """ 196 Populate the function table with information from the last scan of I{SemanticIdentifier}. 197 """ 198 self.funcs_table.setSortingEnabled(False) 199 self.funcs_header_labels = ["Address", "Name", "Blocks"] 200 for tag in sorted(self.si.get_tags()): 201 self.funcs_header_labels.append(tag) 202 self.funcs_table.clear() 203 self.funcs_table.setColumnCount(len(self.funcs_header_labels)) 204 self.funcs_table.setHorizontalHeaderLabels(self.funcs_header_labels) 205 # Identify number of table entries and prepare addresses to display 206 function_addresses = [] 207 if self.function_dummy_only_cb.isChecked(): 208 function_addresses = self.si.get_identified_dummy_function_addresses() 209 else: 210 function_addresses = self.si.get_identified_function_addresses() 211 if self.ida_proxy.BAD_ADDR in function_addresses: 212 self.funcs_table.setRowCount(len(function_addresses) - 1) 213 else: 214 self.funcs_table.setRowCount(len(function_addresses)) 215 self.funcs_table.resizeRowToContents(0) 216 217 for row, function_address in enumerate(function_addresses): 218 # we don't want to render entries in the table that appear because analysis failed on broken code. 219 if function_address == self.ida_proxy.BAD_ADDR: 220 continue 221 for column, column_name in enumerate(self.funcs_header_labels): 222 tmp_item = None 223 if column == 0: 224 tmp_item = self.QtGui.QTableWidgetItem("0x%x" % function_address) 225 elif column == 1: 226 tmp_item = self.QtGui.QTableWidgetItem(self.ida_proxy.GetFunctionName(function_address)) 227 elif column == 2: 228 tmp_item = self.NumberQTableWidgetItem("%d" % \ 229 self.si.get_number_of_basic_blocks_for_function_address(function_address)) 230 else: 231 tmp_item = self.NumberQTableWidgetItem("%d" % \ 232 self.si.get_tag_count_for_function_address(column_name, function_address)) 233 tmp_item.setFlags(tmp_item.flags() & ~self.QtCore.Qt.ItemIsEditable) 234 self.funcs_table.setItem(row, column, tmp_item) 235 self.funcs_table.resizeRowToContents(row) 236 self.funcs_table.setSelectionMode(self.QtGui.QAbstractItemView.SingleSelection) 237 self.funcs_table.resizeColumnsToContents() 238 self.funcs_table.setSortingEnabled(True) 239 self.update_functions_label()240242 """ 243 Populate the calls table based on the selected function in the functions table. 244 """ 245 self.calls_table.setSortingEnabled(False) 246 self.calls_header_labels = ["Address", "API", "Tag"] 247 self.calls_table.clear() 248 self.calls_table.setColumnCount(len(self.calls_header_labels)) 249 self.calls_table.setHorizontalHeaderLabels(self.calls_header_labels) 250 251 tagged_call_contexts = self.si.get_tagged_apis_for_function_address(function_address) 252 self.calls_table.setRowCount(len(tagged_call_contexts)) 253 for row, tagged_call_ctx in enumerate(tagged_call_contexts): 254 for column, column_name in enumerate(self.calls_header_labels): 255 if column == 0: 256 tmp_item = self.QtGui.QTableWidgetItem("0x%x" % tagged_call_ctx.address_of_call) 257 elif column == 1: 258 tmp_item = self.QtGui.QTableWidgetItem(tagged_call_ctx.called_function_name) 259 elif column == 2: 260 tmp_item = self.QtGui.QTableWidgetItem(tagged_call_ctx.tag) 261 tmp_item.setFlags(tmp_item.flags() & ~self.QtCore.Qt.ItemIsEditable) 262 self.calls_table.setItem(row, column, tmp_item) 263 self.calls_table.resizeRowToContents(row) 264 self.calls_table.setSelectionMode(self.QtGui.QAbstractItemView.SingleSelection) 265 self.calls_table.resizeColumnsToContents() 266 self.calls_table.setSortingEnabled(True)267269 """ 270 Populate the parameter table based on the selected API call in the calls table. 271 """ 272 self.parameter_table.setSortingEnabled(False) 273 self.parameter_header_labels = ["Address", "Type", "Name", "Value"] 274 self.parameter_table.clear() 275 self.parameter_table.setColumnCount(len(self.parameter_header_labels)) 276 self.parameter_table.setHorizontalHeaderLabels(self.parameter_header_labels) 277 278 parameter_contexts = self.si.get_parameters_for_call_address(call_address) 279 self.parameter_table.setRowCount(len(parameter_contexts)) 280 for row, parameter_ctx in enumerate(parameter_contexts): 281 for column, column_name in enumerate(self.parameter_header_labels): 282 if column == 0: 283 tmp_item = self.QtGui.QTableWidgetItem(parameter_ctx.get_rendered_push_address()) 284 elif column == 1: 285 tmp_item = self.QtGui.QTableWidgetItem(parameter_ctx.parameter_type) 286 elif column == 2: 287 tmp_item = self.QtGui.QTableWidgetItem(parameter_ctx.parameter_name) 288 elif column == 3: 289 tmp_item = self.QtGui.QTableWidgetItem(parameter_ctx.get_rendered_value()) 290 tmp_item.setFlags(tmp_item.flags() & ~self.QtCore.Qt.ItemIsEditable) 291 self.parameter_table.setItem(row, column, tmp_item) 292 self.parameter_table.resizeRowToContents(row) 293 self.parameter_table.setSelectionMode(self.QtGui.QAbstractItemView.SingleSelection) 294 self.parameter_table.resizeColumnsToContents() 295 self.parameter_table.setSortingEnabled(True)296298 num_displayed_functions = 0 299 if self.function_dummy_only_cb.isChecked(): 300 num_displayed_functions = len(self.si.get_identified_dummy_function_addresses()) 301 else: 302 num_displayed_functions = len(self.si.get_identified_function_addresses()) 303 self.funcs_label.setText("Functions of Interest (%d/%d)" % 304 (num_displayed_functions, self.si.calculate_number_of_functions()))305307 """ 308 Action for renaming functions when the rename action from the toolbar is activated. 309 """ 310 self.si.rename_functions() 311 self.onRefreshButtonClicked()312314 """ 315 Action for refreshing the window data by performing another scan of I{SemanticIdentifier}. 316 """ 317 self.si.scan() 318 self.populate_function_table()319321 """ 322 Action for performing semantic coloring of instructions. 323 """ 324 self.dh.colorize(self.si.get_last_result())325327 """ 328 Action for fixing unknown parts of code (red in address bar) to functions. 329 """ 330 self.dh.convert_non_function_code()331333 """ 334 Action for renaming potential wrapper functions to the wrapped API if they have a dummy name. 335 """ 336 self.si.rename_potential_wrapper_functions()337339 """ 340 If a function in the functions table is clicked, the view of the calls and parameter table are updated. 341 """ 342 clicked_function_address = int(self.funcs_table.item(mi.row(), \ 343 0).text(), 16) 344 self.populate_calls_table(clicked_function_address)345347 """ 348 If a function in the functions table is doubleclicked, IDA View is located to the corresponding address. 349 """ 350 clicked_function_address = self.funcs_table.item(mi.row(), 0).text() 351 self.ida_proxy.Jump(int(clicked_function_address, 16))352354 """ 355 If an API call in the calls table is clicked, the view of the parameter table is updated. 356 """ 357 clicked_function_address = int(self.calls_table.item(mi.row(), \ 358 0).text(), 16) 359 self.populate_parameter_table(clicked_function_address)360362 """ 363 If an API in the calls table is doubleclicked, IDA View is located to the corresponding address. 364 """ 365 if mi.column() == 1: 366 for widget in self.parent.idascope_widgets: 367 if widget.name == "WinAPI Browsing": 368 widget.navigate(self.calls_table.item(mi.row(), mi.column()).text()) 369 self.parent.setTabFocus("WinAPI Browsing") 370 else: 371 clicked_function_address = self.calls_table.item(mi.row(), 0).text() 372 self.ida_proxy.Jump(int(clicked_function_address, 16))373375 """ 376 If a parameter in the parameter table is doubleclicked, IDA View is located to the corresponding address. 377 """ 378 clicked_function_address = self.parameter_table.item(mi.row(), 0).text() 379 self.ida_proxy.Jump(int(clicked_function_address, 16))
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Mon Sep 17 13:18:34 2012 | http://epydoc.sourceforge.net |