summaryrefslogtreecommitdiff
path: root/python/binaryview.py
diff options
context:
space:
mode:
authorRusty Wagner <rusty@vector35.com>2017-06-23 18:36:37 -0400
committerRusty Wagner <rusty@vector35.com>2017-06-23 18:36:37 -0400
commitc51f3bed6bdef577253feee0e85a71fda1931bd7 (patch)
tree1cf26ff28e0b9bfb6bfbed044ba7ca520d63f862 /python/binaryview.py
parent4b988c0d24c8d8c8dc67485f3aaeb7106eb4af18 (diff)
parentcca0fe6ea60eb7f6b35cc433a6fff96cc65b3ff8 (diff)
Merge branch 'dev'
Diffstat (limited to 'python/binaryview.py')
-rw-r--r--python/binaryview.py279
1 files changed, 235 insertions, 44 deletions
diff --git a/python/binaryview.py b/python/binaryview.py
index c021024f..c0ac0abc 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015-2016 Vector 35 LLC
+# 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
@@ -78,6 +78,12 @@ class BinaryDataNotification(object):
def string_removed(self, view, string_type, offset, length):
pass
+ def type_defined(self, view, name, type):
+ pass
+
+ def type_undefined(self, view, name, type):
+ pass
+
class StringReference(object):
def __init__(self, string_type, start, length):
@@ -157,6 +163,8 @@ class BinaryDataNotificationCallbacks(object):
self._cb.dataVariableUpdated = self._cb.dataVariableUpdated.__class__(self._data_var_updated)
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
+ self._cb.typeUndefined = self._cb.typeUndefined.__class__(self._type_undefined)
def _register(self):
core.BNRegisterDataNotification(self.view.handle, self._cb)
@@ -202,27 +210,27 @@ class BinaryDataNotificationCallbacks(object):
def _data_var_added(self, ctxt, view, var):
try:
- address = var.address
- var_type = types.Type(core.BNNewTypeReference(var.type))
- auto_discovered = var.autoDiscovered
+ address = var[0].address
+ var_type = types.Type(core.BNNewTypeReference(var[0].type))
+ auto_discovered = var[0].autoDiscovered
self.notify.data_var_added(self.view, DataVariable(address, var_type, auto_discovered))
except:
log.log_error(traceback.format_exc())
def _data_var_removed(self, ctxt, view, var):
try:
- address = var.address
- var_type = types.Type(core.BNNewTypeReference(var.type))
- auto_discovered = var.autoDiscovered
+ address = var[0].address
+ var_type = types.Type(core.BNNewTypeReference(var[0].type))
+ auto_discovered = var[0].autoDiscovered
self.notify.data_var_removed(self.view, DataVariable(address, var_type, auto_discovered))
except:
log.log_error(traceback.format_exc())
def _data_var_updated(self, ctxt, view, var):
try:
- address = var.address
- var_type = types.Type(core.BNNewTypeReference(var.type))
- auto_discovered = var.autoDiscovered
+ address = var[0].address
+ var_type = types.Type(core.BNNewTypeReference(var[0].type))
+ auto_discovered = var[0].autoDiscovered
self.notify.data_var_updated(self.view, DataVariable(address, var_type, auto_discovered))
except:
log.log_error(traceback.format_exc())
@@ -239,6 +247,20 @@ class BinaryDataNotificationCallbacks(object):
except:
log.log_error(traceback.format_exc())
+ def _type_defined(self, ctxt, view, name, type_obj):
+ try:
+ qualified_name = types.QualifiedName._from_core_struct(name[0])
+ self.notify.type_defined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _type_undefined(self, ctxt, view, name, type_obj):
+ try:
+ qualified_name = types.QualifiedName._from_core_struct(name[0])
+ self.notify.type_undefined(view, qualified_name, types.Type(core.BNNewTypeReference(type_obj)))
+ except:
+ log.log_error(traceback.format_exc())
+
class _BinaryViewTypeMetaclass(type):
@property
@@ -277,6 +299,16 @@ class BinaryViewType(object):
def __init__(self, handle):
self.handle = core.handle_of_type(handle, core.BNBinaryViewType)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryViewType):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryViewType):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def name(self):
"""BinaryView name (read-only)"""
@@ -525,6 +557,16 @@ class BinaryView(object):
self.notifications = {}
self.next_address = None # Do NOT try to access view before init() is called, use placeholder
+ def __eq__(self, value):
+ if not isinstance(value, BinaryView):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryView):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@classmethod
def register(cls):
startup._init_plugins()
@@ -599,7 +641,7 @@ class BinaryView(object):
@classmethod
def set_default_session_data(cls, name, value):
"""
- ```set_default_session_data``` saves a variable to the BinaryView.
+ ``set_default_session_data`` saves a variable to the BinaryView.
:param name: name of the variable to be saved
:param value: value of the variable to be saved
@@ -825,7 +867,8 @@ class BinaryView(object):
type_list = core.BNGetAnalysisTypeList(self.handle, count)
result = {}
for i in xrange(0, count.value):
- result[type_list[i].name] = types.Type(core.BNNewTypeReference(type_list[i].type))
+ name = types.QualifiedName._from_core_struct(type_list[i].name)
+ result[name] = types.Type(core.BNNewTypeReference(type_list[i].type))
core.BNFreeTypeList(type_list, count.value)
return result
@@ -1286,7 +1329,7 @@ class BinaryView(object):
def perform_is_offset_executable(self, addr):
"""
- ``perform_is_offset_writable`` implements a check if a virtual address ``addr`` is executable.
+ ``perform_is_offset_executable`` implements a check if a virtual address ``addr`` is executable.
.. note:: This method **may** be overridden by custom BinaryViews. Use ``add_auto_segment`` to provide
data without overriding this method.
@@ -1367,7 +1410,7 @@ class BinaryView(object):
def create_database(self, filename, progress_func=None):
"""
- ``perform_get_database`` writes the current database (.bndb) file out to the specified file.
+ ``create_database`` writes the current database (.bndb) file out to the specified file.
:param str filename: path and filename to write the bndb to, this string `should` have ".bndb" appended to it.
:param callable() progress_func: optional function to be called with the current progress and total count.
@@ -1808,7 +1851,7 @@ class BinaryView(object):
def define_user_data_var(self, addr, var_type):
"""
- ``define_data_var`` defines a user data variable ``var_type`` at the virtual address ``addr``.
+ ``define_user_data_var`` defines a user data variable ``var_type`` at the virtual address ``addr``.
:param int addr: virtual address to define the given data variable
:param binaryninja.Type var_type: type to be defined at the given virtual address
@@ -1838,7 +1881,7 @@ class BinaryView(object):
def undefine_user_data_var(self, addr):
"""
- ``undefine_data_var`` removes the user data variable at the virtual address ``addr``.
+ ``undefine_user_data_var`` removes the user data variable at the virtual address ``addr``.
:param int addr: virtual address to define the data variable to be removed
:rtype: None
@@ -1867,7 +1910,7 @@ class BinaryView(object):
var = core.BNDataVariable()
if not core.BNGetDataVariableAtAddress(self.handle, addr, var):
return None
- return DataVariable(var.address, type.Type(var.type), var.autoDiscovered)
+ return DataVariable(var.address, types.Type(var.type), var.autoDiscovered)
def get_function_at(self, addr, plat=None):
"""
@@ -2102,6 +2145,8 @@ class BinaryView(object):
"""
``define_auto_symbol`` adds a symbol to the internal list of automatically discovered Symbol objects.
+ .. warning:: If multiple symbols for the same address are defined, only the most recent symbol will ever be used.
+
:param Symbol sym: the symbol to define
:rtype: None
"""
@@ -2111,6 +2156,8 @@ class BinaryView(object):
"""
``define_auto_symbol_and_var_or_function``
+ .. warning:: If multiple symbols for the same address are defined, only the most recent symbol will ever be used.
+
:param Symbol sym: the symbol to define
:param SymbolType sym_type: Type of symbol being defined
:param Platform plat: (optional) platform
@@ -2137,6 +2184,8 @@ class BinaryView(object):
"""
``define_user_symbol`` adds a symbol to the internal list of user added Symbol objects.
+ .. warning:: If multiple symbols for the same address are defined, only the most recent symbol will ever be used.
+
:param Symbol sym: the symbol to define
:rtype: None
"""
@@ -2731,7 +2780,9 @@ class BinaryView(object):
value = lines[i].contents.tokens[j].value
size = lines[i].contents.tokens[j].size
operand = lines[i].contents.tokens[j].operand
- tokens.append(function.InstructionTextToken(token_type, text, value, size, operand))
+ context = lines[i].contents.tokens[j].context
+ address = lines[i].contents.tokens[j].address
+ tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address))
contents = function.DisassemblyTextLine(addr, tokens)
result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents))
@@ -2831,51 +2882,117 @@ class BinaryView(object):
``parse_type_string`` converts `C-style` string into a :py:Class:`Type`.
:param str text: `C-style` string of type to create
- :return: A tuple of a :py:Class:`Type` and string type name
- :rtype: tuple(Type, str)
+ :return: A tuple of a :py:Class:`Type` and type name
+ :rtype: tuple(Type, QualifiedName)
:Example:
>>> bv.parse_type_string("int foo")
(<type: int32_t>, 'foo')
>>>
"""
- result = core.BNNameAndType()
+ result = core.BNQualifiedNameAndType()
errors = ctypes.c_char_p()
if not core.BNParseTypeString(self.handle, text, result, errors):
error_str = errors.value
core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
raise SyntaxError(error_str)
type_obj = types.Type(core.BNNewTypeReference(result.type))
- name = result.name
- core.BNFreeNameAndType(result)
+ name = types.QualifiedName._from_core_struct(result.name)
+ core.BNFreeQualifiedNameAndType(result)
return type_obj, name
def get_type_by_name(self, name):
"""
``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name``
- :param str name: Type name to lookup
+ :param QualifiedName name: Type name to lookup
:return: A :py:Class:`Type` or None if the type does not exist
:rtype: Type or None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> bv.define_user_type(name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
obj = core.BNGetAnalysisTypeByName(self.handle, name)
if not obj:
return None
return types.Type(obj)
+ def get_type_by_id(self, id):
+ """
+ ``get_type_by_id`` returns the defined type whose unique identifier corresponds with the provided ``id``
+
+ :param str id: Unique identifier to lookup
+ :return: A :py:Class:`Type` or None if the type does not exist
+ :rtype: Type or None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
+ >>> bv.get_type_by_id(type_id)
+ <type: int32_t>
+ >>>
+ """
+ obj = core.BNGetAnalysisTypeById(self.handle, id)
+ if not obj:
+ return None
+ return types.Type(obj)
+
+ def get_type_name_by_id(self, id):
+ """
+ ``get_type_name_by_id`` returns the defined type name whose unique identifier corresponds with the provided ``id``
+
+ :param str id: Unique identifier to lookup
+ :return: A QualifiedName or None if the type does not exist
+ :rtype: QualifiedName or None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
+ 'foo'
+ >>> bv.get_type_name_by_id(type_id)
+ 'foo'
+ >>>
+ """
+ name = core.BNGetAnalysisTypeNameById(self.handle, id)
+ result = types.QualifiedName._from_core_struct(name)
+ core.BNFreeQualifiedName(name)
+ if len(result) == 0:
+ return None
+ return result
+
+ def get_type_id(self, name):
+ """
+ ``get_type_id`` returns the unique indentifier of the defined type whose name corresponds with the
+ provided ``name``
+
+ :param QualifiedName name: Type name to lookup
+ :return: The unique identifier of the type
+ :rtype: str
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> registered_name = bv.define_type(type_id, name, type)
+ >>> bv.get_type_id(registered_name) == type_id
+ True
+ >>>
+ """
+ name = types.QualifiedName(name)._get_core_struct()
+ return core.BNGetAnalysisTypeId(self.handle, name)
+
def is_type_auto_defined(self, name):
"""
``is_type_auto_defined`` queries the user type list of name. If name is not in the *user* type list then the name
is considered an *auto* type.
- :param str name: Name of type to query
+ :param QualifiedName name: Name of type to query
:return: True if the type is not a *user* type. False if the type is a *user* type.
:Example:
>>> bv.is_type_auto_defined("foo")
@@ -2885,31 +3002,38 @@ class BinaryView(object):
False
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
return core.BNIsAnalysisTypeAutoDefined(self.handle, name)
- def define_type(self, name, type_obj):
+ def define_type(self, type_id, default_name, type_obj):
"""
``define_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of types for
- the current :py:Class:`BinaryView`.
+ the current :py:Class:`BinaryView`. This method should only be used for automatically generated types.
- :param str name: Name of the type to be registered
+ :param str type_id: Unique identifier for the automatically generated type
+ :param QualifiedName default_name: Name of the type to be registered
:param Type type_obj: Type object to be registered
- :rtype: None
+ :return: Registered name of the type. May not be the same as the requested name if the user has renamed types.
+ :rtype: QualifiedName
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
- >>> bv.get_type_by_name(name)
+ >>> registered_name = bv.define_type(Type.generate_auto_type_id("source", name), name, type)
+ >>> bv.get_type_by_name(registered_name)
<type: int32_t>
"""
- core.BNDefineAnalysisType(self.handle, name, type_obj.handle)
+ name = types.QualifiedName(default_name)._get_core_struct()
+ reg_name = core.BNDefineAnalysisType(self.handle, type_id, name, type_obj.handle)
+ result = types.QualifiedName._from_core_struct(reg_name)
+ core.BNFreeQualifiedName(reg_name)
+ return result
def define_user_type(self, name, type_obj):
"""
``define_user_type`` registers a :py:Class:`Type` ``type_obj`` of the given ``name`` in the global list of user
types for the current :py:Class:`BinaryView`.
- :param str name: Name of the user type to be registered
+ :param QualifiedName name: Name of the user type to be registered
:param Type type_obj: Type object to be registered
:rtype: None
:Example:
@@ -2919,45 +3043,86 @@ class BinaryView(object):
>>> bv.get_type_by_name(name)
<type: int32_t>
"""
+ name = types.QualifiedName(name)._get_core_struct()
core.BNDefineUserAnalysisType(self.handle, name, type_obj.handle)
- def undefine_type(self, name):
+ def undefine_type(self, type_id):
"""
``undefine_type`` removes a :py:Class:`Type` from the global list of types for the current :py:Class:`BinaryView`
- :param str name: Name of type to be undefined
+ :param str type_id: Unique identifier of type to be undefined
:rtype: None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> type_id = Type.generate_auto_type_id("source", name)
+ >>> bv.define_type(type_id, name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
- >>> bv.undefine_type(name)
+ >>> bv.undefine_type(type_id)
>>> bv.get_type_by_name(name)
>>>
"""
- core.BNUndefineAnalysisType(self.handle, name)
+ core.BNUndefineAnalysisType(self.handle, type_id)
def undefine_user_type(self, name):
"""
``undefine_user_type`` removes a :py:Class:`Type` from the global list of user types for the current
:py:Class:`BinaryView`
- :param str name: Name of user type to be undefined
+ :param QualifiedName name: Name of user type to be undefined
:rtype: None
:Example:
>>> type, name = bv.parse_type_string("int foo")
- >>> bv.define_type(name, type)
+ >>> bv.define_user_type(name, type)
>>> bv.get_type_by_name(name)
<type: int32_t>
- >>> bv.undefine_type(name)
+ >>> bv.undefine_user_type(name)
>>> bv.get_type_by_name(name)
>>>
"""
+ name = types.QualifiedName(name)._get_core_struct()
core.BNUndefineUserAnalysisType(self.handle, name)
+ def rename_type(self, old_name, new_name):
+ """
+ ``rename_type`` renames a type in the global list of types for the current :py:Class:`BinaryView`
+
+ :param QualifiedName old_name: Existing name of type to be renamed
+ :param QualifiedName new_name: New name of type to be renamed
+ :rtype: None
+ :Example:
+
+ >>> type, name = bv.parse_type_string("int foo")
+ >>> bv.define_user_type(name, type)
+ >>> bv.get_type_by_name("foo")
+ <type: int32_t>
+ >>> bv.rename_type("foo", "bar")
+ >>> bv.get_type_by_name("bar")
+ <type: int32_t>
+ >>>
+ """
+ old_name = types.QualifiedName(old_name)._get_core_struct()
+ new_name = types.QualifiedName(new_name)._get_core_struct()
+ core.BNRenameAnalysisType(self.handle, old_name, new_name)
+
+ def register_platform_types(self, platform):
+ """
+ ``register_platform_types`` ensures that the platform-specific types for a :py:Class:`Platform` are available
+ for the current :py:Class:`BinaryView`. This is automatically performed when adding a new function or setting
+ the default platform.
+
+ :param Platform platform: Platform containing types to be registered
+ :rtype: None
+ :Example:
+
+ >>> platform = Platform["linux-x86"]
+ >>> bv.register_platform_types(platform)
+ >>>
+ """
+ core.BNRegisterPlatformTypes(self.handle, platform.handle)
+
def find_next_data(self, start, data, flags = 0):
"""
``find_next_data`` searchs for the bytes in data starting at the virtual address ``start`` either, case-sensitive,
@@ -3025,6 +3190,12 @@ class BinaryView(object):
segment.flags)
return result
+ def get_address_for_data_offset(self, offset):
+ address = ctypes.c_ulonglong()
+ if not core.BNGetAddressForDataOffset(self.handle, offset, address):
+ return None
+ return address.value
+
def add_auto_section(self, name, start, length, type = "", align = 1, entry_size = 1, linked_section = "",
info_section = "", info_data = 0):
core.BNAddAutoSection(self.handle, name, start, length, type, align, entry_size, linked_section,
@@ -3110,6 +3281,16 @@ class BinaryReader(object):
def __del__(self):
core.BNFreeBinaryReader(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryReader):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryReader):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def endianness(self):
"""
@@ -3417,6 +3598,16 @@ class BinaryWriter(object):
def __del__(self):
core.BNFreeBinaryWriter(self.handle)
+ def __eq__(self, value):
+ if not isinstance(value, BinaryWriter):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, BinaryWriter):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
@property
def endianness(self):
"""
@@ -3591,7 +3782,7 @@ class BinaryWriter(object):
>>> hex(bw.offset)
'0x100000008L'
>>> bw.seek(0x100000000)
- >>> hex(br.offset)
+ >>> hex(bw.offset)
'0x100000000L'
>>>
"""
@@ -3608,7 +3799,7 @@ class BinaryWriter(object):
>>> hex(bw.offset)
'0x100000008L'
>>> bw.seek_relative(-8)
- >>> hex(br.offset)
+ >>> hex(bw.offset)
'0x100000000L'
>>>
"""