summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py60
-rw-r--r--python/binaryview.py20
-rw-r--r--python/downloadprovider.py7
-rw-r--r--python/generator.cpp7
-rw-r--r--python/pluginmanager.py284
5 files changed, 147 insertions, 231 deletions
diff --git a/python/__init__.py b/python/__init__.py
index bdc6bdd7..f572bdef 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -24,7 +24,7 @@ import atexit
import sys
import ctypes
from time import gmtime
-
+import os
# 2-3 compatibility
PY2 = sys.version_info[0] == 2
@@ -92,37 +92,7 @@ def pyNativeStr(arg):
# Binary Ninja components
import binaryninja._binaryninjacore as core
-# __all__ = [
-# "enums",
-# "databuffer",
-# "filemetadata",
-# "fileaccessor",
-# "binaryview",
-# "transform",
-# "architecture",
-# "basicblock",
-# "function",
-# "log",
-# "lowlevelil",
-# "mediumlevelil",
-# "types",
-# "functionrecognizer",
-# "update",
-# "plugin",
-# "callingconvention",
-# "platform",
-# "demangle",
-# "mainthread",
-# "interaction",
-# "lineardisassembly",
-# "undoaction",
-# "highlight",
-# "scriptingprovider",
-# "pluginmanager",
-# "setting",
-# "metadata",
-# "flowgraph",
-# ]
+
from binaryninja.enums import *
from binaryninja.databuffer import *
from binaryninja.filemetadata import *
@@ -179,34 +149,42 @@ def get_install_directory():
return core.BNGetInstallDirectory()
-_plugin_api_name = "python2"
+_plugin_api_name = "python{}".format(sys.version_info.major)
class PluginManagerLoadPluginCallback(object):
- """Callback for BNLoadPluginForApi("python2", ...), dynamically loads python plugins."""
+ """Callback for BNLoadPluginForApi("python{version}", ...), dynamically loads python plugins."""
def __init__(self):
self.cb = ctypes.CFUNCTYPE(
ctypes.c_bool,
ctypes.c_char_p,
ctypes.c_char_p,
+ ctypes.c_bool,
ctypes.c_void_p)(self._load_plugin)
- def _load_plugin(self, repo_path, plugin_path, ctx):
+ def _load_plugin(self, repo_path, plugin_path, force, ctx):
try:
+ repo_path = repo_path.decode("utf-8")
+ plugin_path = plugin_path.decode("utf-8")
repo = RepositoryManager()[repo_path]
plugin = repo[plugin_path]
- if plugin.api != _plugin_api_name:
+ if not force and _plugin_api_name not in plugin.api:
raise ValueError("Plugin API name is not " + _plugin_api_name)
+ if not force and core.core_platform not in plugin.install_platforms:
+ raise ValueError("Current platform {} ins't in list of valid platforms for this plugin {}".format(
+ core.core_platform, plugin.install_platforms))
if not plugin.installed:
plugin.installed = True
+ plugin_full_path = os.path.join(repo.full_path, plugin.path)
if repo.full_path not in sys.path:
sys.path.append(repo.full_path)
+ if plugin_full_path not in sys.path:
+ sys.path.append(plugin_full_path)
- __import__(plugin.path)
- log_info("Successfully loaded plugin: {}/{}: ".format(repo_path, plugin_path))
+ __import__(plugin_path)
return True
except KeyError:
log_error("Failed to find python plugin: {}/{}".format(repo_path, plugin_path))
@@ -284,12 +262,12 @@ def core_version():
def core_build_id():
"""
- ``core_build_id`` returns a string containing the current build id
+ ``core_build_id`` returns a integer containing the current build id
:return: current build id
- :rtype: str, or None on failure
+ :rtype: int
"""
- core.BNGetBuildId()
+ return core.BNGetBuildId()
def core_serial():
"""
diff --git a/python/binaryview.py b/python/binaryview.py
index 4ffe197e..4f146adc 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -645,7 +645,8 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
:rtype: BinaryView or None
"""
sqlite = b"SQLite format 3"
- if filename.endswith(".bndb"):
+ isDatabase = filename.endswith(".bndb")
+ if isDatabase:
f = open(filename, 'rb')
if f is None or f.read(len(sqlite)) != sqlite:
return None
@@ -658,18 +659,21 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)):
return None
for available in view.available_view_types:
if available.name != "Raw":
- if filename.endswith(".bndb"):
+ if isDatabase:
bv = view.get_view_of_type(available.name)
else:
bv = cls[available.name].open(filename)
+ break
+ else:
+ if isDatabase:
+ bv = view.get_view_of_type("Raw")
+ else:
+ bv = cls["Raw"].open(filename)
- if bv is None:
- raise Exception("Unknown Architecture/Architecture Not Found (check plugins folder)")
+ if bv is not None and update_analysis:
+ bv.update_analysis_and_wait()
+ return bv
- if update_analysis:
- bv.update_analysis_and_wait()
- return bv
- return None
def is_valid_for_data(self, data):
return core.BNIsBinaryViewTypeValidForData(self.handle, data.handle)
diff --git a/python/downloadprovider.py b/python/downloadprovider.py
index 8d3718b9..27f007ff 100644
--- a/python/downloadprovider.py
+++ b/python/downloadprovider.py
@@ -79,9 +79,6 @@ class DownloadInstance(object):
def perform_request(self, ctxt, url):
raise NotImplementedError
- def perform_request(self, url, callbacks):
- return core.BNPerformDownloadRequest(self.handle, url, callbacks)
-
class _DownloadProviderMetaclass(type):
@property
@@ -165,11 +162,9 @@ if (sys.platform != "win32") and (sys.version_info >= (2, 7, 9)):
def __init__(self, provider):
super(PythonDownloadInstance, self).__init__(provider)
- @abc.abstractmethod
def perform_destroy_instance(self):
pass
- @abc.abstractmethod
def perform_request(self, url):
try:
proxy_setting = Settings().get_string('downloadClient.httpsProxy')
@@ -223,11 +218,9 @@ else:
def __init__(self, provider):
super(PythonDownloadInstance, self).__init__(provider)
- @abc.abstractmethod
def perform_destroy_instance(self):
pass
- @abc.abstractmethod
def perform_request(self, url):
try:
proxy_setting = Settings().get_string('downloadClient.httpsProxy')
diff --git a/python/generator.cpp b/python/generator.cpp
index dbb44253..8186647a 100644
--- a/python/generator.cpp
+++ b/python/generator.cpp
@@ -188,13 +188,14 @@ int main(int argc, char* argv[])
fprintf(out, "import platform\n");
fprintf(out, "core = None\n");
fprintf(out, "_base_path = None\n");
- fprintf(out, "if platform.system() == \"Darwin\":\n");
+ fprintf(out, "core_platform = platform.system()\n");
+ fprintf(out, "if core_platform == \"Darwin\":\n");
fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\", \"..\", \"MacOS\")\n");
fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.dylib\"))\n\n");
- fprintf(out, "elif platform.system() == \"Linux\":\n");
+ fprintf(out, "elif core_platform == \"Linux\":\n");
fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n");
fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"libbinaryninjacore.so.1\"))\n\n");
- fprintf(out, "elif platform.system() == \"Windows\":\n");
+ fprintf(out, "elif core_platform == \"Windows\":\n");
fprintf(out, "\t_base_path = os.path.join(os.path.dirname(__file__), \"..\", \"..\")\n");
fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"binaryninjacore.dll\"))\n");
fprintf(out, "else:\n");
diff --git a/python/pluginmanager.py b/python/pluginmanager.py
index 3f75d68b..73fe0db6 100644
--- a/python/pluginmanager.py
+++ b/python/pluginmanager.py
@@ -19,10 +19,13 @@
# IN THE SOFTWARE.
import ctypes
+import json
+from datetime import datetime
# Binary Ninja components
+import binaryninja
from binaryninja import _binaryninjacore as core
-
+from binaryninja.enums import PluginType, PluginStatus
# 2-3 compatibility
from binaryninja import range
@@ -32,9 +35,7 @@ class RepoPlugin(object):
``RepoPlugin` is mostly read-only, however you can install/uninstall enable/disable plugins. RepoPlugins are
created by parsing the plugins.json in a plugin repository.
"""
- from binaryninja.enums import PluginType, PluginUpdateStatus
def __init__(self, handle):
- raise Exception("RepoPlugin temporarily disabled!")
self.handle = core.handle_of_type(handle, core.BNRepoPlugin)
def __del__(self):
@@ -68,14 +69,29 @@ class RepoPlugin(object):
@enabled.setter
def enabled(self, state):
if state:
- return core.BNPluginEnable(self.handle)
+ return core.BNPluginEnable(self.handle, False)
else:
return core.BNPluginDisable(self.handle)
+ def enable(self, force=False):
+ """
+ Enable this plugin, optionally trying to force it.
+ Force loading a plugin with ignore platform and api constraints.
+ (e.g. The plugin author says the plugin will only work on Linux-python3 but you'd like to
+ attempt to load it on Macos-python2)
+ """
+ return core.BNPluginEnable(self.handle, force)
+
@property
def api(self):
"""string indicating the API used by the plugin"""
- return core.BNPluginGetApi(self.handle)
+ result = []
+ count = ctypes.c_ulonglong(0)
+ platforms = core.BNPluginGetApis(self.handle, count)
+ for i in range(count.value):
+ result.append(platforms[i])
+ core.BNFreePluginPlatforms(platforms, count)
+ return result
@property
def description(self):
@@ -100,7 +116,7 @@ class RepoPlugin(object):
@property
def minimum_version(self):
"""String minimum version the plugin was tested on"""
- return core.BNPluginGetMinimimVersions(self.handle)
+ return core.BNPluginGetMinimimVersion(self.handle)
@property
def name(self):
@@ -119,34 +135,109 @@ class RepoPlugin(object):
return result
@property
- def url(self):
+ def project_url(self):
"""String URL of the plugin's git repository"""
- return core.BNPluginGetUrl(self.handle)
+ return core.BNPluginGetProjectUrl(self.handle)
+
+ @property
+ def package_url(self):
+ """String URL of the plugin's zip file"""
+ return core.BNPluginGetPackageUrl(self.handle)
+
+ @property
+ def author_url(self):
+ """String URL of the plugin author's url"""
+ return core.BNPluginGetAuthorUrl(self.handle)
+
+ @property
+ def author(self):
+ """String of the plugin author"""
+ return core.BNPluginGetAuthor(self.handle)
@property
def version(self):
"""String version of the plugin"""
return core.BNPluginGetVersion(self.handle)
+
+ def install_instructions(self, platform):
+ """
+ Installation instructions for the given platform
+
+ :param str platform: One of the valid platforms "Windows", "Linux", "Darwin"
+ :return: String of the installation instructions for the provided platform
+ :rtype: str
+ """
+ return core.BNPluginGetInstallInstructions(self.handle, platform)
+
@property
- def update_status(self):
- """PluginUpdateStatus enumeration indicating if the plugin is up to date or not"""
- return PluginUpdateStatus(core.BNPluginGetPluginUpdateStatus(self.handle))
+ def install_platforms(self):
+ """List of platforms this plugin can execute on"""
+ result = []
+ count = ctypes.c_ulonglong(0)
+ platforms = core.BNPluginGetPlatforms(self.handle, count)
+ for i in range(count.value):
+ result.append(platforms[i])
+ core.BNFreePluginPlatforms(platforms, count)
+ return result
+ @property
+ def being_deleted(self):
+ """Boolean status indicating that the plugin is being deleted"""
+ return core.BNPluginIsBeingDeleted(self.handle)
+
+ @property
+ def being_updated(self):
+ """Boolean status indicating that the plugin is being updated"""
+ return core.BNPluginIsBeingUpdated(self.handle)
+
+ @property
+ def running(self):
+ """Boolean status indicating that the plugin is currently running"""
+ return core.BNPluginIsRunning(self.handle)
+
+ @property
+ def update_pending(self):
+ """Boolean status indicating that the plugin has updates will be installed after the next restart"""
+ return core.BNPluginIsUpdatePending(self.handle)
+
+ @property
+ def disable_pending(self):
+ """Boolean status indicating that the plugin will be disabled after the next restart"""
+ return core.BNPluginIsDisablePending(self.handle)
+
+ @property
+ def delete_pending(self):
+ """Boolean status indicating that the plugin will be deleted after the next restart"""
+ return core.BNPluginIsDeletePending(self.handle)
+
+ @property
+ def update_available(self):
+ """Boolean status indicating that the plugin has updates available"""
+ return core.BNPluginIsUpdateAvailable(self.handle)
+
+ @property
+ def project_data(self):
+ """Gets a json object of the project data field"""
+ return json.loads(core.BNPluginGetProjectData(self.handle))
+
+ @property
+ def last_update(self):
+ """Returns a datetime object representing the plugins last update"""
+ return datetime.fromtimestamp(core.BNPluginGetLastUpdate(self.handle))
class Repository(object):
"""
``Repository`` is a read-only class. Use RepositoryManager to Enable/Disable/Install/Uninstall plugins.
"""
def __init__(self, handle):
- raise Exception("Repository temporarily disabled!")
self.handle = core.handle_of_type(handle, core.BNRepository)
def __del__(self):
core.BNFreeRepository(self.handle)
def __repr__(self):
- return "<{} - {}/{}>".format(self.path, self.remote_reference, self.local_reference)
+ return "<{}>".format(self.path)
def __getitem__(self, plugin_path):
for plugin in self.plugins:
@@ -170,32 +261,17 @@ class Repository(object):
return core.BNRepositoryGetPluginsPath(self.handle)
@property
- def local_reference(self):
- """String for the local git reference (ie 'master')"""
- return core.BNRepositoryGetLocalReference(self.handle)
-
- @property
- def remote_reference(self):
- """String for the remote git reference (ie 'origin')"""
- return core.BNRepositoryGetRemoteReference(self.handle)
-
- @property
def plugins(self):
"""List of RepoPlugin objects contained within this repository"""
pluginlist = []
count = ctypes.c_ulonglong(0)
result = core.BNRepositoryGetPlugins(self.handle, count)
for i in range(count.value):
- pluginlist.append(RepoPlugin(handle=result[i]))
+ pluginlist.append(RepoPlugin(core.BNNewPluginReference(result[i])))
core.BNFreeRepositoryPluginList(result, count.value)
del result
return pluginlist
- @property
- def initialized(self):
- """Boolean True when the repository has been initialized"""
- return core.BNRepositoryIsInitialized(self.handle)
-
class RepositoryManager(object):
"""
@@ -203,7 +279,6 @@ class RepositoryManager(object):
the plugins that are installed/uninstalled enabled/disabled
"""
def __init__(self, handle=None):
- raise Exception("RepositoryManager temporarily disabled!")
self.handle = core.BNGetRepositoryManager()
def __getitem__(self, repo_path):
@@ -223,7 +298,7 @@ class RepositoryManager(object):
count = ctypes.c_ulonglong(0)
repos = core.BNRepositoryManagerGetRepositories(self.handle, count)
for i in range(count.value):
- result.append(Repository(handle=repos[i]))
+ result.append(Repository(core.BNNewRepositoryReference(repos[i])))
core.BNFreeRepositoryManagerRepositoriesList(repos)
return result
@@ -239,160 +314,25 @@ class RepositoryManager(object):
def default_repository(self):
"""Gets the default Repository"""
binaryninja._init_plugins()
- return Repository(handle=core.BNRepositoryManagerGetDefaultRepository(self.handle))
-
- def enable_plugin(self, plugin, install=True, repo=None):
- """
- ``enable_plugin`` Enables the installed plugin 'plugin', optionally installing the plugin if `install` is set to
- True (default), and optionally using the non-default repository.
+ return Repository(core.BNNewRepositoryReference(core.BNRepositoryManagerGetDefaultRepository(self.handle)))
- :param str name: Name of the plugin to enable
- :param Boolean install: Optionally install the repo, defaults to True.
- :param str repo: Optional, specify a repository other than the default repository.
- :return: Boolean value True if the plugin was successfully enabled, False otherwise
- :rtype: Boolean
- :Example:
-
- >>> mgr = RepositoryManager()
- >>> mgr.enable_plugin('binaryninja-bookmarks')
- True
- >>>
- """
- if install:
- if not self.install_plugin(plugin, repo):
- return False
-
- if repo is None:
- repo = self.default_repository
- repopath = repo
- pluginpath = plugin
- if not isinstance(repo, str):
- repopath = repo.path
- if not isinstance(plugin, str):
- pluginpath = plugin.path
- return core.BNRepositoryManagerEnablePlugin(self.handle, repopath, pluginpath)
-
- def disable_plugin(self, plugin, repo=None):
- """
- ``disable_plugin`` Disable the specified plugin, pluginpath
-
- :param Repository or str repo: Repository containing the plugin to disable
- :param RepoPlugin or str plugin: RepoPlugin to disable
- :return: Boolean value True if the plugin was successfully disabled, False otherwise
- :rtype: Boolean
- :Example:
-
- >>> mgr = RepositoryManager()
- >>> mgr.disable_plugin('binaryninja-bookmarks')
- True
- >>>
- """
- if repo is None:
- repo = self.default_repository
- repopath = repo
- pluginpath = plugin
- if not isinstance(repo, str):
- repopath = repo.path
- if not isinstance(plugin, str):
- pluginpath = plugin.path
- return core.BNRepositoryManagerDisablePlugin(self.handle, repopath, pluginpath)
-
- def install_plugin(self, plugin, repo=None):
- """
- ``install_plugin`` install the specified plugin, pluginpath
-
- :param Repository or str repo: Repository containing the plugin to install
- :param RepoPlugin or str plugin: RepoPlugin to install
- :return: Boolean value True if the plugin was successfully installed, False otherwise
- :rtype: Boolean
- :Example:
-
- >>> mgr = RepositoryManager()
- >>> mgr.install_plugin('binaryninja-bookmarks')
- True
- >>>
- """
- if repo is None:
- repo = self.default_repository
- repopath = repo
- pluginpath = plugin
- if not isinstance(repo, str):
- repopath = repo.path
- if not isinstance(plugin, str):
- pluginpath = plugin.path
- return core.BNRepositoryManagerInstallPlugin(self.handle, repopath, pluginpath)
-
- def uninstall_plugin(self, plugin, repo=None):
- """
- ``uninstall_plugin`` uninstall the specified plugin, pluginpath
-
- :param Repository or str repo: Repository containing the plugin to uninstall
- :param RepoPlugin or str plugin: RepoPlugin to uninstall
- :return: Boolean value True if the plugin was successfully uninstalled, False otherwise
- :rtype: Boolean
- :Example:
-
- >>> mgr = RepositoryManager()
- >>> mgr.uninstall_plugin('binaryninja-bookmarks')
- True
- >>>
- """
- if repo is None:
- repo = self.default_repository
- repopath = repo
- pluginpath = plugin
- if not isinstance(repo, str):
- repopath = repo.path
- if not isinstance(plugin, str):
- pluginpath = plugin.path
- return core.BNRepositoryManagerUninstallPlugin(self.handle, repopath, pluginpath)
-
- def update_plugin(self, plugin, repo=None):
- """
- ``update_plugin`` update the specified plugin, pluginpath
-
- :param Repository or str repo: Repository containing the plugin to update
- :param RepoPlugin or str plugin: RepoPlugin to update
- :return: Boolean value True if the plugin was successfully updated, False otherwise
- :rtype: Boolean
- :Example:
-
- >>> mgr = RepositoryManager()
- >>> mgr.update_plugin('binaryninja-bookmarks')
- True
- >>>
- """
- if repo is None:
- repo = self.default_repository
- repopath = repo
- pluginpath = plugin
- if not isinstance(repo, str):
- repopath = repo.path
- if not isinstance(plugin, str):
- pluginpath = plugin.path
- return core.BNRepositoryManagerUpdatePlugin(self.handle, repopath, pluginpath)
- def add_repository(self, url=None, repopath=None, localreference="master", remotereference="origin"):
+ def add_repository(self, url=None, repopath=None):
"""
``add_repository`` adds a new plugin repository for the manager to track.
- :param str url: URL to the git repository where the plugins are stored.
+ :param str url: URL to the plugins.json containing the records for this repository
:param str repopath: path to where the repository will be stored on disk locally
- :param str localreference: Optional reference to the local tracking branch typically "master"
- :param str remotereference: Optional reference to the remote tracking branch typically "origin"
:return: Boolean value True if the repository was successfully added, False otherwise.
:rtype: Boolean
:Example:
>>> mgr = RepositoryManager()
- >>> mgr.add_repository(url="https://github.com/vector35/community-plugins.git",
- repopath="myrepo",
- localreference="master", remotereference="origin")
+ >>> mgr.add_repository("https://raw.githubusercontent.com/Vector35/community-plugins/master/plugins.json", "community")
True
>>>
"""
- if not (isinstance(url, str) and isinstance(repopath, str) and
- isinstance(localreference, str) and isinstance(remotereference, str)):
+ if not isinstance(url, str) or not isinstance(repopath, str):
raise ValueError("Parameter is incorrect type")
- return core.BNRepositoryManagerAddRepository(self.handle, url, repopath, localreference, remotereference)
+ return core.BNRepositoryManagerAddRepository(self.handle, url, repopath)