Capa can't find libbinaryninja.so.1
When running capa (latest release) against binja dev release (8539), it gives me this:
❯ capa -d -b binja -j -r ~/opt/capa/rules/ /media/user/Transfer/BinaryNinjaProjects/ltat.bnpr/data/3b/303e9b-2b2a-4526-8f32-a8ef2b584af9
DEBUG capa: using rules path: /home/user/opt/capa/rules main.py:505
DEBUG capa.rules: reading rules from directory /home/user/opt/capa/rules __init__.py:2167
DEBUG capa.rules.cache: loading rule set from cache: /home/user/.cache/capa/capa-d1b89394.cache cache.py:157
DEBUG capa: successfully loaded 996 rules main.py:693
DEBUG capa.capabilities.common: analyzed file and extracted 1092 features common.py:53
DEBUG capa: skipping library code matching: only supported by the vivisect backend main.py:817
DEBUG capa: format: pe main.py:867
DEBUG capa: backend: binja main.py:868
DEBUG capa.features.extractors.binja.find_binja_api: Binary Ninja API not installed, searching... find_binja_api.py:156
DEBUG capa.features.extractors.binja.find_binja_api: detected OS: linux find_binja_api.py:112
DEBUG capa.features.extractors.binja.find_binja_api: found Binary Ninja application: /home/user/.local/share/applications/com.vector35.binaryninja.desktop find_binja_api.py:127
DEBUG capa.features.extractors.binja.find_binja_api: found Binary Ninja installation: /home/user/opt/binaryninja find_binja_api.py:138
DEBUG capa.features.extractors.binja.find_binja_api: found Binary Ninja API: /home/user/opt/binaryninja/python find_binja_api.py:162
DEBUG capa.features.extractors.binja.find_binja_api: detected OS: linux find_binja_api.py:112
DEBUG capa.features.extractors.binja.find_binja_api: found Binary Ninja application: /home/user/.local/share/applications/com.vector35.binaryninja.desktop find_binja_api.py:127
DEBUG capa.features.extractors.binja.find_binja_api: found Binary Ninja installation: /home/user/opt/binaryninja find_binja_api.py:138
Traceback (most recent call last):
File "features/extractors/binja/find_binja_api.py", line 168, in load_binaryninja
ModuleNotFoundError: No module named 'binaryninja'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "PyInstaller/loader/pyimod03_ctypes.py", line 53, in __init__
File "ctypes/__init__.py", line 374, in __init__
OSError: /home/user/opt/binaryninja/python/binaryninja/../../libbinaryninjacore.so.1: cannot enable executable stack as shared object requires: Invalid argument
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "main.py", line 1149, in <module>
File "main.py", line 1033, in main
File "main.py", line 871, in get_extractor_from_cli
File "loader.py", line 256, in get_extractor
File "features/extractors/binja/find_binja_api.py", line 178, in load_binaryninja
File "/home/user/opt/binaryninja/python/binaryninja/__init__.py", line 30, in <module>
import binaryninja._binaryninjacore as core
File "/home/user/opt/binaryninja/python/binaryninja/_binaryninjacore.py", line 15, in <module>
core = ctypes.CDLL(os.path.join(_base_path, "libbinaryninjacore.so.1"))
File "PyInstaller/loader/pyimod03_ctypes.py", line 55, in __init__
PYI
[pyimod03_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll '/home/user/opt/binaryninja/python/binaryninja/../../libbinaryninjacore.so.1'. Most likely this dynlib/dll was not found when the application was frozen.-159804:ERROR] Failed to execute script 'main' due to unhandled exception!
~
❯ ls -asl /home/user/opt/binaryninja/python/binaryninja/../../libbinaryninjacore.so.1
202844 -rwxrwxr-x 1 user user 207707768 Oct 31 15:27 /home/user/opt/binaryninja/python/binaryninja/../../libbinaryninjacore.so.1
See (at the bottom of the snippet) where I also ls the file it said it could not load and it exists.
@xusheng6
Interesting, I'm surprised we haven't noticed this before.
Seems that PyInstaller tries to prevent loading DLLs not packaged into the frozen project: https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Win-Load-External-DLL (Windows-only, but I wonder if they've done something similar for Linux/macOS).
In the short term, you could use capa distributed via PyPI, though I recognize this is not as convenient as the standalone binary.
This probably also affects the idalib backend.
I think its happening here: https://github.com/rokm/pyinstaller/blob/23b54eb155cea501fda0b1c7cf247907b518d14a/PyInstaller/loader/pyimod03_ctypes.py#L57
PyInstaller hooks ctypes to ensure that it loads shared objects only from the packaged program. I suppose we could override/unhook this behavior once capa starts executing.
Hmmm this is also unexpected. Full disclosure I wrote that code but I have always used capa in development mode so I never really used the standalone binary. But from my vague impression it should have worked at least when I initially wrote it