From 9ba497f6f727791ca30fdd4daefb2244a985980e Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 11 May 2026 08:52:47 +0200 Subject: [PATCH] idalib: remove custom idalib loading --- capa/features/extractors/ida/idalib.py | 99 -------------------------- capa/loader.py | 7 +- scripts/detect-backends.py | 11 ++- tests/fixtures.py | 7 +- tests/test_idalib_features.py | 30 ++++---- 5 files changed, 25 insertions(+), 129 deletions(-) diff --git a/capa/features/extractors/ida/idalib.py b/capa/features/extractors/ida/idalib.py index 44c96d6d..53ff573f 100644 --- a/capa/features/extractors/ida/idalib.py +++ b/capa/features/extractors/ida/idalib.py @@ -12,13 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import sys -import json import logging import importlib.util -from typing import Optional -from pathlib import Path logger = logging.getLogger(__name__) @@ -28,97 +23,3 @@ def is_idalib_installed() -> bool: return importlib.util.find_spec("idapro") is not None except ModuleNotFoundError: return False - - -def get_idalib_user_config_path() -> Optional[Path]: - """Get the path to the user's config file based on platform following IDA's user directories.""" - # derived from `py-activate-idalib.py` from IDA v9.0 Beta 4 - - if sys.platform == "win32": - # On Windows, use the %APPDATA%\Hex-Rays\IDA Pro directory - config_dir = Path(os.getenv("APPDATA")) / "Hex-Rays" / "IDA Pro" - else: - # On macOS and Linux, use ~/.idapro - config_dir = Path.home() / ".idapro" - - # Return the full path to the config file (now in JSON format) - user_config_path = config_dir / "ida-config.json" - if not user_config_path.exists(): - return None - return user_config_path - - -def find_idalib() -> Optional[Path]: - config_path = get_idalib_user_config_path() - if not config_path: - logger.error("IDA Pro user configuration does not exist, please make sure you've installed idalib properly.") - return None - - config = json.loads(config_path.read_text(encoding="utf-8")) - - try: - ida_install_dir = Path(config["Paths"]["ida-install-dir"]) - except KeyError: - logger.error( - "IDA Pro user configuration does not contain location of IDA Pro installation, please make sure you've installed idalib properly." - ) - return None - - if not ida_install_dir.exists(): - return None - - libname = { - "win32": "idalib.dll", - "linux": "libidalib.so", - "linux2": "libidalib.so", - "darwin": "libidalib.dylib", - }[sys.platform] - - if not (ida_install_dir / "ida.hlp").is_file(): - return None - - if not (ida_install_dir / libname).is_file(): - return None - - idalib_path = ida_install_dir / "idalib" / "python" - if not idalib_path.exists(): - return None - - if not (idalib_path / "idapro" / "__init__.py").is_file(): - return None - - return idalib_path - - -def has_idalib() -> bool: - if is_idalib_installed(): - logger.debug("found installed IDA idalib API") - return True - - logger.debug("IDA idalib API not installed, searching...") - - idalib_path = find_idalib() - if not idalib_path: - logger.debug("failed to find IDA idalib installation") - - logger.debug("found IDA idalib API: %s", idalib_path) - return idalib_path is not None - - -def load_idalib() -> bool: - try: - import idapro - - return True - except ImportError: - idalib_path = find_idalib() - if not idalib_path: - return False - - sys.path.append(idalib_path.absolute().as_posix()) - try: - import idapro # noqa: F401 unused import - - return True - except ImportError: - return False diff --git a/capa/loader.py b/capa/loader.py index 344f7929..f12ba45d 100644 --- a/capa/loader.py +++ b/capa/loader.py @@ -386,11 +386,8 @@ def get_extractor( elif backend == BACKEND_IDA: import capa.features.extractors.ida.idalib as idalib - if not idalib.has_idalib(): - raise RuntimeError("cannot find IDA idalib module.") - - if not idalib.load_idalib(): - raise RuntimeError("failed to load IDA idalib module.") + if not idalib.is_idalib_installed(): + raise RuntimeError("idalib not available.") import idapro import ida_auto diff --git a/scripts/detect-backends.py b/scripts/detect-backends.py index 05932891..ebe7189f 100644 --- a/scripts/detect-backends.py +++ b/scripts/detect-backends.py @@ -22,7 +22,7 @@ import rich import rich.table import capa.main -from capa.features.extractors.ida.idalib import find_idalib, load_idalib, is_idalib_installed +from capa.features.extractors.ida.idalib import is_idalib_installed from capa.features.extractors.binja.find_binja_api import find_binaryninja, load_binaryninja, is_binaryninja_installed logger = logging.getLogger(__name__) @@ -101,9 +101,14 @@ def main(argv=None): row.append("-") else: row.append("False") - row.append(str(find_idalib() is not None)) + row.append("False") - row.append(str(load_idalib())) + does_idalib_load = False + try: + import idapro # noqa: F401 [imported but unused] + except ImportError: + does_idalib_load = True + row.append(str(does_idalib_load)) table.add_row(*row) rich.print(table) diff --git a/tests/fixtures.py b/tests/fixtures.py index 2edac7be..3396644b 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -894,11 +894,8 @@ def get_idalib_extractor(path: Path): import capa.features.extractors.ida.idalib as idalib import capa.features.extractors.ida.extractor - if not idalib.has_idalib(): - raise RuntimeError("cannot find IDA idalib module.") - - if not idalib.load_idalib(): - raise RuntimeError("failed to load IDA idalib module.") + if not idalib.is_idalib_installed(): + raise RuntimeError("idalib is not available.") _check_stale_idalib_files(path) diff --git a/tests/test_idalib_features.py b/tests/test_idalib_features.py index 855cc396..7e70c9b2 100644 --- a/tests/test_idalib_features.py +++ b/tests/test_idalib_features.py @@ -16,30 +16,26 @@ import logging import pytest import fixtures -import capa.features.extractors.ida.idalib as idalib from capa.features.file import FunctionName from capa.features.insn import API from capa.features.common import Characteristic logger = logging.getLogger(__name__) -idalib_present = idalib.has_idalib() -if idalib_present: - try: - if True: - # in order to use idalib, we have to import the idapro package - # which manipulates the search path as a side effect. - # we have to do this before importing ida_* packages. - # but isort wants to put idapro after ida_kernwin, so we use - # this dumb branch to keep the ordering correct. - import idapro # noqa: F401 [imported but unused] - import ida_kernwin +try: + if True: + # in order to use idalib, we have to import the idapro package + # which manipulates the search path as a side effect. + # we have to do this before importing ida_* packages. + # but isort wants to put idapro after ida_kernwin, so we use + # this dumb branch to keep the ordering correct. + import idapro # noqa: F401 [imported but unused] + import ida_kernwin - kernel_version: str = ida_kernwin.get_kernel_version() - except ImportError: - idalib_present = False - kernel_version = "0.0" -else: + kernel_version: str = ida_kernwin.get_kernel_version() + idalib_present = True +except ImportError: + idalib_present = False kernel_version = "0.0"