Source code for binaryninja

# Copyright (c) 2015-2021 Vector 35 Inc
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.


from __future__ import absolute_import
import atexit
import sys
import ctypes
from time import gmtime
import os


from binaryninja.compatibility import *


# Binary Ninja components
import binaryninja._binaryninjacore as core

from binaryninja.enums import *
from binaryninja.databuffer import *
from binaryninja.filemetadata import *
from binaryninja.fileaccessor import *
from binaryninja.binaryview import *
from binaryninja.transform import *
from binaryninja.architecture import *
from binaryninja.basicblock import *
from binaryninja.function import *
from binaryninja.log import *
from binaryninja.lowlevelil import *
from binaryninja.mediumlevelil import *
from binaryninja.highlevelil import *
from binaryninja.types import *
from binaryninja.typelibrary import *
from binaryninja.functionrecognizer import *
from binaryninja.update import *
from binaryninja.plugin import *
from binaryninja.callingconvention import *
from binaryninja.platform import *
from binaryninja.demangle import *
from binaryninja.mainthread import *
from binaryninja.interaction import *
from binaryninja.lineardisassembly import *
from binaryninja.highlight import *
from binaryninja.scriptingprovider import *
from binaryninja.downloadprovider import *
from binaryninja.pluginmanager import *
from binaryninja.settings import *
from binaryninja.metadata import *
from binaryninja.flowgraph import *
from binaryninja.datarender import *


[docs]def shutdown(): """ ``shutdown`` cleanly shuts down the core, stopping all workers and closing all log files. """ core.BNShutdown()
atexit.register(shutdown)
[docs]def get_unique_identifier(): return core.BNGetUniqueIdentifierString()
[docs]def get_install_directory(): """ ``get_install_directory`` returns a string pointing to the installed binary currently running .. warning:: ONLY for use within the Binary Ninja UI, behavior is undefined and unreliable if run headlessly """ return core.BNGetInstallDirectory()
_plugin_api_name = "python{}".format(sys.version_info.major)
[docs]class PluginManagerLoadPluginCallback(object): """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, 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 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 {} isn'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) return True except KeyError: log_error("Failed to find python plugin: {}/{}".format(repo_path, plugin_path)) except ImportError as ie: log_error("Failed to import python plugin: {}/{}: {}".format(repo_path, plugin_path, ie)) return False
load_plugin = PluginManagerLoadPluginCallback() core.BNRegisterForPluginLoading(_plugin_api_name, load_plugin.cb, 0) class _DestructionCallbackHandler(object): def __init__(self): self._cb = core.BNObjectDestructionCallbacks() self._cb.context = 0 self._cb.destructBinaryView = self._cb.destructBinaryView.__class__(self.destruct_binary_view) self._cb.destructFileMetadata = self._cb.destructFileMetadata.__class__(self.destruct_file_metadata) self._cb.destructFunction = self._cb.destructFunction.__class__(self.destruct_function) core.BNRegisterObjectDestructionCallbacks(self._cb) def destruct_binary_view(self, ctxt, view): BinaryView._unregister(view) def destruct_file_metadata(self, ctxt, f): FileMetadata._unregister(f) def destruct_function(self, ctxt, func): Function._unregister(func) _enable_default_log = True _plugin_init = False def _init_plugins(): global _enable_default_log global _plugin_init if not _plugin_init: # The first call to BNInitCorePlugins returns True for successful initialization and True in this context indicates headless operation. # The result is pulled from BNInitPlugins as that now wraps BNInitCorePlugins. is_headless_init_once = core.BNInitPlugins(not os.environ.get('BN_DISABLE_USER_PLUGINS')) min_level = Settings().get_string("python.log.minLevel") if _enable_default_log and is_headless_init_once and min_level in LogLevel.__members__ and not core_ui_enabled() and sys.stderr.isatty(): log_to_stderr(LogLevel[min_level]) core.BNInitRepoPlugins() if core.BNIsLicenseValidated(): _plugin_init = True else: raise RuntimeError("License is not valid. Please supply a valid license.") _destruct_callbacks = _DestructionCallbackHandler()
[docs]def disable_default_log(): '''Disable default logging in headless mode for the current session. By default, logging in headless operation is controlled by the 'python.log.minLevel' settings.''' global _enable_default_log _enable_default_log = False close_logs()
[docs]def bundled_plugin_path(): """ ``bundled_plugin_path`` returns a string containing the current plugin path inside the `install path <https://docs.binary.ninja/getting-started.html#binary-path>`_ :return: current bundled plugin path :rtype: str, or None on failure """ return core.BNGetBundledPluginDirectory()
[docs]def user_plugin_path(): """ ``user_plugin_path`` returns a string containing the current plugin path inside the `user directory <https://docs.binary.ninja/getting-started.html#user-folder>`_ :return: current user plugin path :rtype: str, or None on failure """ return core.BNGetUserPluginDirectory()
[docs]def core_version(): """ ``core_version`` returns a string containing the current version :return: current version :rtype: str, or None on failure """ return core.BNGetVersionString()
[docs]def core_build_id(): """ ``core_build_id`` returns a integer containing the current build id :return: current build id :rtype: int """ return core.BNGetBuildId()
[docs]def core_serial(): """ ``core_serial`` returns a string containing the current serial number :return: current serial :rtype: str, or None on failure """ return core.BNGetSerialNumber()
[docs]def core_expires(): '''License Expiration''' return gmtime(core.BNGetLicenseExpirationTime())
[docs]def core_product(): '''Product string from the license file''' return core.BNGetProduct()
[docs]def core_product_type(): '''Product type from the license file''' return core.BNGetProductType()
[docs]def core_license_count(): '''License count from the license file''' return core.BNGetLicenseCount()
[docs]def core_ui_enabled(): '''Indicates that a UI exists and the UI has invoked BNInitUI''' return core.BNIsUIEnabled()
[docs]def core_set_license(licenseData): ''' ``core_set_license`` is used to initialize the core with a license file that doesn't necessarily reside on a file system. This is especially useful for headless environments such as docker where loading the license file via an environment variable allows for greater security of the license file itself. :param str licenseData: string containing the full contents of a license file :return: user plugin path :rtype: None :Example: >>> import os >>> core_set_license(os.environ['BNLICENSE']) #Do this before creating any BinaryViews >>> with open_view("/bin/ls") as bv: ... print(len(bv.functions)) 128 ''' core.BNSetLicense(licenseData)
[docs]def get_memory_usage_info(): count = ctypes.c_ulonglong() info = core.BNGetMemoryUsageInfo(count) result = {} for i in range(0, count.value): result[info[i].name] = info[i].value core.BNFreeMemoryUsageInfo(info, count.value) return result
[docs]def open_view(*args, **kwargs): """ `open_view` opens a BinaryView object. Note: If attempting to open a BNDB, the file MUST have the suffix .bndb, or else the file will not be loaded as a database. :param str filename: path to filename or bndb to open :param bool update_analysis: whether or not to run :func:`update_analysis_and_wait` after opening a :py:class:`BinaryView`, defaults to ``True`` :param callback progress_func: optional function to be called with the current progress and total count :param dict options: a dictionary in the form {setting identifier string : object value} :return: returns a :py:class:`BinaryView` object for the given filename or ``None`` :rtype: :py:class:`BinaryView` or ``None`` :Example: >>> from binaryninja import * >>> with open_view("/bin/ls") as bv: ... print(len(bv.functions)) ... 128 """ return BinaryViewType.get_view_of_file_with_options(*args, **kwargs)