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 from BoundsEditor import BoundsEditor 32 333536937 QtGui.QMainWindow.__init__(self) 38 print "loading CryptoIdentificationWidget" 39 # enable access to shared IDAscope modules 40 self.parent = parent 41 self.name = "Crypto Identification" 42 self.icon = QIcon(self.parent.config.icon_file_path + "crypto.png") 43 # This widget relies on the crypto identifier and uses some functions via IDA proxy 44 self.ci = self.parent.crypto_identifier 45 self.ip = self.parent.ida_proxy 46 # references to Qt-specific modules 47 self.QtGui = QtGui 48 self.QtCore = QtCore 49 self.NumberQTableWidgetItem = NumberQTableWidgetItem 50 51 self.central_widget = self.QtGui.QWidget() 52 self.setCentralWidget(self.central_widget) 53 self.createGui()5456 """ 57 Setup function for the full GUI of this widget. 58 """ 59 # toolbar 60 self.create_toolbar() 61 62 # Aritlog heuristic 63 self.create_aritlog_widget() 64 65 # signature 66 self.create_signature_widget() 67 68 # layout and fill the widget 69 crypto_layout = QtGui.QVBoxLayout() 70 splitter = self.QtGui.QSplitter(self.QtCore.Qt.Vertical) 71 q_clean_style = QtGui.QStyleFactory.create('Plastique') 72 splitter.setStyle(q_clean_style) 73 splitter.addWidget(self.aritlog_widget) 74 splitter.addWidget(self.signature_widget) 75 crypto_layout.addWidget(splitter) 76 77 self.central_widget.setLayout(crypto_layout)7880 """ 81 Creates the toolbar, containing buttons to control the widget. 82 """ 83 self.create_scan_action() 84 self.toolbar = self.addToolBar('Crypto Identification Toobar') 85 self.toolbar.addAction(self.scanAction)8688 """ 89 Create an action for the scan button of the toolbar and connect it. 90 """ 91 self.scanAction = QtGui.QAction(QIcon(self.parent.config.icon_file_path + "refresh.png"), \ 92 "Perform deep scan with crypto signatures (might take some time)", self) 93 self.scanAction.triggered.connect(self.onScanButtonClicked)9496 """ 97 The logic of the scan button from the toolbar. 98 Uses the scanning functions o I{CryptoIdentifier} and updates the elements displaying the results. 99 """ 100 self.ci.scan_crypto_patterns() 101 self.populate_signature_tree() 102 self.ci.scan_aritlog() 103 self.populate_aritlog_table() 104 pass105 106 ################################################################################ 107 # Aritlog GUI 108 ################################################################################ 109111 """ 112 Create the widget for the arithmetic/logic heuristic. 113 """ 114 self.aritlog_widget = QtGui.QWidget() 115 aritlog_layout = QtGui.QVBoxLayout() 116 self.aritlog_label = QtGui.QLabel("Arithmetic/Logic Heuristic") 117 self.aritlog_result_label = QtGui.QLabel("0 Blocks matched with these settings.") 118 119 # aritlog controls 120 self.aritlog_controls_widget = QtGui.QWidget() 121 aritlog_controls_layout = QtGui.QHBoxLayout() 122 123 # aritlog control sliders 124 self.aritlog_controls_slider_widget = QtGui.QWidget() 125 aritlog_controls_editor_layout = QtGui.QVBoxLayout() 126 self.aritlog_controls_threshold_editor = BoundsEditor("ArithLog Rating: ", 0, 100, 40, 100) 127 self.aritlog_controls_threshold_editor.boundsChanged.connect(self.populate_aritlog_table) 128 self.aritlog_controls_bblock_size_editor = BoundsEditor("Basic Blocks size: ", 0, 100, 8, 100, \ 129 False) 130 self.aritlog_controls_bblock_size_editor.boundsChanged.connect(self.populate_aritlog_table) 131 self.aritlog_controls_num_api_editor = BoundsEditor("Allowed calls: ", 0, 10, 0, 1, \ 132 False) 133 self.aritlog_controls_num_api_editor.boundsChanged.connect(self.populate_aritlog_table) 134 aritlog_controls_editor_layout.addWidget(self.aritlog_controls_threshold_editor) 135 aritlog_controls_editor_layout.addWidget(self.aritlog_controls_bblock_size_editor) 136 aritlog_controls_editor_layout.addWidget(self.aritlog_controls_num_api_editor) 137 self.aritlog_controls_slider_widget.setLayout(aritlog_controls_editor_layout) 138 139 # aritlog control result aggregation modes 140 self.aritlog_controls_aggregator_widget = QtGui.QWidget() 141 aritlog_controls_aggregator_layout = QtGui.QVBoxLayout() 142 self.aritlog_controls_zeroing_cb = QtGui.QCheckBox("Exclude Zeroing") 143 self.aritlog_controls_zeroing_cb.setCheckState(self.QtCore.Qt.Checked) 144 self.aritlog_controls_zeroing_cb.stateChanged.connect(self.populate_aritlog_table) 145 self.aritlog_controls_group_cb = QtGui.QCheckBox("Group by Functions") 146 self.aritlog_controls_group_cb.stateChanged.connect(self.populate_aritlog_table) 147 aritlog_controls_aggregator_layout.addWidget(self.aritlog_controls_zeroing_cb) 148 aritlog_controls_aggregator_layout.addWidget(self.aritlog_controls_group_cb) 149 self.aritlog_controls_aggregator_widget.setLayout(aritlog_controls_aggregator_layout) 150 151 aritlog_controls_layout.addWidget(self.aritlog_controls_slider_widget) 152 aritlog_controls_layout.addWidget(self.aritlog_controls_aggregator_widget) 153 self.aritlog_controls_widget.setLayout(aritlog_controls_layout) 154 155 # aritlog result visualization 156 self.aritlog_result_widget = QtGui.QWidget() 157 aritlog_result_layout = QtGui.QVBoxLayout() 158 self.create_aritlog_table() 159 aritlog_result_layout.addWidget(self.aritlog_table) 160 self.aritlog_result_widget.setLayout(aritlog_result_layout) 161 162 # aritlog composition 163 aritlog_layout.addWidget(self.aritlog_label) 164 aritlog_layout.addWidget(self.aritlog_controls_widget) 165 aritlog_layout.addWidget(self.aritlog_result_label) 166 aritlog_layout.addWidget(self.aritlog_result_widget) 167 self.aritlog_widget.setLayout(aritlog_layout)168170 """ 171 Create the result table for displaying results of the arithmetic/logic heuristic. 172 """ 173 self.aritlog_table = QtGui.QTableWidget() 174 self.populate_aritlog_table() 175 self.aritlog_table.doubleClicked.connect(self.onAritlogResultDoubleClicked)176178 """ 179 Populate the result table for the arithmetic/logic table. 180 Called everytime control parameters or scan results change. 181 """ 182 self.aritlog_table.clear() 183 self.aritlog_table.setSortingEnabled(False) 184 ts = self.aritlog_controls_threshold_editor 185 bs = self.aritlog_controls_bblock_size_editor 186 na = self.aritlog_controls_num_api_editor 187 is_grouped = self.aritlog_controls_group_cb.isChecked() 188 is_nonzero = self.aritlog_controls_zeroing_cb.isChecked() 189 190 aritlog_blocks = self.ci.get_aritlog_blocks(ts.low / 100.0, ts.high / 100.0, bs.low, bs.high, na.low, \ 191 na.high, is_nonzero) 192 193 self.set_aritlog_table_header_labels(is_grouped) 194 table_data = self.calculate_aritlog_table_data(aritlog_blocks, is_grouped) 195 row_count = len(table_data) 196 197 self.aritlog_table.setColumnCount(len(self.aritlog_table_header_labels)) 198 self.aritlog_table.setHorizontalHeaderLabels(self.aritlog_table_header_labels) 199 self.aritlog_table.setRowCount(row_count) 200 self.aritlog_table.resizeRowToContents(0) 201 202 for row, data_item in enumerate(table_data): 203 for column, column_name in enumerate(self.aritlog_table_header_labels): 204 tmp_item = self.get_aritlog_table_item(data_item, column, is_grouped) 205 tmp_item.setFlags(tmp_item.flags() & ~self.QtCore.Qt.ItemIsEditable) 206 tmp_item.setTextAlignment(self.QtCore.Qt.AlignRight) 207 self.aritlog_table.setItem(row, column, tmp_item) 208 self.aritlog_table.resizeRowToContents(row) 209 210 self.set_aritlog_result_label(self.aritlog_table.rowCount(), is_grouped) 211 212 self.aritlog_table.setSelectionMode(self.QtGui.QAbstractItemView.SingleSelection) 213 self.aritlog_table.resizeColumnsToContents() 214 self.aritlog_table.setSortingEnabled(True)215217 """ 218 Update the label displaying the current number of result entries (basic blocks or functions) after filtering. 219 @param num_hits: the number to display 220 @type num_hits: int 221 @param is_grouped: decides whether to display in basic block or functions mode 222 @type is_grouped: boolean 223 """ 224 self.aritlog_result_label.setText("%d %s from a total of %d blocks matched with the above settings." % (num_hits, \ 225 (is_grouped and "functions" or "blocks"), self.ci.get_unfiltered_block_count()))226228 """ 229 Prepare data for display in the result table for the arithmetic/logic heuristic. 230 If display is grouped to functions, data is transformed accordingly, otherwise the 231 input is returned without manipulation. 232 @param aritlog_blocks: the blocks to transform for display 233 @type: aritlog_blocks: a list of I{AritLogBasicBlock} 234 @param is_grouped: decides whether preparation shall be made for functionally grouped or basic block display. 235 @type: is_grouped: boolean 236 @return: (a list of elements) where elements are either I{AritLogBasicBlock}s or temporary dictionaries 237 """ 238 if is_grouped: 239 tmp_dict = {} 240 for block in aritlog_blocks: 241 function_address = self.ip.LocByName(self.ip.GetFunctionName(block.start_ea)) 242 if function_address not in tmp_dict.keys(): 243 tmp_dict[function_address] = {"function_address": function_address, "num_blocks": 1, \ 244 "num_log_arith_instructions": block.num_log_arit_instructions} 245 else: 246 tmp_dict[function_address]["num_blocks"] += 1 247 tmp_dict[function_address]["num_log_arith_instructions"] += block.num_log_arit_instructions 248 return [tmp_dict[key] for key in tmp_dict.keys()] 249 else: 250 return aritlog_blocks251253 """ 254 Set the header labels for the arithmetic/logic result table. 255 @param is_grouped: decides whether header labels shall be created for functionally grouped or 256 basic block display. 257 @type: is_grouped: boolean 258 """ 259 if is_grouped: 260 self.aritlog_table_header_labels = ["Address", "Name", "# Blocks", "# Log/Arith Instr"] 261 else: 262 self.aritlog_table_header_labels = ["Address", "Name", "Block Address", "# Instr", \ 263 "Arithmetic/Logic Rating"]264266 """ 267 Transform a data item for display in the arithmetic/logic result table 268 @param data_item: the item to prepare for display 269 @type data_item: either a I{AritLogBasicBlock} or a dictionary for a function 270 @param column_index: the column to prepare the item for 271 @type column_index: int 272 @param is_grouped: decides whether the item shall be prepared for functionally grouped or 273 basic block display. 274 @type: is_grouped: boolean 275 @return: the prepared item 276 """ 277 tmp_item = self.QtGui.QTableWidgetItem() 278 if column_index == 0: 279 if is_grouped: 280 tmp_item = self.QtGui.QTableWidgetItem("0x%x" % data_item["function_address"]) 281 else: 282 function_address = self.ip.LocByName(self.ip.GetFunctionName(data_item.start_ea)) 283 tmp_item = self.QtGui.QTableWidgetItem("0x%x" % function_address) 284 elif column_index == 1: 285 if is_grouped: 286 tmp_item = self.QtGui.QTableWidgetItem(self.ip.GetFunctionName(data_item["function_address"])) 287 else: 288 function_address = self.ip.LocByName(self.ip.GetFunctionName(data_item.start_ea)) 289 tmp_item = self.QtGui.QTableWidgetItem(self.ip.GetFunctionName(function_address)) 290 elif column_index == 2: 291 if is_grouped: 292 tmp_item = self.NumberQTableWidgetItem("%d" % (data_item["num_blocks"])) 293 else: 294 tmp_item = self.QtGui.QTableWidgetItem("0x%x" % data_item.start_ea) 295 elif column_index == 3: 296 if is_grouped: 297 tmp_item = self.NumberQTableWidgetItem("%d" % (data_item["num_log_arith_instructions"])) 298 else: 299 tmp_item = self.NumberQTableWidgetItem("%d" % data_item.num_instructions) 300 elif column_index == 4: 301 if self.aritlog_controls_zeroing_cb.isChecked(): 302 tmp_item = self.NumberQTableWidgetItem("%2.2f" % (100.0 * data_item.get_aritlog_rating(True))) 303 else: 304 tmp_item = self.NumberQTableWidgetItem("%2.2f" % (100.0 * data_item.get_aritlog_rating())) 305 return tmp_item306308 """ 309 The action to perform when an entry in the arithmetic/logic table is double clicked. 310 Changes IDA View either to the function or basic block, depending on the column clicked. 311 """ 312 clicked_address = 0 313 if mi.column() == 0 or mi.column() == 1: 314 clicked_address = self.aritlog_table.item(mi.row(), 0).text() 315 elif mi.column() >= 2: 316 clicked_address = self.aritlog_table.item(mi.row(), 2).text() 317 self.ip.Jump(int(clicked_address, 16))318 319 ################################################################################ 320 # Signature GUI 321 ################################################################################ 322324 """ 325 Create the widget for the signature part. 326 """ 327 self.signature_widget = QtGui.QWidget() 328 signature_layout = QtGui.QVBoxLayout() 329 self.signature_tree = QtGui.QTreeWidget() 330 self.signature_tree.setColumnCount(1) 331 self.signature_tree.setHeaderLabels(["Found Crypto Signatures"]) 332 self.signature_tree.itemDoubleClicked.connect(self.SignatureTreeItemDoubleClicked) 333 signature_layout.addWidget(self.signature_tree) 334 self.signature_widget.setLayout(signature_layout) 335 336 self.populate_signature_tree()337339 """ 340 populate the TreeWidget for display of the signature scanning results. 341 """ 342 self.signature_tree.clear() 343 self.signature_tree.setSortingEnabled(False) 344 signature_hits = self.ci.get_signature_hits() 345 self.qtreewidgetitems_to_addresses = {} 346 347 for signature in signature_hits: 348 root = self.QtGui.QTreeWidgetItem(self.signature_tree) 349 root.setText(0, signature) 350 for hit in signature_hits[signature]: 351 hit_information = self.QtGui.QTreeWidgetItem(root) 352 hit_information.setText(0, "0x%x (%d bytes matched)" % (hit.start_address, len(hit.matched_signature))) 353 self.qtreewidgetitems_to_addresses[hit_information] = hit.start_address 354 for xref in hit.code_refs_to: 355 code_ref = self.QtGui.QTreeWidgetItem(hit_information) 356 code_ref.setText(0, "referenced by 0x%x (function: %s)" % (xref[0], \ 357 self.ip.GetFunctionName(xref[0]))) 358 if xref[1]: 359 code_ref.setForeground(0, self.QtGui.QBrush(self.QtGui.QColor(0xFF0000))) 360 self.qtreewidgetitems_to_addresses[code_ref] = xref[0] 361 self.signature_tree.setSortingEnabled(True)362364 """ 365 The action to perform when an entry in the signature TreeWIdget is double clicked. 366 Changes IDA View either to location clicked. 367 """ 368 self.ip.Jump(self.qtreewidgetitems_to_addresses[item])
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Mon Sep 17 13:18:34 2012 | http://epydoc.sourceforge.net |