summaryrefslogtreecommitdiff
path: root/python/binaryview.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/binaryview.py')
-rw-r--r--python/binaryview.py188
1 files changed, 186 insertions, 2 deletions
diff --git a/python/binaryview.py b/python/binaryview.py
index 9e42d8fb..e38c334c 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -45,7 +45,7 @@ from . import decorators
from .enums import (
AnalysisState, SymbolType, Endianness, ModificationStatus, StringType, SegmentFlag, SectionSemantics, FindFlag,
TypeClass, BinaryViewEventType, FunctionGraphType, TagReferenceType, TagTypeType, RegisterValueType, DisassemblyOption,
- RelocationType
+ RelocationType, DerivedStringLocationType
)
from .exceptions import RelocationWriteException, ExternalLinkException
@@ -82,6 +82,7 @@ from . import typecontainer
from . import externallibrary
from . import project
from . import undo
+from . import stringrecognizer
PathType = Union[str, os.PathLike]
@@ -216,6 +217,8 @@ class NotificationType(IntFlag):
UndoEntryTaken = 1 << 50
RedoEntryTaken = 1 << 51
Rebased = 1 << 52
+ DerivedStringFound = 1 << 53
+ DerivedStringRemoved = 1 << 54
BinaryDataUpdates = DataWritten | DataInserted | DataRemoved
FunctionLifetime = FunctionAdded | FunctionRemoved
@@ -226,7 +229,7 @@ class NotificationType(IntFlag):
TagUpdates = TagLifetime | TagUpdated
SymbolLifetime = SymbolAdded | SymbolRemoved
SymbolUpdates = SymbolLifetime | SymbolUpdated
- StringUpdates = StringFound | StringRemoved
+ StringUpdates = StringFound | StringRemoved | DerivedStringFound | DerivedStringRemoved
TypeLifetime = TypeDefined | TypeUndefined
TypeUpdates = TypeLifetime | TypeReferenceChanged | TypeFieldReferenceChanged
SegmentLifetime = SegmentAdded | SegmentRemoved
@@ -390,6 +393,12 @@ class BinaryDataNotification:
def string_removed(self, view: 'BinaryView', string_type: StringType, offset: int, length: int) -> None:
pass
+ def derived_string_found(self, view: 'BinaryView', string: 'DerivedString') -> None:
+ pass
+
+ def derived_string_removed(self, view: 'BinaryView', string: 'DerivedString') -> None:
+ pass
+
def type_defined(self, view: 'BinaryView', name: '_types.QualifiedName', type: '_types.Type') -> None:
pass
@@ -518,6 +527,136 @@ class StringReference:
return self._view
+class StringRef:
+ def __init__(self, handle):
+ self.handle = core.handle_of_type(handle, core.BNStringRef)
+
+ def __del__(self):
+ if core is not None:
+ core.BNFreeStringRef(self.handle)
+
+ def __bytes__(self):
+ # Do not call the wrapper BNGetStringRefContents here, it will crash as the generator
+ # does not understand that this API gives a direct reference to the string
+ value_ptr = core._BNGetStringRefContents(self.handle)
+ value_len = core.BNGetStringRefSize(self.handle)
+ buf = ctypes.create_string_buffer(value_len)
+ ctypes.memmove(buf, value_ptr, value_len)
+ return bytes(buf.raw)
+
+ def __str__(self):
+ return core.pyNativeStr(bytes(self))
+
+ def __len__(self):
+ return core.BNGetStringRefSize(self.handle)
+
+ def __repr__(self):
+ return repr(str(self))
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) == bytes(other)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __lt__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) < bytes(self)
+
+ def __gt__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) > bytes(other)
+
+ def __le__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) <= bytes(other)
+
+ def __ge__(self, other) -> bool:
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return bytes(self) >= bytes(other)
+
+ def __hash__(self):
+ return hash(bytes(self))
+
+
+@dataclass(frozen=True)
+class DerivedStringLocation:
+ location_type: 'DerivedStringLocationType'
+ address: int
+ length: int
+
+
+@dataclass(frozen=True)
+class DerivedString:
+ value: 'StringRef'
+ location: Optional[DerivedStringLocation]
+ custom_type: Optional[stringrecognizer.CustomStringType]
+
+ def __init__(
+ self, value: Union['StringRef', str, bytes, bytearray, 'databuffer.DataBuffer'],
+ location: Optional[DerivedStringLocation], custom_type: Optional[stringrecognizer.CustomStringType]
+ ):
+ if isinstance(value, str):
+ value = value.encode("utf-8")
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, bytes):
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, bytearray):
+ value = bytes(value)
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif isinstance(value, databuffer.DataBuffer):
+ value = bytes(value)
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+ elif not isinstance(value, StringRef):
+ value = str(value).encode("utf-8")
+ value = StringRef(core.BNCreateStringRefOfLength(value, len(value)))
+
+ object.__setattr__(self, "value", value)
+ object.__setattr__(self, "location", location)
+ object.__setattr__(self, "custom_type", custom_type)
+
+ def _to_core_struct(self, owned: bool) -> 'core.BNDerivedString':
+ result = core.BNDerivedString()
+ if owned:
+ result.value = core.BNDuplicateStringRef(self.value.handle)
+ else:
+ result.value = self.value.handle
+ result.locationValid = self.location is not None
+ if result.locationValid:
+ result.location.locationType = self.location.location_type
+ result.location.addr = self.location.address
+ result.location.len = self.location.length
+ if self.custom_type is None:
+ result.customType = None
+ else:
+ result.customType = self.custom_type.handle
+ return result
+
+ @staticmethod
+ def _from_core_struct(obj: 'core.BNDerivedString', owned: bool) -> 'DerivedString':
+ if owned:
+ value = StringRef(obj.value)
+ else:
+ value = StringRef(core.BNDuplicateStringRef(obj.value))
+ if obj.locationValid:
+ location = DerivedStringLocation(DerivedStringLocationType(obj.location.locationType), obj.location.addr, obj.location.len)
+ else:
+ location = None
+ if obj.customType:
+ custom_type = stringrecognizer.CustomStringType(obj.customType)
+ else:
+ custom_type = None
+ return DerivedString(value, location, custom_type)
+
+
class AnalysisCompletionEvent:
"""
The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving
@@ -701,6 +840,8 @@ class BinaryDataNotificationCallbacks:
self._cb.symbolUpdated = self._cb.symbolUpdated.__class__(self._symbol_updated)
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ self._cb.derivedStringFound = self._cb.derivedStringFound.__class__(self._derived_string_found)
+ self._cb.derivedStringRemoved = self._cb.derivedStringRemoved.__class__(self._derived_string_removed)
self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
self._cb.typeUndefined = self._cb.typeUndefined.__class__(self._type_undefined)
self._cb.typeReferenceChanged = self._cb.typeReferenceChanged.__class__(self._type_ref_changed)
@@ -774,6 +915,10 @@ class BinaryDataNotificationCallbacks:
self._cb.stringFound = self._cb.stringFound.__class__(self._string_found)
if notify.notifications & NotificationType.StringRemoved:
self._cb.stringRemoved = self._cb.stringRemoved.__class__(self._string_removed)
+ if notify.notifications & NotificationType.DerivedStringFound:
+ self._cb.derivedStringFound = self._cb.derivedStringFound.__class__(self._derived_string_found)
+ if notify.notifications & NotificationType.DerivedStringRemoved:
+ self._cb.derivedStringRemoved = self._cb.derivedStringRemoved.__class__(self._derived_string_removed)
if notify.notifications & NotificationType.TypeDefined:
self._cb.typeDefined = self._cb.typeDefined.__class__(self._type_defined)
if notify.notifications & NotificationType.TypeUndefined:
@@ -1017,6 +1162,18 @@ class BinaryDataNotificationCallbacks:
except:
log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._string_removed")
+ def _derived_string_found(self, ctxt, view: core.BNBinaryView, string) -> None:
+ try:
+ self._notify.derived_string_found(self._view, DerivedString._from_core_struct(string[0], False))
+ except:
+ log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._derived_string_found")
+
+ def _derived_string_removed(self, ctxt, view: core.BNBinaryView, string) -> None:
+ try:
+ self._notify.derived_string_removed(self._view, DerivedString._from_core_struct(string[0], False))
+ except:
+ log_error_for_exception("Unhandled Python exception in BinaryDataNotificationCallbacks._derived_string_removed")
+
def _type_defined(self, ctxt, view: core.BNBinaryView, name: str, type_obj: '_types.Type') -> None:
try:
qualified_name = _types.QualifiedName._from_core_struct(name[0])
@@ -3402,6 +3559,19 @@ class BinaryView:
return self.get_strings()
@property
+ def derived_strings(self) -> List['DerivedString']:
+ count = ctypes.c_ulonglong(0)
+ strings = core.BNGetDerivedStrings(self.handle, count)
+ assert strings is not None, "core.BNGetDerivedStrings returned None"
+ try:
+ result = []
+ for i in range(0, count.value):
+ result.append(DerivedString._from_core_struct(strings[i], False))
+ return result
+ finally:
+ core.BNFreeDerivedStringList(strings, count.value)
+
+ @property
def saved(self) -> bool:
"""boolean state of whether or not the file has been saved (read/write)"""
return self._file.saved
@@ -5818,6 +5988,20 @@ class BinaryView:
core.BNFreeTypeReferences(refs, count.value)
return result
+ def get_derived_string_code_refs(self, str: 'DerivedString', max_items: Optional[int] = None) -> Generator['ReferenceSource', None, None]:
+ count = ctypes.c_ulonglong(0)
+ has_max_items = max_items is not None
+ max_items_value = max_items if has_max_items else 0
+ core_str = str._to_core_struct(False)
+ refs = core.BNGetDerivedStringCodeReferences(self.handle, core_str, count, has_max_items, max_items_value)
+ assert refs is not None, "core.BNGetDerivedStringCodeReferences returned None"
+
+ try:
+ for i in range(0, count.value):
+ yield ReferenceSource._from_core_struct(self, refs[i])
+ finally:
+ core.BNFreeCodeReferences(refs, count.value)
+
def add_data_ref(self, from_addr: int, to_addr: int) -> None:
"""
``add_data_ref`` adds an auto data cross-reference (xref) from the address ``from_addr`` to the address ``to_addr``.