From 5974440ab74f52bcb5a46239d0fce1cda338a3ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 14:25:06 +0000 Subject: [PATCH 01/17] build(deps): bump rich from 14.0.0 to 14.2.0 Bumps [rich](https://github.com/Textualize/rich) from 14.0.0 to 14.2.0. - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v14.0.0...v14.2.0) --- updated-dependencies: - dependency-name: rich dependency-version: 14.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 32a476e8e1..b6d78ae1fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ pyelftools==0.32 pygments==2.19.1 python-flirt==0.9.2 pyyaml==6.0.2 -rich==14.0.0 +rich==14.2.0 ruamel-yaml==0.18.6 ruamel-yaml-clib==0.2.8 setuptools==80.9.0 From 3bc2d9915c874310175facf18044b612165adcd3 Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Mon, 13 Oct 2025 18:52:26 +0000 Subject: [PATCH 02/17] Sync capa-testfiles submodule --- tests/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data b/tests/data index af439c7555..a0055a93a2 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit af439c7555779346250c2c6a0c1723042bf1fb9c +Subproject commit a0055a93a27648b6a79684731e1fe135dbaece54 From da0803b671e088e1e193a885310271ffab959b18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Oct 2025 10:58:41 +0000 Subject: [PATCH 03/17] build(deps-dev): bump vite from 6.3.4 to 6.4.0 in /web/explorer Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.4 to 6.4.0. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.0/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.4.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- web/explorer/package-lock.json | 8 ++++---- web/explorer/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/explorer/package-lock.json b/web/explorer/package-lock.json index 0f88dd8b02..b79ee5fbb2 100644 --- a/web/explorer/package-lock.json +++ b/web/explorer/package-lock.json @@ -27,7 +27,7 @@ "eslint-plugin-vue": "^9.23.0", "jsdom": "^24.1.0", "prettier": "^3.2.5", - "vite": "^6.3.4", + "vite": "^6.4.0", "vite-plugin-singlefile": "^2.2.0", "vitest": "^3.0.9" } @@ -3801,9 +3801,9 @@ "dev": true }, "node_modules/vite": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", - "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.0.tgz", + "integrity": "sha512-oLnWs9Hak/LOlKjeSpOwD6JMks8BeICEdYMJBf6P4Lac/pO9tKiv/XhXnAM7nNfSkZahjlCZu9sS50zL8fSnsw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/web/explorer/package.json b/web/explorer/package.json index b72fc58123..7226d00f01 100644 --- a/web/explorer/package.json +++ b/web/explorer/package.json @@ -33,7 +33,7 @@ "eslint-plugin-vue": "^9.23.0", "jsdom": "^24.1.0", "prettier": "^3.2.5", - "vite": "^6.3.4", + "vite": "^6.4.0", "vite-plugin-singlefile": "^2.2.0", "vitest": "^3.0.9" } From 0099e75704954e5d99052232635ab8d447872fc6 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Mon, 20 Oct 2025 18:40:45 +0800 Subject: [PATCH 04/17] binja: fix crash in binja feature extraction when MLIL is unavailable. Fix https://github.com/mandiant/capa/issues/2714 --- CHANGELOG.md | 2 ++ capa/features/extractors/binja/function.py | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c16edf334..0de2e59e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ ### Bug Fixes +- binja: fix a crash during feature extraction when the MLIL is unavaiable @xusheng6 #2714 + ### capa Explorer Web ### capa Explorer IDA Pro plugin diff --git a/capa/features/extractors/binja/function.py b/capa/features/extractors/binja/function.py index 707c572e93..b52c80582a 100644 --- a/capa/features/extractors/binja/function.py +++ b/capa/features/extractors/binja/function.py @@ -19,7 +19,6 @@ Function, BinaryView, SymbolType, - ILException, RegisterValueType, VariableSourceType, LowLevelILOperation, @@ -192,9 +191,8 @@ def extract_stackstring(fh: FunctionHandle): if bv is None: return - try: - mlil = func.mlil - except ILException: + mlil = func.mlil + if mlil is None: return for block in mlil.basic_blocks: From acb34e88d6cbbcb5c9c074682d56f129b186646b Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Mon, 20 Oct 2025 09:05:30 -0600 Subject: [PATCH 05/17] Update CHANGELOG.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0de2e59e33..114c700061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ ### Bug Fixes -- binja: fix a crash during feature extraction when the MLIL is unavaiable @xusheng6 #2714 +- binja: fix a crash during feature extraction when the MLIL is unavailable @xusheng6 #2714 ### capa Explorer Web From add09df061af7b8782b7438fd5cf29b5c9c66e98 Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Mon, 20 Oct 2025 15:18:32 +0000 Subject: [PATCH 06/17] Sync capa-testfiles submodule --- tests/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data b/tests/data index a0055a93a2..dd37e65cee 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit a0055a93a27648b6a79684731e1fe135dbaece54 +Subproject commit dd37e65cee719d3f7993b8fd79f68e29e8b78830 From e6df6ad0cd785976696208c9b1fb98cd7de731aa Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Mon, 20 Oct 2025 15:27:46 +0000 Subject: [PATCH 07/17] Sync capa rules submodule --- CHANGELOG.md | 3 ++- rules | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c16edf334..87097c5484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Breaking Changes -### New Rules (19) +### New Rules (20) - anti-analysis/anti-vm/vm-detection/detect-mouse-movement-via-activity-checks-on-windows tevajdr@gmail.com - nursery/create-executable-heap moritz.raabe@mandiant.com @@ -27,6 +27,7 @@ - host-interaction/network/enumerate-tcp-connections-via-wmi-com-api jakubjozwiak@google.com - host-interaction/network/routing-table/create-routing-table-entry jakubjozwiak@google.com - host-interaction/network/routing-table/get-routing-table michael.hunhoff@mandiant.com +- host-interaction/file-system/use-io_uring-io-interface-on-linux jakubjozwiak@google.com - ### Bug Fixes diff --git a/rules b/rules index fa246a4a9b..7ae786cf70 160000 --- a/rules +++ b/rules @@ -1 +1 @@ -Subproject commit fa246a4a9b869f071efa9c1d3a00ac447efc5efe +Subproject commit 7ae786cf705f9a824ba8ef6d4d8dac648c6250ca From 5906bb3ecfdf7bfecfd5ae1e122dbc698f03f54f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 04:19:00 +0000 Subject: [PATCH 08/17] build(deps-dev): bump vite from 6.4.0 to 6.4.1 in /web/explorer Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.4.0 to 6.4.1. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@6.4.1/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.4.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- web/explorer/package-lock.json | 8 ++++---- web/explorer/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/explorer/package-lock.json b/web/explorer/package-lock.json index b79ee5fbb2..f756f8d5cf 100644 --- a/web/explorer/package-lock.json +++ b/web/explorer/package-lock.json @@ -27,7 +27,7 @@ "eslint-plugin-vue": "^9.23.0", "jsdom": "^24.1.0", "prettier": "^3.2.5", - "vite": "^6.4.0", + "vite": "^6.4.1", "vite-plugin-singlefile": "^2.2.0", "vitest": "^3.0.9" } @@ -3801,9 +3801,9 @@ "dev": true }, "node_modules/vite": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.0.tgz", - "integrity": "sha512-oLnWs9Hak/LOlKjeSpOwD6JMks8BeICEdYMJBf6P4Lac/pO9tKiv/XhXnAM7nNfSkZahjlCZu9sS50zL8fSnsw==", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/web/explorer/package.json b/web/explorer/package.json index 7226d00f01..82920b7f96 100644 --- a/web/explorer/package.json +++ b/web/explorer/package.json @@ -33,7 +33,7 @@ "eslint-plugin-vue": "^9.23.0", "jsdom": "^24.1.0", "prettier": "^3.2.5", - "vite": "^6.4.0", + "vite": "^6.4.1", "vite-plugin-singlefile": "^2.2.0", "vitest": "^3.0.9" } From 41dd9710d8b7931fd5ca76c29d9e1531db9c500d Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Thu, 9 Oct 2025 13:35:25 +0000 Subject: [PATCH 09/17] ida: add Qt compatibility layer for PyQt5 and PySide6 Introduce a new module `qt_compat.py` providing a unified import interface and API compatibility for Qt modules. It handles differences between PyQt5 (used in IDA <9.2) and PySide6 (used in IDA >=9.2). Update all plugin modules to import Qt components via this compatibility layer instead of directly importing from PyQt5. This enhances plugin compatibility across different IDA versions. thanks @mike-hunhoff! changelog --- CHANGELOG.md | 2 + capa/ida/plugin/extractor.py | 4 +- capa/ida/plugin/form.py | 6 +-- capa/ida/plugin/item.py | 4 +- capa/ida/plugin/model.py | 4 +- capa/ida/plugin/proxy.py | 4 +- capa/ida/plugin/qt_compat.py | 76 ++++++++++++++++++++++++++++++++++++ capa/ida/plugin/view.py | 6 +-- pyproject.toml | 5 ++- requirements.txt | 2 +- 10 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 capa/ida/plugin/qt_compat.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 79393a84f4..766c643988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ ### capa Explorer IDA Pro plugin +- ida plugin: add Qt compatibility layer for PyQt5 and PySide6 support @williballenthin #2707 + ### Development - ci: remove redundant "test_run" action from build workflow @mike-hunhoff #2692 diff --git a/capa/ida/plugin/extractor.py b/capa/ida/plugin/extractor.py index a5b86f4ee1..a2f24f22b1 100644 --- a/capa/ida/plugin/extractor.py +++ b/capa/ida/plugin/extractor.py @@ -14,9 +14,9 @@ import ida_kernwin -from PyQt5 import QtCore from capa.ida.plugin.error import UserCancelledError +from capa.ida.plugin.qt_compat import QtCore, Signal from capa.features.extractors.ida.extractor import IdaFeatureExtractor from capa.features.extractors.base_extractor import FunctionHandle @@ -24,7 +24,7 @@ class CapaExplorerProgressIndicator(QtCore.QObject): """implement progress signal, used during feature extraction""" - progress = QtCore.pyqtSignal(str) + progress = Signal(str) def update(self, text): """emit progress update diff --git a/capa/ida/plugin/form.py b/capa/ida/plugin/form.py index 36d104c894..800453bbfa 100644 --- a/capa/ida/plugin/form.py +++ b/capa/ida/plugin/form.py @@ -23,7 +23,6 @@ import idaapi import ida_kernwin import ida_settings -from PyQt5 import QtGui, QtCore, QtWidgets import capa.main import capa.rules @@ -51,6 +50,7 @@ from capa.ida.plugin.model import CapaExplorerDataModel from capa.ida.plugin.proxy import CapaExplorerRangeProxyModel, CapaExplorerSearchProxyModel from capa.ida.plugin.extractor import CapaExplorerFeatureExtractor +from capa.ida.plugin.qt_compat import QtGui, QtCore, QtWidgets from capa.features.extractors.base_extractor import FunctionHandle logger = logging.getLogger(__name__) @@ -1358,7 +1358,7 @@ def slot_checkbox_limit_by_changed(self, state): @param state: checked state """ - if state == QtCore.Qt.Checked: + if state: self.limit_results_to_function(idaapi.get_func(idaapi.get_screen_ea())) else: self.range_model_proxy.reset_address_range_filter() @@ -1367,7 +1367,7 @@ def slot_checkbox_limit_by_changed(self, state): def slot_checkbox_limit_features_by_ea(self, state): """ """ - if state == QtCore.Qt.Checked: + if state: self.view_rulegen_features.filter_items_by_ea(idaapi.get_screen_ea()) else: self.view_rulegen_features.show_all_items() diff --git a/capa/ida/plugin/item.py b/capa/ida/plugin/item.py index c8d3bdab7e..0510d5f971 100644 --- a/capa/ida/plugin/item.py +++ b/capa/ida/plugin/item.py @@ -18,10 +18,10 @@ import idc import idaapi -from PyQt5 import QtCore import capa.ida.helpers from capa.features.address import Address, FileOffsetAddress, AbsoluteVirtualAddress +from capa.ida.plugin.qt_compat import QtCore, qt_get_item_flag_tristate def info_to_name(display): @@ -55,7 +55,7 @@ def __init__(self, parent: Optional["CapaExplorerDataItem"], data: list[str], ca self.flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable if self._can_check: - self.flags = self.flags | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsTristate + self.flags = self.flags | QtCore.Qt.ItemIsUserCheckable | qt_get_item_flag_tristate() if self.pred: self.pred.appendChild(self) diff --git a/capa/ida/plugin/model.py b/capa/ida/plugin/model.py index 405718a15e..046dc1ea3f 100644 --- a/capa/ida/plugin/model.py +++ b/capa/ida/plugin/model.py @@ -18,7 +18,6 @@ import idc import idaapi -from PyQt5 import QtGui, QtCore import capa.rules import capa.ida.helpers @@ -42,6 +41,7 @@ CapaExplorerInstructionViewItem, ) from capa.features.address import Address, AbsoluteVirtualAddress +from capa.ida.plugin.qt_compat import QtGui, QtCore # default highlight color used in IDA window DEFAULT_HIGHLIGHT = 0xE6C700 @@ -269,7 +269,7 @@ def iterateChildrenIndexFromRootIndex(self, model_index, ignore_root=True): visited.add(child_index) for idx in range(self.rowCount(child_index)): - stack.append(child_index.child(idx, 0)) + stack.append(self.index(idx, 0, child_index)) def reset_ida_highlighting(self, item, checked): """reset IDA highlight for item diff --git a/capa/ida/plugin/proxy.py b/capa/ida/plugin/proxy.py index e8b452103b..d76b895686 100644 --- a/capa/ida/plugin/proxy.py +++ b/capa/ida/plugin/proxy.py @@ -12,10 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from PyQt5 import QtCore -from PyQt5.QtCore import Qt - from capa.ida.plugin.model import CapaExplorerDataModel +from capa.ida.plugin.qt_compat import Qt, QtCore class CapaExplorerRangeProxyModel(QtCore.QSortFilterProxyModel): diff --git a/capa/ida/plugin/qt_compat.py b/capa/ida/plugin/qt_compat.py new file mode 100644 index 0000000000..2cc3aa3f1e --- /dev/null +++ b/capa/ida/plugin/qt_compat.py @@ -0,0 +1,76 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Qt compatibility layer for capa IDA Pro plugin. + +Handles PyQt5 (IDA < 9.2) vs PySide6 (IDA >= 9.2) differences. +This module provides a unified import interface for Qt modules and handles +API changes between Qt5 and Qt6. +""" + +try: + # IDA 9.2+ uses PySide6 + from PySide6 import QtGui, QtCore, QtWidgets # noqa: F401 + from PySide6.QtGui import QAction # Import QAction from QtGui + + QT_LIBRARY = "PySide6" + Signal = QtCore.Signal +except ImportError: + # Older IDA versions use PyQt5 + try: + from PyQt5 import QtGui, QtCore, QtWidgets # noqa: F401 + from PyQt5.QtWidgets import QAction # Import QAction from QtWidgets + + QT_LIBRARY = "PyQt5" + Signal = QtCore.pyqtSignal + except ImportError: + raise ImportError("Neither PySide6 nor PyQt5 is available. Cannot initialize capa IDA plugin.") + +Qt = QtCore.Qt + + +def qt_get_item_flag_tristate(): + """ + Get the tristate item flag compatible with Qt5 and Qt6. + + Qt5 (PyQt5): Uses Qt.ItemIsTristate + Qt6 (PySide6): Qt.ItemIsTristate was removed, uses Qt.ItemIsAutoTristate + + ItemIsAutoTristate automatically manages tristate based on child checkboxes, + matching the original ItemIsTristate behavior where parent checkboxes reflect + the check state of their children. + + Returns: + int: The appropriate flag value for the Qt version + + Raises: + AttributeError: If the tristate flag cannot be found in the Qt library + """ + if QT_LIBRARY == "PySide6": + # Qt6: ItemIsTristate was removed, replaced with ItemIsAutoTristate + # Try different possible locations (API varies slightly across PySide6 versions) + if hasattr(Qt, "ItemIsAutoTristate"): + return Qt.ItemIsAutoTristate + elif hasattr(Qt, "ItemFlag") and hasattr(Qt.ItemFlag, "ItemIsAutoTristate"): + return Qt.ItemFlag.ItemIsAutoTristate + else: + raise AttributeError( + "Cannot find ItemIsAutoTristate in PySide6. " + + "Your PySide6 version may be incompatible with capa. " + + f"Available Qt attributes: {[attr for attr in dir(Qt) if 'Item' in attr]}" + ) + else: + # Qt5: Use the original ItemIsTristate flag + return Qt.ItemIsTristate diff --git a/capa/ida/plugin/view.py b/capa/ida/plugin/view.py index ed188a841c..a442f4d1e9 100644 --- a/capa/ida/plugin/view.py +++ b/capa/ida/plugin/view.py @@ -18,7 +18,6 @@ import idc import idaapi -from PyQt5 import QtGui, QtCore, QtWidgets import capa.rules import capa.engine @@ -28,6 +27,7 @@ from capa.ida.plugin.item import CapaExplorerFunctionItem from capa.features.address import AbsoluteVirtualAddress, _NoAddress from capa.ida.plugin.model import CapaExplorerDataModel +from capa.ida.plugin.qt_compat import QtGui, QtCore, Signal, QAction, QtWidgets MAX_SECTION_SIZE = 750 @@ -147,7 +147,7 @@ def calc_item_depth(o): def build_action(o, display, data, slot): """ """ - action = QtWidgets.QAction(display, o) + action = QAction(display, o) action.setData(data) action.triggered.connect(lambda checked: slot(action)) @@ -312,7 +312,7 @@ def set_selection(self, start, end, max): class CapaExplorerRulegenEditor(QtWidgets.QTreeWidget): - updated = QtCore.pyqtSignal() + updated = Signal() def __init__(self, preview, parent=None): """ """ diff --git a/pyproject.toml b/pyproject.toml index c2fcbac4a4..2a0056e835 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,7 @@ dependencies = [ # comments and context. "pyyaml>=6", "colorama>=0.4", - "ida-settings>=2.1.0,<3", # v3 has breaking changes + "ida-settings>=3.1.0", "ruamel.yaml>=0.18", "pefile>=2023.2.7", "pyelftools>=0.31", @@ -197,7 +197,8 @@ known_first_party = [ "idc", "java", "netnode", - "PyQt5" + "PyQt5", + "PySide6" ] [tool.deptry.per_rule_ignores] diff --git a/requirements.txt b/requirements.txt index b6d78ae1fb..1b211a9364 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ dnfile==0.16.4 funcy==2.0 humanize==4.13.0 ida-netnode==3.0 -ida-settings==2.1.0 +ida-settings==3.2.2 intervaltree==3.1.0 markdown-it-py==4.0.0 mdurl==0.1.2 From f1f4753970b997709640363855f36881985526c5 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Thu, 9 Oct 2025 13:56:16 +0000 Subject: [PATCH 10/17] gitignore uv.lock --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 997cef4cc9..cef85dbae6 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,7 @@ scripts/perf/*.zip */.DS_Store Pipfile Pipfile.lock +uv.lock /cache/ .github/binja/binaryninja .github/binja/download_headless.py From f4cc0e48ebf66c6a477cbe0f7e5348fe58fe8124 Mon Sep 17 00:00:00 2001 From: mr-tz Date: Mon, 27 Oct 2025 18:49:34 +0000 Subject: [PATCH 11/17] update dependencies --- pyproject.toml | 8 +++++--- requirements.txt | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2a0056e835..ae8e86d6a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,7 +104,7 @@ dependencies = [ "networkx>=3", - "dnfile>=0.15.0", + "dnfile>=0.17.0", ] dynamic = ["version"] @@ -161,11 +161,13 @@ build = [ "build==1.2.2" ] scripts = [ + # can (optionally) be more lenient on dependencies here + # see comment on dependencies for more context "jschema_to_python==1.2.3", - "psutil==7.0.0", + "psutil==7.1.2", "stix2==3.0.1", "sarif_om==1.0.4", - "requests==2.32.3", + "requests>=2.32.4", ] [tool.deptry] diff --git a/requirements.txt b/requirements.txt index 1b211a9364..7ae5c96cd2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ annotated-types==0.7.0 colorama==0.4.6 cxxfilt==0.3.0 dncil==1.0.2 -dnfile==0.16.4 +dnfile==0.17.0 funcy==2.0 humanize==4.13.0 ida-netnode==3.0 @@ -38,7 +38,7 @@ python-flirt==0.9.2 pyyaml==6.0.2 rich==14.2.0 ruamel-yaml==0.18.6 -ruamel-yaml-clib==0.2.8 +ruamel-yaml-clib==0.2.14 setuptools==80.9.0 six==1.17.0 sortedcontainers==2.4.0 From 68cf74d60c0b380b4c0c73fafb891b3c8f0e7119 Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Tue, 28 Oct 2025 13:12:29 +0000 Subject: [PATCH 12/17] Sync capa rules submodule --- CHANGELOG.md | 3 ++- rules | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79393a84f4..ba185cedb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Breaking Changes -### New Rules (20) +### New Rules (21) - anti-analysis/anti-vm/vm-detection/detect-mouse-movement-via-activity-checks-on-windows tevajdr@gmail.com - nursery/create-executable-heap moritz.raabe@mandiant.com @@ -28,6 +28,7 @@ - host-interaction/network/routing-table/create-routing-table-entry jakubjozwiak@google.com - host-interaction/network/routing-table/get-routing-table michael.hunhoff@mandiant.com - host-interaction/file-system/use-io_uring-io-interface-on-linux jakubjozwiak@google.com +- collection/keylog/log-keystrokes-via-direct-input zeze-zeze - ### Bug Fixes diff --git a/rules b/rules index 7ae786cf70..14dcc55c32 160000 --- a/rules +++ b/rules @@ -1 +1 @@ -Subproject commit 7ae786cf705f9a824ba8ef6d4d8dac648c6250ca +Subproject commit 14dcc55c3209b2137aff10e09d823114ff3ffb94 From ca708ca52eefb1bd23f416d19d3a41a712738522 Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Tue, 28 Oct 2025 15:15:42 +0000 Subject: [PATCH 13/17] Sync capa-testfiles submodule --- tests/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data b/tests/data index dd37e65cee..5ea5d9f572 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit dd37e65cee719d3f7993b8fd79f68e29e8b78830 +Subproject commit 5ea5d9f572902c9c74f0e662ff2c9a5d600bb4ed From 6795813fbec5ce1238d8fff57f1201bed7c0bbea Mon Sep 17 00:00:00 2001 From: Capa Bot Date: Tue, 28 Oct 2025 15:21:05 +0000 Subject: [PATCH 14/17] Sync capa rules submodule --- rules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules b/rules index 14dcc55c32..9e4cc28265 160000 --- a/rules +++ b/rules @@ -1 +1 @@ -Subproject commit 14dcc55c3209b2137aff10e09d823114ff3ffb94 +Subproject commit 9e4cc2826585d1c939aee25df5067330937d7655 From e3288931aae4b310c07949d83db6891d411dbb73 Mon Sep 17 00:00:00 2001 From: mr-tz Date: Wed, 29 Oct 2025 15:26:55 +0000 Subject: [PATCH 15/17] add ruff noqa --- capa/ida/plugin/qt_compat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/capa/ida/plugin/qt_compat.py b/capa/ida/plugin/qt_compat.py index 2cc3aa3f1e..7729548212 100644 --- a/capa/ida/plugin/qt_compat.py +++ b/capa/ida/plugin/qt_compat.py @@ -23,7 +23,7 @@ try: # IDA 9.2+ uses PySide6 from PySide6 import QtGui, QtCore, QtWidgets # noqa: F401 - from PySide6.QtGui import QAction # Import QAction from QtGui + from PySide6.QtGui import QAction # noqa: F401 QT_LIBRARY = "PySide6" Signal = QtCore.Signal @@ -31,7 +31,7 @@ # Older IDA versions use PyQt5 try: from PyQt5 import QtGui, QtCore, QtWidgets # noqa: F401 - from PyQt5.QtWidgets import QAction # Import QAction from QtWidgets + from PyQt5.QtWidgets import QAction # noqa: F401 QT_LIBRARY = "PyQt5" Signal = QtCore.pyqtSignal From 5ea63770ba3ea4ab8c273750a421e34ee687d237 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Wed, 29 Oct 2025 17:55:49 +0100 Subject: [PATCH 16/17] Merge pull request #2724 from HexRays-plugin-contributions/ida-plugin-json add `ida-plugin.json` --- .bumpversion.toml | 22 +++++++++++++++++++ CHANGELOG.md | 3 +++ capa/ida/plugin/ida-plugin.json | 38 +++++++++++++++++++++++++++++++++ doc/release.md | 2 +- pyproject.toml | 2 ++ requirements.txt | 1 + 6 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .bumpversion.toml create mode 100644 capa/ida/plugin/ida-plugin.json diff --git a/.bumpversion.toml b/.bumpversion.toml new file mode 100644 index 0000000000..221cd9b81d --- /dev/null +++ b/.bumpversion.toml @@ -0,0 +1,22 @@ +[tool.bumpversion] +current_version = "9.2.1" + +[[tool.bumpversion.files]] +filename = "capa/version.py" +search = '__version__ = "{current_version}"' +replace = '__version__ = "{new_version}"' + +[[tool.bumpversion.files]] +filename = "capa/ida/plugin/ida-plugin.json" +search = '"version": "{current_version}"' +replace = '"version": "{new_version}"' + +[[tool.bumpversion.files]] +filename = "capa/ida/plugin/ida-plugin.json" +search = '"flare-capa=={current_version}"' +replace = '"flare-capa=={new_version}"' + +[[tool.bumpversion.files]] +filename = "CHANGELOG.md" +search = "v{current_version}...master" +replace = "{current_version}...{new_version}" diff --git a/CHANGELOG.md b/CHANGELOG.md index ba185cedb3..e01ea6c260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,9 +39,12 @@ ### capa Explorer IDA Pro plugin +- add `ida-plugin.json` for inclusion in the IDA Pro plugin repository @williballenthin + ### Development - ci: remove redundant "test_run" action from build workflow @mike-hunhoff #2692 +- dev: add bumpmyversion to bump and sync versions across the project @mr-tz ### Raw diffs - [capa v9.2.1...master](https://github.com/mandiant/capa/compare/v9.2.1...master) diff --git a/capa/ida/plugin/ida-plugin.json b/capa/ida/plugin/ida-plugin.json new file mode 100644 index 0000000000..c63fd80e54 --- /dev/null +++ b/capa/ida/plugin/ida-plugin.json @@ -0,0 +1,38 @@ +{ + "IDAMetadataDescriptorVersion": 1, + "plugin": { + "name": "capa", + "entryPoint": "capa_explorer.py", + "version": "9.2.1", + "idaVersions": ">=7.4", + "description": "Identify capabilities in executable files using FLARE's capa framework", + "license": "Apache-2.0", + "categories": [ + "malware-analysis", + "api-scripting-and-automation", + "ui-ux-and-visualization" + ], + "pythonDependencies": ["flare-capa==9.2.1"], + "urls": { + "repository": "https://github.com/mandiant/capa" + }, + "authors": [ + {"name": "Willi Ballenthin", "email": "wballenthin@hex-rays.com"}, + {"name": "Moritz Raabe", "email": "moritzraabe@google.com"}, + {"name": "Mike Hunhoff", "email": "mike.hunhoff@gmail.com"}, + {"name": "Yacine Elhamer", "email": "elhamer.yacine@gmail.com"} + ], + "keywords": [ + "capability-detection", + "malware-analysis", + "behavior-analysis", + "reverse-engineering", + "att&ck", + "rule-engine", + "feature-extraction", + "yara-like-rules", + "static-analysis", + "dynamic-analysis" + ] + } +} diff --git a/doc/release.md b/doc/release.md index 6d85290079..3b8242a5db 100644 --- a/doc/release.md +++ b/doc/release.md @@ -7,6 +7,7 @@ - [ ] Review changes - capa https://github.com/mandiant/capa/compare/\...master - capa-rules https://github.com/mandiant/capa-rules/compare/\\...master +- [ ] Run `$ bump-my-version bump {patch/minor/major} [--allow-dirty]` to update [capa/version.py](https://github.com/mandiant/capa/blob/master/capa/version.py) and other version files - [ ] Update [CHANGELOG.md](https://github.com/mandiant/capa/blob/master/CHANGELOG.md) - Do not forget to add a nice introduction thanking contributors - Remember that we need a major release if we introduce breaking changes @@ -36,7 +37,6 @@ - [capa ...master](https://github.com/mandiant/capa/compare/...master) - [capa-rules ...master](https://github.com/mandiant/capa-rules/compare/...master) ``` -- [ ] Update [capa/version.py](https://github.com/mandiant/capa/blob/master/capa/version.py) - [ ] Create a PR with the updated [CHANGELOG.md](https://github.com/mandiant/capa/blob/master/CHANGELOG.md) and [capa/version.py](https://github.com/mandiant/capa/blob/master/capa/version.py). Copy this checklist in the PR description. - [ ] Update the [homepage](https://github.com/mandiant/capa/blob/master/web/public/index.html) (i.e. What's New section) - [ ] After PR review, merge the PR and [create the release in GH](https://github.com/mandiant/capa/releases/new) using text from the [CHANGELOG.md](https://github.com/mandiant/capa/blob/master/CHANGELOG.md). diff --git a/pyproject.toml b/pyproject.toml index c2fcbac4a4..69bb10c248 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,6 +142,7 @@ dev = [ "mypy==1.17.1", "mypy-protobuf==3.6.0", "PyGithub==2.6.0", + "bump-my-version==1.2.4", # type stubs for mypy "types-backports==0.1.3", "types-colorama==0.4.15.11", @@ -205,6 +206,7 @@ known_first_party = [ DEP002 = [ "black", "build", + "bump-my-version", "deptry", "flake8", "flake8-bugbear", diff --git a/requirements.txt b/requirements.txt index b6d78ae1fb..0d0dd2177b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -45,3 +45,4 @@ sortedcontainers==2.4.0 viv-utils==0.8.0 vivisect==1.2.1 msgspec==0.19.0 +bump-my-version==1.2.4 From 8d697207dec8adc2c76bb2c513cbef5479b82e95 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 3 Nov 2025 12:50:49 +0100 Subject: [PATCH 17/17] qt_compat: use __all__ rather than noqa --- capa/ida/plugin/qt_compat.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/capa/ida/plugin/qt_compat.py b/capa/ida/plugin/qt_compat.py index 7729548212..7b3858a719 100644 --- a/capa/ida/plugin/qt_compat.py +++ b/capa/ida/plugin/qt_compat.py @@ -22,16 +22,16 @@ try: # IDA 9.2+ uses PySide6 - from PySide6 import QtGui, QtCore, QtWidgets # noqa: F401 - from PySide6.QtGui import QAction # noqa: F401 + from PySide6 import QtGui, QtCore, QtWidgets + from PySide6.QtGui import QAction QT_LIBRARY = "PySide6" Signal = QtCore.Signal except ImportError: # Older IDA versions use PyQt5 try: - from PyQt5 import QtGui, QtCore, QtWidgets # noqa: F401 - from PyQt5.QtWidgets import QAction # noqa: F401 + from PyQt5 import QtGui, QtCore, QtWidgets + from PyQt5.QtWidgets import QAction QT_LIBRARY = "PyQt5" Signal = QtCore.pyqtSignal @@ -74,3 +74,6 @@ def qt_get_item_flag_tristate(): else: # Qt5: Use the original ItemIsTristate flag return Qt.ItemIsTristate + + +__all__ = ["qt_get_item_flag_tristate", "Signal", "QAction", "QtGui", "QtCore", "QtWidgets"]