summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/__init__.py1
-rw-r--r--python/binaryview.py188
-rw-r--r--python/examples/encoded_strings.py25
-rw-r--r--python/highlevelil.py24
-rw-r--r--python/stringrecognizer.py293
5 files changed, 517 insertions, 14 deletions
diff --git a/python/__init__.py b/python/__init__.py
index acf8b293..02703972 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -83,6 +83,7 @@ from .languagerepresentation import *
from .lineformatter import *
from .renderlayer import *
from .constantrenderer import *
+from .stringrecognizer import *
# We import each of these by name to prevent conflicts between
# log.py and the function 'log' which we don't import below
from .log import (
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``.
diff --git a/python/examples/encoded_strings.py b/python/examples/encoded_strings.py
index ce7d02db..691d116c 100644
--- a/python/examples/encoded_strings.py
+++ b/python/examples/encoded_strings.py
@@ -1,8 +1,11 @@
-from binaryninja import (ConstantRenderer, PointerType, InstructionTextToken, InstructionTextTokenType, DataBuffer)
+from binaryninja import (StringRecognizer, CustomStringType, DataBuffer, DerivedString, DerivedStringLocation,
+ DerivedStringLocationType, PointerType, InstructionTextToken, InstructionTextTokenType)
+encoded_string_type = CustomStringType.register("Encoded", "", "_enc")
-class EncodedStringConstantRenderer(ConstantRenderer):
- renderer_name = "encoded_strings"
+
+class EncodedStringRecognizer(StringRecognizer):
+ recognizer_name = "encoded_strings"
decoders = {
"xor_encoded": lambda encoded, key: encoded ^ key,
"sub_encoded": lambda encoded, key: (encoded - key) & 0xff,
@@ -17,9 +20,9 @@ class EncodedStringConstantRenderer(ConstantRenderer):
return True
return False
- def render_constant_pointer(self, instr, type, val, tokens, settings, precedence):
+ def recognize_constant_pointer(self, instr, type, val):
if not isinstance(type, PointerType):
- return False
+ return None
values = None
decoder = None
@@ -29,9 +32,9 @@ class EncodedStringConstantRenderer(ConstantRenderer):
values = bytes.fromhex(type.target.attributes[name])
decoder = self.__class__.decoders[name]
except:
- return False
+ return None
if values is None or decoder is None:
- return False
+ return None
encoded_null = "encoded_null" in type.target.attributes
@@ -49,10 +52,8 @@ class EncodedStringConstantRenderer(ConstantRenderer):
result += bytes([byte])
i += 1
- tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "\""))
- tokens.append(InstructionTextToken(InstructionTextTokenType.StringToken, DataBuffer(result).escape()))
- tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "\"_enc"))
- return True
+ loc = DerivedStringLocation(DerivedStringLocationType.DataBackedStringLocation, val, i)
+ return DerivedString(result, loc, encoded_string_type)
-EncodedStringConstantRenderer().register()
+EncodedStringRecognizer().register()
diff --git a/python/highlevelil.py b/python/highlevelil.py
index ce264e19..ef1b3de2 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -41,6 +41,7 @@ from . import highlight
from . import flowgraph
from . import variable
from . import databuffer
+from . import stringrecognizer
from . import types as _types
from .interaction import show_graph_report
from .commonil import (
@@ -973,6 +974,13 @@ class HighLevelILInstruction(BaseILInstruction):
hash ^= rotl(discriminator, 47)
return hash
+ @property
+ def derived_string_reference(self) -> Optional['binaryview.DerivedString']:
+ str = core.BNDerivedString()
+ if not core.BNGetHighLevelILDerivedStringReferenceForExpr(self.function.handle, self.expr_index, str):
+ return None
+ return binaryview.DerivedString._from_core_struct(str, True)
+
@dataclass(frozen=True, repr=False, eq=False)
class HighLevelILUnaryBase(HighLevelILInstruction, UnaryOperation):
@@ -3003,6 +3011,22 @@ class HighLevelILFunction:
result |= flag.value
core.BNSetHighLevelILExprAttributes(self.handle, expr, result)
+ def set_derived_string_reference_for_expr(self, expr: InstructionOrExpression, str: 'binaryview.DerivedString'):
+ if isinstance(expr, HighLevelILInstruction):
+ expr = expr.expr_index
+ elif isinstance(expr, int):
+ expr = ExpressionIndex(expr)
+
+ str_obj = str._to_core_struct(False)
+ core.BNSetHighLevelILDerivedStringReferenceForExpr(self.handle, expr, str_obj)
+
+ def remove_derived_string_reference_for_expr(self, expr: InstructionOrExpression):
+ if isinstance(expr, HighLevelILInstruction):
+ expr = expr.expr_index
+ elif isinstance(expr, int):
+ expr = ExpressionIndex(expr)
+ core.BNRemoveHighLevelILDerivedStringReferenceForExpr(self.handle, expr)
+
def nop(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``nop`` no operation, this instruction does nothing
diff --git a/python/stringrecognizer.py b/python/stringrecognizer.py
new file mode 100644
index 00000000..8f503d8b
--- /dev/null
+++ b/python/stringrecognizer.py
@@ -0,0 +1,293 @@
+# Copyright (c) 2015-2025 Vector 35 Inc
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+from typing import Optional, Union
+from dataclasses import dataclass
+import ctypes
+
+import binaryninja
+from . import _binaryninjacore as core
+from .log import log_error_for_exception
+from . import types
+from . import highlevelil
+from . import binaryview
+
+
+class _CustomStringTypeMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ types = core.BNGetCustomStringTypeList(count)
+ assert types is not None, "core.BNGetCustomStringTypeList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CustomStringType(handle=types[i])
+ finally:
+ core.BNFreeCustomStringTypeList(types)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ string_type = core.BNGetCustomStringTypeByName(str(value))
+ if string_type is None:
+ raise KeyError("'%s' is not a valid type" % str(value))
+ return CustomStringType(handle=string_type)
+
+
+class CustomStringType(metaclass=_CustomStringTypeMetaClass):
+ def __init__(self, handle):
+ self.handle = core.handle_of_type(handle, core.BNCustomStringType)
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return f"<{self.__class__.__name__}: {self.name}>"
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(other.handle.contents)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __hash__(self):
+ return hash(ctypes.addressof(self.handle.contents))
+
+ @staticmethod
+ def register(name: str, string_prefix="", string_postfix="") -> 'CustomStringType':
+ info = core.BNCustomStringTypeInfo()
+ info.name = name
+ info.stringPrefix = string_prefix
+ info.stringPostfix = string_postfix
+ handle = core.BNRegisterCustomStringType(info)
+ return CustomStringType(handle)
+
+ @property
+ def name(self) -> str:
+ return core.BNGetCustomStringTypeName(self.handle)
+
+ @property
+ def string_prefix(self) -> str:
+ return core.BNGetCustomStringTypePrefix(self.handle)
+
+ @property
+ def string_postfix(self) -> str:
+ return core.BNGetCustomStringTypePostfix(self.handle)
+
+
+class _StringRecognizerMetaClass(type):
+ def __iter__(self):
+ binaryninja._init_plugins()
+ count = ctypes.c_ulonglong()
+ recognizers = core.BNGetStringRecognizerList(count)
+ assert recognizers is not None, "core.BNGetStringRecognizerList returned None"
+ try:
+ for i in range(0, count.value):
+ yield CoreStringRecognizer(handle=recognizers[i])
+ finally:
+ core.BNFreeStringRecognizerList(recognizers)
+
+ def __getitem__(cls, value):
+ binaryninja._init_plugins()
+ recognizer = core.BNGetStringRecognizerByName(str(value))
+ if recognizer is None:
+ raise KeyError("'%s' is not a valid recognizer" % str(value))
+ return CoreStringRecognizer(handle=recognizer)
+
+
+class StringRecognizer(metaclass=_StringRecognizerMetaClass):
+ _registered_recognizers = []
+ recognizer_name = None
+
+ def __init__(self, handle=None):
+ if handle is not None:
+ self.handle = core.handle_of_type(handle, core.BNStringRecognizer)
+
+ def register(self):
+ if self.__class__.recognizer_name is None:
+ raise ValueError("Recognizer name is missing")
+ self._cb = core.BNCustomStringRecognizer()
+ self._cb.context = 0
+ if self.is_valid_for_type.__func__ != StringRecognizer.is_valid_for_type:
+ self._cb.isValidForType = self._cb.isValidForType.__class__(self._is_valid_for_type)
+ if self.recognize_constant.__func__ != StringRecognizer.recognize_constant:
+ self._cb.recognizeConstant = self._cb.recognizeConstant.__class__(self._recognize_constant)
+ if self.recognize_constant_pointer.__func__ != StringRecognizer.recognize_constant_pointer:
+ self._cb.recognizeConstantPointer = self._cb.recognizeConstantPointer.__class__(
+ self._recognize_constant_pointer)
+ if self.recognize_extern_pointer.__func__ != StringRecognizer.recognize_extern_pointer:
+ self._cb.recognizeExternPointer = self._cb.recognizeExternPointer.__class__(self._recognize_extern_pointer)
+ if self.recognize_import.__func__ != StringRecognizer.recognize_import:
+ self._cb.recognizeImport = self._cb.recognizeImport.__class__(self._recognize_import)
+ self.handle = core.BNRegisterStringRecognizer(self.__class__.recognizer_name, self._cb)
+ self.__class__._registered_recognizers.append(self)
+
+ def _is_valid_for_type(self, ctxt, hlil, type):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ return self.is_valid_for_type(hlil, type)
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._is_valid_for_type")
+ return False
+
+ def _recognize_constant(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_constant(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_constant")
+ return False
+
+ def _recognize_constant_pointer(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_constant_pointer(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_constant_pointer")
+ return False
+
+ def _recognize_extern_pointer(self, ctxt, hlil, expr, type, val, offset, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_extern_pointer(instr, type, val, offset)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_extern_pointer")
+ return False
+
+ def _recognize_import(self, ctxt, hlil, expr, type, val, result):
+ try:
+ hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(hlil))
+ type = types.Type.create(handle=core.BNNewTypeReference(type))
+ instr = hlil.get_expr(highlevelil.ExpressionIndex(expr))
+ ref = self.recognize_import(instr, type, val)
+ if ref is None:
+ return False
+ result[0] = ref._to_core_struct(True)
+ return True
+ except:
+ log_error_for_exception("Unhandled Python exception in StringRecognizer._recognize_import")
+ return False
+
+ @property
+ def name(self) -> str:
+ if hasattr(self, 'handle'):
+ return core.BNGetStringRecognizerName(self.handle)
+ return self.__class__.recognizer_name
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return True
+
+ def recognize_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_extern_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int, offset: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+ def recognize_import(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ return None
+
+
+_recognizer_cache = {}
+
+
+class CoreStringRecognizer(StringRecognizer):
+ def __init__(self, handle: core.BNStringRecognizer):
+ super(CoreStringRecognizer, self).__init__(handle=handle)
+ if type(self) is CoreStringRecognizer:
+ global _recognizer_cache
+ _recognizer_cache[ctypes.addressof(handle.contents)] = self
+
+ @classmethod
+ def _from_cache(cls, handle) -> 'StringRecognizer':
+ """
+ Look up a recognizer from a given BNStringRecognizer handle
+ :param handle: BNStringRecognizer pointer
+ :return: Recognizer instance responsible for this handle
+ """
+ global _recognizer_cache
+ return _recognizer_cache.get(ctypes.addressof(handle.contents)) or cls(handle)
+
+ def is_valid_for_type(self, func: 'highlevelil.HighLevelILFunction', type: 'types.Type') -> bool:
+ return core.BNIsStringRecognizerValidForType(self.handle, func.handle, type.handle)
+
+ def recognize_constant(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeConstant(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_constant_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeConstantPointer(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_extern_pointer(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int, offset: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeExternPointer(self.handle, instr.function.handle, instr.expr_index, type.handle, val, offset, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)
+
+ def recognize_import(
+ self, instr: 'highlevelil.HighLevelILInstruction', type: 'types.Type', val: int
+ ) -> Optional['binaryview.DerivedString']:
+ string = core.BNDerivedString()
+ if not core.BNStringRecognizerRecognizeImport(self.handle, instr.function.handle, instr.expr_index, type.handle, val, string):
+ return None
+ return binaryview.DerivedString._from_core_struct(string, True)