diff --git a/CHANGELOG.md b/CHANGELOG.md index 5678f185..6aed7fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,6 +124,7 @@ ### capa Explorer Web ### capa Explorer IDA Pro plugin +- ida: display file-scope feature addresses (`file:0x...`) in rule generator tree and safely handle file-offset navigation/filtering @vee1e #3009 ### Development - tests: update binja version to 5.3 @mr-tz #3011 @@ -277,7 +278,7 @@ Additionally a Binary Ninja bug has been fixed. Released binaries now include AR ### Bug Fixes -- binja: fix a crash during feature extraction when the MLIL is unavailable @xusheng6 #2714 +- binja: fix a crash during feature extraction when the MLIL is unavailable @xusheng6 #2714 ### capa Explorer Web diff --git a/capa/ida/plugin/view.py b/capa/ida/plugin/view.py index 7e589ae9..7a775916 100644 --- a/capa/ida/plugin/view.py +++ b/capa/ida/plugin/view.py @@ -18,12 +18,13 @@ from collections import Counter import idc import idaapi +import ida_loader import capa.ida.helpers import capa.features.common import capa.features.basicblock from capa.ida.plugin.item import CapaExplorerFunctionItem -from capa.features.address import AbsoluteVirtualAddress, _NoAddress +from capa.features.address import FileOffsetAddress, AbsoluteVirtualAddress, _NoAddress from capa.ida.plugin.model import CapaExplorerDataModel from capa.ida.plugin.qt_compat import QtGui, QtCore, Signal, QAction, QtWidgets @@ -895,7 +896,22 @@ class CapaExplorerRulegenFeatures(QtWidgets.QTreeWidget): def slot_item_double_clicked(self, o, column): """ """ if column == CapaExplorerRulegenFeatures.get_column_address_index() and o.text(column): - idc.jumpto(int(o.text(column), 0x10)) + addr_text = o.text(column).strip() + + if addr_text.startswith("file:"): + try: + file_offset = int(addr_text[len("file:") :], 16) + except (ValueError, TypeError): + return + + ea = ida_loader.get_fileregion_ea(file_offset) + if ea != idc.BADADDR: + idc.jumpto(ea) + else: + try: + idc.jumpto(int(addr_text, 16)) + except (ValueError, TypeError): + return elif o.capa_type == CapaExplorerRulegenFeatures.get_node_type_leaf(): self.editor.update_features([o.data(0, 0x100)]) @@ -945,13 +961,18 @@ class CapaExplorerRulegenFeatures(QtWidgets.QTreeWidget): # read ea from "Address" column o_ea = o.text(CapaExplorerRulegenFeatures.get_column_address_index()) - if o_ea == "": - # ea may be empty, hide by default + if o_ea == "" or o_ea.startswith("file:"): + # ea may be empty or a file offset, hide by default when filtering by VA if not o.isHidden(): o.setHidden(True) continue - o_ea = int(o_ea, 16) + try: + o_ea = int(o_ea, 16) + except (ValueError, TypeError): + if not o.isHidden(): + o.setHidden(True) + continue if max_ea is not None and min_ea <= o_ea <= max_ea: show_item_and_parents(o) @@ -1035,8 +1056,9 @@ class CapaExplorerRulegenFeatures(QtWidgets.QTreeWidget): def format_address(e): if isinstance(e, AbsoluteVirtualAddress): return f"{hex(int(e))}" - else: - return "" + if isinstance(e, FileOffsetAddress): + return f"file:{hex(e)}" + return "" def format_feature(feature): """ """