From 4c065ca12267d862568d6ac86386fa58b281fdff Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Thu, 10 May 2018 13:05:14 -0400 Subject: default to loglevel info for log_to_stdout --- python/log.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'python/log.py') diff --git a/python/log.py b/python/log.py index f7144183..b1fd7095 100644 --- a/python/log.py +++ b/python/log.py @@ -21,6 +21,7 @@ # Binary Ninja components import _binaryninjacore as core +from enums import LogLevel _output_to_log = False @@ -135,7 +136,7 @@ def log_alert(text): core.BNLogAlert("%s", str(text)) -def log_to_stdout(min_level): +def log_to_stdout(min_level=LogLevel.InfoLog): """ ``log_to_stdout`` redirects minimum log level to standard out. -- cgit v1.3.1 From 8849fb2b2b8dc824bd3f17ce1026a04856477a94 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Sun, 4 Mar 2018 18:08:04 -0500 Subject: working division, prints, and metaclasses, but imports broken, still needs work --- python/__init__.py | 60 +-- python/architecture.py | 36 +- python/basicblock.py | 12 +- python/binaryview.py | 66 ++- python/callingconvention.py | 17 +- python/databuffer.py | 4 +- python/demangle.py | 7 +- python/examples/README.md | 56 --- python/examples/angr_plugin.py | 153 ------- python/examples/arch_hook.py | 16 - python/examples/bin_info.py | 72 ---- python/examples/breakpoint.py | 50 --- python/examples/export_svg.py | 224 ----------- python/examples/instruction_iterator.py | 53 --- python/examples/jump_table.py | 86 ---- python/examples/nds.py | 117 ------ python/examples/nes.py | 646 ------------------------------ python/examples/notification_callbacks.py | 51 --- python/examples/nsf.py | 145 ------- python/examples/print_syscalls.py | 55 --- python/examples/version_switcher.py | 150 ------- python/fileaccessor.py | 7 +- python/filemetadata.py | 17 +- python/function.py | 35 +- python/functionrecognizer.py | 14 +- python/generator.cpp | 4 +- python/highlight.py | 6 +- python/interaction.py | 12 +- python/log.py | 5 +- python/lowlevelil.py | 25 +- python/mainthread.py | 6 +- python/mediumlevelil.py | 18 +- python/metadata.py | 7 +- python/platform.py | 19 +- python/plugin.py | 29 +- python/pluginmanager.py | 8 +- python/scriptingprovider.py | 25 +- python/setting.py | 4 +- python/startup.py | 2 +- python/transform.py | 18 +- python/types.py | 15 +- python/undoaction.py | 10 +- python/update.py | 17 +- 43 files changed, 278 insertions(+), 2101 deletions(-) delete mode 100644 python/examples/README.md delete mode 100644 python/examples/angr_plugin.py delete mode 100644 python/examples/arch_hook.py delete mode 100644 python/examples/bin_info.py delete mode 100644 python/examples/breakpoint.py delete mode 100755 python/examples/export_svg.py delete mode 100644 python/examples/instruction_iterator.py delete mode 100644 python/examples/jump_table.py delete mode 100644 python/examples/nds.py delete mode 100644 python/examples/nes.py delete mode 100644 python/examples/notification_callbacks.py delete mode 100644 python/examples/nsf.py delete mode 100644 python/examples/print_syscalls.py delete mode 100644 python/examples/version_switcher.py (limited to 'python/log.py') diff --git a/python/__init__.py b/python/__init__.py index fda5f297..66f4bfe8 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -19,41 +19,41 @@ # IN THE SOFTWARE. +from __future__ import absolute_import import atexit import sys from time import gmtime # Binary Ninja components -import _binaryninjacore as core -from .enums import * -from .databuffer import * -from .filemetadata import * -from .fileaccessor import * -from .binaryview import * -from .transform import * -from .architecture import * -from .basicblock import * -from .function import * -from .log import * -from .lowlevelil import * -from .mediumlevelil import * -from .types import * -from .functionrecognizer import * -from .update import * -from .plugin import * -from .callingconvention import * -from .platform import * -from .demangle import * -from .mainthread import * -from .interaction import * -from .lineardisassembly import * -from .undoaction import * -from .highlight import * -from .scriptingprovider import * -from .downloadprovider import * -from .pluginmanager import * -from .setting import * -from .metadata import * +from binaryninja import _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.types 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.undoaction import * +from binaryninja.highlight import * +from binaryninja.scriptingprovider import * +from binaryninja.pluginmanager import * +from binaryninja.setting import * +from binaryninja.metadata import * def shutdown(): diff --git a/python/architecture.py b/python/architecture.py index df22da7f..360ce6bf 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -18,25 +18,22 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. +from __future__ import absolute_import import traceback import ctypes import abc -# Binary Ninja components -import _binaryninjacore as core -from enums import (Endianness, ImplicitRegisterExtend, BranchType, +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import (Endianness, ImplicitRegisterExtend, BranchType, InstructionTextTokenType, LowLevelILFlagCondition, FlagRole) -import startup -import function -import lowlevelil -import callingconvention -import platform -import log -import databuffer -import types + +#2-3 compatibility +from six import with_metaclass class _ArchitectureMetaClass(type): + from binaryninja import startup @property def list(self): startup._init_plugins() @@ -80,12 +77,12 @@ class _ArchitectureMetaClass(type): raise AttributeError("attribute '%s' is read only" % name) -class Architecture(object): +class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ ``class Architecture`` is the parent class for all CPU architectures. Subclasses of Architecture implement assembly, disassembly, IL lifting, and patching. - ``class Architecture`` has a ``__metaclass__`` with the additional methods ``register``, and supports + ``class Architecture`` has a metaclass with the additional methods ``register``, and supports iteration:: >>> #List the architectures @@ -130,10 +127,17 @@ class Architecture(object): semantic_class_for_flag_write_type = {} reg_stacks = {} intrinsics = {} - __metaclass__ = _ArchitectureMetaClass next_address = 0 def __init__(self): + from binaryninja import function + from binaryninja import startup + from binaryninja import lowlevelil + from binaryninja import types + from binaryninja import databuffer + from binaryninja import log + from binaryninja import platform + from binaryninja import callingconvention startup._init_plugins() if self.__class__.opcode_display_length > self.__class__.max_instr_length: @@ -2045,6 +2049,10 @@ class Architecture(object): _architecture_cache = {} class CoreArchitecture(Architecture): def __init__(self, handle): + from binaryninja import function + from binaryninja import types + from binaryninja import databuffer + from binaryninja import lowlevelil super(CoreArchitecture, self).__init__() self.handle = core.handle_of_type(handle, core.BNArchitecture) diff --git a/python/basicblock.py b/python/basicblock.py index a79b53ad..907b4065 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -20,12 +20,9 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType -import architecture -import highlight -import function +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType class BasicBlockEdge(object): @@ -54,6 +51,9 @@ class BasicBlockEdge(object): class BasicBlock(object): def __init__(self, view, handle): + from binaryninja import architecture + from binaryninja import function + from binaryninja import highlight self.view = view self.handle = core.handle_of_type(handle, core.BNBasicBlock) self._arch = None diff --git a/python/binaryview.py b/python/binaryview.py index 1e078523..f6a1bc83 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -24,23 +24,14 @@ import ctypes import abc import threading -# Binary Ninja components -import _binaryninjacore as core -from enums import (AnalysisState, SymbolType, InstructionTextTokenType, +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import (AnalysisState, SymbolType, InstructionTextTokenType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics) -import function -import startup -import architecture -import platform -import associateddatastore -import fileaccessor -import filemetadata -import log -import databuffer -import basicblock -import types -import lineardisassembly -import metadata +from binaryninja import associateddatastore # required for _BinaryViewAssociatedDataStore + +#2-3 compatibility +from six import with_metaclass class BinaryDataNotification(object): @@ -113,12 +104,13 @@ class AnalysisCompletionEvent(object): :Example: >>> def on_complete(self): - ... print "Analysis Complete", self.view + ... print("Analysis Complete", self.view) ... >>> evt = AnalysisCompletionEvent(bv, on_complete) >>> """ def __init__(self, view, callback): + from binaryninja import log self.view = view self.callback = callback self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify) @@ -197,6 +189,9 @@ class DataVariable(object): class BinaryDataNotificationCallbacks(object): def __init__(self, view, notify): + from binaryninja import function + from binaryninja import types + from binaryninja import log self.view = view self.notify = notify self._cb = core.BNBinaryDataNotification() @@ -319,6 +314,7 @@ class BinaryDataNotificationCallbacks(object): class _BinaryViewTypeMetaclass(type): + from binaryninja import startup @property def list(self): """List all BinaryView types (read-only)""" @@ -349,10 +345,12 @@ class _BinaryViewTypeMetaclass(type): return BinaryViewType(view_type) -class BinaryViewType(object): - __metaclass__ = _BinaryViewTypeMetaclass +class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)): def __init__(self, handle): + from binaryninja import architecture + from binaryninja import filemetadata + from binaryninja import platform self.handle = core.handle_of_type(handle, core.BNBinaryViewType) def __eq__(self, value): @@ -581,6 +579,18 @@ class BinaryView(object): database (e.g. ``remove_user_function()`` rather than ``remove_function()``). Thus use ``_user_`` methods if saving \ to the database is desired. """ + import binaryninja.function + import binaryninja.architecture + import binaryninja.platform + import binaryninja.fileaccessor + import binaryninja.filemetadata + import binaryninja.databuffer + import binaryninja.basicblock + import binaryninja.types + import binaryninja.log + import binaryninja.startup + import binaryninja.lineardisassembly + import binaryninja.metadata name = None long_name = None _registered = False @@ -590,6 +600,18 @@ class BinaryView(object): _associated_data = {} def __init__(self, file_metadata=None, parent_view=None, handle=None): + function = binaryninja.function + architecture = binaryninja.architecture + platform = binaryninja.platform + fileaccessor = binaryninja.fileaccessor + filemetadata = binaryninja.filemetadata + databuffer = binaryninja.databuffer + basicblock = binaryninja.basicblock + types = binaryninja.types + log = binaryninja.log + startup = binaryninja.startup + lineardisassembly = binaryninja.lineardisassembly + metadata = binaryninja.metadata if handle is not None: self.handle = core.handle_of_type(handle, core.BNBinaryView) if file_metadata is None: @@ -680,7 +702,7 @@ class BinaryView(object): @classmethod def open(cls, src, file_metadata=None): - startup._init_plugins() + binaryninja.startup._init_plugins() if isinstance(src, fileaccessor.FileAccessor): if file_metadata is None: file_metadata = filemetadata.FileMetadata() @@ -2790,7 +2812,7 @@ class BinaryView(object): :Example: >>> def completionEvent(): - ... print "done" + ... print("done") ... >>> bv.add_analysis_completion_event(completionEvent) @@ -3098,7 +3120,7 @@ class BinaryView(object): >>> settings = DisassemblySettings() >>> lines = bv.get_linear_disassembly(settings) >>> for line in lines: - ... print line + ... print(line) ... break ... cf fa ed fe 07 00 00 01 ........ diff --git a/python/callingconvention.py b/python/callingconvention.py index e3ec7261..ab8058fc 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -21,17 +21,11 @@ import traceback import ctypes -# Binary Ninja components -import _binaryninjacore as core -import architecture -import log -import types -import function -import binaryview -from enums import VariableSourceType - +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class CallingConvention(object): + from binaryninja import types name = None caller_saved_regs = [] int_arg_regs = [] @@ -48,6 +42,11 @@ class CallingConvention(object): _registered_calling_conventions = [] def __init__(self, arch=None, name=None, handle=None, confidence=types.max_confidence): + from binaryninja import architecture + from binaryninja import log + from binaryninja import function + from binaryninja import binaryview + from binaryninja.enums import VariableSourceType if handle is None: if arch is None or name is None: raise ValueError("Must specify either handle or architecture and name") diff --git a/python/databuffer.py b/python/databuffer.py index 3f9e4ce5..bf366750 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -20,8 +20,8 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class DataBuffer(object): diff --git a/python/demangle.py b/python/demangle.py index 11673263..50322694 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -20,9 +20,8 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core -import types +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core def get_qualified_name(names): @@ -56,6 +55,7 @@ def demangle_ms(arch, mangled_name): (, ['Foobar', 'testf']) >>> """ + from binaryninja import types handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() @@ -69,6 +69,7 @@ def demangle_ms(arch, mangled_name): def demangle_gnu3(arch, mangled_name): + from binaryninja import types handle = ctypes.POINTER(core.BNType)() outName = ctypes.POINTER(ctypes.c_char_p)() outSize = ctypes.c_ulonglong() diff --git a/python/examples/README.md b/python/examples/README.md deleted file mode 100644 index 43af34be..00000000 --- a/python/examples/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Binary Ninja Python API Examples - -The following examples demonstrate some of the Binary Ninja API. They include both stand-alone examples that directly call into the core without a GUI, as well as examples meant to be loaded as plugins available from the UI. - -## Stand-alone - -These plugins only operate when run directly outside of the UI - -* bin_info.py - general binary information -* print_syscalls.py - extract syscall numbers from IL on specified file. Can be run both headless and in Binary Ninja -* version_switcher.py - uses the update API to see raw version notes and manually downgrade or upgrade -* instruction_iterator.py - very simple plugin that iterates through functions, blocks, and instructions - -To use the stand-alone Python examples, make sure your `PYTHON_PATH` includes the API, as shown below. Please note, this is a feature that requires the "GUI-less processing" capability not available in the personal edition. In the personal edition, all scripts must by run from the integrated python console (follow the directions below under "Loading Plugins" section) - -``` -PYTHONPATH=$PYTHONPATH:/Applications/Binary\ Ninja.app/Contents/Resources/python -``` - -## GUI Plugins - -These plugins require the UI to be running - -* breakpoint.py - small example showing how to modify a file and register a GUI menu item -* jump_table.py - heuristic based jump table detection for when the data-flow based computation fails, triggered by right-clicking on the location where the jump value is computed -* angr_plugin.py - a plugin to demonstrate both background threads, the simplified plugin UI elements, and highlighting -* export_svg.py - exports the graph view of a function to an SVG file for including in reports - -## Both - -These plugins are able to operate in either the GUI or as stand-alone plugins - -* nes.py - 6502 CPU architecture including LLIL lifting and `.NES` file format parser - - -## Loading Plugins - -Plugins are meant to be loaded into a running Binary Ninja GUI and should either be copied or symlinked into the appropriate plugin folder. You'll need to then re-start Binary Ninja. - -### OSX - -``` -~/Library/Application Support/Binary Ninja/plugins -``` - -### Windows - -``` -%APPDATA%\Binary Ninja\plugins -``` - -### Linux - -``` -~/.binaryninja/plugins -``` diff --git a/python/examples/angr_plugin.py b/python/examples/angr_plugin.py deleted file mode 100644 index 26f8040c..00000000 --- a/python/examples/angr_plugin.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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. - - -# This plugin assumes angr is already installed and available on the system. See the angr documentation -# for information about installing angr. It should be installed using the virtualenv method. -# -# This plugin is currently only known to work on Linux using virtualenv. Switch to the virtual environment -# (using a command such as "workon angr"), then run the Binary Ninja UI from the command line. -# -# This method is known to fail on Mac OS X as the virtualenv used by angr does not appear to provide a -# way to automatically link to the correct version of Python, even when running the UI from within the -# virtual environment. A later update may allow for a manual override to link to the required version -# of Python. - -import tempfile -import logging -import os - -__name__ = "__console__" # angr looks for this, it won't load from within a UI without it - -import angr -# For the lazy instead you can just import everything 'from binaryninja import *'' -from binaryninja.binaryview import BinaryView -from binaryninja.plugin import BackgroundTaskThread, PluginCommand -from binaryninja.interaction import show_plain_text_report, show_message_box -from binaryninja.highlight import HighlightColor -from binaryninja.enums import HighlightStandardColor, MessageBoxButtonSet, MessageBoxIcon - -# Disable warning logs as they show up as errors in the UI -logging.disable(logging.WARNING) - -# Create sets in the BinaryView's data field to store the desired path for each view -BinaryView.set_default_session_data("angr_find", set()) -BinaryView.set_default_session_data("angr_avoid", set()) - - -def escaped_output(str): - return '\n'.join([s.encode("string_escape") for s in str.split('\n')]) - - -# Define a background thread object for solving in the background -class Solver(BackgroundTaskThread): - def __init__(self, find, avoid, view): - BackgroundTaskThread.__init__(self, "Solving with angr...", True) - self.find = tuple(find) - self.avoid = tuple(avoid) - self.view = view - - # Write the binary to disk so that the angr API can read it - self.binary = tempfile.NamedTemporaryFile() - self.binary.write(view.file.raw.read(0, len(view.file.raw))) - self.binary.flush() - - def run(self): - # Create an angr project and an explorer with the user's settings - p = angr.Project(self.binary.name) - e = p.surveyors.Explorer(find = self.find, avoid = self.avoid) - - # Solve loop - while not e.done: - if self.cancelled: - # Solve cancelled, show results if there were any - if len(e.found) > 0: - break - return - - # Perform the next step in the solve - e.step() - - # Update status - active_count = len(e.active) - found_count = len(e.found) - - progress = "Solving with angr (%d active path%s" % (active_count, "s" if active_count != 1 else "") - if found_count > 0: - progress += ", %d path%s found" % (found_count, "s" if found_count != 1 else "") - self.progress = progress + ")..." - - # Solve complete, show report - text_report = "Found %d path%s.\n\n" % (len(e.found), "s" if len(e.found) != 1 else "") - i = 1 - for f in e.found: - text_report += "Path %d\n" % i + "=" * 10 + "\n" - text_report += "stdin:\n" + escaped_output(f.state.posix.dumps(0)) + "\n\n" - text_report += "stdout:\n" + escaped_output(f.state.posix.dumps(1)) + "\n\n" - text_report += "stderr:\n" + escaped_output(f.state.posix.dumps(2)) + "\n\n" - i += 1 - - name = self.view.file.filename - if len(name) > 0: - show_plain_text_report("Results from angr - " + os.path.basename(self.view.file.filename), text_report) - else: - show_plain_text_report("Results from angr", text_report) - - -def find_instr(bv, addr): - # Highlight the instruction in green - blocks = bv.get_basic_blocks_at(addr) - for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.GreenHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(addr, HighlightStandardColor.GreenHighlightColor) - - # Add the instruction to the list associated with the current view - bv.session_data.angr_find.add(addr) - - -def avoid_instr(bv, addr): - # Highlight the instruction in red - blocks = bv.get_basic_blocks_at(addr) - for block in blocks: - block.set_auto_highlight(HighlightColor(HighlightStandardColor.RedHighlightColor, alpha = 128)) - block.function.set_auto_instr_highlight(addr, HighlightStandardColor.RedHighlightColor) - - # Add the instruction to the list associated with the current view - bv.session_data.angr_avoid.add(addr) - - -def solve(bv): - if len(bv.session_data.angr_find) == 0: - show_message_box("Angr Solve", "You have not specified a goal instruction.\n\n" + - "Please right click on the goal instruction and select \"Find Path to This Instruction\" to " + - "continue.", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon) - return - - # Start a solver thread for the path associated with the view - s = Solver(bv.session_data.angr_find, bv.session_data.angr_avoid, bv) - s.start() - - -# Register commands for the user to interact with the plugin -PluginCommand.register_for_address("Find Path to This Instruction", - "When solving, find a path that gets to this instruction", find_instr) -PluginCommand.register_for_address("Avoid This Instruction", - "When solving, avoid paths that reach this instruction", avoid_instr) -PluginCommand.register("Solve With Angr", "Attempt to solve for a path that satisfies the constraints given", solve) diff --git a/python/examples/arch_hook.py b/python/examples/arch_hook.py deleted file mode 100644 index 452bd2b6..00000000 --- a/python/examples/arch_hook.py +++ /dev/null @@ -1,16 +0,0 @@ -from binaryninja.architecture import Architecture, ArchitectureHook - -class X86ReturnHook(ArchitectureHook): - def get_instruction_text(self, data, addr): - # Call the original implementation's method by calling the superclass - result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) - - # Patch the name of the 'retn' instruction to 'ret' - if len(result) > 0 and result[0].text == 'retn': - result[0].text = 'ret' - - return result, length - -# Install the hook by constructing it with the desired architecture to hook, then registering it -X86ReturnHook(Architecture['x86']).register() - diff --git a/python/examples/bin_info.py b/python/examples/bin_info.py deleted file mode 100644 index 17a96685..00000000 --- a/python/examples/bin_info.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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. - -import sys -import binaryninja.log as log -from binaryninja.binaryview import BinaryViewType -import binaryninja.interaction as interaction -from binaryninja.plugin import PluginCommand - - -def get_bininfo(bv): - if bv is None: - filename = "" - if len(sys.argv) > 1: - filename = sys.argv[1] - else: - filename = interaction.get_open_filename_input("Filename:") - if filename is None: - log.log_warn("No file specified") - sys.exit(1) - - bv = BinaryViewType.get_view_of_file(filename) - log.log_to_stdout(True) - - contents = "## %s ##\n" % bv.file.filename - contents += "- START: 0x%x\n\n" % bv.start - contents += "- ENTRY: 0x%x\n\n" % bv.entry_point - contents += "- ARCH: %s\n\n" % bv.arch.name - contents += "### First 10 Functions ###\n" - - contents += "| Start | Name |\n" - contents += "|------:|:-------|\n" - for i in xrange(min(10, len(bv.functions))): - contents += "| 0x%x | %s |\n" % (bv.functions[i].start, bv.functions[i].symbol.full_name) - - contents += "### First 10 Strings ###\n" - contents += "| Start | Length | String |\n" - contents += "|------:|-------:|:-------|\n" - for i in xrange(min(10, len(bv.strings))): - start = bv.strings[i].start - length = bv.strings[i].length - string = bv.read(start, length) - contents += "| 0x%x |%d | %s |\n" % (start, length, string) - return contents - - -def display_bininfo(bv): - interaction.show_markdown_report("Binary Info Report", get_bininfo(bv)) - - -if __name__ == "__main__": - print get_bininfo(None) -else: - PluginCommand.register("Binary Info", "Display basic info about the binary", display_bininfo) diff --git a/python/examples/breakpoint.py b/python/examples/breakpoint.py deleted file mode 100644 index a2801511..00000000 --- a/python/examples/breakpoint.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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 binaryninja.plugin import PluginCommand -from binaryninja.log import log_error - - -def write_breakpoint(view, start, length): - """Sample function to show registering a plugin menu item for a range of bytes. Also possible: - register - register_for_address - register_for_function - """ - bkpt_str = { - "x86": "int3", - "x86_64": "int3", - "armv7": "bkpt", - "aarch64": "brk #0", - "mips32": "break"} - - if view.arch.name not in bkpt_str: - log_error("Architecture %s not supported" % view.arch.name) - return - - bkpt, err = view.arch.assemble(bkpt_str[view.arch.name]) - if bkpt is None: - log_error(err) - return - view.write(start, bkpt * length / len(bkpt)) - - -PluginCommand.register_for_range("Convert to breakpoint", "Fill region with breakpoint instructions.", write_breakpoint) diff --git a/python/examples/export_svg.py b/python/examples/export_svg.py deleted file mode 100755 index 7814c9fd..00000000 --- a/python/examples/export_svg.py +++ /dev/null @@ -1,224 +0,0 @@ -# from binaryninja import * -import os -import webbrowser -import time -try: - from urllib import pathname2url # Python 2.x -except: - from urllib.request import pathname2url # Python 3.x - -from binaryninja.interaction import get_save_filename_input, show_message_box -from binaryninja.enums import MessageBoxButtonSet, MessageBoxIcon, MessageBoxButtonResult, InstructionTextTokenType, BranchType -from binaryninja.plugin import PluginCommand - -colors = {'green': [162, 217, 175], 'red': [222, 143, 151], 'blue': [128, 198, 233], 'cyan': [142, 230, 237], 'lightCyan': [176, 221, 228], 'orange': [237, 189, 129], 'yellow': [237, 223, 179], 'magenta': [218, 196, 209], 'none': [74, 74, 74]} - -escape_table = { - "'": "'", - ">": ">", - "<": "<", - '"': """, - ' ': " " -} - - -def escape(toescape): - toescape = toescape.decode('utf-8').encode('ascii', 'xmlcharrefreplace') # handle extended unicode - return ''.join(escape_table.get(i, i) for i in toescape) # still escape the basics - - -def save_svg(bv, function): - address = hex(function.start).replace('L', '') - path = os.path.dirname(bv.file.filename) - origname = os.path.basename(bv.file.filename) - filename = os.path.join(path, 'binaryninja-{filename}-{function}.html'.format(filename=origname, function=address)) - outputfile = get_save_filename_input('File name for export_svg', 'HTML files (*.html)', filename) - if outputfile is None: - return - content = render_svg(function, origname) - output = open(outputfile, 'w') - output.write(content) - output.close() - result = show_message_box("Open SVG", "Would you like to view the exported SVG?", - buttons = MessageBoxButtonSet.YesNoButtonSet, icon = MessageBoxIcon.QuestionIcon) - if result == MessageBoxButtonResult.YesButton: - url = 'file:{}'.format(pathname2url(outputfile)) - webbrowser.open(url) - - -def instruction_data_flow(function, address): - ''' TODO: Extract data flow information ''' - length = function.view.get_instruction_length(address) - bytes = function.view.read(address, length) - hex = bytes.encode('hex') - padded = ' '.join([hex[i:i + 2] for i in range(0, len(hex), 2)]) - return 'Opcode: {bytes}'.format(bytes=padded) - - -def render_svg(function, origname): - graph = function.create_graph() - graph.layout_and_wait() - heightconst = 15 - ratio = 0.48 - widthconst = heightconst * ratio - - output = ''' - - - - -''' - output += ''' - - - - - - - - - - - - - - - '''.format(width=graph.width * widthconst + 20, height=graph.height * heightconst + 20) - output += ''' - Function Graph 0 - ''' - edges = '' - for i, block in enumerate(graph.blocks): - - # Calculate basic block location and coordinates - x = ((block.x) * widthconst) - y = ((block.y) * heightconst) - width = ((block.width) * widthconst) - height = ((block.height) * heightconst) - - # Render block - output += ' \n'.format(i=i) - output += ' Basic Block {i}\n'.format(i=i) - rgb = colors['none'] - try: - bb = block.basic_block - color_code = bb.highlight.color - color_str = bb.highlight._standard_color_to_str(color_code) - if color_str in colors: - rgb = colors[color_str] - except: - pass - output += ' \n'.format(x=x, y=y, width=width + 16, height=height + 12, r=rgb[0], g=rgb[1], b=rgb[2]) - - # Render instructions, unfortunately tspans don't allow copying/pasting more - # than one line at a time, need SVG 1.2 textarea tags for that it looks like - - output += ' \n'.format(x=x, y=y + (i + 1) * heightconst) - for i, line in enumerate(block.lines): - output += ' '.format(x=x + 6, y=y + 6 + (i + 0.7) * heightconst, address=hex(line.address)[:-1]) - hover = instruction_data_flow(function, line.address) - output += '{hover}'.format(hover=hover) - for token in line.tokens: - # TODO: add hover for hex, function, and reg tokens - output += '{text}'.format(text=escape(token.text), tokentype=InstructionTextTokenType(token.type).name) - output += '\n' - output += ' \n' - output += ' \n' - - # Edges are rendered in a seperate chunk so they have priority over the - # basic blocks or else they'd render below them - - for edge in block.outgoing_edges: - points = "" - x, y = edge.points[0] - points += str(x * widthconst) + "," + str(y * heightconst + 12) + " " - for x, y in edge.points[1:-1]: - points += str(x * widthconst) + "," + str(y * heightconst) + " " - x, y = edge.points[-1] - points += str(x * widthconst) + "," + str(y * heightconst + 0) + " " - if edge.back_edge: - edges += ' \n'.format(type=BranchType(edge.type).name, points=points) - else: - edges += ' \n'.format(type=BranchType(edge.type).name, points=points) - output += ' ' + edges + '\n' - output += ' \n' - output += '' - - output += '

This CFG generated by Binary Ninja from {filename} on {timestring}.

'.format(filename = origname, timestring = time.strftime("%c")) - output += '' - return output - - -PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function", save_svg) diff --git a/python/examples/instruction_iterator.py b/python/examples/instruction_iterator.py deleted file mode 100644 index f55e1c1b..00000000 --- a/python/examples/instruction_iterator.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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. - -import sys -import binaryninja as binja - -if len(sys.argv) > 1: - target = sys.argv[1] - -bv = binja.BinaryViewType.get_view_of_file(target) -binja.log_to_stdout(True) -binja.log_info("-------- %s --------" % target) -binja.log_info("START: 0x%x" % bv.start) -binja.log_info("ENTRY: 0x%x" % bv.entry_point) -binja.log_info("ARCH: %s" % bv.arch.name) -binja.log_info("\n-------- Function List --------") - -""" print all the functions, their basic blocks, and their il instructions """ -for func in bv.functions: - binja.log_info(repr(func)) - for block in func.low_level_il: - binja.log_info("\t{0}".format(block)) - - for insn in block: - binja.log_info("\t\t{0}".format(insn)) - - -""" print all the functions, their basic blocks, and their mc instructions """ -for func in bv.functions: - binja.log_info(repr(func)) - for block in func: - binja.log_info("\t{0}".format(block)) - - for insn in block: - binja.log_info("\t\t{0}".format(insn)) diff --git a/python/examples/jump_table.py b/python/examples/jump_table.py deleted file mode 100644 index 419cc188..00000000 --- a/python/examples/jump_table.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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. - -# This plugin will attempt to resolve simple jump tables (an array of code pointers) and add the destinations -# as indirect branch targets so that the flow graph reflects the jump table's control flow. -from binaryninja.plugin import PluginCommand -from binaryninja.enums import InstructionTextTokenType -import struct - - -def find_jump_table(bv, addr): - for block in bv.get_basic_blocks_at(addr): - func = block.function - arch = func.arch - addrsize = arch.address_size - - # Grab the instruction tokens so that we can look for the table's starting address - tokens, length = arch.get_instruction_text(bv.read(addr, 16), addr) - - # Look for the next jump instruction, which may be the current instruction. Some jump tables will - # compute the address first then jump to the computed address as a separate instruction. - jump_addr = addr - while jump_addr < block.end: - info = arch.get_instruction_info(bv.read(jump_addr, 16), jump_addr) - if len(info.branches) != 0: - break - jump_addr += info.length - if jump_addr >= block.end: - print "Unable to find jump after instruction 0x%x" % addr - continue - print "Jump at 0x%x" % jump_addr - - # Collect the branch targets for any tables referenced by the clicked instruction - branches = [] - for token in tokens: - if InstructionTextTokenType(token.type) == InstructionTextTokenType.PossibleAddressToken: # Table addresses will be a "possible address" token - tbl = token.value - print "Found possible table at 0x%x" % tbl - i = 0 - while True: - # Read the next pointer from the table - data = bv.read(tbl + (i * addrsize), addrsize) - if len(data) == addrsize: - if addrsize == 4: - ptr = struct.unpack("= bv.start) and (ptr < bv.end): - print "Found destination 0x%x" % ptr - branches.append((arch, ptr)) - else: - # Once a value that is not a pointer is encountered, the jump table is ended - break - else: - # Reading invalid memory - break - - i += 1 - - # Set the indirect branch targets on the jump instruction to be the list of targets discovered - func.set_user_indirect_branches(jump_addr, branches) - - -# Create a plugin command so that the user can right click on an instruction referencing a jump table and -# invoke the command -PluginCommand.register_for_address("Process jump table", "Look for jump table destinations", find_jump_table) diff --git a/python/examples/nds.py b/python/examples/nds.py deleted file mode 100644 index 34d8a292..00000000 --- a/python/examples/nds.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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 binaryninja import * -from binaryninja.binaryview import BinaryView -from binaryninja.architecture import Architecture -from binaryninja.enums import SegmentFlag -from binaryninja.log import log_error - -import struct -import traceback - - -def crc16(data): - crc = 0xffff - for ch in data: - crc ^= ord(ch) - for bit in xrange(0, 8): - if (crc & 1) == 1: - crc = (crc >> 1) ^ 0xa001 - else: - crc >>= 1 - return crc - - -class DSView(BinaryView): - def __init__(self, data): - BinaryView.__init__(self, file_metadata = data.file, parent_view = data) - self.raw = data - - @classmethod - def is_valid_for_data(self, data): - hdr = data.read(0, 0x160) - if len(hdr) < 0x160: - return False - if struct.unpack("> 4) - self.ram_banks = struct.unpack("B", hdr[8])[0] - self.rom_offset = 16 - if self.rom_flags & 4: - self.rom_offset += 512 - self.rom_length = self.rom_banks * 0x4000 - - # Add mapping for RAM and hardware registers, not backed by file contents - self.add_auto_segment(0, 0x8000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) - - # Add ROM mappings - self.add_auto_segment(0x8000, 0x4000, self.rom_offset + (self.__class__.bank * 0x4000), 0x4000, - SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) - self.add_auto_segment(0xc000, 0x4000, self.rom_offset + self.rom_length - 0x4000, 0x4000, - SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) - - nmi = struct.unpack("= 0x8000: - self.add_function(addr) - - return True - except: - log_error(traceback.format_exc()) - return False - - def perform_is_executable(self): - return True - - def perform_get_entry_point(self): - return struct.unpack("'.format(sys.argv[0])) - else: - print_syscalls(sys.argv[1]) diff --git a/python/examples/version_switcher.py b/python/examples/version_switcher.py deleted file mode 100644 index 3e1cab40..00000000 --- a/python/examples/version_switcher.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2015-2017 Vector 35 LLC -# -# 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. - -import sys - -from binaryninja.update import UpdateChannel, are_auto_updates_enabled, set_auto_updates_enabled, is_update_installation_pending, install_pending_update -from binaryninja import core_version -import datetime - -chandefault = UpdateChannel.list[0].name -channel = None -versions = [] - - -def load_channel(newchannel): - global channel - global versions - if (channel is not None and newchannel == channel.name): - print "Same channel, not updating." - else: - try: - print "Loading channel %s" % newchannel - channel = UpdateChannel[newchannel] - print "Loading versions..." - versions = channel.versions - except Exception: - print "%s is not a valid channel name. Defaulting to " % chandefault - channel = UpdateChannel[chandefault] - - -def select(version): - done = False - date = datetime.datetime.fromtimestamp(version.time).strftime('%c') - while not done: - print "Version:\t%s" % version.version - print "Updated:\t%s" % date - print "Notes:\n\n-----\n%s" % version.notes - print "-----" - print "\t1)\tSwitch to version" - print "\t2)\tMain Menu" - selection = raw_input('Choice: ') - if selection.isdigit(): - selection = int(selection) - else: - selection = 0 - if (selection == 2): - done = True - elif (selection == 1): - if (version.version == channel.latest_version.version): - print "Requesting update to latest version." - else: - print "Requesting update to prior version." - if are_auto_updates_enabled(): - print "Disabling automatic updates." - set_auto_updates_enabled(False) - if (version.version == core_version): - print "Already running %s" % version.version - else: - print "version.version %s" % version.version - print "core_version %s" % core_version - print "Downloading..." - print version.update() - print "Installing..." - if is_update_installation_pending: - #note that the GUI will be launched after update but should still do the upgrade headless - install_pending_update() - # forward updating won't work without reloading - sys.exit() - else: - print "Invalid selection" - - -def list_channels(): - done = False - print "\tSelect channel:\n" - while not done: - channel_list = UpdateChannel.list - for index, item in enumerate(channel_list): - print "\t%d)\t%s" % (index + 1, item.name) - print "\t%d)\t%s" % (len(channel_list) + 1, "Main Menu") - selection = raw_input('Choice: ') - if selection.isdigit(): - selection = int(selection) - else: - selection = 0 - if (selection <= 0 or selection > len(channel_list) + 1): - print "%s is an invalid choice." % selection - else: - done = True - if (selection != len(channel_list) + 1): - load_channel(channel_list[selection - 1].name) - - -def toggle_updates(): - set_auto_updates_enabled(not are_auto_updates_enabled()) - - -def main(): - global channel - done = False - load_channel(chandefault) - while not done: - print "\n\tBinary Ninja Version Switcher" - print "\t\tCurrent Channel:\t%s" % channel.name - print "\t\tCurrent Version:\t%s" % core_version - print "\t\tAuto-Updates On:\t%s\n" % are_auto_updates_enabled() - for index, version in enumerate(versions): - date = datetime.datetime.fromtimestamp(version.time).strftime('%c') - print "\t%d)\t%s (%s)" % (index + 1, version.version, date) - print "\t%d)\t%s" % (len(versions) + 1, "Switch Channel") - print "\t%d)\t%s" % (len(versions) + 2, "Toggle Auto Updates") - print "\t%d)\t%s" % (len(versions) + 3, "Exit") - selection = raw_input('Choice: ') - if selection.isdigit(): - selection = int(selection) - else: - selection = 0 - if (selection <= 0 or selection > len(versions) + 3): - print "%d is an invalid choice.\n\n" % selection - else: - if (selection == len(versions) + 3): - done = True - elif (selection == len(versions) + 2): - toggle_updates() - elif (selection == len(versions) + 1): - list_channels() - else: - select(versions[selection - 1]) - - -if __name__ == "__main__": - main() diff --git a/python/fileaccessor.py b/python/fileaccessor.py index 2c1f1d19..5a602b89 100644 --- a/python/fileaccessor.py +++ b/python/fileaccessor.py @@ -21,12 +21,11 @@ import traceback import ctypes -# Binary Ninja components -import _binaryninjacore as core -import log - +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class FileAccessor(object): + from binaryninja import log def __init__(self): self._cb = core.BNFileAccessor() self._cb.context = 0 diff --git a/python/filemetadata.py b/python/filemetadata.py index 4bfc0214..695b95f3 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -18,18 +18,17 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. +from __future__ import absolute_import import traceback import ctypes -# Binary Ninja components -import _binaryninjacore as core -import startup -import associateddatastore -import log -import binaryview +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja import associateddatastore #required for _FileMetadataAssociatedDataStore class NavigationHandler(object): + from binaryninja import log def _register(self, handle): self._cb = core.BNNavigationHandler() self._cb.context = 0 @@ -66,12 +65,14 @@ class _FileMetadataAssociatedDataStore(associateddatastore._AssociatedDataStore) class FileMetadata(object): - _associated_data = {} - """ ``class FileMetadata`` represents the file being analyzed by Binary Ninja. It is responsible for opening, closing, creating the database (.bndb) files, and is used to keep track of undoable actions. """ + from binaryninja import startup + from binaryninja import binaryview + _associated_data = {} + def __init__(self, filename = None, handle = None): """ Instantiates a new FileMetadata class. diff --git a/python/function.py b/python/function.py index 2f794f47..2ee9b20d 100644 --- a/python/function.py +++ b/python/function.py @@ -18,27 +18,18 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. +from __future__ import absolute_import import threading import traceback import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import (AnalysisSkipReason, FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import (AnalysisSkipReason, FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType, FunctionAnalysisSkipOverride) -import architecture -import platform -import highlight -import associateddatastore -import types -import basicblock -import lowlevelil -import mediumlevelil -import binaryview -import log -import callingconvention +from binaryninja import associateddatastore #required in the main scope due to being an argument for _FunctionAssociatedDataStore class LookupTableEntry(object): @@ -51,6 +42,7 @@ class LookupTableEntry(object): class RegisterValue(object): + from binaryninja import types def __init__(self, arch = None, value = None, confidence = types.max_confidence): self.is_constant = False if value is None: @@ -329,6 +321,7 @@ class IndirectBranchInfo(object): class ParameterVariables(object): + from binaryninja import types def __init__(self, var_list, confidence = types.max_confidence): self.vars = var_list self.confidence = confidence @@ -355,6 +348,14 @@ class _FunctionAssociatedDataStore(associateddatastore._AssociatedDataStore): class Function(object): + from binaryninja import callingconvention + from binaryninja import mediumlevelil + from binaryninja import lowlevelil + from binaryninja import basicblock + from binaryninja import types + from binaryninja import highlight + from binaryninja import platform + from binaryninja import architecture _associated_data = {} def __init__(self, view, handle): @@ -1631,7 +1632,8 @@ class FunctionGraphEdge(object): class FunctionGraphBlock(object): - def __init__(self, handle, graph): + def __init__(self, handle): + from binaryninja import binaryview self.handle = handle self.graph = graph @@ -1839,6 +1841,8 @@ class DisassemblySettings(object): class FunctionGraph(object): + from binaryninja import log + from binaryninja import types def __init__(self, view, handle): self.view = view self.handle = handle @@ -2140,6 +2144,7 @@ class InstructionTextToken(object): ========================== ============================================ """ + from binaryninja import types def __init__(self, token_type, text, value = 0, size = 0, operand = 0xffffffff, context = InstructionTextTokenContext.NoTokenContext, address = 0, confidence = types.max_confidence): self.type = InstructionTextTokenType(token_type) diff --git a/python/functionrecognizer.py b/python/functionrecognizer.py index 4ac304ca..158a0700 100644 --- a/python/functionrecognizer.py +++ b/python/functionrecognizer.py @@ -20,16 +20,16 @@ import traceback -# Binary Ninja components -import _binaryninjacore as core -import function -import filemetadata -import binaryview -import lowlevelil -import log +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class FunctionRecognizer(object): + from binaryninja import function + from binaryninja import filemetadata + from binaryninja import binaryview + from binaryninja import lowlevelil + from binaryninja import log _instance = None def __init__(self): diff --git a/python/generator.cpp b/python/generator.cpp index f838b36d..bb32ab69 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -374,10 +374,10 @@ int main(int argc, char* argv[]) fprintf(out, "def handle_of_type(value, handle_type):\n"); fprintf(out, "\tif isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n"); fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n"); - fprintf(out, "\traise ValueError, 'expected pointer to %%s' %% str(handle_type)\n"); + fprintf(out, "\traise ValueError('expected pointer to %%s' %% str(handle_type))\n"); fprintf(out, "\n# Set path for core plugins\n"); - fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\"))\n"); + fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\").encode('utf-8'))\n"); fclose(out); fclose(enums); diff --git a/python/highlight.py b/python/highlight.py index 96bc543d..b04561bd 100644 --- a/python/highlight.py +++ b/python/highlight.py @@ -19,9 +19,9 @@ # IN THE SOFTWARE. -# Binary Ninja components -import _binaryninjacore as core -from enums import HighlightColorStyle, HighlightStandardColor +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import HighlightColorStyle, HighlightStandardColor class HighlightColor(object): diff --git a/python/interaction.py b/python/interaction.py index 5b7ec497..8507682c 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -21,11 +21,9 @@ import ctypes import traceback -# Binary Ninja components -import _binaryninjacore as core -from enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult -import binaryview -import log +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult class LabelField(object): @@ -241,6 +239,8 @@ class DirectoryNameField(object): class InteractionHandler(object): + from binaryninja import log + from binaryninja import binaryview _interaction_handler = None def __init__(self): @@ -724,7 +724,7 @@ def get_form_input(fields, title): 3) Maybe Options 1 >>> True - >>> print tex_f.result, int_f.result, choice_f.result + >>> print(tex_f.result, int_f.result, choice_f.result) Peter 1337 0 """ value = (core.BNFormInputField * len(fields))() diff --git a/python/log.py b/python/log.py index b1fd7095..e7cd956d 100644 --- a/python/log.py +++ b/python/log.py @@ -19,9 +19,8 @@ # IN THE SOFTWARE. -# Binary Ninja components -import _binaryninjacore as core -from enums import LogLevel +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core _output_to_log = False diff --git a/python/lowlevelil.py b/python/lowlevelil.py index bd1e9349..3b12c118 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -19,15 +19,13 @@ # IN THE SOFTWARE. import ctypes - -# Binary Ninja components -import _binaryninjacore as core -from .enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType -import function -import basicblock -import mediumlevelil import struct +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType +from binaryninja import basicblock #required for LowLevelILBasicBlock + class LowLevelILLabel(object): def __init__(self, handle = None): @@ -342,6 +340,8 @@ class LowLevelILInstruction(object): } def __init__(self, func, expr_index, instr_index=None): + from binaryninja import function + from binaryninja import mediumlevelil instr = core.BNGetLowLevelILByIndex(func.handle, expr_index) self.function = func self.expr_index = expr_index @@ -441,7 +441,7 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): reg = operand_list[j * 2] reg_version = operand_list[(j * 2) + 1] value.append(SSARegister(ILRegister(func.arch, reg), reg_version)) @@ -451,7 +451,7 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): reg_stack = operand_list[j * 2] reg_version = operand_list[(j * 2) + 1] value.append(SSARegisterStack(ILRegisterStack(func.arch, reg_stack), reg_version)) @@ -461,7 +461,7 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): flag = operand_list[j * 2] flag_version = operand_list[(j * 2) + 1] value.append(SSAFlag(ILFlag(func.arch, flag), flag_version)) @@ -471,7 +471,7 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): if (operand_list[j * 2] & (1 << 32)) != 0: reg_or_flag = ILFlag(func.arch, operand_list[j * 2] & 0xffffffff) else: @@ -484,7 +484,7 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = {} - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): reg_stack = operand_list[j * 2] adjust = operand_list[(j * 2) + 1] if adjust & 0x80000000: @@ -720,6 +720,7 @@ class LowLevelILFunction(object): LLFC_NO !overflow No overflow ======================= ========== =============================== """ + from binaryninja import mediumlevelil def __init__(self, arch, handle = None, source_func = None): self.arch = arch self.source_function = source_func diff --git a/python/mainthread.py b/python/mainthread.py index 3e12bd65..16938f1a 100644 --- a/python/mainthread.py +++ b/python/mainthread.py @@ -18,9 +18,9 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -# Binary Ninja components -import _binaryninjacore as core -import scriptingprovider +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja import scriptingprovider def execute_on_main_thread(func): diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 100795fe..9a21bb23 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -19,16 +19,13 @@ # IN THE SOFTWARE. import ctypes - -# Binary Ninja components -import _binaryninjacore as core -from .enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence -import function -import basicblock -import lowlevelil -import types import struct +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence +from binaryninja import basicblock #required for MediumLevelILBasicBlock argument + class SSAVariable(object): def __init__(self, var, version): @@ -208,6 +205,9 @@ class MediumLevelILInstruction(object): } def __init__(self, func, expr_index, instr_index=None): + from binaryninja import function + from binaryninja import types + from binaryninja import lowlevelil instr = core.BNGetMediumLevelILByIndex(func.handle, expr_index) self.function = func self.expr_index = expr_index @@ -272,7 +272,7 @@ class MediumLevelILInstruction(object): operand_list = core.BNMediumLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for j in xrange(count.value / 2): + for j in xrange(count.value // 2): var_id = operand_list[j * 2] var_version = operand_list[(j * 2) + 1] value.append(SSAVariable(function.Variable.from_identifier(self.function.source_function, diff --git a/python/metadata.py b/python/metadata.py index 554bbcf4..21e74533 100644 --- a/python/metadata.py +++ b/python/metadata.py @@ -19,11 +19,12 @@ # IN THE SOFTWARE. +from __future__ import absolute_import import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import MetadataType +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import MetadataType class Metadata(object): diff --git a/python/platform.py b/python/platform.py index dd756178..ff59be50 100644 --- a/python/platform.py +++ b/python/platform.py @@ -20,15 +20,16 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core -import startup -import architecture -import callingconvention -import types +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core + +#2-3 compatibility +from six import with_metaclass class _PlatformMetaClass(type): + from binaryninja import startup + from binaryninja import types @property def list(self): startup._init_plugins() @@ -90,12 +91,14 @@ class _PlatformMetaClass(type): return result -class Platform(object): +class Platform(with_metaclass(_PlatformMetaClass, object)): """ ``class Platform`` contains all information releated to the execution environment of the binary, mainly the calling conventions used. """ - __metaclass__ = _PlatformMetaClass + from binaryninja import architecture + from binaryninja import callingconvention + from binaryninja import types name = None def __init__(self, arch, handle = None): diff --git a/python/plugin.py b/python/plugin.py index 13ca51af..5dad9fb6 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -22,16 +22,12 @@ import traceback import ctypes import threading -# Binary Ninja components -import _binaryninjacore as core -from enums import PluginCommandType -import startup -import filemetadata -import binaryview -import function -import log -import lowlevelil -import mediumlevelil +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import PluginCommandType + +#2-3 compatibility +from six import with_metaclass class PluginCommandContext(object): @@ -44,6 +40,7 @@ class PluginCommandContext(object): class _PluginCommandMetaClass(type): + from binaryninja import startup @property def list(self): startup._init_plugins() @@ -72,9 +69,13 @@ class _PluginCommandMetaClass(type): raise AttributeError("attribute '%s' is read only" % name) -class PluginCommand(object): +class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): + from binaryninja import startup + from binaryninja import filemetadata + from binaryninja import binaryview + from binaryninja import function + from binaryninja import log _registered_commands = [] - __metaclass__ = _PluginCommandMetaClass def __init__(self, cmd): self.command = core.BNPluginCommand() @@ -536,6 +537,7 @@ class MainThreadAction(object): class MainThreadActionHandler(object): + from binaryninja import log _main_thread = None def __init__(self): @@ -580,8 +582,7 @@ class _BackgroundTaskMetaclass(type): core.BNFreeBackgroundTaskList(tasks, count.value) -class BackgroundTask(object): - __metaclass__ = _BackgroundTaskMetaclass +class BackgroundTask(with_metaclass(_BackgroundTaskMetaclass, object)): def __init__(self, initial_progress_text = "", can_cancel = False, handle = None): if handle is None: diff --git a/python/pluginmanager.py b/python/pluginmanager.py index 0cc43aca..66f642c3 100644 --- a/python/pluginmanager.py +++ b/python/pluginmanager.py @@ -20,10 +20,8 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core -from .enums import PluginType, PluginUpdateStatus -import startup +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class RepoPlugin(object): @@ -31,6 +29,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) @@ -200,6 +199,7 @@ class RepositoryManager(object): ``RepositoryManager`` Keeps track of all the repositories and keeps the enabled_plugins.json file coherent with the plugins that are installed/unstalled enabled/disabled """ + from binaryninja import startup def __init__(self, handle=None): raise Exception("RepositoryManager temporarily disabled!") self.handle = core.BNGetRepositoryManager() diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 9cacc6ad..ac0ffd4c 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -26,14 +26,12 @@ import threading import abc import sys -# Binary Ninja Components -import _binaryninjacore as core -from enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState -import binaryview -import function -import basicblock -import startup -import log +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState + +#2-3 compatibility +from six import with_metaclass class _ThreadActionContext(object): @@ -60,6 +58,7 @@ class _ThreadActionContext(object): class ScriptingOutputListener(object): + from binaryninja import log def _register(self, handle): self._cb = core.BNScriptingOutputListener() self._cb.context = 0 @@ -100,6 +99,10 @@ class ScriptingOutputListener(object): class ScriptingInstance(object): + from binaryninja import binaryview + from binaryninja import basicblock + from binaryninja import log + from binaryninja import function def __init__(self, provider, handle = None): if handle is None: self._cb = core.BNScriptingInstanceCallbacks() @@ -256,6 +259,7 @@ class ScriptingInstance(object): class _ScriptingProviderMetaclass(type): + from binaryninja import startup @property def list(self): """List all ScriptingProvider types (read-only)""" @@ -292,8 +296,8 @@ class _ScriptingProviderMetaclass(type): raise AttributeError("attribute '%s' is read only" % name) -class ScriptingProvider(object): - __metaclass__ = _ScriptingProviderMetaclass +class ScriptingProvider(with_metaclass(_ScriptingProviderMetaclass, object)): + from binaryninja import log name = None instance_class = None @@ -335,6 +339,7 @@ class ScriptingProvider(object): class _PythonScriptingInstanceOutput(object): + from binaryninja import log def __init__(self, orig, is_error): self.orig = orig self.is_error = is_error diff --git a/python/setting.py b/python/setting.py index d58c8955..7cde3865 100644 --- a/python/setting.py +++ b/python/setting.py @@ -20,8 +20,8 @@ import ctypes -# Binary Ninja components -import _binaryninjacore as core +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core class Setting(object): diff --git a/python/startup.py b/python/startup.py index 0abc47cb..919a8fbe 100644 --- a/python/startup.py +++ b/python/startup.py @@ -18,7 +18,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -import _binaryninjacore as core +from binaryninja import _binaryninjacore as core _plugin_init = False diff --git a/python/transform.py b/python/transform.py index 3284ed74..f04bfdca 100644 --- a/python/transform.py +++ b/python/transform.py @@ -22,15 +22,16 @@ import traceback import ctypes import abc -# Binary Ninja components -import _binaryninjacore as core -from enums import TransformType -import startup -import log -import databuffer +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import TransformType + +#2-3 compatibility +from six import with_metaclass class _TransformMetaClass(type): + from binaryninja import startup @property def list(self): startup._init_plugins() @@ -90,14 +91,15 @@ class TransformParameter(object): self.fixed_length = fixed_length -class Transform(object): +class Transform(with_metaclass(_TransformMetaClass, object)): + from binaryninja import log + from binaryninja import databuffer transform_type = None name = None long_name = None group = None parameters = [] _registered_cb = None - __metaclass__ = _TransformMetaClass def __init__(self, handle): if handle is None: diff --git a/python/types.py b/python/types.py index 42ed7ddd..cbe5a7bc 100644 --- a/python/types.py +++ b/python/types.py @@ -18,15 +18,14 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. +from __future__ import absolute_import max_confidence = 255 import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType -import callingconvention -import function +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType class QualifiedName(object): @@ -213,6 +212,8 @@ class FunctionParameter(object): class Type(object): def __init__(self, handle, platform = None, confidence = max_confidence): + from binaryninja import callingconvention + from binaryninja import function self.handle = handle self.confidence = confidence self.platform = platform @@ -344,7 +345,7 @@ class Type(object): return None return Enumeration(result) - @property + @property def named_type_reference(self): """Reference to a named type (read-only)""" result = core.BNGetTypeNamedTypeReference(self.handle) @@ -376,7 +377,7 @@ class Type(object): def __repr__(self): if self.confidence < max_confidence: - return "" % (str(self), (self.confidence * 100) / max_confidence) + return "" % (str(self), (self.confidence * 100) // max_confidence) return "" % str(self) def get_string_before_name(self): diff --git a/python/undoaction.py b/python/undoaction.py index 7e3c76a0..9771df38 100644 --- a/python/undoaction.py +++ b/python/undoaction.py @@ -22,14 +22,14 @@ import traceback import json import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import ActionType -import startup -import log +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import ActionType class UndoAction(object): + from binaryninja import startup + from binaryninja import log name = None action_type = None _registered = False diff --git a/python/update.py b/python/update.py index 1eb8ea61..1fda149b 100644 --- a/python/update.py +++ b/python/update.py @@ -21,14 +21,17 @@ import traceback import ctypes -# Binary Ninja components -import _binaryninjacore as core -from enums import UpdateResult -import startup -import log +# Binary Ninja components -- additional imports belong in the appropriate class +from binaryninja import _binaryninjacore as core +from binaryninja.enums import UpdateResult + + +#2-3 compatibility +from six import with_metaclass class _UpdateChannelMetaClass(type): + from binaryninja import startup @property def list(self): startup._init_plugins() @@ -95,6 +98,7 @@ class _UpdateChannelMetaClass(type): class UpdateProgressCallback(object): + from binaryninja import log def __init__(self, func): self.cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(self.callback) self.func = func @@ -108,8 +112,7 @@ class UpdateProgressCallback(object): log.log_error(traceback.format_exc()) -class UpdateChannel(object): - __metaclass__ = _UpdateChannelMetaClass +class UpdateChannel(with_metaclass(_UpdateChannelMetaClass, object)): def __init__(self, name, desc, ver): self.name = name -- cgit v1.3.1 From 5cff3bf3cc5aa11875569a6aeddf88ef867411f1 Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Wed, 30 May 2018 15:41:10 -0400 Subject: Various Python 3 support changes --- Makefile | 75 ++++++++++++++++++-- basicblock.cpp | 4 +- python/__init__.py | 6 +- python/architecture.py | 13 ---- python/binaryview.py | 9 ++- python/databuffer.py | 28 +++++--- python/demangle.py | 4 +- python/generator.cpp | 179 ++++++++++++++++++++++++++++++++++++------------ python/log.py | 1 + python/lowlevelil.py | 1 - python/mediumlevelil.py | 54 +++++++-------- python/metadata.py | 9 ++- python/setting.py | 6 +- python/types.py | 2 +- 14 files changed, 275 insertions(+), 116 deletions(-) (limited to 'python/log.py') diff --git a/Makefile b/Makefile index 23414c45..852569a0 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ # LIB := -L$(HOME)/binaryninja/ -lbinaryninjacore #endif +INSTALLPATH := ~/binaryninja TARGETDIR := bin TARGETNAME := libbinaryninjaapi @@ -15,7 +16,8 @@ SOURCES = $(wildcard *$(SRCEXT)) OBJECTS = $(SOURCES:.cpp=.o) json.o -CFLAGS := -c -fPIC -O2 -pipe -std=gnu++11 -Wall -W +CFLAGS := -c -fPIC -O2 -pipe -std=gnu++11 -Wall -W -Wextra -Wshadow +CPPFLAGS := -O2 -std=c++11 -Wall -W -Wextra -Wshadow ifeq ($(UNAME_S),Darwin) CC := $(shell xcrun -f g++) AR := $(shell xcrun -f ar) @@ -38,8 +40,73 @@ $(TARGET).a: $(OBJECTS) json.o: ./json/jsoncpp.cpp ./json/json.h ./json/json-forwards.h $(CC) $(CFLAGS) -I. -c -o $@ $< -clean: +install: generate $(TARGET).a + @echo "Installing binaryninja API."; + cp -r python/* $(INSTALLPATH)/python/binaryninja + cp $(TARGETDIR)/$(TARGET).a $(INSTALLPATH) + +generator: python/generator.cpp $(TARGET).a + @echo "Building generator..."; + $(CC) $(CPPFLAGS) -I . $< -L$(TARGETDIR) -lbinaryninjaapi -L $(INSTALLPATH) -lbinaryninjacore -o $@ + chmod +x $@ + +generate: generator + @echo "Running generator..."; + LD_LIBRARY_PATH=$(INSTALLPATH) ./generator binaryninjacore.h python/_binaryninjacore.py python/enums.py + +python/_binaryninjacore.py: generate + +python/enums.py: generate + +python_test: environment python/_binaryninjacore.py python/enums.py + python2 suite/unit.py + python3 suite/unit.py + +oracle: environment python/_binaryninjacore.py python/enums.py + python3 suite/generator.py + +environment: python/_binaryninjacore.py python/enums.py + @echo "Copying libs to needed locations..." + @cp $(INSTALLPATH)/libbinaryninjacore.so.1 . + @cp $(INSTALLPATH)/libcurl.so.4 . + @cp $(INSTALLPATH)/libcrypto.so.1.0.2 . + @cp $(INSTALLPATH)/libssl.so.1.0.2 . + + @mkdir -p api/python/examples + @cp python/examples/bin_info.py api/python/examples/ + @cp $(INSTALLPATH)/libbinaryninjacore.so.1 api/python/ + @cp $(INSTALLPATH)/libcurl.so.4 api/python/ + @cp $(INSTALLPATH)/libcrypto.so.1.0.2 api/python/ + @cp $(INSTALLPATH)/libssl.so.1.0.2 api/python/ + + @echo "Building 'binaryninja' Packages..." + @mkdir -p suite/binaryninja/ + @cp -r python/* suite/binaryninja/ + @mkdir -p api/python/examples/binaryninja/ + @cp -r python/* api/python/examples/binaryninja/ + + @echo "Copying Architectures Over..." + @cp -r $(INSTALLPATH)/types/ . + @cp -r $(INSTALLPATH)/plugins/ . + @cp -r $(INSTALLPATH)/plugins/ api/python/ + +environment_clean: + @echo "Removing 'binaryninja' Packages..." + @rm -r suite/binaryninja/ + @rm -r api/ + -@rm suite/*.pyc + + @echo "Removing libs..." + @rm lib* + + @echo "Removing Architectures..." + @rm -r types/ + @rm -r plugins/ + +clean: @echo " Cleaning..."; - $(RM) -r *.o $(TARGETDIR) + $(RM) -r *.o $(TARGETDIR) generator + +squeaky: clean environment_clean -.PHONY: clean +.PHONY: clean environment_clean squeaky python/_binaryninjacore.py python/enums.py diff --git a/basicblock.cpp b/basicblock.cpp index 33f57d40..13b3e7a8 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -245,8 +245,8 @@ set> BasicBlock::GetIteratedDominanceFrontier(const set> result; - for (size_t i = 0; i < count; i++) - result.insert(new BasicBlock(BNNewBasicBlockReference(resultBlocks[i]))); + for (size_t k = 0; k < count; k++) + result.insert(new BasicBlock(BNNewBasicBlockReference(resultBlocks[k]))); BNFreeBasicBlockList(resultBlocks, count); return result; diff --git a/python/__init__.py b/python/__init__.py index a3ba0453..2f7cc5a0 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -118,10 +118,8 @@ class PluginManagerLoadPluginCallback(object): def __init__(self): self.cb = ctypes.CFUNCTYPE( ctypes.c_bool, - core.compatstring, - core.compatstring, - # ctypes.c_char_p, - # ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, ctypes.c_void_p)(self._load_plugin) def _load_plugin(self, repo_path, plugin_path, ctx): diff --git a/python/architecture.py b/python/architecture.py index b99da184..521c750a 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -1073,7 +1073,6 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): errors[0] = core.BNAllocString(str(error_str)) if data is None: return False - data = str(data) buf = ctypes.create_string_buffer(len(data)) ctypes.memmove(buf, data, len(data)) core.BNSetDataBufferContents(result, buf, len(data)) @@ -2294,7 +2293,6 @@ class CoreArchitecture(Architecture): :rtype: InstructionInfo """ info = core.BNInstructionInfo() - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info): @@ -2322,7 +2320,6 @@ class CoreArchitecture(Architecture): :return: an InstructionTextToken list for the current instruction :rtype: list(InstructionTextToken) """ - data = str(data) count = ctypes.c_ulonglong() length = ctypes.c_ulonglong() length.value = len(data) @@ -2359,7 +2356,6 @@ class CoreArchitecture(Architecture): :return: the length of the current instruction :rtype: int """ - data = str(data) length = ctypes.c_ulonglong() length.value = len(data) buf = (ctypes.c_ubyte * len(data))() @@ -2449,7 +2445,6 @@ class CoreArchitecture(Architecture): False >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data)) @@ -2471,7 +2466,6 @@ class CoreArchitecture(Architecture): False >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data)) @@ -2492,7 +2486,6 @@ class CoreArchitecture(Architecture): False >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data)) @@ -2516,7 +2509,6 @@ class CoreArchitecture(Architecture): False >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data)) @@ -2538,7 +2530,6 @@ class CoreArchitecture(Architecture): False >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data)) @@ -2558,7 +2549,6 @@ class CoreArchitecture(Architecture): '\\x90\\x90' >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNArchitectureConvertToNop(self.handle, buf, addr, len(data)): @@ -2585,7 +2575,6 @@ class CoreArchitecture(Architecture): (['jmp ', '0x9'], 5L) >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNArchitectureAlwaysBranch(self.handle, buf, addr, len(data)): @@ -2613,7 +2602,6 @@ class CoreArchitecture(Architecture): (['jl ', '0xa'], 6L) >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNArchitectureInvertBranch(self.handle, buf, addr, len(data)): @@ -2637,7 +2625,6 @@ class CoreArchitecture(Architecture): (['mov ', 'eax', ', ', '0x0'], 5L) >>> """ - data = str(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNArchitectureSkipAndReturnValue(self.handle, buf, addr, len(data), value): diff --git a/python/binaryview.py b/python/binaryview.py index ac08ad76..b1bc4822 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -372,12 +372,12 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)): @property def name(self): """BinaryView name (read-only)""" - return core.BNGetBinaryViewTypeName(self.handle).decode('utf8') + return core.BNGetBinaryViewTypeName(self.handle) @property def long_name(self): """BinaryView long name (read-only)""" - return core.BNGetBinaryViewTypeLongName(self.handle).decode('utf8') + return core.BNGetBinaryViewTypeLongName(self.handle) def __repr__(self): return "" % self.name @@ -423,6 +423,9 @@ class BinaryViewType(with_metaclass(_BinaryViewTypeMetaclass, object)): else: bv = cls[available.name].open(filename) + if bv is None: + raise Exception("Unknown Architecture/Architecture Not Found (check plugins folder)") + if update_analysis: bv.update_analysis_and_wait() return bv @@ -1740,7 +1743,7 @@ class BinaryView(object): \'\\xcf\\xfa\\xed\\xfe\' """ buf = databuffer.DataBuffer(handle=core.BNReadViewBuffer(self.handle, addr, length)) - return str(buf) + return bytes(buf) def write(self, addr, data): """ diff --git a/python/databuffer.py b/python/databuffer.py index bf366750..1b29a7eb 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -26,6 +26,13 @@ from binaryninja import _binaryninjacore as core class DataBuffer(object): def __init__(self, contents="", handle=None): + + # python3 no longer has longs + try: + long + except NameError: + long = int + if handle is not None: self.handle = core.handle_of_type(handle, core.BNDataBuffer) elif isinstance(contents, int) or isinstance(contents, long): @@ -44,7 +51,7 @@ class DataBuffer(object): def __getitem__(self, i): if isinstance(i, tuple): result = "" - source = str(self) + source = bytes(self) for s in i: result += source[s] return result @@ -59,7 +66,7 @@ class DataBuffer(object): ctypes.memmove(buf, core.BNGetDataBufferContentsAt(self.handle, start), stop - start) return buf.raw else: - return str(self)[i] + return bytes(self)[i] elif i < 0: if i >= -len(self): return chr(core.BNGetDataBufferByte(self.handle, int(len(self) + i))) @@ -79,7 +86,7 @@ class DataBuffer(object): if stop < start: stop = start if len(value) != (stop - start): - data = str(self) + data = bytes(self) data = data[0:start] + value + data[stop:] core.BNSetDataBufferContents(self.handle, data, len(data)) else: @@ -107,22 +114,27 @@ class DataBuffer(object): def __str__(self): buf = ctypes.create_string_buffer(len(self)) ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self)) - return buf.raw + if type(buf.raw) is str: + return buf.raw + else: + return buf.raw.decode("charmap") - def __repr__(self): - return repr(str(self)) + def __bytes__(self): + buf = ctypes.create_string_buffer(len(self)) + ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self)) + return buf.raw def escape(self): return core.BNDataBufferToEscapedString(self.handle) def unescape(self): - return DataBuffer(handle=core.BNDecodeEscapedString(str(self))) + return DataBuffer(handle=core.BNDecodeEscapedString(bytes(self))) def base64_encode(self): return core.BNDataBufferToBase64(self.handle) def base64_decode(self): - return DataBuffer(handle = core.BNDecodeBase64(str(self))) + return DataBuffer(handle = core.BNDecodeBase64(bytes(self))) def zlib_compress(self): buf = core.BNZlibCompress(self.handle) diff --git a/python/demangle.py b/python/demangle.py index ceb1e48b..90a19761 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -65,7 +65,7 @@ def demangle_ms(arch, mangled_name): names = [] if core.BNDemangleMS(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): - names.append(outName[i]) + names.append(outName[i].decode('charmap')) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) return (types.Type(handle), names) return (None, mangled_name) @@ -79,7 +79,7 @@ def demangle_gnu3(arch, mangled_name): names = [] if core.BNDemangleGNU3(arch.handle, mangled_name, ctypes.byref(handle), ctypes.byref(outName), ctypes.byref(outSize)): for i in range(outSize.value): - names.append(outName[i]) + names.append(outName[i].decode('charmap')) core.BNFreeDemangledName(ctypes.byref(outName), outSize.value) if not handle: return (None, names) diff --git a/python/generator.cpp b/python/generator.cpp index 8fc415b0..2da856ff 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -121,10 +121,8 @@ void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallbac { if (isReturnType) fprintf(out, "ctypes.POINTER(ctypes.c_byte)"); - else { - //fprintf(out, "compatstring"); + else fprintf(out, "ctypes.c_char_p"); - } break; } else if (type->GetChildType()->GetClass() == FunctionTypeClass) @@ -175,7 +173,7 @@ int main(int argc, char* argv[]) } bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors); - fprintf(stderr, "Errors: %s", errors.c_str()); + fprintf(stderr, "Errors: %s\n", errors.c_str()); if (!ok) return 1; @@ -190,7 +188,6 @@ int main(int argc, char* argv[]) fprintf(out, "import platform\n"); fprintf(out, "core = None\n"); fprintf(out, "_base_path = None\n"); - fprintf(out, "ctypes.set_conversion_mode('utf-8', 'strict')\n"); fprintf(out, "if platform.system() == \"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"); @@ -202,40 +199,12 @@ int main(int argc, char* argv[]) fprintf(out, "\tcore = ctypes.CDLL(os.path.join(_base_path, \"binaryninjacore.dll\"))\n"); fprintf(out, "else:\n"); fprintf(out, "\traise Exception(\"OS not supported\")\n\n"); - // fprintf(out, "class compatstring(ctypes.c_char_p):\n"); - // fprintf(out, "\tdef __init__(self, value=None):\n"); - // fprintf(out, "\t\tsuper(compatstring, self).__init__()\n"); - // fprintf(out, "\t\tif value is not None:\n"); - // fprintf(out, "\t\t\tself.value = value\n"); - // fprintf(out, "\t@classmethod\n"); - // fprintf(out, "\tdef from_param(cls, value):\n"); - // fprintf(out, "\t\tif not isinstance(value, bytes):\n"); - // fprintf(out, "\t\t\treturn super(compatstring, cls).from_param(value.encode('utf8'))\n"); - // fprintf(out, "\t\treturn super(compatstring, cls).from_param(value)\n\n"); - // fprintf(out, "\t@property\n"); - // fprintf(out, "\tdef value(self, value):\n"); - // fprintf(out, "\t\tif not isinstance(value, bytes):\n"); - // fprintf(out, "\t\t\treturn super(compatstring, cls).from_param(value.encode('utf8'))\n"); - // fprintf(out, "\t\treturn super(compatstring, cls).from_param(value)\n\n"); - fprintf(out, "class compatstring(ctypes.c_char_p):\n"); - fprintf(out, " @classmethod\n"); - fprintf(out, " def from_param(cls, obj):\n"); - fprintf(out, " if (obj is not None) and (not isinstance(obj, cls)):\n"); - fprintf(out, " if not isinstance(obj, basestring):\n"); - fprintf(out, " raise TypeError('parameter must be a string type instance')\n"); - fprintf(out, " if not isinstance(obj, unicode):\n"); - fprintf(out, " obj = unicode(obj)\n"); - fprintf(out, " obj = obj.encode('utf-8')\n"); - fprintf(out, " return ctypes.c_char_p.from_param(obj)\n"); - fprintf(out, "\n"); - fprintf(out, " def decode(self):\n"); - fprintf(out, " if self.value is None:\n"); - fprintf(out, " return None\n"); - fprintf(out, " return self.value.decode('utf-8')\n"); - fprintf(out, " @property\n"); - fprintf(out, " def value(self, c_void_p=ctypes.c_void_p):\n"); - fprintf(out, " addr = c_void_p.from_buffer(self).value\n"); - fprintf(out, " return \n"); + + fprintf(out, "def cstr(arg):\n"); + fprintf(out, "\tif isinstance(arg, str):\n"); + fprintf(out, "\t\treturn arg.encode('charmap')\n"); + fprintf(out, "\telse:\n"); + fprintf(out, "\t\treturn arg\n\n"); // Create type objects fprintf(out, "# Type definitions\n"); @@ -248,7 +217,23 @@ int main(int argc, char* argv[]) if (i.second->GetClass() == StructureTypeClass) { fprintf(out, "class %s(ctypes.Structure):\n", name.c_str()); - fprintf(out, "\tpass\n"); + + // python uses str's, C uses byte-arrays + bool stringField = false; + for (auto& arg : i.second->GetStructure()->GetMembers()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + fprintf(out, "\t@property\n\tdef %s(self):\n\t\treturn self._%s.decode('charmap')\n", arg.name.c_str(), arg.name.c_str()); + fprintf(out, "\t@%s.setter\n\tdef %s(self, value):\n\t\tself._%s = value.encode('charmap')\n", arg.name.c_str(), arg.name.c_str(), arg.name.c_str()); + stringField = true; + } + } + + if (!stringField) + fprintf(out, "\tpass\n"); } else if (i.second->GetClass() == EnumerationTypeClass) { @@ -313,7 +298,15 @@ int main(int argc, char* argv[]) fprintf(out, "%s._fields_ = [\n", name.c_str()); for (auto& j : type->GetStructure()->GetMembers()) { - fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); + // To help the python->C wrappers + if ((j.type->GetClass() == PointerTypeClass) && + (j.type->GetChildType()->GetWidth() == 1) && + (j.type->GetChildType()->IsSigned())) + { + fprintf(out, "\t\t(\"_%s\", ", j.name.c_str()); + } + else + fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); OutputType(out, j.type); fprintf(out, "),\n"); } @@ -347,6 +340,22 @@ int main(int argc, char* argv[]) (i.second->GetChildType()->GetChildType()->IsSigned()); // Pointer returns will be automatically wrapped to return None on null pointer bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass); + + // From python -> C python3 requires str -> str.encode('charmap') + bool stringArgument = false; + for (auto& arg : i.second->GetParameters()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + stringArgument = true; + break; + } + } + if (name == "BNFreeString") + stringArgument = false; + bool callbackConvention = false; if (name == "BNAllocString") { @@ -358,7 +367,7 @@ int main(int argc, char* argv[]) } string funcName = name; - if (stringResult || pointerResult) + if (stringResult || pointerResult || stringArgument) funcName = string("_") + funcName; fprintf(out, "%s = core.%s\n", funcName.c_str(), name.c_str()); @@ -391,8 +400,30 @@ int main(int argc, char* argv[]) { // Emit wrapper to get Python string and free native memory fprintf(out, "def %s(*args):\n", name.c_str()); - fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); - fprintf(out, "\tstring = ctypes.cast(result, ctypes.c_char_p).value\n"); + if (stringArgument) + { + fprintf(out, "\tresult = %s(", funcName.c_str()); + string stringArgFuncCall = ""; + size_t argN = 0; + for (auto& arg : i.second->GetParameters()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), "; + } + else + stringArgFuncCall += "args[" + to_string(argN) + "], "; + argN++; + } + stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2); + stringArgFuncCall += ")\n"; + fprintf(out, "%s", stringArgFuncCall.c_str()); + } + else + fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); + fprintf(out, "\tstring = str(ctypes.cast(result, ctypes.c_char_p).value.decode('charmap'))\n"); fprintf(out, "\tBNFreeString(result)\n"); fprintf(out, "\treturn string\n"); } @@ -400,11 +431,58 @@ int main(int argc, char* argv[]) { // Emit wrapper to return None on null pointer fprintf(out, "def %s(*args):\n", name.c_str()); - fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); + if (stringArgument) + { + fprintf(out, "\tresult = %s(", funcName.c_str()); + string stringArgFuncCall = ""; + size_t argN = 0; + for (auto& arg : i.second->GetParameters()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), "; + } + else + stringArgFuncCall += "args[" + to_string(argN) + "], "; + argN++; + } + stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2); + stringArgFuncCall += ")\n"; + fprintf(out, "%s", stringArgFuncCall.c_str()); + } + else + fprintf(out, "\tresult = %s(*args)\n", funcName.c_str()); fprintf(out, "\tif not result:\n"); fprintf(out, "\t\treturn None\n"); fprintf(out, "\treturn result\n"); } + else if (stringArgument) + { + fprintf(out, "def %s(*args):\n", name.c_str()); + { + fprintf(out, "\treturn %s(", funcName.c_str()); + string stringArgFuncCall = ""; + size_t argN = 0; + for (auto& arg : i.second->GetParameters()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + stringArgFuncCall += "cstr(args[" + to_string(argN) + "]), "; + } + else + stringArgFuncCall += "args[" + to_string(argN) + "], "; + argN++; + } + stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2); + stringArgFuncCall += ")\n"; + fprintf(out, "%s", stringArgFuncCall.c_str()); + } + } + fprintf(out, "\n"); } fprintf(out, "\n# Helper functions\n"); @@ -413,6 +491,17 @@ int main(int argc, char* argv[]) fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n"); fprintf(out, "\traise ValueError('expected pointer to %%s' %% str(handle_type))\n"); + // The following method is addapted from python/enum/__init__.py, lines 25-36 + fprintf(out, "\ntry:\n"); + fprintf(out, "\tbasestring\n"); + fprintf(out, "\tunicode\n"); + fprintf(out, "except NameError:\n"); + fprintf(out, "\t# In Python 2 basestring is the ancestor of both str and unicode\n"); + fprintf(out, "\t# in Python 3 it's just str, but was missing in 3.1\n"); + fprintf(out, "\t# In Python 3 unicode no longer exists (it's just str)\n"); + fprintf(out, "\tbasestring = str\n"); + fprintf(out, "\tunicode = str\n"); + fprintf(out, "\n# Set path for core plugins\n"); fprintf(out, "BNSetBundledPluginDirectory(os.path.join(_base_path, \"plugins\"))\n"); diff --git a/python/log.py b/python/log.py index e7cd956d..d4d87019 100644 --- a/python/log.py +++ b/python/log.py @@ -21,6 +21,7 @@ # Binary Ninja components -- additional imports belong in the appropriate class from binaryninja import _binaryninjacore as core +from binaryninja.enums import LogLevel _output_to_log = False diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 333bb5a1..272b2474 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -722,7 +722,6 @@ class LowLevelILFunction(object): LLFC_NO !overflow No overflow ======================= ========== =============================== """ - from binaryninja import mediumlevelil def __init__(self, arch, handle = None, source_func = None): self.arch = arch self.source_function = source_func diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 707915d7..f7e9951a 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -21,10 +21,13 @@ import ctypes import struct -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence from binaryninja import basicblock #required for MediumLevelILBasicBlock argument +from binaryninja import function +from binaryninja import types +from binaryninja import lowlevelil # 2-3 compatibility from six.moves import range @@ -208,9 +211,6 @@ class MediumLevelILInstruction(object): } def __init__(self, func, expr_index, instr_index=None): - from binaryninja import function - from binaryninja import types - from binaryninja import lowlevelil instr = core.BNGetMediumLevelILByIndex(func.handle, expr_index) self.function = func self.expr_index = expr_index @@ -241,14 +241,14 @@ class MediumLevelILInstruction(object): elif operand_type == "intrinsic": value = lowlevelil.ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "var": - value = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + value = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) elif operand_type == "var_ssa": - var = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) version = instr.operands[i + 1] i += 1 value = SSAVariable(var, version) elif operand_type == "var_ssa_dest_and_src": - var = binaryninja.function.Variable.from_identifier(self.function.source_function, instr.operands[i]) + var = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) dest_version = instr.operands[i + 1] src_version = instr.operands[i + 2] i += 2 @@ -349,14 +349,14 @@ class MediumLevelILInstruction(object): def value(self): """Value of expression if constant or a known value (read-only)""" value = core.BNGetMediumLevelILExprValue(self.function.handle, self.expr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result @property def possible_values(self): """Possible values of expression using path-sensitive static data flow analysis (read-only)""" value = core.BNGetMediumLevelILPossibleExprValues(self.function.handle, self.expr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -454,7 +454,7 @@ class MediumLevelILInstruction(object): return [] result = [] for operand in self.operands: - if (isinstance(operand, binaryninja.function.Variable)) or (isinstance(operand, SSAVariable)): + if (isinstance(operand, function.Variable)) or (isinstance(operand, SSAVariable)): result.append(operand) elif isinstance(operand, MediumLevelILInstruction): result += operand.vars_read @@ -477,7 +477,7 @@ class MediumLevelILInstruction(object): var_data.index = ssa_var.var.index var_data.storage = ssa_var.var.storage value = core.BNGetMediumLevelILPossibleSSAVarValues(self.function.handle, var_data, ssa_var.version, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -491,88 +491,88 @@ class MediumLevelILInstruction(object): def get_var_for_reg(self, reg): reg = self.function.arch.get_reg_index(reg) result = core.BNGetMediumLevelILVariableForRegisterAtInstruction(self.function.handle, reg, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_var_for_flag(self, flag): flag = self.function.arch.get_flag_index(flag) result = core.BNGetMediumLevelILVariableForFlagAtInstruction(self.function.handle, flag, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_var_for_stack_location(self, offset): result = core.BNGetMediumLevelILVariableForStackLocationAtInstruction(self.function.handle, offset, self.instr_index) - return binaryninja.function.Variable(self.function.source_function, result.type, result.index, result.storage) + return function.Variable(self.function.source_function, result.type, result.index, result.storage) def get_reg_value(self, reg): reg = self.function.arch.get_reg_index(reg) value = core.BNGetMediumLevelILRegisterValueAtInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_reg_value_after(self, reg): reg = self.function.arch.get_reg_index(reg) value = core.BNGetMediumLevelILRegisterValueAfterInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_possible_reg_values(self, reg): reg = self.function.arch.get_reg_index(reg) value = core.BNGetMediumLevelILPossibleRegisterValuesAtInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_possible_reg_values_after(self, reg): reg = self.function.arch.get_reg_index(reg) value = core.BNGetMediumLevelILPossibleRegisterValuesAfterInstruction(self.function.handle, reg, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_flag_value(self, flag): flag = self.function.arch.get_flag_index(flag) value = core.BNGetMediumLevelILFlagValueAtInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_flag_value_after(self, flag): flag = self.function.arch.get_flag_index(flag) value = core.BNGetMediumLevelILFlagValueAfterInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_possible_flag_values(self, flag): flag = self.function.arch.get_flag_index(flag) value = core.BNGetMediumLevelILPossibleFlagValuesAtInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_possible_flag_values_after(self, flag): flag = self.function.arch.get_flag_index(flag) value = core.BNGetMediumLevelILPossibleFlagValuesAfterInstruction(self.function.handle, flag, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_stack_contents(self, offset, size): value = core.BNGetMediumLevelILStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_stack_contents_after(self, offset, size): value = core.BNGetMediumLevelILStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.RegisterValue(self.function.arch, value) + result = function.RegisterValue(self.function.arch, value) return result def get_possible_stack_contents(self, offset, size): value = core.BNGetMediumLevelILPossibleStackContentsAtInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result def get_possible_stack_contents_after(self, offset, size): value = core.BNGetMediumLevelILPossibleStackContentsAfterInstruction(self.function.handle, offset, size, self.instr_index) - result = binaryninja.function.PossibleValueSet(self.function.arch, value) + result = function.PossibleValueSet(self.function.arch, value) core.BNFreePossibleValueSet(value) return result @@ -905,7 +905,7 @@ class MediumLevelILFunction(object): var_data.index = ssa_var.var.index var_data.storage = ssa_var.var.storage value = core.BNGetMediumLevelILSSAVarValue(self.handle, var_data, ssa_var.version) - result = binaryninja.function.RegisterValue(self.arch, value) + result = function.RegisterValue(self.arch, value) return result def get_low_level_il_instruction_index(self, instr): diff --git a/python/metadata.py b/python/metadata.py index 64080060..fed8bdaa 100644 --- a/python/metadata.py +++ b/python/metadata.py @@ -43,7 +43,7 @@ class Metadata(object): self.handle = core.BNCreateMetadataBooleanData(value) elif isinstance(value, str): if raw: - buffer = (ctypes.c_ubyte * len(value)).from_buffer_copy(value) + buffer = (ctypes.c_ubyte * len(value)).from_buffer_copy(value.encode('charmap')) self.handle = core.BNCreateMetadataRawData(buffer, len(value)) else: self.handle = core.BNCreateMetadataStringData(value) @@ -147,7 +147,10 @@ class Metadata(object): result = core.BNMetadataGetValueStore(self.handle) try: for i in range(result.contents.size): - yield result.contents.keys[i] + if type(result.contents.keys[i]) is bytes: + yield str(result.contents.keys[i].decode('charmap')) + else: + yield result.contents.keys[i] finally: core.BNFreeMetadataValueStore(result) else: @@ -172,7 +175,7 @@ class Metadata(object): def __str__(self): if self.is_string: - return core.BNMetadataGetString(self.handle) + return str(core.BNMetadataGetString(self.handle)) if self.is_raw: length = ctypes.c_ulonglong() length.value = 0 diff --git a/python/setting.py b/python/setting.py index 16d943e7..fea06140 100644 --- a/python/setting.py +++ b/python/setting.py @@ -58,11 +58,11 @@ class Setting(object): length.value = len(default_value) default_list = (ctypes.c_char_p * len(default_value))() for i in range(len(default_value)): - default_list[i] = default_value[i] + default_list[i] = default_value[i].encode('charmap') result = core.BNSettingGetStringList(self.plugin_name, name, default_list, ctypes.byref(length)) out_list = [] for i in range(length.value): - out_list.append(result[i]) + out_list.append(result[i].decode('charmap')) core.BNFreeStringList(result, length) return out_list @@ -113,7 +113,7 @@ class Setting(object): length.value = len(value) default_list = (ctypes.c_char_p * len(value))() for i in range(len(value)): - default_list[i] = str(value[i]) + default_list[i] = value[i].encode('utf-8') return core.BNSettingSetStringList(self.plugin_name, name, default_list, length, auto_flush) diff --git a/python/types.py b/python/types.py index 857f67e6..2ad8d2c2 100644 --- a/python/types.py +++ b/python/types.py @@ -39,7 +39,7 @@ class QualifiedName(object): elif isinstance(name, QualifiedName): self.name = name.name else: - self.name = name + self.name = [i.decode('utf-8') for i in name] def __str__(self): return "::".join(self.name) -- cgit v1.3.1 From 5d4015659d20cfee839ccccdcfb96094ac8e610a Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Wed, 6 Jun 2018 20:44:47 -0400 Subject: Various Python 3 support changes --- .gitignore | 14 ++ Makefile | 50 +++---- python/__init__.py | 26 ++++ python/architecture.py | 35 ++--- python/basicblock.py | 5 +- python/binaryview.py | 34 +++-- python/callingconvention.py | 7 +- python/databuffer.py | 4 +- python/demangle.py | 4 +- python/downloadprovider.py | 4 +- python/fileaccessor.py | 3 +- python/filemetadata.py | 2 +- python/function.py | 25 +++- python/functionrecognizer.py | 14 +- python/highlight.py | 2 +- python/interaction.py | 17 ++- python/log.py | 14 +- python/lowlevelil.py | 4 +- python/mainthread.py | 2 +- python/mediumlevelil.py | 2 +- python/metadata.py | 6 +- python/platform.py | 76 +++++------ python/plugin.py | 19 +-- python/pluginmanager.py | 6 +- python/scriptingprovider.py | 46 ++++--- python/setting.py | 8 +- python/transform.py | 15 +-- python/types.py | 15 ++- python/undoaction.py | 4 +- python/update.py | 12 +- scripts/install_api.py | 2 +- suite/binaries | 2 +- suite/generator.py | 107 +++++++++------ suite/testcommon.py | 282 ++++++++++++++++++++++++++------------- suite/unit.py | 309 +++++++++++++------------------------------ 35 files changed, 621 insertions(+), 556 deletions(-) (limited to 'python/log.py') diff --git a/.gitignore b/.gitignore index fc71333a..eff64eb4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,17 @@ CTestTestfile.cmake api-docs/source/python.rst api-docs/source/index.rst .coverage +# Make +generator +libcrypto.so.1.0.2 +libcurl.so.4 +libssl.so.1.0.2 +plugins/ +python/examples/binaryninja/ +python/libcrypto.so.1.0.2 +python/libcurl.so.4 +python/libssl.so.1.0.2 +python/plugins/ +python/types/ +suite/binaryninja/ +types/ diff --git a/Makefile b/Makefile index 852569a0..e1576dcf 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,8 @@ json.o: ./json/jsoncpp.cpp ./json/json.h ./json/json-forwards.h install: generate $(TARGET).a @echo "Installing binaryninja API."; cp -r python/* $(INSTALLPATH)/python/binaryninja - cp $(TARGETDIR)/$(TARGET).a $(INSTALLPATH) + cp $(TARGET).a $(INSTALLPATH) + @echo "Done."; generator: python/generator.cpp $(TARGET).a @echo "Building generator..."; @@ -65,43 +66,36 @@ python_test: environment python/_binaryninjacore.py python/enums.py oracle: environment python/_binaryninjacore.py python/enums.py python3 suite/generator.py -environment: python/_binaryninjacore.py python/enums.py - @echo "Copying libs to needed locations..." - @cp $(INSTALLPATH)/libbinaryninjacore.so.1 . - @cp $(INSTALLPATH)/libcurl.so.4 . - @cp $(INSTALLPATH)/libcrypto.so.1.0.2 . - @cp $(INSTALLPATH)/libssl.so.1.0.2 . - - @mkdir -p api/python/examples - @cp python/examples/bin_info.py api/python/examples/ - @cp $(INSTALLPATH)/libbinaryninjacore.so.1 api/python/ - @cp $(INSTALLPATH)/libcurl.so.4 api/python/ - @cp $(INSTALLPATH)/libcrypto.so.1.0.2 api/python/ - @cp $(INSTALLPATH)/libssl.so.1.0.2 api/python/ +environment: environment_clean python/_binaryninjacore.py python/enums.py + @echo "Copying over libs..." + cp $(INSTALLPATH)/libbinaryninjacore.so.1 . + cp $(INSTALLPATH)/libbinaryninjacore.so.1 python/ @echo "Building 'binaryninja' Packages..." - @mkdir -p suite/binaryninja/ - @cp -r python/* suite/binaryninja/ - @mkdir -p api/python/examples/binaryninja/ - @cp -r python/* api/python/examples/binaryninja/ + mkdir -p suite/binaryninja/ + cp -r python/* suite/binaryninja/ + cp -r suite/binaryninja/ python/examples/ @echo "Copying Architectures Over..." - @cp -r $(INSTALLPATH)/types/ . - @cp -r $(INSTALLPATH)/plugins/ . - @cp -r $(INSTALLPATH)/plugins/ api/python/ + cp -r $(INSTALLPATH)/types/ . + cp -r $(INSTALLPATH)/plugins/ . + cp -r $(INSTALLPATH)/types/ python/ + cp -r $(INSTALLPATH)/plugins/ python/ environment_clean: @echo "Removing 'binaryninja' Packages..." - @rm -r suite/binaryninja/ - @rm -r api/ - -@rm suite/*.pyc - + rm -rf suite/binaryninja/ + rm -rf python/examples/binaryninja/ + @echo "Removing libs..." - @rm lib* + rm -f libbinaryninjacore.so.1 + rm -f python/libbinaryninjacore.so.1 @echo "Removing Architectures..." - @rm -r types/ - @rm -r plugins/ + rm -rf types/ + rm -rf plugins/ + rm -rf python/types/ + rm -rf python/plugins/ clean: @echo " Cleaning..."; diff --git a/python/__init__.py b/python/__init__.py index 2f7cc5a0..e1288b0a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -25,6 +25,32 @@ import sys import ctypes from time import gmtime + +# 2-3 compatibility +try: + import builtins # __builtins__ for python2 +except ImportError: + pass +def range(*args): + """ A Python2 and Python3 Compatible Range Generator """ + try: + return xrange(*args) + except NameError: + return builtins.range(*args) + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + class metaclass(type): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + # Binary Ninja components import binaryninja._binaryninjacore as core # __all__ = [ diff --git a/python/architecture.py b/python/architecture.py index 521c750a..aee7c301 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -23,13 +23,12 @@ import traceback import ctypes import abc -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import (Endianness, ImplicitRegisterExtend, BranchType, InstructionTextTokenType, LowLevelILFlagCondition, FlagRole) import binaryninja from binaryninja import log - from binaryninja import lowlevelil from binaryninja import types from binaryninja import databuffer @@ -37,8 +36,9 @@ from binaryninja import platform from binaryninja import callingconvention # 2-3 compatibility -from six import with_metaclass -from six.moves import range +from binaryninja import range +from binaryninja import with_metaclass + class _ArchitectureMetaClass(type): @@ -624,7 +624,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_full_width_registers(self, ctxt, count): try: - regs = self._full_width_regs.values() + regs = list(self._full_width_regs.values()) count[0] = len(regs) reg_buf = (ctypes.c_uint * len(regs))() for i in range(0, len(regs)): @@ -639,7 +639,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_registers(self, ctxt, count): try: - regs = self._regs_by_index.keys() + regs = list(self._regs_by_index.keys()) count[0] = len(regs) reg_buf = (ctypes.c_uint * len(regs))() for i in range(0, len(regs)): @@ -654,7 +654,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_flags(self, ctxt, count): try: - flags = self._flags_by_index.keys() + flags = list(self._flags_by_index.keys()) count[0] = len(flags) flag_buf = (ctypes.c_uint * len(flags))() for i in range(0, len(flags)): @@ -669,7 +669,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_flag_write_types(self, ctxt, count): try: - write_types = self._flag_write_types_by_index.keys() + write_types = list(self._flag_write_types_by_index.keys()) count[0] = len(write_types) type_buf = (ctypes.c_uint * len(write_types))() for i in range(0, len(write_types)): @@ -684,7 +684,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_semantic_flag_classes(self, ctxt, count): try: - sem_classes = self._semantic_flag_classes_by_index.keys() + sem_classes = list(self._semantic_flag_classes_by_index.keys()) count[0] = len(sem_classes) class_buf = (ctypes.c_uint * len(sem_classes))() for i in range(0, len(sem_classes)): @@ -699,7 +699,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_semantic_flag_groups(self, ctxt, count): try: - sem_groups = self._semantic_flag_groups_by_index.keys() + sem_groups = list(self._semantic_flag_groups_by_index.keys()) count[0] = len(sem_groups) group_buf = (ctypes.c_uint * len(sem_groups))() for i in range(0, len(sem_groups)): @@ -938,7 +938,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_register_stacks(self, ctxt, count): try: - regs = self._reg_stacks_by_index.keys() + regs = list(self._reg_stacks_by_index.keys()) count[0] = len(regs) reg_buf = (ctypes.c_uint * len(regs))() for i in range(0, len(regs)): @@ -989,7 +989,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def _get_all_intrinsics(self, ctxt, count): try: - regs = self._intrinsics_by_index.keys() + regs = list(self._intrinsics_by_index.keys()) count[0] = len(regs) reg_buf = (ctypes.c_uint * len(regs))() for i in range(0, len(regs)): @@ -2415,8 +2415,8 @@ class CoreArchitecture(Architecture): :param str code: string representation of the instructions to be assembled :param int addr: virtual address that the instructions will be loaded at - :return: the bytes for the assembled instructions or error string - :rtype: (a tuple of instructions and empty string) or (or None and error string) + :return: the bytes for the assembled instructions + :rtype: Python3 - a 'bytes' object; Python2 - a 'str' :Example: >>> arch.assemble("je 10") @@ -2426,8 +2426,11 @@ class CoreArchitecture(Architecture): result = databuffer.DataBuffer() errors = ctypes.c_char_p() if not core.BNAssemble(self.handle, code, addr, result.handle, errors): - return None, errors.value - return str(result), errors.value + raise ValueError("Could not assemble") + if isinstance(str(result), bytes): + return str(result) + else: + return bytes(result) def is_never_branch_patch_available(self, data, addr): """ diff --git a/python/basicblock.py b/python/basicblock.py index b1f95ba3..11d5a7f4 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -20,14 +20,15 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import highlight from binaryninja import _binaryninjacore as core from binaryninja.enums import BranchType, HighlightColorStyle, HighlightStandardColor, InstructionTextTokenType # 2-3 compatibility -from six.moves import range +from binaryninja import range + class BasicBlockEdge(object): def __init__(self, branch_type, source, target, back_edge): diff --git a/python/binaryview.py b/python/binaryview.py index b1bc4822..d439f563 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -23,7 +23,7 @@ import traceback import ctypes import abc -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import (AnalysisState, SymbolType, InstructionTextTokenType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics) @@ -38,8 +38,8 @@ from binaryninja import lineardisassembly from binaryninja import metadata # 2-3 compatibility -from six import with_metaclass -from six.moves import range +from binaryninja import range +from binaryninja import with_metaclass class BinaryDataNotification(object): @@ -98,17 +98,19 @@ class StringReference(object): @property def value(self): - return self.view.read(self.start, self.length) + return self.view.read(self.start, self.length).decode("charmap") def __repr__(self): return "<%s: %#x, len %#x>" % (self.type, self.start, self.length) +_pending_analysis_completion_events = {} class AnalysisCompletionEvent(object): """ The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving callbacks when analysis is complete. The callback runs once. A completion event must be added - for each new analysis in order to be notified of each analysis completion. + for each new analysis in order to be notified of each analysis completion. The + AnalysisCompletionEvent class takes responcibility for keeping track of the object's lifetime. :Example: >>> def on_complete(self): @@ -122,11 +124,19 @@ class AnalysisCompletionEvent(object): self.callback = callback self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify) self.handle = core.BNAddAnalysisCompletionEvent(self.view.handle, None, self._cb) + global _pending_analysis_completion_events + _pending_analysis_completion_events[id(self)] = self def __del__(self): + global _pending_analysis_completion_events + if id(self) in _pending_analysis_completion_events: + del _pending_analysis_completion_events[id(self)] core.BNFreeAnalysisCompletionEvent(self.handle) def _notify(self, ctxt): + global _pending_analysis_completion_events + if id(self) in _pending_analysis_completion_events: + del _pending_analysis_completion_events[id(self)] try: self.callback(self) except: @@ -142,6 +152,9 @@ class AnalysisCompletionEvent(object): """ self.callback = self._empty_callback core.BNCancelAnalysisCompletionEvent(self.handle) + global _pending_analysis_completion_events + if id(self) in _pending_analysis_completion_events: + del _pending_analysis_completion_events[id(self)] class ActiveAnalysisInfo(object): @@ -1731,10 +1744,13 @@ class BinaryView(object): """ ``read`` returns the data reads at most ``length`` bytes from virtual address ``addr``. + Note: Python2 returns a str, but Python3 returns a bytes object. str(DataBufferObject) will + still get you a str in either case. + :param int addr: virtual address to read from. :param int length: number of bytes to read. :return: at most ``length`` bytes from the virtual address ``addr``, empty string on error or no data. - :rtype: str + :rtype: python2 - str; python3 - bytes :Example: >>> #Opening a x86_64 Mach-O binary @@ -2784,7 +2800,9 @@ class BinaryView(object): def add_analysis_completion_event(self, callback): """ ``add_analysis_completion_event`` sets up a call back function to be called when analysis has been completed. - This is helpful when using asynchronously analysis. + This is helpful when using ``update_analysis`` which does not wait for analysis completion before returning. + + The callee of this function is not resposible for maintaining the lifetime of the returned AnalysisCompletionEvent object. :param callable() callback: A function to be called with no parameters when analysis has completed. :return: An initialized AnalysisCompletionEvent object. @@ -3481,7 +3499,7 @@ class BinaryView(object): def get_unique_section_names(self, name_list): incoming_names = (ctypes.c_char_p * len(name_list))() for i in range(0, len(name_list)): - incoming_names[i] = name_list[i] + incoming_names[i] = name_list[i].encode('charmap') outgoing_names = core.BNGetUniqueSectionNames(self.handle, incoming_names, len(name_list)) result = [] for i in range(0, len(name_list)): diff --git a/python/callingconvention.py b/python/callingconvention.py index 1b0d068e..6b906184 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -21,18 +21,17 @@ import traceback import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core from binaryninja import log from binaryninja.enums import VariableSourceType # 2-3 compatibility -from six.moves import range +from binaryninja import range class CallingConvention(object): - from binaryninja import types name = None caller_saved_regs = [] int_arg_regs = [] @@ -48,7 +47,7 @@ class CallingConvention(object): _registered_calling_conventions = [] - def __init__(self, arch=None, name=None, handle=None, confidence=types.max_confidence): + def __init__(self, arch=None, name=None, handle=None, confidence=binaryninja.types.max_confidence): if handle is None: if arch is None or name is None: raise ValueError("Must specify either handle or architecture and name") diff --git a/python/databuffer.py b/python/databuffer.py index 1b29a7eb..298d0002 100644 --- a/python/databuffer.py +++ b/python/databuffer.py @@ -20,7 +20,7 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core @@ -114,7 +114,7 @@ class DataBuffer(object): def __str__(self): buf = ctypes.create_string_buffer(len(self)) ctypes.memmove(buf, core.BNGetDataBufferContents(self.handle), len(self)) - if type(buf.raw) is str: + if isinstance(buf.raw, str): return buf.raw else: return buf.raw.decode("charmap") diff --git a/python/demangle.py b/python/demangle.py index 90a19761..466324bc 100644 --- a/python/demangle.py +++ b/python/demangle.py @@ -20,11 +20,11 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core # 2-3 compatibility -from six.moves import range +from binaryninja import range def get_qualified_name(names): diff --git a/python/downloadprovider.py b/python/downloadprovider.py index d34ca358..c714cb98 100644 --- a/python/downloadprovider.py +++ b/python/downloadprovider.py @@ -28,6 +28,7 @@ import traceback # Binary Ninja Components import binaryninja._binaryninjacore as core from binaryninja.setting import Setting +from binaryninja import with_metaclass from binaryninja import startup from binaryninja import log @@ -109,8 +110,7 @@ class _DownloadProviderMetaclass(type): raise AttributeError("attribute '%s' is read only" % name) -class DownloadProvider(object): - __metaclass__ = _DownloadProviderMetaclass +class DownloadProvider(with_metaclass(_DownloadProviderMetaclass, object)): name = None instance_class = None _registered_providers = [] diff --git a/python/fileaccessor.py b/python/fileaccessor.py index 3c7c5e45..c2539b39 100644 --- a/python/fileaccessor.py +++ b/python/fileaccessor.py @@ -21,11 +21,10 @@ import traceback import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core class FileAccessor(object): - def __init__(self): self._cb = core.BNFileAccessor() self._cb.context = 0 diff --git a/python/filemetadata.py b/python/filemetadata.py index ee69dce8..cafe1d67 100644 --- a/python/filemetadata.py +++ b/python/filemetadata.py @@ -22,7 +22,7 @@ from __future__ import absolute_import import traceback import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja Components import binaryninja from binaryninja import _binaryninjacore as core from binaryninja import associateddatastore #required for _FileMetadataAssociatedDataStore diff --git a/python/function.py b/python/function.py index 6392d7f2..8407eece 100644 --- a/python/function.py +++ b/python/function.py @@ -23,20 +23,20 @@ import threading import traceback import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core +from binaryninja import associateddatastore #required in the main scope due to being an argument for _FunctionAssociatedDataStore +from binaryninja import highlight +from binaryninja import log +from binaryninja import types from binaryninja.enums import (AnalysisSkipReason, FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType, FunctionAnalysisSkipOverride) -from binaryninja import associateddatastore #required in the main scope due to being an argument for _FunctionAssociatedDataStore -from binaryninja import types -from binaryninja import highlight -from binaryninja import log # 2-3 compatibility -from six.moves import range +from binaryninja import range class LookupTableEntry(object): @@ -49,7 +49,7 @@ class LookupTableEntry(object): class RegisterValue(object): - def __init__(self, arch = None, value = None, confidence = binaryninja.types.max_confidence): + def __init__(self, arch = None, value = None, confidence = types.max_confidence): self.is_constant = False if value is None: self.type = RegisterValueType.UndeterminedValue @@ -1160,6 +1160,8 @@ class Function(object): for j in range(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) text = lines[i].tokens[j].text + if not isinstance(text, str): + text = text.encode("charmap") value = lines[i].tokens[j].value size = lines[i].tokens[j].size operand = lines[i].tokens[j].operand @@ -1836,6 +1838,7 @@ class DisassemblySettings(object): core.BNSetDisassemblySettingsOption(self.handle, option, state) +_pending_function_graph_completion_events = {} class FunctionGraph(object): def __init__(self, view, handle): self.view = view @@ -1969,6 +1972,9 @@ class FunctionGraph(object): try: if self._on_complete is not None: self._on_complete() + global _pending_function_graph_completion_events + if id(self) in _pending_function_graph_completion_events: + del _pending_function_graph_completion_events[id(self)] except: log.log_error(traceback.format_exc()) @@ -1993,11 +1999,16 @@ class FunctionGraph(object): self._wait_cond.release() def on_complete(self, callback): + global _pending_function_graph_completion_events + _pending_function_graph_completion_events[id(self)] = self self._on_complete = callback core.BNSetFunctionGraphCompleteCallback(self.handle, None, self._cb) def abort(self): core.BNAbortFunctionGraph(self.handle) + global _pending_function_graph_completion_events + if id(self) in _pending_function_graph_completion_events: + del _pending_function_graph_completion_events[id(self)] def get_blocks_in_region(self, left, top, right, bottom): count = ctypes.c_ulonglong() diff --git a/python/functionrecognizer.py b/python/functionrecognizer.py index e390a3c8..319bff0e 100644 --- a/python/functionrecognizer.py +++ b/python/functionrecognizer.py @@ -20,15 +20,15 @@ import traceback -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core +from binaryninja import function +from binaryninja import filemetadata +from binaryninja import binaryview +from binaryninja import lowlevelil class FunctionRecognizer(object): - from binaryninja import function - from binaryninja import filemetadata - from binaryninja import binaryview - from binaryninja import lowlevelil _instance = None @@ -54,7 +54,7 @@ class FunctionRecognizer(object): try: file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(data)) view = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data)) - func = binaryninja.function.Function(view, handle = core.BNNewFunctionReference(func)) + func = function.Function(view, handle = core.BNNewFunctionReference(func)) il = lowlevelil.LowLevelILFunction(func.arch, handle = core.BNNewLowLevelILFunctionReference(il)) return self.recognize_low_level_il(view, func, il) except: @@ -68,7 +68,7 @@ class FunctionRecognizer(object): try: file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(data)) view = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(data)) - func = binaryninja.function.Function(view, handle = core.BNNewFunctionReference(func)) + func = function.Function(view, handle = core.BNNewFunctionReference(func)) il = mediumlevelil.MediumLevelILFunction(func.arch, handle = core.BNNewMediumLevelILFunctionReference(il)) return self.recognize_medium_level_il(view, func, il) except: diff --git a/python/highlight.py b/python/highlight.py index b04561bd..55246a9a 100644 --- a/python/highlight.py +++ b/python/highlight.py @@ -19,7 +19,7 @@ # IN THE SOFTWARE. -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import HighlightColorStyle, HighlightStandardColor diff --git a/python/interaction.py b/python/interaction.py index 5b78b278..49b4e024 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -21,12 +21,13 @@ import ctypes import traceback -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult +from binaryninja import binaryview # 2-3 compatibility -from six.moves import range +from binaryninja import range class LabelField(object): @@ -152,7 +153,11 @@ class AddressField(object): class ChoiceField(object): """ ``ChoiceField`` prompts the user to choose from the list of strings provided in ``choices``. Result is stored - in self.result as an index in to the coices array. + in self.result as an index in to the choices array. + + :attr str prompt: prompt to be presented to the user + :attr list(str) choices: list of choices to choose from + """ def __init__(self, prompt, choices): self.prompt = prompt @@ -164,7 +169,7 @@ class ChoiceField(object): value.prompt = self.prompt choice_buf = (ctypes.c_char_p * len(self.choices))() for i in range(0, len(self.choices)): - choice_buf[i] = str(self.choices[i]) + choice_buf[i] = self.choices[i].encode('charmap') value.choices = choice_buf value.count = len(self.choices) @@ -242,8 +247,6 @@ class DirectoryNameField(object): class InteractionHandler(object): - - from binaryninja import binaryview _interaction_handler = None def __init__(self): @@ -617,7 +620,7 @@ def get_choice_input(prompt, title, choices): """ choice_buf = (ctypes.c_char_p * len(choices))() for i in range(0, len(choices)): - choice_buf[i] = str(choices[i]) + choice_buf[i] = str(choices[i]).encode('charmap') value = ctypes.c_ulonglong() if not core.BNGetChoiceInput(value, prompt, title, choice_buf, len(choices)): return None diff --git a/python/log.py b/python/log.py index d4d87019..9a5e1358 100644 --- a/python/log.py +++ b/python/log.py @@ -19,7 +19,7 @@ # IN THE SOFTWARE. -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import LogLevel @@ -55,7 +55,7 @@ def log(level, text): :param str text: message to print :rtype: None """ - core.BNLog(level, "%s", str(text)) + core.BNLog(level,text) def log_debug(text): @@ -70,7 +70,7 @@ def log_debug(text): >>> log_debug("Hotdogs!") Hotdogs! """ - core.BNLogDebug("%s", str(text)) + core.BNLogDebug(text) def log_info(text): @@ -85,7 +85,7 @@ def log_info(text): Saucisson! >>> """ - core.BNLogInfo("%s", str(text)) + core.BNLogInfo(text) def log_warn(text): @@ -101,7 +101,7 @@ def log_warn(text): Chilidogs! >>> """ - core.BNLogWarn("%s", str(text)) + core.BNLogWarn(text) def log_error(text): @@ -117,7 +117,7 @@ def log_error(text): Spanferkel! >>> """ - core.BNLogError("%s", str(text)) + core.BNLogError(text) def log_alert(text): @@ -133,7 +133,7 @@ def log_alert(text): Kielbasa! >>> """ - core.BNLogAlert("%s", str(text)) + core.BNLogAlert(text) def log_to_stdout(min_level=LogLevel.InfoLog): diff --git a/python/lowlevelil.py b/python/lowlevelil.py index 272b2474..e714eb48 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -21,14 +21,14 @@ import ctypes import struct -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core from binaryninja.enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionTextTokenType from binaryninja import basicblock #required for LowLevelILBasicBlock # 2-3 compatibility -from six.moves import range +from binaryninja import range class LowLevelILLabel(object): diff --git a/python/mainthread.py b/python/mainthread.py index 16938f1a..5b0cd53c 100644 --- a/python/mainthread.py +++ b/python/mainthread.py @@ -18,7 +18,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja import scriptingprovider diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index f7e9951a..cfa8f900 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -30,7 +30,7 @@ from binaryninja import types from binaryninja import lowlevelil # 2-3 compatibility -from six.moves import range +from binaryninja import range class SSAVariable(object): diff --git a/python/metadata.py b/python/metadata.py index fed8bdaa..b17bbf4f 100644 --- a/python/metadata.py +++ b/python/metadata.py @@ -22,12 +22,12 @@ from __future__ import absolute_import import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import MetadataType # 2-3 compatibility -from six.moves import range +from binaryninja import range class Metadata(object): @@ -147,7 +147,7 @@ class Metadata(object): result = core.BNMetadataGetValueStore(self.handle) try: for i in range(result.contents.size): - if type(result.contents.keys[i]) is bytes: + if isinstance(result.contents.keys[i], bytes): yield str(result.contents.keys[i].decode('charmap')) else: yield result.contents.keys[i] diff --git a/python/platform.py b/python/platform.py index c57315ce..9a5f70df 100644 --- a/python/platform.py +++ b/python/platform.py @@ -20,18 +20,18 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core +from binaryninja import types -#2-3 compatibility -from six import with_metaclass -from six.moves import range +# 2-3 compatibility +from binaryninja import range +from binaryninja import with_metaclass class _PlatformMetaClass(type): - from binaryninja import types @property def list(self): binaryninja._init_plugins() @@ -240,8 +240,8 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): type_list = core.BNGetPlatformTypes(self.handle, count) result = {} for i in range(0, count.value): - name = binaryninja.types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = binaryninja.types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + name = types.QualifiedName._from_core_struct(type_list[i].name) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -252,8 +252,8 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): type_list = core.BNGetPlatformVariables(self.handle, count) result = {} for i in range(0, count.value): - name = binaryninja.types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = binaryninja.types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + name = types.QualifiedName._from_core_struct(type_list[i].name) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -264,8 +264,8 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): type_list = core.BNGetPlatformFunctions(self.handle, count) result = {} for i in range(0, count.value): - name = binaryninja.types.QualifiedName._from_core_struct(type_list[i].name) - result[name] = binaryninja.types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) + name = types.QualifiedName._from_core_struct(type_list[i].name) + result[name] = types.Type(core.BNNewTypeReference(type_list[i].type), platform = self) core.BNFreeTypeList(type_list, count.value) return result @@ -276,8 +276,8 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): call_list = core.BNGetPlatformSystemCalls(self.handle, count) result = {} for i in range(0, count.value): - name = binaryninja.types.QualifiedName._from_core_struct(call_list[i].name) - t = binaryninja.types.Type(core.BNNewTypeReference(call_list[i].type), platform = self) + name = types.QualifiedName._from_core_struct(call_list[i].name) + t = types.Type(core.BNNewTypeReference(call_list[i].type), platform = self) result[call_list[i].number] = (name, t) core.BNFreeSystemCallList(call_list, count.value) return result @@ -328,25 +328,25 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): return Platform(None, handle = result), new_addr.value def get_type_by_name(self, name): - name = binaryninja.types.QualifiedName(name)._get_core_struct() + name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformTypeByName(self.handle, name) if not obj: return None - return binaryninja.types.Type(obj, platform = self) + return types.Type(obj, platform = self) def get_variable_by_name(self, name): - name = binaryninja.types.QualifiedName(name)._get_core_struct() + name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformVariableByName(self.handle, name) if not obj: return None - return binaryninja.types.Type(obj, platform = self) + return types.Type(obj, platform = self) def get_function_by_name(self, name): - name = binaryninja.types.QualifiedName(name)._get_core_struct() + name = types.QualifiedName(name)._get_core_struct() obj = core.BNGetPlatformFunctionByName(self.handle, name) if not obj: return None - return binaryninja.types.Type(obj, platform = self) + return types.Type(obj, platform = self) def get_system_call_name(self, number): return core.BNGetPlatformSystemCallName(self.handle, number) @@ -355,15 +355,15 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): obj = core.BNGetPlatformSystemCallType(self.handle, number) if not obj: return None - return binaryninja.types.Type(obj, platform = self) + return types.Type(obj, platform = self) def generate_auto_platform_type_id(self, name): - name = binaryninja.types.QualifiedName(name)._get_core_struct() + name = types.QualifiedName(name)._get_core_struct() return core.BNGenerateAutoPlatformTypeId(self.handle, name) def generate_auto_platform_type_ref(self, type_class, name): type_id = self.generate_auto_platform_type_id(name) - return binaryninja.types.NamedTypeReference(type_class, type_id, name) + return types.NamedTypeReference(type_class, type_id, name) def get_auto_platform_type_id_source(self): return core.BNGetAutoPlatformTypeIdSource(self.handle) @@ -391,7 +391,7 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): filename = "input" dir_buf = (ctypes.c_char_p * len(include_dirs))() for i in range(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) + dir_buf[i] = include_dirs[i].encode('charmap') parse = core.BNTypeParserResult() errors = ctypes.c_char_p() result = core.BNParseTypesFromSource(self.handle, source, filename, parse, errors, dir_buf, @@ -404,16 +404,16 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): variables = {} functions = {} for i in range(0, parse.typeCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.types[i].name) + type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) for i in range(0, parse.variableCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.variables[i].name) + variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) for i in range(0, parse.functionCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.functions[i].name) + functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) core.BNFreeTypeParserResult(parse) - return binaryninja.types.TypeParserResult(type_dict, variables, functions) + return types.TypeParserResult(type_dict, variables, functions) def parse_types_from_source_file(self, filename, include_dirs=[], auto_type_source=None): """ @@ -437,7 +437,7 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): """ dir_buf = (ctypes.c_char_p * len(include_dirs))() for i in range(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) + dir_buf[i] = include_dirs[i].encode('charmap') parse = core.BNTypeParserResult() errors = ctypes.c_char_p() result = core.BNParseTypesFromSourceFile(self.handle, filename, parse, errors, dir_buf, @@ -450,13 +450,13 @@ class Platform(with_metaclass(_PlatformMetaClass, object)): variables = {} functions = {} for i in range(0, parse.typeCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.types[i].name) - type_dict[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.types[i].name) + type_dict[name] = types.Type(core.BNNewTypeReference(parse.types[i].type), platform = self) for i in range(0, parse.variableCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.variables[i].name) - variables[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.variables[i].name) + variables[name] = types.Type(core.BNNewTypeReference(parse.variables[i].type), platform = self) for i in range(0, parse.functionCount): - name = binaryninja.types.QualifiedName._from_core_struct(parse.functions[i].name) - functions[name] = binaryninja.types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) + name = types.QualifiedName._from_core_struct(parse.functions[i].name) + functions[name] = types.Type(core.BNNewTypeReference(parse.functions[i].type), platform = self) core.BNFreeTypeParserResult(parse) - return binaryninja.types.TypeParserResult(type_dict, variables, functions) + return types.TypeParserResult(type_dict, variables, functions) diff --git a/python/plugin.py b/python/plugin.py index 52feced4..b8217f0b 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -22,15 +22,18 @@ import traceback import ctypes import threading -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import log from binaryninja import _binaryninjacore as core from binaryninja.enums import PluginCommandType +from binaryninja import filemetadata +from binaryninja import binaryview +from binaryninja import function -#2-3 compatibility -from six import with_metaclass -from six.moves import range +# 2-3 compatibility +from binaryninja import range +from binaryninja import with_metaclass class PluginCommandContext(object): @@ -43,7 +46,6 @@ class PluginCommandContext(object): class _PluginCommandMetaClass(type): - @property def list(self): binaryninja._init_plugins() @@ -73,11 +75,6 @@ class _PluginCommandMetaClass(type): class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): - - from binaryninja import filemetadata - from binaryninja import binaryview - from binaryninja import function - _registered_commands = [] def __init__(self, cmd): @@ -540,7 +537,6 @@ class MainThreadAction(object): class MainThreadActionHandler(object): - _main_thread = None def __init__(self): @@ -586,7 +582,6 @@ class _BackgroundTaskMetaclass(type): class BackgroundTask(with_metaclass(_BackgroundTaskMetaclass, object)): - def __init__(self, initial_progress_text = "", can_cancel = False, handle = None): if handle is None: self.handle = core.BNBeginBackgroundTask(initial_progress_text, can_cancel) diff --git a/python/pluginmanager.py b/python/pluginmanager.py index ad314629..c7a0c83a 100644 --- a/python/pluginmanager.py +++ b/python/pluginmanager.py @@ -20,11 +20,12 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core # 2-3 compatibility -from six.moves import range +from binaryninja import range + class RepoPlugin(object): """ @@ -201,7 +202,6 @@ class RepositoryManager(object): ``RepositoryManager`` Keeps track of all the repositories and keeps the enabled_plugins.json file coherent with the plugins that are installed/unstalled enabled/disabled """ - def __init__(self, handle=None): raise Exception("RepositoryManager temporarily disabled!") self.handle = core.BNGetRepositoryManager() diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 374b2f41..37642ed4 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -26,14 +26,15 @@ import threading import abc import sys -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components +import binaryninja from binaryninja import _binaryninjacore as core from binaryninja.enums import ScriptingProviderExecuteResult, ScriptingProviderInputReadyState -import binaryninja.log +from binaryninja import log -#2-3 compatibility -from six import with_metaclass -from six.moves import range +# 2-3 compatibility +from binaryninja import range +from binaryninja import with_metaclass class _ThreadActionContext(object): @@ -75,19 +76,19 @@ class ScriptingOutputListener(object): try: self.notify_output(text) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _error(self, ctxt, text): try: self.notify_error(text) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _input_ready_state_changed(self, ctxt, state): try: self.notify_input_ready_state_changed(state) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def notify_output(self, text): pass @@ -123,13 +124,13 @@ class ScriptingInstance(object): try: self.perform_destroy_instance() except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _execute_script_input(self, ctxt, text): try: return self.perform_execute_script_input(text) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) return ScriptingProviderExecuteResult.InvalidScriptInput def _set_current_binary_view(self, ctxt, view): @@ -140,7 +141,7 @@ class ScriptingInstance(object): view = None self.perform_set_current_binary_view(view) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _set_current_function(self, ctxt, func): try: @@ -150,7 +151,7 @@ class ScriptingInstance(object): func = None self.perform_set_current_function(func) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _set_current_basic_block(self, ctxt, block): try: @@ -165,19 +166,19 @@ class ScriptingInstance(object): block = None self.perform_set_current_basic_block(block) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _set_current_address(self, ctxt, addr): try: self.perform_set_current_address(addr) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) def _set_current_selection(self, ctxt, begin, end): try: self.perform_set_current_selection(begin, end) except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) @abc.abstractmethod def perform_destroy_instance(self): @@ -324,7 +325,7 @@ class ScriptingProvider(with_metaclass(_ScriptingProviderMetaclass, object)): return None return ctypes.cast(core.BNNewScriptingInstanceReference(result.handle), ctypes.c_void_p).value except: - binaryninja.log.log_error(traceback.format_exc()) + log.log_error(traceback.format_exc()) return None def create_instance(self): @@ -390,7 +391,7 @@ class _PythonScriptingInstanceOutput(object): interpreter = PythonScriptingInstance._interpreter.value if interpreter is None: - if binaryninja.log.is_output_redirected_to_log(): + if log.is_output_redirected_to_log(): self.buffer += data while True: i = self.buffer.find('\n') @@ -400,9 +401,9 @@ class _PythonScriptingInstanceOutput(object): self.buffer = self.buffer[i + 1:] if self.is_error: - binaryninja.log.log_error(line) + log.log_error(line) else: - binaryninja.log.log_info(line) + log.log_info(line) else: self.orig.write(data) else: @@ -490,7 +491,7 @@ class PythonScriptingInstance(ScriptingInstance): self.code = None self.input = "" - self.interpreter.push("from binaryninja import *\n") + self.interpreter.push("from binaryninja import *") def execute(self, code): self.code = code @@ -553,8 +554,8 @@ class PythonScriptingInstance(ScriptingInstance): self.locals["current_llil"] = self.active_func.low_level_il self.locals["current_mlil"] = self.active_func.medium_level_il - for line in code.split("\n"): - self.interpreter.push(line) + for line in code.split(b'\n'): + self.interpreter.push(line.decode('charmap')) if self.locals["here"] != self.active_addr: if not self.active_view.file.navigate(self.active_view.file.view, self.locals["here"]): @@ -660,3 +661,4 @@ def redirect_stdio(): sys.stdin = _PythonScriptingInstanceInput(sys.stdin) sys.stdout = _PythonScriptingInstanceOutput(sys.stdout, False) sys.stderr = _PythonScriptingInstanceOutput(sys.stderr, True) + sys.excepthook = sys.__excepthook__ \ No newline at end of file diff --git a/python/setting.py b/python/setting.py index fea06140..355492aa 100644 --- a/python/setting.py +++ b/python/setting.py @@ -20,11 +20,11 @@ import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core # 2-3 compatibility -from six.moves import range +from binaryninja import range class Setting(object): @@ -113,7 +113,7 @@ class Setting(object): length.value = len(value) default_list = (ctypes.c_char_p * len(value))() for i in range(len(value)): - default_list[i] = value[i].encode('utf-8') + default_list[i] = value[i].encode('charmap') return core.BNSettingSetStringList(self.plugin_name, name, default_list, length, auto_flush) @@ -141,4 +141,4 @@ class Setting(object): core.BNSettingRemoveSettingGroup(self.plugin_name, auto_flush) def remove_setting(self, setting, auto_flush=True): - core.BNSettingRemoveSetting(self.plugin_name, setting, auto_flush) \ No newline at end of file + core.BNSettingRemoveSetting(self.plugin_name, setting, auto_flush) diff --git a/python/transform.py b/python/transform.py index e16c6bfc..1734d248 100644 --- a/python/transform.py +++ b/python/transform.py @@ -22,20 +22,19 @@ import traceback import ctypes import abc -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import log from binaryninja import databuffer from binaryninja import _binaryninjacore as core from binaryninja.enums import TransformType -#2-3 compatibility -from six import with_metaclass -from six.moves import range +# 2-3 compatibility +from binaryninja import range +from binaryninja import with_metaclass class _TransformMetaClass(type): - @property def list(self): binaryninja._init_plugins() @@ -96,8 +95,6 @@ class TransformParameter(object): class Transform(with_metaclass(_TransformMetaClass, object)): - - from binaryninja import databuffer transform_type = None name = None long_name = None @@ -224,7 +221,7 @@ class Transform(with_metaclass(_TransformMetaClass, object)): def decode(self, input_buf, params = {}): input_buf = databuffer.DataBuffer(input_buf) output_buf = databuffer.DataBuffer() - keys = params.keys() + keys = list(params.keys()) param_buf = (core.BNTransformParameter * len(keys))() for i in range(0, len(keys)): data = databuffer.DataBuffer(params[keys[i]]) @@ -237,7 +234,7 @@ class Transform(with_metaclass(_TransformMetaClass, object)): def encode(self, input_buf, params = {}): input_buf = databuffer.DataBuffer(input_buf) output_buf = databuffer.DataBuffer() - keys = params.keys() + keys = list(params.keys()) param_buf = (core.BNTransformParameter * len(keys))() for i in range(0, len(keys)): data = databuffer.DataBuffer(params[keys[i]]) diff --git a/python/types.py b/python/types.py index 2ad8d2c2..e8ce7464 100644 --- a/python/types.py +++ b/python/types.py @@ -23,23 +23,26 @@ max_confidence = 255 import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components import binaryninja from binaryninja import _binaryninjacore as core from binaryninja.enums import SymbolType, TypeClass, NamedTypeReferenceClass, InstructionTextTokenType, StructureType, ReferenceType, VariableSourceType -#2-3 compatibility -from six.moves import range +# 2-3 compatibility +from binaryninja import range class QualifiedName(object): def __init__(self, name = []): if isinstance(name, str): self.name = [name] + self.byte_name = [name.encode('charmap')] elif isinstance(name, QualifiedName): self.name = name.name + self.byte_name = [n.encode('charmap') for n in name.name] else: - self.name = [i.decode('utf-8') for i in name] + self.name = [i.decode('charmap') for i in name] + self.byte_name = name def __str__(self): return "::".join(self.name) @@ -102,7 +105,7 @@ class QualifiedName(object): result = core.BNQualifiedName() name_list = (ctypes.c_char_p * len(self.name))() for i in range(0, len(self.name)): - name_list[i] = self.name[i] + name_list[i] = self.name[i].encode('charmap') result.name = name_list result.nameCount = len(self.name) return result @@ -1022,7 +1025,7 @@ def preprocess_source(source, filename=None, include_dirs=[]): filename = "input" dir_buf = (ctypes.c_char_p * len(include_dirs))() for i in range(0, len(include_dirs)): - dir_buf[i] = str(include_dirs[i]) + dir_buf[i] = include_dirs[i].encode('charmap') output = ctypes.c_char_p() errors = ctypes.c_char_p() result = core.BNPreprocessSource(source, filename, output, errors, dir_buf, len(include_dirs)) diff --git a/python/undoaction.py b/python/undoaction.py index 732d559a..7891bf54 100644 --- a/python/undoaction.py +++ b/python/undoaction.py @@ -22,14 +22,12 @@ import traceback import json import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import ActionType class UndoAction(object): - - name = None action_type = None _registered = False diff --git a/python/update.py b/python/update.py index 4c77b202..7f5d6f9c 100644 --- a/python/update.py +++ b/python/update.py @@ -21,18 +21,16 @@ import traceback import ctypes -# Binary Ninja components -- additional imports belong in the appropriate class +# Binary Ninja components from binaryninja import _binaryninjacore as core from binaryninja.enums import UpdateResult - -#2-3 compatibility -from six import with_metaclass -from six.moves import range +# 2-3 compatibility +from binaryninja import range +from binaryninja import with_metaclass class _UpdateChannelMetaClass(type): - @property def list(self): binaryninja._init_plugins() @@ -99,7 +97,6 @@ class _UpdateChannelMetaClass(type): class UpdateProgressCallback(object): - def __init__(self, func): self.cb = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_ulonglong, ctypes.c_ulonglong)(self.callback) self.func = func @@ -114,7 +111,6 @@ class UpdateProgressCallback(object): class UpdateChannel(with_metaclass(_UpdateChannelMetaClass, object)): - def __init__(self, name, desc, ver): self.name = name self.description = desc diff --git a/scripts/install_api.py b/scripts/install_api.py index 53679ba5..3cc0ed0d 100755 --- a/scripts/install_api.py +++ b/scripts/install_api.py @@ -80,6 +80,6 @@ else: sys.exit(1) binaryninja_pth_path = os.path.join(install_path, 'binaryninja.pth') -open(binaryninja_pth_path, 'wb').write(api_path) +open(binaryninja_pth_path, 'wb').write(api_path.encode('charmap')) print("Binary Ninja API installed using {}".format(binaryninja_pth_path)) diff --git a/suite/binaries b/suite/binaries index 7d5d207d..ab6b1816 160000 --- a/suite/binaries +++ b/suite/binaries @@ -1 +1 @@ -Subproject commit 7d5d207de812ccd7c4648331b00fa936ef0a82c3 +Subproject commit ab6b18161a5b9ccd3588c88233f150fb6c7e2ce9 diff --git a/suite/generator.py b/suite/generator.py index b812b1b5..3302d118 100755 --- a/suite/generator.py +++ b/suite/generator.py @@ -10,24 +10,77 @@ import time unit_test_template = """#!/usr/bin/env python # This is an auto generated unit test file do not edit directly import os +import sys import unittest import pickle import zipfile import testcommon -import binaryninja import api_test import difflib +from collections import Counter +global verbose +verbose = False class TestBinaryNinjaAPI(unittest.TestCase): + # Returns a tuple of: + # bool : Two lists are equal + # string : The string diff + # Args: + # list + # list : (compare list one vs list two) + # string : anything additional wanted to be printed before the string diff + # bool : the ordering of the items in the two lists must be the same + def report(self, oracle, test, firstText='', strictOrdering = False): + stringDiff = "" + + equality = False + if not strictOrdering: + equality = (Counter(oracle) == Counter(test)) + else: + equality = (oracle == test) + + if equality: + return (True, '') + elif not strictOrdering: + try: + for elem in oracle: + test.remove(elem) + oracle.remove(elem) # If it's not in the test, it won't get here! + except ValueError: + pass + + differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) + skipped_lines = 0 + for delta in differ.compare(oracle, test): + if delta[0] == ' ': + skipped_lines += 1 + continue + if skipped_lines > 0: + stringDiff += "<---" + str(skipped_lines) + ' same lines--->\\n' + skipped_lines = 0 + delta = delta.replace(\'\\n\', '') + stringDiff += delta + \'\\n\' + + stringDiffList = stringDiff.split(\'\\n\') + + if len(stringDiffList) > 10: + if not verbose: + stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10]) + stringDiff += \'\\n\\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###" + elif not verbose: + stringDiff = \'\\n\'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList) + stringDiff = \'\\n\\n\' + firstText + stringDiff + return (equality, stringDiff) + @classmethod def setUpClass(self): self.builder = testcommon.TestBuilder("{3}") try: - #Python 2 does not have the encodings option - self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rUb"), errors="ignore") + # Python 2 does not have the encodings option + self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rb"), encoding='charmap') except TypeError: - self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "rU")) + self.oracle_test_data = pickle.load(open(os.path.join("{0}", "oracle.pkl"), "r")) self.verifybuilder = testcommon.VerifyBuilder("{3}") def run_binary_test(self, testfile): @@ -38,10 +91,10 @@ class TestBinaryNinjaAPI(unittest.TestCase): self.assertTrue(os.path.exists(testname + ".pkl"), "Test pickle doesn't exist") try: - #Python 2 does not have the encodings option - binary_oracle = pickle.load(open(testname + ".pkl", "rUb"), errors="ignore") + # Python 2 does not have the encodings option + binary_oracle = pickle.load(open(testname + ".pkl", "rb"), encoding='charmap') except TypeError: - binary_oracle = pickle.load(open(testname + ".pkl", "rU")) + binary_oracle = pickle.load(open(testname + ".pkl", "r")) test_builder = testcommon.BinaryViewTestBuilder(testname, "{3}") for method in test_builder.methods(): @@ -52,22 +105,16 @@ class TestBinaryNinjaAPI(unittest.TestCase): result = getattr(test_builder, method).__doc__ result += ":\\n" - d = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in d.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\\n' - skipped_lines = 0 - delta = delta.replace('\\n', '') - result += delta + '\\n' - self.assertTrue(False, result) + report = self.report(oracle, test, result) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle os.unlink(testname) {1}{2} if __name__ == "__main__": + if len(sys.argv) > 1: + if sys.argv[1] == '-v' or sys.argv[1] == '-V' or sys.argv[1] == '--verbose': + verbose = True + test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test) test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinjaAPI)) runner = unittest.TextTestRunner(verbosity=2) @@ -83,20 +130,8 @@ test_string = """ def {0}(self): oracle = self.oracle_test_data['{0}'] test = self.builder.{0}() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\\n' - skipped_lines = 0 - delta = delta.replace('\\n', '') - result += delta + '\\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle """ verify_string = """ @@ -108,7 +143,7 @@ verify_string = """ class OracleTestFile: def __init__(self, filename): self.f = open(filename + ".pkl", "wb") - self.pkl = pickle.Pickler(self.f) + self.pkl = pickle.Pickler(self.f, protocol=2) self.filename = filename self.oracle_test_data = {} @@ -131,7 +166,7 @@ class UnitTestFile: self.binary_tests = "" def close(self): - self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, self.test_store).encode('utf-8')) + self.f.write(self.template.format(self.outdir, self.tests, self.binary_tests, self.test_store).encode('charmap')) self.f.close() def add_verify(self, test_name): @@ -146,8 +181,6 @@ class UnitTestFile: quiet = False - - def myprint(stuff): if not quiet: print(stuff) diff --git a/suite/testcommon.py b/suite/testcommon.py index 1bbc0d47..ef85c053 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -1,14 +1,54 @@ import tempfile import pickle import os +import sys import zipfile import inspect import binaryninja as binja from binaryninja.binaryview import BinaryViewType, BinaryView from binaryninja.filemetadata import FileMetadata import subprocess -import traceback -import types +import re + + +# Dear people from the future: If you're adding tests or debuging an +# issue where python2 and python3 are producing different output +# for the same function and it's a issue of `longs`, run the output +# through this function. If it's a unicode/bytes issue, fix it in +# api/python/ +def fixOutput(outputList): + # Apply regular expression to detect python2 longs + splitList = [] + for elem in outputList: + if isinstance(elem, str): + splitList.append(re.split(r"((?<=[\[ ])0x[\da-f]+L|[\d]+L)", elem)) + else: + splitList.append(elem) + + # Resolve application of regular expression + result = [] + for elem in splitList: + if isinstance(elem, list): + newElem = [] + for item in elem: + if len(item) > 1 and item[-1] == 'L': + newElem.append(item[:-1]) + else: + newElem.append(item) + result.append(''.join(newElem)) + else: + result.append(elem) + return result + + +# Alright so this one is here for Binja functions that output +def fixSet(string): + # Apply regular expression + splitList = (re.split(r"((?<=))", string)) + if len(splitList) > 1: + return splitList[0] + ', '.join(sorted(splitList[1].split(', '))) + splitList[2] + else: + return string def get_file_list(test_store): @@ -16,13 +56,12 @@ def get_file_list(test_store): for root, dir, files in os.walk(test_store): for file in files: all_files.append(os.path.join(root, file)) - return all_files def remove_low_confidence(type_string): low_confidence_types = ["int32_t", "void"] for lct in low_confidence_types: - type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties + type_string = type_string.replace(lct + " ", '') # done to resolve confidence ties return type_string class Builder(object): @@ -66,15 +105,24 @@ class BinaryViewTestBuilder(Builder): def test_function_starts(self): """Function starts list doesnt match""" - return ["Function start: " + hex(x.start) for x in self.bv.functions] + result = [] + for x in self.bv.functions: + result.append("Function start: " + hex(x.start)) + return fixOutput(result) def test_function_symbol_names(self): """Function.symbol.name list doesnt match""" - return ["Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address) for x in self.bv.functions] + result = [] + for x in self.bv.functions: + result.append("Symbol: " + x.symbol.name + ' ' + str(x.symbol.type) + ' ' + hex(x.symbol.address)) + return fixOutput(result) def test_function_can_return(self): """Function.can_return list doesnt match""" - return ["function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return)) for x in self.bv.functions] + result = [] + for x in self.bv.functions: + result.append("function name: " + x.symbol.name + ' type: ' + str(x.symbol.type) + ' address: ' + hex(x.symbol.address) + ' can_return: ' + str(bool(x.can_return))) + return fixOutput(result) def test_function_basic_blocks(self): """Function basic_block list doesnt match (start, end, has_undetermined_outgoing_edges)""" @@ -85,32 +133,31 @@ class BinaryViewTestBuilder(Builder): for anno in func.get_block_annotations(bb.start): bblist.append("basic block {} function annotation: ".format(str(bb)) + str(anno)) bblist.append("basic block {} test get self: ".format(str(bb)) + str(func.get_basic_block_at(bb.start))) - return bblist + return fixOutput(bblist) def test_function_low_il_basic_blocks(self): - """"Function low_il_basic_block list doesnt match""" + """Function low_il_basic_block list doesnt match""" ilbblist = [] for func in self.bv.functions: for bb in func.low_level_il.basic_blocks: ilbblist.append("LLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing edges: ' + str(len(bb.outgoing_edges))) - return ilbblist + return fixOutput(ilbblist) def test_function_med_il_basic_blocks(self): - """"Function med_il_basic_block list doesn't match""" + """Function med_il_basic_block list doesn't match""" ilbblist = [] for func in self.bv.functions: for bb in func.medium_level_il.basic_blocks: ilbblist.append("MLIL basic block {} start: ".format(str(bb)) + hex(bb.start) + ' end: ' + hex(bb.end) + ' outgoing_edges: ' + str(len(bb.outgoing_edges))) - return ilbblist + return fixOutput(ilbblist) def test_symbols(self): - """"Symbols list doesn't match""" + """Symbols list doesn't match""" return ["Symbol: " + str(i) for i in sorted(self.bv.symbols)] def test_strings(self): """Strings list doesn't match""" - return ["String: " + x.value + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings] - + return fixOutput(["String: " + str(x.value) + ' type: ' + str(x.type) + ' at: ' + hex(x.start) for x in self.bv.strings]) def test_low_il_instructions(self): """LLIL instructions produced different output""" @@ -126,9 +173,7 @@ class BinaryViewTestBuilder(Builder): retinfo.append("Postfix operands: " + str(ins.postfix_operands)) retinfo.append("SSA form: " + str(ins.ssa_form)) retinfo.append("Non-SSA form: " + str(ins.non_ssa_form)) - - return retinfo - + return fixOutput(retinfo) def test_low_il_ssa(self): """LLIL ssa produced different output""" @@ -151,9 +196,7 @@ class BinaryViewTestBuilder(Builder): retinfo.append("SSA instruction index: " + str(func.get_ssa_instruction_index(tempind))) retinfo.append("MLIL instruction index: " + str(func.get_medium_level_il_instruction_index(ins.instr_index))) retinfo.append("Mapped MLIL instruction index: " + str(func.get_mapped_medium_level_il_instruction_index(ins.instr_index))) - - return retinfo - + return fixOutput(retinfo) def test_med_il_instructions(self): """MLIL instructions produced different output""" @@ -165,18 +208,33 @@ class BinaryViewTestBuilder(Builder): retinfo.append("LLIL: " + str(ins.low_level_il)) retinfo.append("Value: " + str(ins.value)) retinfo.append("Possible values: " + str(ins.possible_values)) - retinfo.append("Branch dependence: " + str(ins.branch_dependence)) - retinfo.append("Prefix operands: " + str(sorted([str(i) for i in ins.prefix_operands]))) - retinfo.append("Postfix operands: " + str(sorted([str(i) for i in ins.postfix_operands]))) + retinfo.append("Branch dependence: " + str(sorted(ins.branch_dependence.items()))) + + prefixList = [] + for i in ins.prefix_operands: + if isinstance(i, float) and 'e' in str(i): + prefixList.append(str(round(i, 21))) + elif isinstance(i, float): + prefixList.append(str(round(i, 11))) + else: + prefixList.append(str(i)) + retinfo.append("Prefix operands: " + str(sorted(prefixList))) + postfixList = [] + for i in ins.prefix_operands: + if isinstance(i, float) and 'e' in str(i): + postfixList.append(str(round(i, 21))) + elif isinstance(i, float): + postfixList.append(str(round(i, 11))) + else: + postfixList.append(str(i)) + + retinfo.append("Postfix operands: " + str(sorted(postfixList))) retinfo.append("SSA form: " + str(ins.ssa_form)) retinfo.append("Non-SSA form" + str(ins.non_ssa_form)) - - return retinfo - - + return fixOutput(retinfo) def test_med_il_vars(self): - """"Function med_il_vars doesn't match""" + """Function med_il_vars doesn't match""" varlist = [] for func in self.bv.functions: func = func.medium_level_il @@ -184,14 +242,13 @@ class BinaryViewTestBuilder(Builder): for instruction in bb: instruction = instruction.ssa_form for var in (instruction.vars_read + instruction.vars_written): - #varlist.append((func.get_var_uses(var), func.get_var_definitions(var))) if hasattr(var, "var"): varlist.append("SSA var definition: " + str(func.get_ssa_var_definition(var))) varlist.append("SSA var uses: " + str(func.get_ssa_var_uses(var))) varlist.append("SSA var value: " + str(func.get_ssa_var_value(var))) - varlist.append("SSA var possible values: " + str(instruction.get_ssa_var_possible_values(var))) + varlist.append("SSA var possible values: " + fixSet(str(instruction.get_ssa_var_possible_values(var)))) varlist.append("SSA var version: " + str(instruction.get_ssa_var_version)) - return varlist + return fixOutput(varlist) def test_function_stack(self): """Function stack produced different output""" @@ -211,32 +268,26 @@ class BinaryViewTestBuilder(Builder): funcinfo.append("Sample stack var: " + str(func.get_stack_var_at_frame_offset(0, 0))) func.delete_user_stack_var(0) func.delete_auto_stack_var(0) - return funcinfo def test_function_llil(self): """Function LLIL produced different output""" retinfo = [] - for func in self.bv.functions: for llilbb in func.llil_basic_blocks: retinfo.append("LLIL basic block: " + str(llilbb)) for llilins in func.llil_instructions: retinfo.append("LLIL instruction: " + str(llilins)) - for mlilbb in func.mlil_basic_blocks: retinfo.append("MLIL basic block: " + str(mlilbb)) for mlilins in func.mlil_instructions: retinfo.append("MLIL instruction: " + str(mlilins)) - for ins in func.instructions: - retinfo.append("Instructiin: {}: ".format(hex(ins[1])) + ''.join([str(i) for i in ins[0]])) - - return retinfo - + retinfo.append("Instruction: {}: ".format(hex(ins[1])) + ''.join([str(i) for i in ins[0]])) + return fixOutput(retinfo) def test_functions_attributes(self): - """"Function attributes don't match""" + """Function attributes don't match""" funcinfo = [] for func in self.bv.functions: func.comment = "testcomment " + func.name @@ -284,9 +335,7 @@ class BinaryViewTestBuilder(Builder): token = str(token) token = remove_low_confidence(token) funcinfo.append("Function {} type token: ".format(func.name) + str(token)) - - - return funcinfo + return fixOutput(funcinfo) def test_BinaryView(self): """BinaryView produced different results""" @@ -309,11 +358,12 @@ class BinaryViewTestBuilder(Builder): retinfo.append("BV entry point: " + hex(self.bv.entry_point)) retinfo.append("BV start: " + hex(self.bv.start)) retinfo.append("BV length: " + hex(len(self.bv))) - return retinfo + + return fixOutput(retinfo) class TestBuilder(Builder): - """ The TestBuilder is for tests that need to be checked against + """ The TestBuilder is for tests that need to be checked againsttest_BinaryView stored oracle data that isn't from a binary. These test are generated on your local machine then run again on the build machine to verify correctness. @@ -335,23 +385,81 @@ class TestBuilder(Builder): """unexpected assemble result""" result = [] # success cases - result.append("x86 assembly: " + str(binja.Architecture["x86"].assemble("xor eax, eax"))) - result.append("x86_64 assembly: " + str(binja.Architecture["x86_64"].assemble("xor rax, rax"))) - result.append("mips32 assembly: " + str(binja.Architecture["mips32"].assemble("move $ra, $zero"))) - result.append("mipsel32 assembly: " + str(binja.Architecture["mipsel32"].assemble("move $ra, $zero"))) - result.append("armv7 assembly: " + str(binja.Architecture["armv7"].assemble("str r2, [sp, #-0x4]!"))) - result.append("aarch64 assembly: " + str(binja.Architecture["aarch64"].assemble("mov x0, x0"))) - result.append("thumb2 assembly: " + str(binja.Architecture["thumb2"].assemble("ldr r4, [r4]"))) - result.append("thumb2eb assembly: " + str(binja.Architecture["thumb2eb"].assemble("ldr r4, [r4]"))) + + strResult = binja.Architecture["x86"].assemble("xor eax, eax") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("x86 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("x86 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["x86_64"].assemble("xor rax, rax") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("x86_64 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("x86_64 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["mips32"].assemble("move $ra, $zero") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("mips32 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("mips32 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["mipsel32"].assemble("move $ra, $zero") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("mipsel32 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("mipsel32 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["armv7"].assemble("str r2, [sp, #-0x4]!") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("armv7 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("armv7 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["aarch64"].assemble("mov x0, x0") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("aarch64 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("aarch64 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["thumb2"].assemble("ldr r4, [r4]") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("thumb2 assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("thumb2 assembly: " + repr(str(strResult))) + strResult = binja.Architecture["thumb2eb"].assemble("ldr r4, [r4]") + if sys.version_info.major == 3 and not strResult[0] is None: + result.append("thumb2eb assembly: " + "'" + str(strResult)[2:-1] + "'") + else: + result.append("thumb2eb assembly: " + repr(str(strResult))) + # fail cases - result.append("x86 assembly: " + str(binja.Architecture["x86"].assemble("thisisnotaninstruction"))) - result.append("x86_64 assembly: " + str(binja.Architecture["x86_64"].assemble("thisisnotaninstruction"))) - result.append("mips32 assembly: " + str(binja.Architecture["mips32"].assemble("thisisnotaninstruction"))) - result.append("mipsel32 assembly: " + str(binja.Architecture["mipsel32"].assemble("thisisnotaninstruction"))) - result.append("armv7 assembly: " + str(binja.Architecture["armv7"].assemble("thisisnotaninstruction"))) - result.append("aarch64 assembly: " + str(binja.Architecture["aarch64"].assemble("thisisnotaninstruction"))) - result.append("thumb2 assembly: " + str(binja.Architecture["thumb2"].assemble("thisisnotaninstruction"))) - result.append("thumb2eb assembly: " + str(binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction"))) + try: + strResult = binja.Architecture["x86"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86'") + try: + strResult = binja.Architecture["x86_64"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'x86_64'") + try: + strResult = binja.Architecture["mips32"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mips32'") + try: + strResult = binja.Architecture["mipsel32"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'mipsel32'") + try: + strResult = binja.Architecture["armv7"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'armv7'") + try: + strResult = binja.Architecture["aarch64"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'aarch64'") + try: + strResult = binja.Architecture["thumb2"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2'") + try: + strResult = binja.Architecture["thumb2eb"].assemble("thisisnotaninstruction") + except ValueError: + result.append("Assemble Failed As Expected; 'thisisnotaninstruction' is not an instruction on 'thumb2eb'") return result def test_Architecture(self): @@ -385,8 +493,6 @@ class TestBuilder(Builder): retinfo.append("Instruction: " + str(ins)) return retinfo - - def test_Function(self): """Function produced different result""" inttype = binja.Type.int(4) @@ -433,7 +539,6 @@ class TestBuilder(Builder): def test_Types(self): """Types produced different result""" - file_name = os.path.join(self.test_store, "helloworld") bv = binja.BinaryViewType.get_view_of_file(file_name) preprocessed = binja.preprocess_source(""" @@ -445,7 +550,7 @@ class TestBuilder(Builder): long long bar1 = 2; #endif """) - source = '\n'.join([i.decode("utf-8") for i in preprocessed[0].split('\n') if not b"#line" in i and len(i) > 0]) + source = '\n'.join([i.decode('utf-8') for i in preprocessed[0].split(b'\n') if not b'#line' in i and len(i) > 0]) typelist = bv.platform.parse_types_from_source(source) inttype = binja.Type.int(4) @@ -464,12 +569,11 @@ class TestBuilder(Builder): def test_Plugin_bin_info(self): """print_syscalls plugin produced different result""" - file_name = os.path.join(self.test_store, "helloworld") self.unpackage_file(file_name) result = subprocess.Popen(["python", os.path.join(self.examples_dir, "bin_info.py"), file_name], stdout=subprocess.PIPE).communicate()[0] # normalize line endings and path sep - return [result.replace(b"\\", b"/").replace(b"\r\n", b"\n")] + return [result.replace(b"\\", b"/").replace(b"\r\n", b"\n").decode("charmap")] def test_linear_disassembly(self): """linear_disassembly produced different result""" @@ -486,7 +590,6 @@ class TestBuilder(Builder): def test_partial_register_dataflow(self): """partial_register_dataflow produced different results""" - file_name = os.path.join(self.test_store, "partial_register_dataflow") self.unpackage_file(file_name) result = [] @@ -505,7 +608,6 @@ class TestBuilder(Builder): del bv finally: os.unlink(file_name) - return result @@ -524,20 +626,13 @@ class TestBuilder(Builder): retinfo.append("LLIL second stack element: " + str(ins.get_stack_contents_after(0,1))) retinfo.append("LLIL possible first stack element: " + str(ins.get_possible_stack_contents(0,1))) retinfo.append("LLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0,1))) - - for flag in flag_list: retinfo.append("LLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag))) retinfo.append("LLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag))) - retinfo.append("LLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag))) retinfo.append("LLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values_after(flag))) - - os.unlink(file_name) - os.unlink(file_name) - - return retinfo + return fixOutput(retinfo) def test_med_il_stack(self): """MLIL stack produced different output""" @@ -555,25 +650,21 @@ class TestBuilder(Builder): retinfo.append("MLIL second stack element: " + str(ins.get_stack_contents_after(0, 1))) retinfo.append("MLIL possible first stack element: " + str(ins.get_possible_stack_contents(0, 1))) retinfo.append("MLIL possible second stack element: " + str(ins.get_possible_stack_contents_after(0, 1))) - + for reg in reg_list: retinfo.append("MLIL reg {} var at {}: ".format(reg, hex(ins.address)) + str(ins.get_var_for_reg(reg))) retinfo.append("MLIL reg {} value at {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value(reg))) retinfo.append("MLIL reg {} value after {}: ".format(reg, hex(ins.address)) + str(ins.get_reg_value_after(reg))) - retinfo.append("MLIL reg {} possible value at {}: ".format(reg, hex(ins.address)) + str(ins.get_possible_reg_values(reg))) - retinfo.append("MLIL reg {} possible value after {}: ".format(reg, hex(ins.address)) + str(ins.get_possible_reg_values_after(reg))) - + retinfo.append("MLIL reg {} possible value at {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values(reg)))) + retinfo.append("MLIL reg {} possible value after {}: ".format(reg, hex(ins.address)) + fixSet(str(ins.get_possible_reg_values_after(reg)))) for flag in flag_list: retinfo.append("MLIL flag {} value at: ".format(flag, hex(ins.address)) + str(ins.get_flag_value(flag))) retinfo.append("MLIL flag {} value after {}: ".format(flag, hex(ins.address)) + str(ins.get_flag_value_after(flag))) - retinfo.append("MLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag))) - retinfo.append("MLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + str(ins.get_possible_flag_values(flag))) - + retinfo.append("MLIL flag {} possible value at {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag)))) + retinfo.append("MLIL flag {} possible value after {}: ".format(flag, hex(ins.address)) + fixSet(str(ins.get_possible_flag_values(flag)))) os.unlink(file_name) - - return retinfo - + return fixOutput(retinfo) def test_events(self): """Event failure""" @@ -582,11 +673,9 @@ class TestBuilder(Builder): bv = binja.BinaryViewType['ELF'].open(file_name) results = [] - def simple_complete(self): results.append("analysis complete") - evt = binja.AnalysisCompletionEvent(bv, simple_complete) class NotifyTest(binja.BinaryDataNotification): @@ -643,7 +732,13 @@ class TestBuilder(Builder): def string_found(self, view, string_type, offset, length): def string_found_complete(self): - results.append("string found: offset {0} length {1}".format(hex(offset), hex(length))) + offset = hex(offset) + length = hex(length) + if offset[-1] == 'L': + offset = offset[:-1] + if length[-1] == 'L': + length = length[:-1] + results.append("string found: offset {0} length {1}".format(offset, length)) evt = binja.AnalysisCompletionEvent(bv, string_found_complete) def string_removed(self, view, string_type, offset, length): @@ -666,7 +761,6 @@ class TestBuilder(Builder): bv.register_notification(test) sacrificial_addr = 0x84fc - type, name = bv.parse_type_string("int foo") type_id = type.generate_auto_type_id("source", name) bv.define_type(type_id, name, type) @@ -684,10 +778,10 @@ class TestBuilder(Builder): bv.remove(sacrificial_addr, 4) bv.update_analysis_and_wait() - + bv.unregister_notification(test) - return sorted(results) + return fixOutput(sorted(results)) def unpackage(self, fileName): testname = None diff --git a/suite/unit.py b/suite/unit.py index 9a59b13f..fe2c4b8c 100644 --- a/suite/unit.py +++ b/suite/unit.py @@ -1,24 +1,77 @@ #!/usr/bin/env python # This is an auto generated unit test file do not edit directly import os +import sys import unittest import pickle import zipfile import testcommon -import binaryninja import api_test import difflib +from collections import Counter +global verbose +verbose = False class TestBinaryNinjaAPI(unittest.TestCase): + # Returns a tuple of: + # bool : Two lists are equal + # string : The string diff + # Args: + # list + # list : (compare list one vs list two) + # string : anything additional wanted to be printed before the string diff + # bool : the ordering of the items in the two lists must be the same + def report(self, oracle, test, firstText='', strictOrdering = False): + stringDiff = "" + + equality = False + if not strictOrdering: + equality = (Counter(oracle) == Counter(test)) + else: + equality = (oracle == test) + + if equality: + return (True, '') + elif not strictOrdering: + try: + for elem in oracle: + test.remove(elem) + oracle.remove(elem) # If it's not in the test, it won't get here! + except ValueError: + pass + + differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) + skipped_lines = 0 + for delta in differ.compare(oracle, test): + if delta[0] == ' ': + skipped_lines += 1 + continue + if skipped_lines > 0: + stringDiff += "<---" + str(skipped_lines) + ' same lines--->\n' + skipped_lines = 0 + delta = delta.replace('\n', '') + stringDiff += delta + '\n' + + stringDiffList = stringDiff.split('\n') + + if len(stringDiffList) > 10: + if not verbose: + stringDiff = '\n'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList[:10]) + stringDiff += '\n\n### And ' + str(len(stringDiffList)) + " more lines, use '-v' to show ###" + elif not verbose: + stringDiff = '\n'.join(line if len(line) <= 100 else line[:100] + "...and " + str(len(line) - 100) + " more characters" for line in stringDiffList) + stringDiff = '\n\n' + firstText + stringDiff + return (equality, stringDiff) + @classmethod def setUpClass(self): self.builder = testcommon.TestBuilder("suite/binaries/test_corpus") try: - #Python 2 does not have the encodings option - self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rUb"), errors="ignore") + # Python 2 does not have the encodings option + self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rb"), encoding='charmap') except TypeError: - self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "rU")) + self.oracle_test_data = pickle.load(open(os.path.join("suite", "oracle.pkl"), "r")) self.verifybuilder = testcommon.VerifyBuilder("suite/binaries/test_corpus") def run_binary_test(self, testfile): @@ -29,10 +82,10 @@ class TestBinaryNinjaAPI(unittest.TestCase): self.assertTrue(os.path.exists(testname + ".pkl"), "Test pickle doesn't exist") try: - #Python 2 does not have the encodings option - binary_oracle = pickle.load(open(testname + ".pkl", "rUb"), errors="ignore") + # Python 2 does not have the encodings option + binary_oracle = pickle.load(open(testname + ".pkl", "rb"), encoding='charmap') except TypeError: - binary_oracle = pickle.load(open(testname + ".pkl", "rU")) + binary_oracle = pickle.load(open(testname + ".pkl", "r")) test_builder = testcommon.BinaryViewTestBuilder(testname, "suite/binaries/test_corpus") for method in test_builder.methods(): @@ -43,271 +96,93 @@ class TestBinaryNinjaAPI(unittest.TestCase): result = getattr(test_builder, method).__doc__ result += ":\n" - d = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in d.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - self.assertTrue(False, result) + report = self.report(oracle, test, result) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle os.unlink(testname) def test_Architecture(self): oracle = self.oracle_test_data['test_Architecture'] test = self.builder.test_Architecture() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Architecture_list(self): oracle = self.oracle_test_data['test_Architecture_list'] test = self.builder.test_Architecture_list() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Assemble(self): oracle = self.oracle_test_data['test_Assemble'] test = self.builder.test_Assemble() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_BinaryViewType_list(self): oracle = self.oracle_test_data['test_BinaryViewType_list'] test = self.builder.test_BinaryViewType_list() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Enumeration(self): oracle = self.oracle_test_data['test_Enumeration'] test = self.builder.test_Enumeration() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Function(self): oracle = self.oracle_test_data['test_Function'] test = self.builder.test_Function() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Plugin_bin_info(self): oracle = self.oracle_test_data['test_Plugin_bin_info'] test = self.builder.test_Plugin_bin_info() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Struct(self): oracle = self.oracle_test_data['test_Struct'] test = self.builder.test_Struct() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_Types(self): oracle = self.oracle_test_data['test_Types'] test = self.builder.test_Types() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_events(self): oracle = self.oracle_test_data['test_events'] test = self.builder.test_events() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_linear_disassembly(self): oracle = self.oracle_test_data['test_linear_disassembly'] test = self.builder.test_linear_disassembly() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_low_il_stack(self): oracle = self.oracle_test_data['test_low_il_stack'] test = self.builder.test_low_il_stack() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_med_il_stack(self): oracle = self.oracle_test_data['test_med_il_stack'] test = self.builder.test_med_il_stack() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_partial_register_dataflow(self): oracle = self.oracle_test_data['test_partial_register_dataflow'] test = self.builder.test_partial_register_dataflow() - result = "" - differ = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) - skipped_lines = 0 - for delta in differ.compare(test, oracle): - if delta[0] == ' ': - skipped_lines += 1 - continue - if skipped_lines > 0: - result += "<---" + str(skipped_lines) + ' same lines--->\n' - skipped_lines = 0 - delta = delta.replace('\n', '') - result += delta + '\n' - - self.assertTrue(oracle == test, result) + report = self.report(oracle, test) + self.assertTrue(report[0], report[1]) # Test does not agree with oracle def test_verify_BNDB_round_trip(self): self.assertTrue(self.verifybuilder.test_verify_BNDB_round_trip(), self.test_verify_BNDB_round_trip.__doc__) @@ -386,6 +261,10 @@ class TestBinaryNinjaAPI(unittest.TestCase): if __name__ == "__main__": + if len(sys.argv) > 1: + if sys.argv[1] == '-v' or sys.argv[1] == '-V' or sys.argv[1] == '--verbose': + verbose = True + test_suite = unittest.defaultTestLoader.loadTestsFromModule(api_test) test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestBinaryNinjaAPI)) runner = unittest.TextTestRunner(verbosity=2) -- cgit v1.3.1 From f9d7cc83105d6cbfe03409c6eddbc039b0d9839c Mon Sep 17 00:00:00 2001 From: KyleMiles Date: Mon, 16 Jul 2018 15:56:28 -0400 Subject: Fix format of strings in python/log.py --- .gitignore | 1 + Makefile | 6 +++--- python/generator.cpp | 10 ++++++++++ python/log.py | 12 ++++++------ python/plugin.py | 35 +++++++++++++++++------------------ 5 files changed, 37 insertions(+), 27 deletions(-) (limited to 'python/log.py') diff --git a/.gitignore b/.gitignore index fca3f67d..088713e7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ api-docs/build/* .env api-docs/source/binaryninja.* bin/ +suite/unit.py # CMake CMakeCache.txt CMakeFiles diff --git a/Makefile b/Makefile index e1576dcf..8480c05a 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ all: $(TARGET).a $(TARGET).a: $(OBJECTS) @mkdir -p $(TARGETDIR) $(AR) rcs $@ $^ - + %.o: %.cpp @echo " Compiling... $@ $<" $(CC) $(CFLAGS) $(INC) -c -o $@ $< @@ -86,7 +86,7 @@ environment_clean: @echo "Removing 'binaryninja' Packages..." rm -rf suite/binaryninja/ rm -rf python/examples/binaryninja/ - + @echo "Removing libs..." rm -f libbinaryninjacore.so.1 rm -f python/libbinaryninjacore.so.1 @@ -97,7 +97,7 @@ environment_clean: rm -rf python/types/ rm -rf python/plugins/ -clean: +clean: @echo " Cleaning..."; $(RM) -r *.o $(TARGETDIR) generator diff --git a/python/generator.cpp b/python/generator.cpp index afc77254..39e45aea 100644 --- a/python/generator.cpp +++ b/python/generator.cpp @@ -391,6 +391,16 @@ int main(int argc, char* argv[]) } fprintf(out, "\t]\n"); } + else + { + // As of writing this, only BNLog's have variable instruction lengths, but in an attempt not to break in the future: + if (funcName.compare(0, 6, "_BNLog") == 0) + { + fprintf(out, "def %s(*args):\n", name.c_str()); + fprintf(out, "\treturn %s(*[cstr(arg) for arg in args])\n\n", funcName.c_str()); + continue; + } + } if (stringResult) { diff --git a/python/log.py b/python/log.py index 9a5e1358..4997b222 100644 --- a/python/log.py +++ b/python/log.py @@ -55,7 +55,7 @@ def log(level, text): :param str text: message to print :rtype: None """ - core.BNLog(level,text) + core.BNLog(level, '%s', text) def log_debug(text): @@ -70,7 +70,7 @@ def log_debug(text): >>> log_debug("Hotdogs!") Hotdogs! """ - core.BNLogDebug(text) + core.BNLogDebug('%s', text) def log_info(text): @@ -85,7 +85,7 @@ def log_info(text): Saucisson! >>> """ - core.BNLogInfo(text) + core.BNLogInfo('%s', text) def log_warn(text): @@ -101,7 +101,7 @@ def log_warn(text): Chilidogs! >>> """ - core.BNLogWarn(text) + core.BNLogWarn('%s', text) def log_error(text): @@ -117,7 +117,7 @@ def log_error(text): Spanferkel! >>> """ - core.BNLogError(text) + core.BNLogError('%s', text) def log_alert(text): @@ -133,7 +133,7 @@ def log_alert(text): Kielbasa! >>> """ - core.BNLogAlert(text) + core.BNLogAlert('%s', text) def log_to_stdout(min_level=LogLevel.InfoLog): diff --git a/python/plugin.py b/python/plugin.py index 2fc30052..6ca930c9 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -24,7 +24,6 @@ import threading # Binary Ninja components import binaryninja -from binaryninja import log from binaryninja import _binaryninjacore as core from binaryninja.enums import PluginCommandType from binaryninja import filemetadata @@ -96,7 +95,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _address_action(cls, view, addr, action): @@ -105,7 +104,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj, addr) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _range_action(cls, view, addr, length, action): @@ -114,7 +113,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) action(view_obj, addr, length) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _function_action(cls, view, func, action): @@ -124,7 +123,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = function.Function(view_obj, core.BNNewFunctionReference(func)) action(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _low_level_il_function_action(cls, view, func, action): @@ -135,7 +134,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) action(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _low_level_il_instruction_action(cls, view, func, instr, action): @@ -146,7 +145,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) action(view_obj, func_obj[instr]) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _medium_level_il_function_action(cls, view, func, action): @@ -157,7 +156,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) action(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _medium_level_il_instruction_action(cls, view, func, instr, action): @@ -168,7 +167,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) action(view_obj, func_obj[instr]) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) @classmethod def _default_is_valid(cls, view, is_valid): @@ -179,7 +178,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -191,7 +190,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj, addr) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -203,7 +202,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): view_obj = binaryninja.binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) return is_valid(view_obj, addr, length) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -216,7 +215,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = function.Function(view_obj, core.BNNewFunctionReference(func)) return is_valid(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -230,7 +229,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -244,7 +243,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj[instr]) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -258,7 +257,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -272,7 +271,7 @@ class PluginCommand(with_metaclass(_PluginCommandMetaClass, object)): func_obj = binaryninja.mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) return is_valid(view_obj, func_obj[instr]) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) return False @classmethod @@ -552,7 +551,7 @@ class MainThreadActionHandler(object): try: self.add_action(MainThreadAction(action)) except: - log.log_error(traceback.format_exc()) + binaryninja.log.log_error(traceback.format_exc()) def add_action(self, action): pass -- cgit v1.3.1