Skip to content

Commit d226573

Browse files
committed
idalib: simplify discovery to ida-config.json only, improve error guidance
Remove the .desktop entry fallback for locating IDA installations. As IDA's tooling has matured, ida-config.json (created by py-activate-idalib.py) is the canonical way to locate idalib; additional discovery heuristics are no longer needed. When ida-config.json is missing or misconfigured, the error messages now tell the user exactly which file was expected and how to create it (by running the idalib activation script). Also extract _get_install_dir_from_config() and _locate_idalib_in_install_dir() from find_idalib() for clarity, add robust error handling for corrupt/unreadable config files, and fix a pre-existing mypy type error with os.getenv("APPDATA"). Fixes #2412.
1 parent cbe005a commit d226573

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
- ghidra: support PyGhidra @mike-hunhoff #2788
88
- vmray: extract number features from whitelisted void_ptr parameters (hKey, hKeyRoot) @adeboyedn #2835
9+
- idalib: improve error guidance when ida-config.json is missing or misconfigured @devs6186 #2412
910

1011
### Breaking Changes
1112

capa/features/extractors/ida/idalib.py

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
logger = logging.getLogger(__name__)
2424

25+
# The idalib activation script shipped with IDA creates ida-config.json.
26+
IDALIB_ACTIVATION_SCRIPT = "python3 <ida-install-dir>/idalib/python/py-activate-idalib.py"
27+
2528

2629
def is_idalib_installed() -> bool:
2730
try:
@@ -31,39 +34,45 @@ def is_idalib_installed() -> bool:
3134

3235

3336
def get_idalib_user_config_path() -> Optional[Path]:
34-
"""Get the path to the user's config file based on platform following IDA's user directories."""
37+
"""Get the path to the user's ida-config.json based on platform following IDA's user directories."""
3538
# derived from `py-activate-idalib.py` from IDA v9.0 Beta 4
3639

3740
if sys.platform == "win32":
3841
# On Windows, use the %APPDATA%\Hex-Rays\IDA Pro directory
39-
config_dir = Path(os.getenv("APPDATA")) / "Hex-Rays" / "IDA Pro"
42+
appdata = os.getenv("APPDATA", "")
43+
config_dir = Path(appdata) / "Hex-Rays" / "IDA Pro"
4044
else:
4145
# On macOS and Linux, use ~/.idapro
4246
config_dir = Path.home() / ".idapro"
4347

44-
# Return the full path to the config file (now in JSON format)
4548
user_config_path = config_dir / "ida-config.json"
4649
if not user_config_path.exists():
4750
return None
4851
return user_config_path
4952

5053

51-
def find_idalib() -> Optional[Path]:
52-
config_path = get_idalib_user_config_path()
53-
if not config_path:
54-
logger.error("IDA Pro user configuration does not exist, please make sure you've installed idalib properly.")
54+
def _get_install_dir_from_config(config_path: Path) -> Optional[Path]:
55+
"""Read the ida-install-dir from the idalib JSON config."""
56+
try:
57+
config = json.loads(config_path.read_text(encoding="utf-8"))
58+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as e:
59+
logger.error("failed to read IDA Pro user configuration %s: %s", config_path, e)
5560
return None
5661

57-
config = json.loads(config_path.read_text(encoding="utf-8"))
58-
5962
try:
60-
ida_install_dir = Path(config["Paths"]["ida-install-dir"])
63+
return Path(config["Paths"]["ida-install-dir"])
6164
except KeyError:
6265
logger.error(
63-
"IDA Pro user configuration does not contain location of IDA Pro installation, please make sure you've installed idalib properly."
66+
"%s does not contain Paths.ida-install-dir. " # noqa: G003 [logging statement uses +]
67+
+ "Re-run the idalib activation script to regenerate it: %s",
68+
config_path,
69+
IDALIB_ACTIVATION_SCRIPT,
6470
)
6571
return None
6672

73+
74+
def _locate_idalib_in_install_dir(ida_install_dir: Path) -> Optional[Path]:
75+
"""Given an IDA installation directory, verify it contains idalib and return the Python path."""
6776
if not ida_install_dir.exists():
6877
return None
6978

@@ -90,6 +99,38 @@ def find_idalib() -> Optional[Path]:
9099
return idalib_path
91100

92101

102+
def find_idalib() -> Optional[Path]:
103+
config_path = get_idalib_user_config_path()
104+
if not config_path:
105+
if sys.platform == "win32":
106+
config_location = "%APPDATA%\\Hex-Rays\\IDA Pro\\ida-config.json"
107+
else:
108+
config_location = "~/.idapro/ida-config.json"
109+
logger.error(
110+
"IDA Pro user configuration not found at %s. " # noqa: G003 [logging statement uses +]
111+
+ "To set up idalib, run the activation script: %s",
112+
config_location,
113+
IDALIB_ACTIVATION_SCRIPT,
114+
)
115+
return None
116+
117+
ida_install_dir = _get_install_dir_from_config(config_path)
118+
if not ida_install_dir:
119+
return None
120+
121+
idalib_path = _locate_idalib_in_install_dir(ida_install_dir)
122+
if not idalib_path:
123+
logger.error(
124+
"idalib not found in IDA installation at %s. " # noqa: G003 [logging statement uses +]
125+
+ "Ensure idalib is set up by running: %s",
126+
ida_install_dir,
127+
IDALIB_ACTIVATION_SCRIPT,
128+
)
129+
return None
130+
131+
return idalib_path
132+
133+
93134
def has_idalib() -> bool:
94135
if is_idalib_installed():
95136
logger.debug("found installed IDA idalib API")

0 commit comments

Comments
 (0)