summaryrefslogtreecommitdiff
path: root/python/examples/mappedview.py
diff options
context:
space:
mode:
authorBrian Potchik <brian@vector35.com>2020-02-16 15:40:34 -0500
committerBrian Potchik <brian@vector35.com>2020-02-16 15:40:34 -0500
commitc80d7c1d394764d95f59e450a715cedb79e3c32f (patch)
tree94e9852f0ba0f99f5101f18c5e3c9d6b0a81c873 /python/examples/mappedview.py
parent5dde4481ed477dd67f3ef35364153f8243dbeb99 (diff)
Add example binary view plugin which demonstrates the load settings system.
Diffstat (limited to 'python/examples/mappedview.py')
-rw-r--r--python/examples/mappedview.py133
1 files changed, 133 insertions, 0 deletions
diff --git a/python/examples/mappedview.py b/python/examples/mappedview.py
new file mode 100644
index 00000000..3ea7aa0d
--- /dev/null
+++ b/python/examples/mappedview.py
@@ -0,0 +1,133 @@
+# Copyright (c) 2015-2020 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+# This is an example BinaryView plugin which demonstrates how to specify
+# and generate a load settings spec. Load settings can subsequently be presented
+# by the UI in the Open With Options dialog or headless when opening a
+# file with options.
+
+from binaryninja import log
+from binaryninja import _binaryninjacore as core
+from binaryninja.architecture import Architecture
+from binaryninja.binaryview import BinaryView
+from binaryninja.binaryview import BinaryViewType
+from binaryninja.enums import SegmentFlag
+from binaryninja import Settings
+import json
+
+use_default_loader_settings = True
+
+class MappedView(BinaryView):
+ name = "Mapped (Python)"
+ long_name = "Mapped (Python)"
+ load_address = 0x100000
+
+ def __init__(self, data):
+ BinaryView.__init__(self, parent_view = data, file_metadata = data.file)
+
+ @classmethod
+ def is_valid_for_data(cls, data):
+ # Insert code that looks for a magic identifier and return True if this BinaryViewType can handle/parse the binary
+ return True
+
+ @classmethod
+ def get_load_settings_for_data(cls, data):
+ # This method is optional. If provided this is where the Load Settings for a BinaryViewType are specified. Binary Ninja provides
+ # some default read-only load settings which are:
+ # ["loader.architecture", "loader.platform", "loader.entryPoint", "loader.imageBase", "loader.segments", "loader.sections"]
+ # The default load settings are provided for consistency and convenience.
+ # The default load settings are always generated with a read-only indication which is respected by the UI.
+ # The read-only indication is a property that consists of a JSON name/value pair ("readOnly" : true).
+ load_settings = None
+ if not use_default_loader_settings:
+ # Create a new named Settings container for the load settings.
+ Settings("mapped_load_settings")
+ else:
+ # Optionally, perform light-weight parsing of the 'Raw' BinaryView to extract required information for load settings generation.
+ # This allows finer control of the settings provided as well as their default values.
+ # For example, the view.relocatable property could be used to control the read-only attribute of "loader.imageBase"
+ view = cls.registered_view_type.parse(data)
+
+ # Populate settings container with default load settings
+ # Note: `get_default_load_settings_for_data` automatically tries to parse the input if the `data` BinaryViewType name does not match the
+ # cls BinaryViewType name. In this case a parsed view is already being passed.
+ load_settings = cls.registered_view_type.get_default_load_settings_for_data(view)
+
+ # Specify default load settings that can be overridden (from the UI).
+ overrides = ["loader.architecture", "loader.platform", "loader.entryPoint", "loader.imageBase", "loader.segments", "loader.sections"]
+ for override in overrides:
+ if load_settings.contains(override):
+ load_settings.update_property(override, json.dumps({'readOnly': False}))
+
+ # Override the default setting values.
+ load_settings.update_property("loader.imageBase", json.dumps({'default': 0}))
+ load_settings.update_property("loader.entryPoint", json.dumps({'default': 0}))
+
+ # Specify additional custom settings.
+ load_settings.register_setting("loader.my_custom_arch.customLoadSetting",
+ '{"title" : "My Custom Load Setting",\
+ "type" : "boolean",\
+ "default" : false,\
+ "description" : "My custom load setting description."}')
+
+ return load_settings
+
+ def init(self):
+ if self.parse_only is True:
+ # Perform light-weight parsing to extract required information for load settings generation.
+ # A light-weight parsed view does not get finalized.
+ print("Mapped (Python): init(): perform light-weight parsing")
+ else:
+ # Perform normal BinaryView initialization
+ print("Mapped (Python): init(): perform normal BinaryView initialization")
+
+ # Finish BinaryView initialization using the load settings, if they exist
+ try:
+ load_settings = self.get_load_settings(self.name)
+ if load_settings is None:
+ self.arch = Architecture['x86']
+ self.platform = Architecture['x86'].standalone_platform
+ self.add_auto_segment(0, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable)
+ return True
+ arch = load_settings.get_string("loader.architecture", self)
+ self.arch = Architecture[arch]
+ self.platform = Architecture[arch].standalone_platform
+ self.load_address = load_settings.get_integer("loader.imageBase", self)
+ entry_point = load_settings.get_integer("loader.entryPoint", self)
+ self.add_entry_point(self.load_address + entry_point)
+ self.add_auto_segment(self.load_address, len(self.parent_view), 0, len(self.parent_view), SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable)
+ return True
+ except:
+ log_error(traceback.format_exc())
+ return False
+
+ def perform_get_entry_point(self):
+ return self.load_address
+
+ def perform_is_executable(self):
+ return True
+
+ def perform_is_relocatable(self):
+ return True
+
+ def perform_get_address_size(self):
+ return self.arch.address_size
+
+MappedView.register()