From 61b4bb24e06aa955484293d35fa926c07887544b Mon Sep 17 00:00:00 2001 From: Peter LaFosse Date: Mon, 7 Jun 2021 09:59:54 -0400 Subject: Add type hints to basicblock.py, lowlevelil.py, architecture.py --- python/architecture.py | 1456 +++++++++++++++++++++++------------------------- 1 file changed, 691 insertions(+), 765 deletions(-) (limited to 'python/architecture.py') diff --git a/python/architecture.py b/python/architecture.py index 2206f50e..51b1ae00 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -20,66 +20,323 @@ import traceback import ctypes -import abc +from typing import Generator, Union, List, Optional, Mapping, Tuple, NewType # 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 -from binaryninja import platform -from binaryninja import callingconvention +from . import _binaryninjacore as core +from .enums import (Endianness, ImplicitRegisterExtend, BranchType, + LowLevelILFlagCondition, FlagRole, LowLevelILOperation) +from . import log +from . import lowlevelil +from . import types +from . import databuffer +from . import platform +from . import callingconvention +from . import typelibrary +from . import function +from . import binaryview + +RegisterIndex = NewType('RegisterIndex', int) +RegisterStackIndex = NewType('RegisterStackIndex', int) +FlagIndex = NewType('FlagIndex', int) +SemanticClassIndex = NewType('SemanticClassIndex', int) +SemanticGroupIndex = NewType('SemanticGroupIndex', int) +IntrinsicIndex = NewType('IntrinsicIndex', int) +FlagWriteTypeIndex = NewType('FlagWriteTypeIndex', int) + +RegisterName = NewType('RegisterName', str) +RegisterStackName = NewType('RegisterStackName', str) +FlagName = NewType('FlagName', str) +SemanticClassName = NewType('SemanticClassName', str) +SemanticGroupName = NewType('SemanticGroupName', str) +IntrinsicName = NewType('IntrinsicName', str) +FlagWriteTypeName = NewType('FlagWriteTypeName', str) + +RegisterType = Union[RegisterName, 'lowlevelil.ILRegister', RegisterIndex] +FlagType = Union[FlagName, 'lowlevelil.ILFlag', FlagIndex] +RegisterStackType = Union[RegisterStackName, 'lowlevelil.ILRegisterStack', RegisterStackIndex] +SemanticClassType = Union[SemanticClassName, 'lowlevelil.ILSemanticFlagClass', SemanticClassIndex] +SemanticGroupType = Union[SemanticGroupName, 'lowlevelil.ILSemanticFlagGroup', SemanticGroupIndex] +IntrinsicType = Union[IntrinsicName, 'lowlevelil.ILIntrinsic', IntrinsicIndex] + + + +class RegisterInfo(object): + def __init__(self, full_width_reg:RegisterName, size:int, offset:int=0, + extend:ImplicitRegisterExtend=ImplicitRegisterExtend.NoExtend, index:RegisterIndex=None): + self._full_width_reg = full_width_reg + self._offset = offset + self._size = size + self._extend = extend + self._index = index -# 2-3 compatibility -from binaryninja import range -from binaryninja import with_metaclass -import numbers + def __repr__(self): + if self._extend == ImplicitRegisterExtend.ZeroExtendToFullWidth: + extend = ", zero extend" + elif self._extend == ImplicitRegisterExtend.SignExtendToFullWidth: + extend = ", sign extend" + else: + extend = "" + return "" % (self._size, self._offset, self._full_width_reg, extend) + @property + def full_width_reg(self) -> RegisterName: + return self._full_width_reg -class _ArchitectureMetaClass(type): + @full_width_reg.setter + def full_width_reg(self, value:RegisterName) -> None: + self._full_width_reg = value @property - def list(self): - binaryninja._init_plugins() - count = ctypes.c_ulonglong() - archs = core.BNGetArchitectureList(count) - result = [] - for i in range(0, count.value): - result.append(CoreArchitecture._from_cache(archs[i])) - core.BNFreeArchitectureList(archs) - return result + def offset(self) -> int: + return self._offset + + @offset.setter + def offset(self, value:int) -> None: + self._offset = value + + @property + def size(self) -> int: + return self._size + + @size.setter + def size(self, value:int) -> None: + self._size = value + + @property + def extend(self) -> ImplicitRegisterExtend: + return self._extend + + @extend.setter + def extend(self, value:ImplicitRegisterExtend) -> None: + self._extend = value + + @property + def index(self) -> Optional[RegisterIndex]: + return self._index + + @index.setter + def index(self, value:RegisterIndex) -> None: + self._index = value + + +class RegisterStackInfo(object): + def __init__(self, storage_regs:List[RegisterName], top_relative_regs:List[RegisterName], + stack_top_reg:RegisterName, index:RegisterStackIndex=None): + self._storage_regs = storage_regs + self._top_relative_regs = top_relative_regs + self._stack_top_reg = stack_top_reg + self._index = index + + def __repr__(self): + return "" % (len(self._storage_regs), self._stack_top_reg) - def __iter__(self): + @property + def storage_regs(self) -> List[RegisterName]: + return self._storage_regs + + @storage_regs.setter + def storage_regs(self, value:List[RegisterName]) -> None: + self._storage_regs = value + + @property + def top_relative_regs(self) -> List[RegisterName]: + return self._top_relative_regs + + @top_relative_regs.setter + def top_relative_regs(self, value:List[RegisterName]) -> None: + self._top_relative_regs = value + + @property + def stack_top_reg(self) -> RegisterName: + return self._stack_top_reg + + @stack_top_reg.setter + def stack_top_reg(self, value:RegisterName) -> None: + self._stack_top_reg = value + + @property + def index(self) -> Optional[RegisterStackIndex]: + return self._index + + @index.setter + def index(self, value:RegisterStackIndex) -> None: + self._index = value + + +class IntrinsicInput(object): + def __init__(self, type_obj, name=""): + self._name = name + self._type = type_obj + + def __repr__(self): + if len(self._name) == 0: + return "" % str(self._type) + return "" % (str(self._type), self._name) + + @property + def name(self): + return self._name + + @name.setter + def name(self, value): + self._name = value + + @property + def type(self): + return self._type + + @type.setter + def type(self, value): + self._type = value + + +class IntrinsicInfo(object): + def __init__(self, inputs, outputs, index=None): + self._inputs = inputs + self._outputs = outputs + self._index = index + + def __repr__(self): + return " %s>" % (repr(self._inputs), repr(self._outputs)) + + @property + def inputs(self): + return self._inputs + + @inputs.setter + def inputs(self, value): + self._inputs = value + + @property + def outputs(self): + return self._outputs + + @outputs.setter + def outputs(self, value): + self._outputs = value + + @property + def index(self): + return self._index + + @index.setter + def index(self, value): + self._index = value + + +class InstructionBranch(object): + def __init__(self, branch_type, target = 0, arch = None): + self._type = branch_type + self._target = target + self._arch = arch + + def __repr__(self): + branch_type = self._type + if self._arch is not None: + return "<%s: %s@%#x>" % (branch_type.name, self._arch.name, self._target) + return "<%s: %#x>" % (branch_type, self._target) + + @property + def type(self): + return self._type + + @type.setter + def type(self, value): + self._type = value + + @property + def target(self): + return self._target + + @target.setter + def target(self, value): + self._target = value + + @property + def arch(self): + return self._arch + + @arch.setter + def arch(self, value): + self._arch = value + + +class InstructionInfo(object): + def __init__(self): + self.length = 0 + self.arch_transition_by_target_addr = False + self.branch_delay = False + self.branches = [] + + def add_branch(self, branch_type, target = 0, arch = None): + self._branches.append(InstructionBranch(branch_type, target, arch)) + + def __len__(self): + return self._length + + def __repr__(self): + branch_delay = "" + if self._branch_delay: + branch_delay = ", delay slot" + return "" % (self._length, branch_delay, repr(self._branches)) + + @property + def length(self): + return self._length + + @length.setter + def length(self, value): + self._length = value + + @property + def arch_transition_by_target_addr(self): + return self._arch_transition_by_target_addr + + @arch_transition_by_target_addr.setter + def arch_transition_by_target_addr(self, value): + self._arch_transition_by_target_addr = value + + @property + def branch_delay(self): + return self._branch_delay + + @branch_delay.setter + def branch_delay(self, value): + self._branch_delay = value + + @property + def branches(self): + return self._branches + + @branches.setter + def branches(self, value): + self._branches = value + + +class _ArchitectureMetaClass(type): + def __iter__(self) -> Generator['Architecture', None, None]: binaryninja._init_plugins() count = ctypes.c_ulonglong() archs = core.BNGetArchitectureList(count) + if archs is None: + return try: for i in range(0, count.value): yield CoreArchitecture._from_cache(archs[i]) finally: core.BNFreeArchitectureList(archs) - def __getitem__(cls, name): + def __getitem__(cls:'_ArchitectureMetaClass', name:str) -> 'Architecture': binaryninja._init_plugins() arch = core.BNGetArchitectureByName(name) if arch is None: raise KeyError("'%s' is not a valid architecture" % str(name)) return CoreArchitecture._from_cache(arch) - def register(cls): - binaryninja._init_plugins() - if cls.name is None: - raise ValueError("architecture 'name' is not defined") - arch = cls() - cls._registered_cb = arch._cb - arch.handle = core.BNRegisterArchitecture(cls.name, arch._cb) - -class Architecture(with_metaclass(_ArchitectureMetaClass, object)): +class Architecture(metaclass=_ArchitectureMetaClass): """ ``class Architecture`` is the parent class for all CPU architectures. Subclasses of Architecture implement assembly, disassembly, IL lifting, and patching. @@ -120,7 +377,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): global_regs = [] system_regs = [] flags = [] - flag_write_types = [] + flag_write_types:List[FlagWriteTypeName] = [] semantic_flag_classes = [] semantic_flag_groups = [] flag_roles = {} @@ -217,119 +474,117 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value) - self.__dict__["endianness"] = self.__class__.endianness - self.__dict__["address_size"] = self.__class__.address_size - self.__dict__["default_int_size"] = self.__class__.default_int_size - self.__dict__["instr_alignment"] = self.__class__.instr_alignment - self.__dict__["max_instr_length"] = self.__class__.max_instr_length - self.__dict__["opcode_display_length"] = self.__class__.opcode_display_length - self.__dict__["stack_pointer"] = self.__class__.stack_pointer - self.__dict__["link_reg"] = self.__class__.link_reg - - self._all_regs = {} - self._full_width_regs = {} - self._regs_by_index = {} - self.__dict__["regs"] = self.__class__.regs - reg_index = 0 + self.__dict__['endianness'] = self.__class__.endianness + self.__dict__['address_size'] = self.__class__.address_size + self.__dict__['default_int_size'] = self.__class__.default_int_size + self.__dict__['instr_alignment'] = self.__class__.instr_alignment + self.__dict__['max_instr_length'] = self.__class__.max_instr_length + self.__dict__['opcode_display_length'] = self.__class__.opcode_display_length + self.__dict__['stack_pointer'] = self.__class__.stack_pointer + self.__dict__['link_reg'] = self.__class__.link_reg + + self._all_regs:Mapping[RegisterName, RegisterIndex] = {} + self._full_width_regs:Mapping[RegisterName, RegisterIndex] = {} + self._regs_by_index:Mapping[RegisterIndex, RegisterName] = {} + self.regs:Mapping[RegisterName, RegisterInfo] = self.__class__.regs + reg_index = RegisterIndex(0) # Registers used for storage in register stacks must be sequential, so allocate these in order first - self._all_reg_stacks = {} - self._reg_stacks_by_index = {} - self.__dict__["reg_stacks"] = self.__class__.reg_stacks - reg_stack_index = 0 - for reg_stack in self.reg_stacks: - info = self.reg_stacks[reg_stack] + self._all_reg_stacks:Mapping[RegisterStackName, RegisterStackIndex] = {} + self._reg_stacks_by_index:Mapping[RegisterStackIndex, RegisterStackName] = {} + self.reg_stacks:Mapping[RegisterStackName, RegisterStackInfo] = self.__class__.reg_stacks + reg_stack_index = RegisterStackIndex(0) + for reg_stack, info in self.reg_stacks.items(): for reg in info.storage_regs: self._all_regs[reg] = reg_index self._regs_by_index[reg_index] = reg self.regs[reg].index = reg_index - reg_index += 1 + reg_index = RegisterIndex(reg_index + 1) for reg in info.top_relative_regs: self._all_regs[reg] = reg_index self._regs_by_index[reg_index] = reg self.regs[reg].index = reg_index - reg_index += 1 + reg_index = RegisterIndex(reg_index + 1) if reg_stack not in self._all_reg_stacks: self._all_reg_stacks[reg_stack] = reg_stack_index self._reg_stacks_by_index[reg_stack_index] = reg_stack self.reg_stacks[reg_stack].index = reg_stack_index - reg_stack_index += 1 + reg_stack_index = RegisterStackIndex(reg_stack_index + 1) - for reg in self.regs: - info = self.regs[reg] + for reg, info in self.regs.items(): if reg not in self._all_regs: self._all_regs[reg] = reg_index self._regs_by_index[reg_index] = reg self.regs[reg].index = reg_index - reg_index += 1 + reg_index = RegisterIndex(reg_index + 1) if info.full_width_reg not in self._all_regs: self._all_regs[info.full_width_reg] = reg_index self._regs_by_index[reg_index] = info.full_width_reg self.regs[info.full_width_reg].index = reg_index - reg_index += 1 + reg_index = RegisterIndex(reg_index + 1) if info.full_width_reg not in self._full_width_regs: self._full_width_regs[info.full_width_reg] = self._all_regs[info.full_width_reg] - self._flags = {} - self._flags_by_index = {} - self.__dict__["flags"] = self.__class__.flags - flag_index = 0 + self._flags:Mapping[FlagName, FlagIndex] = {} + self._flags_by_index:Mapping[FlagIndex, FlagName] = {} + self.flags:List[FlagName] = self.__class__.flags + flag_index = FlagIndex(0) for flag in self.__class__.flags: if flag not in self._flags: self._flags[flag] = flag_index self._flags_by_index[flag_index] = flag - flag_index += 1 + flag_index = FlagIndex(flag_index + 1) - self._flag_write_types = {} - self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = self.__class__.flag_write_types - write_type_index = 1 + self._flag_write_types:Mapping[FlagWriteTypeName, FlagWriteTypeIndex] = {} + self._flag_write_types_by_index:Mapping[FlagWriteTypeIndex, FlagWriteTypeName] = {} + self.flag_write_types:List[FlagWriteTypeName] = self.__class__.flag_write_types + write_type_index = FlagWriteTypeIndex(1) for write_type in self.__class__.flag_write_types: if write_type not in self._flag_write_types: self._flag_write_types[write_type] = write_type_index self._flag_write_types_by_index[write_type_index] = write_type - write_type_index += 1 + write_type_index = FlagWriteTypeIndex(write_type_index + 1) - self._semantic_flag_classes = {} - self._semantic_flag_classes_by_index = {} - self.__dict__["semantic_flag_classes"] = self.__class__.semantic_flag_classes - semantic_class_index = 1 + self._semantic_flag_classes:Mapping[SemanticClassName, SemanticClassIndex] = {} + self._semantic_flag_classes_by_index:Mapping[SemanticClassIndex, SemanticClassName] = {} + self.semantic_flag_classes:List[SemanticClassName] = self.__class__.semantic_flag_classes + semantic_class_index = SemanticClassIndex(1) for sem_class in self.__class__.semantic_flag_classes: if sem_class not in self._semantic_flag_classes: self._semantic_flag_classes[sem_class] = semantic_class_index self._semantic_flag_classes_by_index[semantic_class_index] = sem_class - semantic_class_index += 1 + semantic_class_index = SemanticClassIndex(semantic_class_index + 1) - self._semantic_flag_groups = {} - self._semantic_flag_groups_by_index = {} - self.__dict__["semantic_flag_groups"] = self.__class__.semantic_flag_groups - semantic_group_index = 0 + self._semantic_flag_groups:Mapping[SemanticGroupName, SemanticGroupIndex] = {} + self._semantic_flag_groups_by_index:Mapping[SemanticGroupIndex, SemanticGroupName] = {} + self.semantic_flag_groups:List[SemanticGroupName] = self.__class__.semantic_flag_groups + semantic_group_index = SemanticGroupIndex(0) for sem_group in self.__class__.semantic_flag_groups: if sem_group not in self._semantic_flag_groups: self._semantic_flag_groups[sem_group] = semantic_group_index self._semantic_flag_groups_by_index[semantic_group_index] = sem_group - semantic_group_index += 1 + semantic_group_index = SemanticGroupIndex(semantic_group_index + 1) - self._flag_roles = {} - self.__dict__["flag_roles"] = self.__class__.flag_roles + self._flag_roles:Mapping[FlagIndex, FlagRole] = {} + self.flag_roles:Mapping[FlagName, FlagRole] = self.__class__.flag_roles for flag in self.__class__.flag_roles: role = self.__class__.flag_roles[flag] if isinstance(role, str): role = FlagRole[role] self._flag_roles[self._flags[flag]] = role - self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition + self.flags_required_for_flag_condition:Mapping['lowlevelil.LowLevelILFlagCondition', List[FlagName]] = self.__class__.flags_required_for_flag_condition - self._flags_required_by_semantic_flag_group = {} - self.__dict__["flags_required_for_semantic_flag_group"] = self.__class__.flags_required_for_semantic_flag_group + self._flags_required_by_semantic_flag_group:Mapping[SemanticGroupIndex, List[FlagIndex]] = {} + self.flags_required_for_semantic_flag_group:Mapping[SemanticGroupName, List[FlagName]] = self.__class__.flags_required_for_semantic_flag_group for group in self.__class__.flags_required_for_semantic_flag_group: - flags = [] + flags:List[FlagIndex] = [] for flag in self.__class__.flags_required_for_semantic_flag_group[group]: flags.append(self._flags[flag]) self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flags self._flag_conditions_for_semantic_flag_group = {} - self.__dict__["flag_conditions_for_semantic_flag_group"] = self.__class__.flag_conditions_for_semantic_flag_group + self.flag_conditions_for_semantic_flag_group = self.__class__.flag_conditions_for_semantic_flag_group for group in self.__class__.flag_conditions_for_semantic_flag_group: class_cond = {} for sem_class in self.__class__.flag_conditions_for_semantic_flag_group[group]: @@ -340,7 +595,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_cond self._flags_written_by_flag_write_type = {} - self.__dict__["flags_written_by_flag_write_type"] = self.__class__.flags_written_by_flag_write_type + self.flags_written_by_flag_write_type = self.__class__.flags_written_by_flag_write_type for write_type in self.__class__.flags_written_by_flag_write_type: flags = [] for flag in self.__class__.flags_written_by_flag_write_type[write_type]: @@ -348,7 +603,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags self._semantic_class_for_flag_write_type = {} - self.__dict__["semantic_class_for_flag_write_type"] = self.__class__.semantic_class_for_flag_write_type + self.semantic_class_for_flag_write_type = self.__class__.semantic_class_for_flag_write_type for write_type in self.__class__.semantic_class_for_flag_write_type: sem_class = self.__class__.semantic_class_for_flag_write_type[write_type] if sem_class in self._semantic_flag_classes: @@ -357,25 +612,25 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): sem_class_index = 0 self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class_index - self.__dict__["global_regs"] = self.__class__.global_regs - self.__dict__["system_regs"] = self.__class__.system_regs + self.global_regs = self.__class__.global_regs + self.system_regs = self.__class__.system_regs - self._intrinsics = {} - self._intrinsics_by_index = {} - self.__dict__["intrinsics"] = self.__class__.intrinsics - intrinsic_index = 0 + self._intrinsics:Mapping[IntrinsicName, IntrinsicIndex] = {} + self._intrinsics_by_index:Mapping[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} + self.intrinsics = self.__class__.intrinsics + intrinsic_index = IntrinsicIndex(0) for intrinsic in self.__class__.intrinsics.keys(): if intrinsic not in self._intrinsics: info = self.__class__.intrinsics[intrinsic] for i in range(0, len(info.inputs)): if isinstance(info.inputs[i], types.Type): - info.inputs[i] = binaryninja.function.IntrinsicInput(info.inputs[i]) + info.inputs[i] = IntrinsicInput(info.inputs[i]) elif isinstance(info.inputs[i], tuple): - info.inputs[i] = binaryninja.function.IntrinsicInput(info.inputs[i][0], info.inputs[i][1]) + info.inputs[i] = IntrinsicInput(info.inputs[i][0], info.inputs[i][1]) info.index = intrinsic_index self._intrinsics[intrinsic] = intrinsic_index self._intrinsics_by_index[intrinsic_index] = (intrinsic, info) - intrinsic_index += 1 + intrinsic_index = IntrinsicIndex(intrinsic_index + 1) self._pending_reg_lists = {} self._pending_token_lists = {} @@ -399,27 +654,32 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): def __hash__(self): return hash(ctypes.addressof(self.handle.contents)) - def __setattr__(self, name, value): - if ((name == "name") or (name == "endianness") or (name == "address_size") or - (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length") or - (name == "get_instruction_alignment")): - raise AttributeError("attribute '%s' is read only" % name) - else: - try: - object.__setattr__(self, name, value) - except AttributeError: - raise AttributeError("attribute '%s' is read only" % name) + # def __setattr__(self, name, value): + # if ((name == "name") or (name == "endianness") or (name == "address_size") or + # (name == "default_int_size") or (name == "regs") or (name == "get_max_instruction_length") or + # (name == "get_instruction_alignment")): + # raise AttributeError("attribute '%s' is read only" % name) + # else: + # try: + # object.__setattr__(self, name, value) + # except AttributeError: + # raise AttributeError("attribute '%s' is read only" % name) - @property - def list(self): - """Allow tab completion to discover metaclass list property""" - pass + @classmethod + def register(cls) -> None: + binaryninja._init_plugins() + if cls.name is None: + raise ValueError("architecture 'name' is not defined") + arch = cls() + cls._registered_cb = arch._cb + arch.handle = core.BNRegisterArchitecture(cls.name, arch._cb) @property - def full_width_regs(self): + def full_width_regs(self) -> List[RegisterName]: """List of full width register strings (read-only)""" count = ctypes.c_ulonglong() regs = core.BNGetFullWidthArchitectureRegisters(self.handle, count) + assert regs is not None, "core.BNGetFullWidthArchitectureRegisters returned None" result = [] for i in range(0, count.value): result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) @@ -427,10 +687,11 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): return result @property - def calling_conventions(self): + def calling_conventions(self) -> Mapping[str, 'callingconvention.CallingConvention']: """Dict of CallingConvention objects (read-only)""" count = ctypes.c_ulonglong() cc = core.BNGetArchitectureCallingConventions(self.handle, count) + assert cc is not None, "core.BNGetArchitectureCallingConventions returned None" result = {} for i in range(0, count.value): obj = callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i])) @@ -439,24 +700,25 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): return result @property - def standalone_platform(self): + def standalone_platform(self) -> 'platform.Platform': """Architecture standalone platform (read-only)""" pl = core.BNGetArchitectureStandalonePlatform(self.handle) return platform.Platform(self, pl) @property - def type_libraries(self): + def type_libraries(self) -> List['typelibrary.TypeLibrary']: """Architecture type libraries""" count = ctypes.c_ulonglong(0) result = [] handles = core.BNGetArchitectureTypeLibraries(self.handle, count) + assert handles is not None, "core.BNGetArchitectureTypeLibraries returned None" for i in range(0, count.value): - result.append(binaryninja.typelibrary.TypeLibrary(core.BNNewTypeLibraryReference(handles[i]))) + result.append(typelibrary.TypeLibrary(core.BNNewTypeLibraryReference(handles[i]))) core.BNFreeTypeLibraryList(handles, count.value) return result @property - def can_assemble(self): + def can_assemble(self) -> bool: """returns if the architecture can assemble instructions (read-only)""" return core.BNCanArchitectureAssemble(self.handle) @@ -550,7 +812,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): tokens = info[0] length[0] = info[1] count[0] = len(tokens) - token_buf = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens) + token_buf = function.InstructionTextToken._get_core_struct(tokens) result[0] = token_buf ptr = ctypes.cast(token_buf, ctypes.c_void_p) self._pending_token_lists[ptr.value] = (ptr.value, token_buf) @@ -600,7 +862,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): log.log_error(traceback.format_exc()) return core.BNAllocString("") - def _get_flag_write_type_name(self, ctxt, write_type): + def _get_flag_write_type_name(self, ctxt, write_type:FlagWriteTypeIndex): try: if write_type in self._flag_write_types_by_index: return core.BNAllocString(self._flag_write_types_by_index[write_type]) @@ -717,16 +979,13 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): count[0] = 0 return None - def _get_flag_role(self, ctxt, flag, sem_class): - try: - if sem_class in self._semantic_flag_classes_by_index: - sem_class = self._semantic_flag_classes_by_index[sem_class] - else: - sem_class = None - return self.get_flag_role(flag, sem_class) - except KeyError: - log.log_error(traceback.format_exc()) - return FlagRole.SpecialFlagRole + def _get_flag_role(self, ctxt, flag:FlagIndex, sem_class:Optional[SemanticClassName]=None): + if sem_class in self._semantic_flag_classes: + assert sem_class is not None + _sem_class = self._semantic_flag_classes[sem_class] + else: + _sem_class = None + return self.get_flag_role(flag, _sem_class) def _get_flags_required_for_flag_condition(self, ctxt, cond, sem_class, count): try: @@ -903,6 +1162,8 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): result[0].extend = ImplicitRegisterExtend.NoExtend def _get_stack_pointer_register(self, ctxt): + if self.stack_pointer is None: + return None try: return self._all_regs[self.stack_pointer] except KeyError: @@ -1214,234 +1475,10 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): log.log_error(traceback.format_exc()) return False - def perform_get_associated_arch_by_address(self, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_associated_arch_by_address`. - """ + def get_associated_arch_by_address(self, addr:int) -> Tuple['Architecture', int]: return self, addr - @abc.abstractmethod - def perform_get_instruction_info(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_instruction_info`. - - :param str data: bytes to decode - :param int addr: virtual address of the byte to be decoded - :return: a :py:class:`InstructionInfo` object containing the length and branch types for the given instruction - :rtype: InstructionInfo - """ - raise NotImplementedError - - @abc.abstractmethod - def perform_get_instruction_text(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_instruction_text`. - - :param str data: bytes to decode - :param int addr: virtual address of the byte to be decoded - :return: a tuple of list(InstructionTextToken) and length of instruction decoded - :rtype: tuple(list(InstructionTextToken), int) - """ - raise NotImplementedError - - @abc.abstractmethod - def perform_get_instruction_low_level_il(self, data, addr, il): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_instruction_low_level_il`. - - :param str data: bytes to be interpreted as low-level IL instructions - :param int addr: virtual address of start of ``data`` - :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to - :rtype: length of bytes read on success, None on failure - """ - raise NotImplementedError - - @abc.abstractmethod - def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_flag_write_low_level_il`. - - :param LowLevelILOperation op: - :param int size: - :param int write_type: - :param int flag: - :param operands: - :type operands: list(str) or list(int) - :param LowLevelILFunction il: - :rtype: LowLevelILExpr - """ - flag = self.get_flag_index(flag) - if flag not in self._flag_roles: - return il.unimplemented() - return self.get_default_flag_write_low_level_il(op, size, self._flag_roles[flag], operands, il) - - @abc.abstractmethod - def perform_get_flag_condition_low_level_il(self, cond, sem_class, il): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_flag_condition_low_level_il`. - - :param LowLevelILFlagCondition cond: Flag condition to be computed - :param str sem_class: Semantic class to be used (None for default semantics) - :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to - :rtype: LowLevelILExpr - """ - return self.get_default_flag_condition_low_level_il(cond, sem_class, il) - - @abc.abstractmethod - def perform_get_semantic_flag_group_low_level_il(self, sem_group, il): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_semantic_flag_group_low_level_il`. - - :param str sem_group: Semantic group to be computed - :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to - :rtype: LowLevelILExpr - """ - return il.unimplemented() - - @abc.abstractmethod - def perform_assemble(self, code, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`assemble`. - - :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) - """ - raise NotImplementedError("Architecture does not implement an assembler.\n") - - @abc.abstractmethod - def perform_is_never_branch_patch_available(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`is_never_branch_patch_available`. - - .. note:: Architecture subclasses should implement this method. - - .. warning:: This method should never be called directly. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: True if the instruction can be patched, False otherwise - :rtype: bool - """ - return False - - @abc.abstractmethod - def perform_is_always_branch_patch_available(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`is_always_branch_patch_available`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: True if the instruction can be patched, False otherwise - :rtype: bool - """ - return False - - @abc.abstractmethod - def perform_is_invert_branch_patch_available(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`is_invert_branch_patch_available`. - - :param int addr: the virtual address of the instruction to be patched - :return: True if the instruction can be patched, False otherwise - :rtype: bool - """ - return False - - @abc.abstractmethod - def perform_is_skip_and_return_zero_patch_available(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`is_skip_and_return_zero_patch_available`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: True if the instruction can be patched, False otherwise - :rtype: bool - """ - return False - - @abc.abstractmethod - def perform_is_skip_and_return_value_patch_available(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`is_skip_and_return_value_patch_available`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: True if the instruction can be patched, False otherwise - :rtype: bool - """ - return False - - @abc.abstractmethod - def perform_convert_to_nop(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`convert_to_nop`. - - :param str data: bytes at virtual address ``addr`` - :param int addr: the virtual address of the instruction to be patched - :return: nop sequence of same length as ``data`` or None - :rtype: str or None - """ - return None - - @abc.abstractmethod - def perform_always_branch(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`always_branch`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: The bytes of the replacement unconditional branch instruction - :rtype: str - """ - return None - - @abc.abstractmethod - def perform_invert_branch(self, data, addr): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`invert_branch`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :return: The bytes of the replacement unconditional branch instruction - :rtype: str - """ - return None - - @abc.abstractmethod - def perform_skip_and_return_value(self, data, addr, value): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`skip_and_return_value`. - - :param str data: bytes to be checked - :param int addr: the virtual address of the instruction to be patched - :param int value: value to be returned - :return: The bytes of the replacement unconditional branch instruction - :rtype: str - """ - return None - - def perform_get_flag_role(self, flag, sem_class): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_flag_role`. - """ - if flag in self._flag_roles: - return self._flag_roles[flag] - return FlagRole.SpecialFlagRole - - def perform_get_flags_required_for_flag_condition(self, cond, sem_class): - """ - Deprecated method provided for compatibility. Architecture plugins should override :func:`get_flags_required_for_flag_condition`. - """ - if cond in self.flags_required_for_flag_condition: - return self.flags_required_for_flag_condition[cond] - return [] - - def get_associated_arch_by_address(self, addr): - return self.perform_get_associated_arch_by_address(addr) - - def get_instruction_info(self, data, addr): + def get_instruction_info(self, data:bytes, addr:int) -> Optional[InstructionInfo]: """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. @@ -1471,9 +1508,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: the InstructionInfo for the current instruction :rtype: InstructionInfo """ - return self.perform_get_instruction_info(data, addr) + raise NotImplementedError - def get_instruction_text(self, data, addr): + def get_instruction_text(self, data:bytes, addr:int) -> Tuple[List['function.InstructionTextToken'], int]: """ ``get_instruction_text`` returns a tuple containing a list of decoded InstructionTextToken objects and the bytes used at the given virtual address ``addr`` with data ``data``. @@ -1485,15 +1522,15 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: a tuple containing the InstructionTextToken list and length of bytes decoded :rtype: tuple(list(InstructionTextToken), int) """ - return self.perform_get_instruction_text(data, addr) + raise NotImplementedError - def get_instruction_low_level_il_instruction(self, bv, addr): + def get_instruction_low_level_il_instruction(self, bv:'binaryview.BinaryView', addr:int) -> 'lowlevelil.LowLevelILInstruction': il = lowlevelil.LowLevelILFunction(self) data = bv.read(addr, self.max_instr_length) self.get_instruction_low_level_il(data, addr, il) return il[0] - def get_instruction_low_level_il(self, data, addr, il): + def get_instruction_low_level_il(self, data:bytes, addr:int, il:'lowlevelil.LowLevelILFunction') -> int: """ ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given virtual address ``addr`` with data ``data``. @@ -1509,94 +1546,108 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: the length of the current instruction :rtype: int """ - return self.perform_get_instruction_low_level_il(data, addr, il) + raise NotImplementedError - def get_low_level_il_from_bytes(self, data, addr): + def get_low_level_il_from_bytes(self, data:bytes, addr:int) -> Generator['lowlevelil.LowLevelILInstruction', None, None]: """ ``get_low_level_il_from_bytes`` converts the instruction in bytes to ``il`` at the given virtual address :param str data: the bytes of the instruction :param int addr: virtual address of bytes in ``data`` - :return: the instruction - :rtype: LowLevelILInstruction + :return: a list of low level il instructions + :rtype: List[LowLevelILInstruction] :Example: - >>> arch.get_low_level_il_from_bytes(b'\\xeb\\xfe', 0x40DEAD) - + >>> list(arch.get_low_level_il_from_bytes(b'\\xeb\\xfe', 0x40DEAD)) + [] >>> """ func = lowlevelil.LowLevelILFunction(self) self.get_instruction_low_level_il(data, addr, func) - return func[0] + return func.instructions - def get_reg_name(self, reg): + def get_reg_name(self, reg:RegisterIndex) -> RegisterName: """ - ``get_reg_name`` gets a register name from a register number. + ``get_reg_name`` gets a register name from a register index. - :param int reg: register number - :return: the corresponding register string - :rtype: str + :param RegisterIndex reg: register index + :return: the corresponding register name + :rtype: RegisterName """ - return core.BNGetArchitectureRegisterName(self.handle, reg) + return RegisterName(core.BNGetArchitectureRegisterName(self.handle, reg)) - def get_reg_stack_name(self, reg_stack): + def get_reg_stack_name(self, reg_stack:RegisterStackIndex) -> RegisterStackName: """ ``get_reg_stack_name`` gets a register stack name from a register stack number. :param int reg_stack: register stack number :return: the corresponding register string - :rtype: str + :rtype: RegisterStackName """ - return core.BNGetArchitectureRegisterStackName(self.handle, reg_stack) + return RegisterStackName(core.BNGetArchitectureRegisterStackName(self.handle, reg_stack)) - def get_reg_stack_for_reg(self, reg): - reg = self.get_reg_index(reg) - result = core.BNGetArchitectureRegisterStackForRegister(self.handle, reg) + def get_reg_stack_for_reg(self, reg:RegisterName) -> Optional[RegisterStackName]: + _reg = self.get_reg_index(reg) + result = core.BNGetArchitectureRegisterStackForRegister(self.handle, _reg) if result == 0xffffffff: return None return self.get_reg_stack_name(result) - def get_flag_name(self, flag): + def get_flag_name(self, flag:FlagIndex) -> FlagName: """ - ``get_flag_name`` gets a flag name from a flag number. + ``get_flag_name`` gets a flag name from a flag index. - :param int reg: register number - :return: the corresponding register string - :rtype: str + :param int flag: flag index + :return: the corresponding flag name string + :rtype: FlagName """ - return core.BNGetArchitectureFlagName(self.handle, flag) + return FlagName(core.BNGetArchitectureFlagName(self.handle, flag)) - def get_reg_index(self, reg): + def get_reg_index(self, reg:RegisterType) -> RegisterIndex: if isinstance(reg, str): - return self.regs[reg].index + try: + index = self.regs[reg].index + assert index is not None + return index + except KeyError: + log.log_error(f"Failed to map string {reg} to register index: ") + log.log_error(traceback.format_exc()) elif isinstance(reg, lowlevelil.ILRegister): return reg.index - return reg + elif isinstance(reg, RegisterIndex): + return reg + raise Exception("Attempting to get register index of non-existant register") - def get_reg_stack_index(self, reg_stack): + def get_reg_stack_index(self, reg_stack:RegisterStackType) -> RegisterStackIndex: if isinstance(reg_stack, str): - return self.reg_stacks[reg_stack].index + reg_stack_info = self.reg_stacks[reg_stack] + if reg_stack_info is not None and reg_stack_info.index is not None: + return reg_stack_info.index elif isinstance(reg_stack, lowlevelil.ILRegisterStack): return reg_stack.index - return reg_stack + elif isinstance(reg_stack, RegisterStackIndex): + return reg_stack + raise Exception("reg_stack is not convertable to index") - def get_flag_index(self, flag): + def get_flag_index(self, flag:FlagType) -> FlagIndex: if isinstance(flag, str): return self._flags[flag] elif isinstance(flag, lowlevelil.ILFlag): return flag.index - return flag + elif isinstance(flag, FlagIndex): + return flag + raise Exception("flag is not convertable to index") - def get_semantic_flag_class_index(self, sem_class): - if sem_class is None: - return 0 - elif isinstance(sem_class, str): + def get_semantic_flag_class_index(self, sem_class:SemanticClassType) -> SemanticClassIndex: + if isinstance(sem_class, SemanticClassName): return self._semantic_flag_classes[sem_class] elif isinstance(sem_class, lowlevelil.ILSemanticFlagClass): return sem_class.index - return sem_class + elif isinstance(sem_class, SemanticClassIndex): + return sem_class + raise Exception("sem_class is not convertable to index") - def get_semantic_flag_class_name(self, class_index): + def get_semantic_flag_class_name(self, class_index:SemanticClassIndex) -> SemanticClassName: """ ``get_semantic_flag_class_name`` gets the name of a semantic flag class from the index. @@ -1604,21 +1655,21 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: the name of the semantic flag class :rtype: str """ - if not isinstance(class_index, numbers.Integral): + if not isinstance(class_index, int): raise ValueError("argument 'class_index' must be an integer") try: return self._semantic_flag_classes_by_index[class_index] except KeyError: raise AttributeError("argument class_index is not a valid class index") - def get_semantic_flag_group_index(self, sem_group): + def get_semantic_flag_group_index(self, sem_group:SemanticGroupType) -> SemanticGroupIndex: if isinstance(sem_group, str): return self._semantic_flag_groups[sem_group] elif isinstance(sem_group, lowlevelil.ILSemanticFlagGroup): return sem_group.index return sem_group - def get_semantic_flag_group_name(self, group_index): + def get_semantic_flag_group_name(self, group_index:SemanticGroupIndex) -> SemanticGroupName: """ ``get_semantic_flag_group_name`` gets the name of a semantic flag group from the index. @@ -1626,61 +1677,70 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: the name of the semantic flag group :rtype: str """ - if not isinstance(group_index, numbers.Integral): + if not isinstance(group_index, int): raise ValueError("argument 'group_index' must be an integer") try: return self._semantic_flag_groups_by_index[group_index] except KeyError: raise AttributeError("argument group_index is not a valid group index") - def get_intrinsic_name(self, intrinsic): + def get_intrinsic_name(self, intrinsic:IntrinsicIndex) -> IntrinsicName: """ ``get_intrinsic_name`` gets an intrinsic name from an intrinsic number. :param int intrinsic: intrinsic number :return: the corresponding intrinsic string - :rtype: str + :rtype: IntrinsicName """ - return core.BNGetArchitectureIntrinsicName(self.handle, intrinsic) + return IntrinsicName(core.BNGetArchitectureIntrinsicName(self.handle, intrinsic)) - def get_intrinsic_index(self, intrinsic): - if isinstance(intrinsic, str): + def get_intrinsic_index(self, intrinsic:IntrinsicType) -> IntrinsicIndex: + """ + ``get_intrinsic_index`` gets an intrinsic index given an IntrinsicType. + + :param IntrinsicType intrinsic: intrinsic number + :return: the corresponding intrinsic string + :rtype: IntrinsicIndex + """ + if isinstance(intrinsic, IntrinsicName): return self._intrinsics[intrinsic] elif isinstance(intrinsic, lowlevelil.ILIntrinsic): return intrinsic.index - return intrinsic + elif isinstance(intrinsic, IntrinsicIndex): + return intrinsic + raise Exception("intrinsic is not convertable to index") - def get_flag_write_type_name(self, write_type): + def get_flag_write_type_name(self, write_type:FlagWriteTypeIndex) -> FlagWriteTypeName: """ ``get_flag_write_type_name`` gets the flag write type name for the given flag. - :param int write_type: flag + :param FlagWriteTypeIndex write_type: flag :return: flag write type name - :rtype: str + :rtype: FlagWriteTypeName """ - return core.BNGetArchitectureFlagWriteTypeName(self.handle, write_type) + return FlagWriteTypeName(core.BNGetArchitectureFlagWriteTypeName(self.handle, write_type)) - def get_flag_by_name(self, flag): + def get_flag_by_name(self, flag:FlagName) -> FlagIndex: """ ``get_flag_by_name`` get flag name for flag index. - :param int flag: flag index - :return: flag name for flag index - :rtype: str + :param FlagName flag: flag name + :return: flag index for flag name + :rtype: FlagIndex """ return self._flags[flag] - def get_flag_write_type_by_name(self, write_type): + def get_flag_write_type_by_name(self, write_type:FlagWriteTypeName) -> FlagWriteTypeIndex: """ ``get_flag_write_type_by_name`` gets the flag write type name for the flag write type. - :param int write_type: flag write type + :param str write_type: flag write type :return: flag write type - :rtype: str + :rtype: int """ return self._flag_write_types[write_type] - def get_semantic_flag_class_by_name(self, sem_class): + def get_semantic_flag_class_by_name(self, sem_class:SemanticClassName) -> SemanticClassIndex: """ ``get_semantic_flag_class_by_name`` gets the semantic flag class index by name. @@ -1690,17 +1750,17 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ return self._semantic_flag_classes[sem_class] - def get_semantic_flag_group_by_name(self, sem_group): + def get_semantic_flag_group_by_name(self, sem_group:SemanticGroupName) -> SemanticGroupIndex: """ ``get_semantic_flag_group_by_name`` gets the semantic flag group index by name. - :param int sem_group: semantic flag group + :param SemanticGroupName sem_group: semantic flag group name :return: semantic flag group index - :rtype: str + :rtype: int """ return self._semantic_flag_groups[sem_group] - def get_flag_role(self, flag, sem_class = None): + def get_flag_role(self, flag:FlagIndex, sem_class:Optional[SemanticClassIndex]= None) -> FlagRole: """ ``get_flag_role`` gets the role of a given flag. @@ -1709,9 +1769,12 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :return: flag role :rtype: FlagRole """ - return self.perform_get_flag_role(flag, sem_class) + if flag in self._flag_roles: + return self._flag_roles[flag] + return FlagRole.SpecialFlagRole - def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + def get_flag_write_low_level_il(self, op:LowLevelILOperation, size:int, write_type:Optional[FlagWriteTypeName], flag:FlagType, + operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILOperation op: :param int size: @@ -1721,9 +1784,13 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - return self.perform_get_flag_write_low_level_il(op, size, write_type, flag, operands, il) + flag = self.get_flag_index(flag) + if flag not in self._flag_roles: + return il.unimplemented() + return self.get_default_flag_write_low_level_il(op, size, self._flag_roles[flag], operands, il) - def get_default_flag_write_low_level_il(self, op, size, role, operands, il): + def get_default_flag_write_low_level_il(self, op:'lowlevelil.LowLevelILOperation', size:int, role:FlagRole, + operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILOperation op: :param int size: @@ -1735,49 +1802,59 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ operand_list = (core.BNRegisterOrConstant * len(operands))() for i in range(len(operands)): - if isinstance(operands[i], str): + operand = operands[i] + if isinstance(operand, RegisterName): operand_list[i].constant = False - operand_list[i].reg = self.regs[operands[i]].index - elif isinstance(operands[i], lowlevelil.ILRegister): + operand_list[i].reg = self.regs[operand].index + elif isinstance(operand, lowlevelil.ILRegister): operand_list[i].constant = False - operand_list[i].reg = operands[i].index + operand_list[i].reg = operand.index else: operand_list[i].constant = True - operand_list[i].value = operands[i] + operand_list[i].value = operand return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagWriteLowLevelIL(self.handle, op, size, role, operand_list, len(operand_list), il.handle)) - def get_flag_condition_low_level_il(self, cond, sem_class, il): + def get_flag_condition_low_level_il(self, cond:'lowlevelil.LowLevelILFlagCondition', sem_class:Optional[SemanticClassType], + il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILFlagCondition cond: Flag condition to be computed - :param str sem_class: Semantic class to be used (None for default semantics) + :param SemanticClassType sem_class: Semantic class to be used (None for default semantics) :param LowLevelILFunction il: LowLevelILFunction object to append LowLevelILExpr objects to :rtype: LowLevelILExpr """ - return self.perform_get_flag_condition_low_level_il(cond, sem_class, il) + return self.get_default_flag_condition_low_level_il(cond, sem_class, il) - def get_default_flag_condition_low_level_il(self, cond, sem_class, il): + def get_default_flag_condition_low_level_il(self, cond:'lowlevelil.LowLevelILFlagCondition', + sem_class:Optional[SemanticClassType], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILFlagCondition cond: + :param SemanticClassType sem_class: :param LowLevelILFunction il: - :param str sem_class: :rtype: LowLevelILExpr """ - class_index = self.get_semantic_flag_class_index(sem_class) - return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, class_index, il.handle)) + _class_index = None + if sem_class is not None: + _class_index = self.get_semantic_flag_class_index(sem_class) + return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, + _class_index, il.handle)) - def get_semantic_flag_group_low_level_il(self, sem_group, il): + def get_semantic_flag_group_low_level_il(self, sem_group:Optional[SemanticGroupType], + il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ - :param str sem_group: + :param Optional[SemanticGroupType] sem_group: :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - return self.perform_get_semantic_flag_group_low_level_il(sem_group, il) + return il.unimplemented() - def get_flags_required_for_flag_condition(self, cond, sem_class = None): - return self.perform_get_flags_required_for_flag_condition(cond, sem_class) + def get_flags_required_for_flag_condition(self, cond:'lowlevelil.LowLevelILFlagCondition', + sem_class:Optional[SemanticClassType]=None): + if cond in self.flags_required_for_flag_condition: + return self.flags_required_for_flag_condition[cond] + return [] - def get_modified_regs_on_write(self, reg): + def get_modified_regs_on_write(self, reg:RegisterName) -> List[RegisterName]: """ ``get_modified_regs_on_write`` returns a list of register names that are modified when ``reg`` is written. @@ -1788,13 +1865,14 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): reg = core.BNGetArchitectureRegisterByName(self.handle, str(reg)) count = ctypes.c_ulonglong() regs = core.BNGetModifiedArchitectureRegistersOnWrite(self.handle, reg, count) + assert regs is not None, "core.BNGetModifiedArchitectureRegistersOnWrite is not None" result = [] for i in range(0, count.value): result.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) core.BNFreeRegisterList(regs) return result - def assemble(self, code, addr=0): + def assemble(self, code:str, addr:int=0) -> bytes: """ ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. @@ -1819,9 +1897,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): b'\\x0f\\x84\\x04\\x00\\x00\\x00' >>> """ - return self.perform_assemble(code, addr) + return NotImplemented - def is_never_branch_patch_available(self, data, addr): + def is_never_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. @@ -1839,9 +1917,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): False >>> """ - return self.perform_is_never_branch_patch_available(data, addr) + return NotImplemented - def is_always_branch_patch_available(self, data, addr): + def is_always_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **always branch**. @@ -1860,9 +1938,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): False >>> """ - return self.perform_is_always_branch_patch_available(data, addr) + return NotImplemented - def is_invert_branch_patch_available(self, data, addr): + def is_invert_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. @@ -1880,9 +1958,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): False >>> """ - return self.perform_is_invert_branch_patch_available(data, addr) + return NotImplemented - def is_skip_and_return_zero_patch_available(self, data, addr): + def is_skip_and_return_zero_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns zero*. @@ -1903,9 +1981,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): False >>> """ - return self.perform_is_skip_and_return_zero_patch_available(data, addr) + return NotImplemented - def is_skip_and_return_value_patch_available(self, data, addr): + def is_skip_and_return_value_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns a value*. @@ -1924,9 +2002,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): False >>> """ - return self.perform_is_skip_and_return_value_patch_available(data, addr) + return NotImplemented - def convert_to_nop(self, data, addr): + def convert_to_nop(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop instructions of the same length as data. @@ -1943,9 +2021,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): b'\\x90\\x90' >>> """ - return self.perform_convert_to_nop(data, addr) + return NotImplemented - def always_branch(self, data, addr): + def always_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which always branches. @@ -1965,9 +2043,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): (['jmp', ' ', '0x9'], 5) >>> """ - return self.perform_always_branch(data, addr) + return NotImplemented - def invert_branch(self, data, addr): + def invert_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which inverts the branch of provided instruction. @@ -1988,9 +2066,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): (['jl', ' ', '0xa'], 6) >>> """ - return self.perform_invert_branch(data, addr) + return NotImplemented - def skip_and_return_value(self, data, addr, value): + def skip_and_return_value(self, data:bytes, addr:int, value:int) -> Optional[bytes]: """ ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which doesn't call and instead *return a value*. @@ -2007,9 +2085,9 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): (['mov', ' ', 'eax', ', ', '0x0'], 5) >>> """ - return self.perform_skip_and_return_value(data, addr, value) + return NotImplemented - def is_view_type_constant_defined(self, type_name, const_name): + def is_view_type_constant_defined(self, type_name:str, const_name:str) -> bool: """ :param str type_name: the BinaryView type name of the constant to query @@ -2027,7 +2105,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ return core.BNIsBinaryViewTypeArchitectureConstantDefined(self.handle, type_name, const_name) - def get_view_type_constant(self, type_name, const_name, default_value=0): + def get_view_type_constant(self, type_name:str, const_name:str, default_value:int=0) -> int: """ ``get_view_type_constant`` retrieves the view type constant for the given type_name and const_name. @@ -2047,7 +2125,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ return core.BNGetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, default_value) - def set_view_type_constant(self, type_name, const_name, value): + def set_view_type_constant(self, type_name:str, const_name:str, value:int) -> None: """ ``set_view_type_constant`` creates a new binaryview type constant. @@ -2063,7 +2141,7 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): """ core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) - def register_calling_convention(self, cc): + def register_calling_convention(self, cc:'callingconvention.CallingConvention') -> None: """ ``register_calling_convention`` registers a new calling convention for the Architecture. @@ -2075,54 +2153,57 @@ class Architecture(with_metaclass(_ArchitectureMetaClass, object)): _architecture_cache = {} class CoreArchitecture(Architecture): - def __init__(self, handle): + def __init__(self, handle:core.BNArchitecture): super(CoreArchitecture, self).__init__() self.handle = core.handle_of_type(handle, core.BNArchitecture) - self.__dict__["name"] = core.BNGetArchitectureName(self.handle) - self.__dict__["endianness"] = Endianness(core.BNGetArchitectureEndianness(self.handle)) - self.__dict__["address_size"] = core.BNGetArchitectureAddressSize(self.handle) - self.__dict__["default_int_size"] = core.BNGetArchitectureDefaultIntegerSize(self.handle) - self.__dict__["instr_alignment"] = core.BNGetArchitectureInstructionAlignment(self.handle) - self.__dict__["max_instr_length"] = core.BNGetArchitectureMaxInstructionLength(self.handle) - self.__dict__["opcode_display_length"] = core.BNGetArchitectureOpcodeDisplayLength(self.handle) - self.__dict__["stack_pointer"] = core.BNGetArchitectureRegisterName(self.handle, + self.name = core.BNGetArchitectureName(self.handle) + self.endianness = Endianness(core.BNGetArchitectureEndianness(self.handle)) + self.address_size = core.BNGetArchitectureAddressSize(self.handle) + self.default_int_size = core.BNGetArchitectureDefaultIntegerSize(self.handle) + self.instr_alignment = core.BNGetArchitectureInstructionAlignment(self.handle) + self.max_instr_length = core.BNGetArchitectureMaxInstructionLength(self.handle) + self.opcode_display_length = core.BNGetArchitectureOpcodeDisplayLength(self.handle) + self.stack_pointer:str = core.BNGetArchitectureRegisterName(self.handle, core.BNGetArchitectureStackPointerRegister(self.handle)) link_reg = core.BNGetArchitectureLinkRegister(self.handle) if link_reg == 0xffffffff: - self.__dict__["link_reg"] = None + self.link_reg = None else: - self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle, link_reg) + self.link_reg = core.BNGetArchitectureRegisterName(self.handle, link_reg) count = ctypes.c_ulonglong() regs = core.BNGetAllArchitectureRegisters(self.handle, count) + assert regs is not None, "core.BNGetAllArchitectureRegisters returned None" self._all_regs = {} self._regs_by_index = {} self._full_width_regs = {} - self.__dict__["regs"] = {} + self.regs = {} for i in range(0, count.value): - name = core.BNGetArchitectureRegisterName(self.handle, regs[i]) + name = RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + assert name is not None, "" info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) - full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) - self.regs[name] = binaryninja.function.RegisterInfo(full_width_reg, info.size, info.offset, + full_width_reg = RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)) + self.regs[name] = RegisterInfo(full_width_reg, info.size, info.offset, ImplicitRegisterExtend(info.extend), regs[i]) self._all_regs[name] = regs[i] self._regs_by_index[regs[i]] = name for i in range(0, count.value): info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) - full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) + full_width_reg = RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister)) if full_width_reg not in self._full_width_regs: self._full_width_regs[full_width_reg] = self._all_regs[full_width_reg] core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() flags = core.BNGetAllArchitectureFlags(self.handle, count) + assert flags is not None, "core.BNGetAllArchitectureFlags returned None" self._flags = {} self._flags_by_index = {} - self.__dict__["flags"] = [] + self.flags = [] for i in range(0, count.value): - name = core.BNGetArchitectureFlagName(self.handle, flags[i]) + name = FlagName(core.BNGetArchitectureFlagName(self.handle, flags[i])) self._flags[name] = flags[i] self._flags_by_index[flags[i]] = name self.flags.append(name) @@ -2130,11 +2211,12 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() write_types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) - self._flag_write_types = {} + assert write_types is not None, "core.BNGetAllArchitectureFlagWriteTypes returned None" + self._flag_write_types:Mapping[str, FlagWriteTypeIndex] = {} self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = [] + self.flag_write_types = [] for i in range(0, count.value): - name = core.BNGetArchitectureFlagWriteTypeName(self.handle, write_types[i]) + name = FlagWriteTypeName(core.BNGetArchitectureFlagWriteTypeName(self.handle, write_types[i])) self._flag_write_types[name] = write_types[i] self._flag_write_types_by_index[write_types[i]] = name self.flag_write_types.append(name) @@ -2142,11 +2224,12 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() sem_classes = core.BNGetAllArchitectureSemanticFlagClasses(self.handle, count) + assert sem_classes is not None,"core.BNGetAllArchitectureSemanticFlagClasses returned None" self._semantic_flag_classes = {} self._semantic_flag_classes_by_index = {} - self.__dict__["semantic_flag_classes"] = [] + self.semantic_flag_classes = [] for i in range(0, count.value): - name = core.BNGetArchitectureSemanticFlagClassName(self.handle, sem_classes[i]) + name = SemanticClassName(core.BNGetArchitectureSemanticFlagClassName(self.handle, sem_classes[i])) self._semantic_flag_classes[name] = sem_classes[i] self._semantic_flag_classes_by_index[sem_classes[i]] = name self.semantic_flag_classes.append(name) @@ -2154,39 +2237,42 @@ class CoreArchitecture(Architecture): count = ctypes.c_ulonglong() sem_groups = core.BNGetAllArchitectureSemanticFlagGroups(self.handle, count) + assert sem_groups is not None,"core.BNGetAllArchitectureSemanticFlagGroups returned Non" self._semantic_flag_groups = {} self._semantic_flag_groups_by_index = {} - self.__dict__["semantic_flag_groups"] = [] + self.semantic_flag_groups = [] for i in range(0, count.value): - name = core.BNGetArchitectureSemanticFlagGroupName(self.handle, sem_groups[i]) + name = SemanticGroupName(core.BNGetArchitectureSemanticFlagGroupName(self.handle, sem_groups[i])) self._semantic_flag_groups[name] = sem_groups[i] self._semantic_flag_groups_by_index[sem_groups[i]] = name self.semantic_flag_groups.append(name) core.BNFreeRegisterList(sem_groups) self._flag_roles = {} - self.__dict__["flag_roles"] = {} - for flag in self.__dict__["flags"]: + self.flag_roles = {} + for flag in self.flags: role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag], 0)) - self.__dict__["flag_roles"][flag] = role + self.flag_roles[flag] = role self._flag_roles[self._flags[flag]] = role - self.__dict__["flags_required_for_flag_condition"] = {} + self.flags_required_for_flag_condition:Mapping[LowLevelILFlagCondition, List[FlagName]] = {} for cond in LowLevelILFlagCondition: count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count) + assert flags is not None, "core.BNGetArchitectureFlagsRequiredForFlagCondition returned None" flag_names = [] for i in range(0, count.value): flag_names.append(self._flags_by_index[flags[i]]) core.BNFreeRegisterList(flags) - self.__dict__["flags_required_for_flag_condition"][cond] = flag_names + self.flags_required_for_flag_condition[cond] = flag_names self._flags_required_by_semantic_flag_group = {} - self.__dict__["flags_required_for_semantic_flag_group"] = {} + self.flags_required_for_semantic_flag_group = {} for group in self.semantic_flag_groups: count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup(self.handle, self._semantic_flag_groups[group], count) + assert flags is not None, "core.BNGetArchitectureFlagsRequiredForSemanticFlagGroup returned None" flag_indexes = [] flag_names = [] for i in range(0, count.value): @@ -2194,14 +2280,15 @@ class CoreArchitecture(Architecture): flag_names.append(self._flags_by_index[flags[i]]) core.BNFreeRegisterList(flags) self._flags_required_by_semantic_flag_group[self._semantic_flag_groups[group]] = flag_indexes - self.__dict__["flags_required_for_semantic_flag_group"][cond] = flag_names + self.flags_required_for_semantic_flag_group[group] = flag_names self._flag_conditions_for_semantic_flag_group = {} - self.__dict__["flag_conditions_for_semantic_flag_group"] = {} + self.flag_conditions_for_semantic_flag_group = {} for group in self.semantic_flag_groups: count = ctypes.c_ulonglong() conditions = core.BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.handle, self._semantic_flag_groups[group], count) + assert conditions is not None, "core.BNGetArchitectureFlagConditionsForSemanticFlagGroup returned None" class_index_cond = {} class_cond = {} for i in range(0, count.value): @@ -2212,14 +2299,15 @@ class CoreArchitecture(Architecture): class_cond[self._semantic_flag_classes_by_index[conditions[i].semanticClass]] = conditions[i].condition core.BNFreeFlagConditionsForSemanticFlagGroup(conditions) self._flag_conditions_for_semantic_flag_group[self._semantic_flag_groups[group]] = class_index_cond - self.__dict__["flag_conditions_for_semantic_flag_group"][group] = class_cond + self.flag_conditions_for_semantic_flag_group[group] = class_cond self._flags_written_by_flag_write_type = {} - self.__dict__["flags_written_by_flag_write_type"] = {} + self.flags_written_by_flag_write_type = {} for write_type in self.flag_write_types: count = ctypes.c_ulonglong() flags = core.BNGetArchitectureFlagsWrittenByFlagWriteType(self.handle, self._flag_write_types[write_type], count) + assert flags is not None, "core.BNGetArchitectureFlagsWrittenByFlagWriteType returned None" flag_indexes = [] flag_names = [] for i in range(0, count.value): @@ -2227,10 +2315,10 @@ class CoreArchitecture(Architecture): flag_names.append(self._flags_by_index[flags[i]]) core.BNFreeRegisterList(flags) self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flag_indexes - self.__dict__["flags_written_by_flag_write_type"][write_type] = flag_names + self.flags_written_by_flag_write_type[write_type] = flag_names self._semantic_class_for_flag_write_type = {} - self.__dict__["semantic_class_for_flag_write_type"] = {} + self.semantic_class_for_flag_write_type = {} for write_type in self.flag_write_types: sem_class = core.BNGetArchitectureSemanticClassForFlagWriteType(self.handle, self._flag_write_types[write_type]) @@ -2239,83 +2327,90 @@ class CoreArchitecture(Architecture): else: sem_class_name = self._semantic_flag_classes_by_index[sem_class] self._semantic_class_for_flag_write_type[self._flag_write_types[write_type]] = sem_class - self.__dict__["semantic_class_for_flag_write_type"][write_type] = sem_class_name + self.semantic_class_for_flag_write_type[write_type] = sem_class_name count = ctypes.c_ulonglong() regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) - self.__dict__["global_regs"] = [] + assert regs is not None, "core.BNGetArchitectureGlobalRegisters returned None" + self.global_regs:List[RegisterName] = [] for i in range(0, count.value): - self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + self.global_regs.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() regs = core.BNGetArchitectureSystemRegisters(self.handle, count) - self.__dict__["system_regs"] = [] + self.system_regs:List[RegisterName] = [] for i in range(0, count.value): - self.system_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + assert regs is not None, "core.BNGetArchitectureSystemRegisters returned None" + self.system_regs.append(RegisterName(core.BNGetArchitectureRegisterName(self.handle, regs[i]))) core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() regs = core.BNGetAllArchitectureRegisterStacks(self.handle, count) + assert regs is not None, "core.BNGetAllArchitectureRegisterStacks returned None" self._all_reg_stacks = {} self._reg_stacks_by_index = {} - self.__dict__["reg_stacks"] = {} + self.reg_stacks = {} for i in range(0, count.value): - name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i]) + name = RegisterStackName(core.BNGetArchitectureRegisterStackName(self.handle, regs[i])) info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) storage = [] for j in range(0, info.storageCount): storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j)) - top_rel = [] + top_rel:List[RegisterName] = [] for j in range(0, info.topRelativeCount): - top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) + reg_name = RegisterName(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) + top_rel.append(reg_name) top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) - self.reg_stacks[name] = binaryninja.function.RegisterStackInfo(storage, top_rel, top, regs[i]) + self.reg_stacks[name] = RegisterStackInfo(storage, top_rel, RegisterName(top), regs[i]) self._all_reg_stacks[name] = regs[i] self._reg_stacks_by_index[regs[i]] = name core.BNFreeRegisterList(regs) count = ctypes.c_ulonglong() intrinsics = core.BNGetAllArchitectureIntrinsics(self.handle, count) - self._intrinsics = {} - self._intrinsics_by_index = {} - self.__dict__["intrinsics"] = {} - for i in range(0, count.value): - name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i]) + assert intrinsics is not None, "core.BNGetAllArchitectureIntrinsics returned None" + self._intrinsics:Mapping[IntrinsicName, IntrinsicIndex] = {} + self._intrinsics_by_index:Mapping[IntrinsicIndex, Tuple[IntrinsicName, IntrinsicInfo]] = {} + self._intrinsics_info:Mapping[IntrinsicName, IntrinsicInfo] = {} + for i in range(count.value): + name = IntrinsicName(core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i])) input_count = ctypes.c_ulonglong() inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) + assert inputs is not None, "core.BNGetArchitectureIntrinsicInputs returned None" input_list = [] for j in range(0, input_count.value): input_name = inputs[j].name type_obj = types.Type(core.BNNewTypeReference(inputs[j].type), confidence = inputs[j].typeConfidence) - input_list.append(binaryninja.function.IntrinsicInput(type_obj, input_name)) + input_list.append(IntrinsicInput(type_obj, input_name)) core.BNFreeNameAndTypeList(inputs, input_count.value) output_count = ctypes.c_ulonglong() outputs = core.BNGetArchitectureIntrinsicOutputs(self.handle, intrinsics[i], output_count) + assert outputs is not None, "core.BNGetArchitectureIntrinsicOutputs returned None" output_list = [] - for j in range(0, output_count.value): + for j in range(output_count.value): output_list.append(types.Type(core.BNNewTypeReference(outputs[j].type), confidence = outputs[j].confidence)) core.BNFreeOutputTypeList(outputs, output_count.value) - self.intrinsics[name] = binaryninja.function.IntrinsicInfo(input_list, output_list) + self._intrinsics_info[name] = IntrinsicInfo(input_list, output_list) self._intrinsics[name] = intrinsics[i] - self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name]) + self._intrinsics_by_index[intrinsics[i]] = (name, self._intrinsics_info[name]) core.BNFreeRegisterList(intrinsics) if type(self) is CoreArchitecture: global _architecture_cache _architecture_cache[ctypes.addressof(handle.contents)] = self @classmethod - def _from_cache(cls, handle): + def _from_cache(cls, handle) -> 'Architecture': global _architecture_cache return _architecture_cache.get(ctypes.addressof(handle.contents)) or cls(handle) - def get_associated_arch_by_address(self, addr): + def get_associated_arch_by_address(self, addr:int) -> Tuple['Architecture', int]: new_addr = ctypes.c_ulonglong() new_addr.value = addr result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) return CoreArchitecture._from_cache(handle = result), new_addr.value - def get_instruction_info(self, data, addr): + def get_instruction_info(self, data:Union[bytes, str], addr:int) -> Optional[InstructionInfo]: """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2328,12 +2423,17 @@ class CoreArchitecture(Architecture): :return: the InstructionInfo for the current instruction :rtype: InstructionInfo """ + if not isinstance(data, bytes): + if isinstance(data, str): + data=data.encode() + else: + raise TypeError("Must be bytes or str") info = core.BNInstructionInfo() buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) if not core.BNGetInstructionInfo(self.handle, buf, addr, len(data), info): return None - result = binaryninja.function.InstructionInfo() + result = InstructionInfo() result.length = info.length result.arch_transition_by_target_addr = info.archTransitionByTargetAddr result.branch_delay = info.branchDelay @@ -2346,7 +2446,7 @@ class CoreArchitecture(Architecture): result.add_branch(BranchType(info.branchType[i]), target, arch) return result - def get_instruction_text(self, data, addr): + def get_instruction_text(self, data:bytes, addr:int) -> Tuple[List['function.InstructionTextToken'], int]: """ ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2367,13 +2467,15 @@ class CoreArchitecture(Architecture): buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) tokens = ctypes.POINTER(core.BNInstructionTextToken)() - if not core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count): - return None, 0 - result = binaryninja.function.InstructionTextToken.get_instruction_lines(tokens, count.value) - core.BNFreeInstructionText(tokens, count.value) - return result, length.value + result = [] + result_length = 0 + if core.BNGetInstructionText(self.handle, buf, addr, length, tokens, count): + result = function.InstructionTextToken._from_core_struct(tokens, count.value) + result_length = length.value + core.BNFreeInstructionText(tokens, count.value) + return result, result_length - def get_instruction_low_level_il(self, data, addr, il): + def get_instruction_low_level_il(self, data:Union[bytes, str], addr:int, il:lowlevelil.LowLevelILFunction) -> int: """ ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given virtual address ``addr`` with data ``data``. @@ -2381,20 +2483,27 @@ class CoreArchitecture(Architecture): This is used to analyze arbitrary data at an address, if you are working with an existing binary, you likely want to be using :func:`Function.get_low_level_il_at`. - :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param str|bytes data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :param LowLevelILFunction il: The function the current instruction belongs to :return: the length of the current instruction :rtype: int """ + if not isinstance(data, bytes): + if isinstance(data, str): + data=data.encode() + else: + raise TypeError("Must be bytes or str") length = ctypes.c_ulonglong() length.value = len(data) buf = (ctypes.c_ubyte * len(data))() ctypes.memmove(buf, data, len(data)) - core.BNGetInstructionLowLevelIL(self.handle, buf, addr, length, il.handle) + if not core.BNGetInstructionLowLevelIL(self.handle, buf, addr, length, il.handle): + raise Exception("BNGetInstructionLowLevelIL failed") return length.value - def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + def get_flag_write_low_level_il(self, op:LowLevelILOperation, size:int, write_type:FlagWriteTypeName, + flag:FlagType, operands:List['lowlevelil.ILRegisterType'], il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILOperation op: :param int size: @@ -2407,19 +2516,21 @@ class CoreArchitecture(Architecture): flag = self.get_flag_index(flag) operand_list = (core.BNRegisterOrConstant * len(operands))() for i in range(len(operands)): - if isinstance(operands[i], str): + operand = operands[i] + if isinstance(operand, RegisterName): operand_list[i].constant = False - operand_list[i].reg = self.regs[operands[i]].index - elif isinstance(operands[i], lowlevelil.ILRegister): + operand_list[i].reg = self.regs[operand].index + elif isinstance(operand, lowlevelil.ILRegister): operand_list[i].constant = False - operand_list[i].reg = operands[i].index + operand_list[i].reg = operand.index else: operand_list[i].constant = True - operand_list[i].value = operands[i] + operand_list[i].value = operand return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagWriteLowLevelIL(self.handle, op, size, self._flag_write_types[write_type], flag, operand_list, len(operand_list), il.handle)) - def get_flag_condition_low_level_il(self, cond, sem_class, il): + def get_flag_condition_low_level_il(self, cond:LowLevelILFlagCondition, sem_class:SemanticClassType, + il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param LowLevelILFlagCondition cond: Flag condition to be computed :param str sem_class: Semantic class to be used (None for default semantics) @@ -2430,7 +2541,8 @@ class CoreArchitecture(Architecture): return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, class_index, il.handle)) - def get_semantic_flag_group_low_level_il(self, sem_group, il): + def get_semantic_flag_group_low_level_il(self, sem_group:SemanticGroupName, + il:'lowlevelil.LowLevelILFunction') -> 'lowlevelil.LowLevelILExpr': """ :param str sem_group: :param LowLevelILFunction il: @@ -2439,7 +2551,7 @@ class CoreArchitecture(Architecture): group_index = self.get_semantic_flag_group_index(sem_group) return lowlevelil.LowLevelILExpr(core.BNGetArchitectureSemanticFlagGroupLowLevelIL(self.handle, group_index, il.handle)) - def assemble(self, code, addr=0): + def assemble(self, code:str, addr:int=0) -> bytes: """ ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. @@ -2460,12 +2572,9 @@ class CoreArchitecture(Architecture): error_str = errors.value core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte))) raise ValueError("Could not assemble: %s" % error_str) - if isinstance(str(result), bytes): - return str(result) - else: - return bytes(result) + return bytes(result) - def is_never_branch_patch_available(self, data, addr): + def is_never_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. @@ -2485,7 +2594,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureNeverBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_always_branch_patch_available(self, data, addr): + def is_always_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **always branch**. @@ -2506,7 +2615,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureAlwaysBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_invert_branch_patch_available(self, data, addr): + def is_invert_branch_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. @@ -2526,7 +2635,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureInvertBranchPatchAvailable(self.handle, buf, addr, len(data)) - def is_skip_and_return_zero_patch_available(self, data, addr): + def is_skip_and_return_zero_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns zero*. @@ -2549,7 +2658,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnZeroPatchAvailable(self.handle, buf, addr, len(data)) - def is_skip_and_return_value_patch_available(self, data, addr): + def is_skip_and_return_value_patch_available(self, data:bytes, addr:int=0) -> bool: """ ``is_skip_and_return_value_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* instruction that can be made into an instruction *returns a value*. @@ -2570,7 +2679,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(buf, data, len(data)) return core.BNIsArchitectureSkipAndReturnValuePatchAvailable(self.handle, buf, addr, len(data)) - def convert_to_nop(self, data, addr): + def convert_to_nop(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``convert_to_nop`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of nop instructions of the same length as data. @@ -2593,7 +2702,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def always_branch(self, data, addr): + def always_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``always_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which always branches. @@ -2619,7 +2728,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def invert_branch(self, data, addr): + def invert_branch(self, data:bytes, addr:int=0) -> Optional[bytes]: """ ``invert_branch`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which inverts the branch of provided instruction. @@ -2646,7 +2755,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def skip_and_return_value(self, data, addr, value): + def skip_and_return_value(self, data:bytes, addr:int, value:int) -> Optional[bytes]: """ ``skip_and_return_value`` reads the instruction(s) in ``data`` at virtual address ``addr`` and returns a string of bytes of the same length which doesn't call and instead *return a value*. @@ -2669,7 +2778,7 @@ class CoreArchitecture(Architecture): ctypes.memmove(result, buf, len(data)) return result.raw - def get_flag_role(self, flag, sem_class = None): + def get_flag_role(self, flag:FlagIndex, sem_class:Optional[SemanticClassIndex]= None) -> FlagRole: """ ``get_flag_role`` gets the role of a given flag. @@ -2679,13 +2788,19 @@ class CoreArchitecture(Architecture): :rtype: FlagRole """ flag = self.get_flag_index(flag) - sem_class = self.get_semantic_flag_class_index(sem_class) - return FlagRole(core.BNGetArchitectureFlagRole(self.handle, flag, sem_class)) - - def get_flags_required_for_flag_condition(self, cond, sem_class = None): - sem_class = self.get_semantic_flag_class_index(sem_class) + _sem_class = None + if sem_class is not None: + _sem_class = self.get_semantic_flag_class_index(sem_class) + return FlagRole(core.BNGetArchitectureFlagRole(self.handle, flag, _sem_class)) + + def get_flags_required_for_flag_condition(self, cond:LowLevelILFlagCondition, + sem_class:Optional[SemanticClassType]=None) -> List[FlagName]: + _sem_class = None + if sem_class is not None: + _sem_class = self.get_semantic_flag_class_index(sem_class) count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, sem_class, count) + flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, _sem_class, count) + assert flags is not None, "core.BNGetArchitectureFlagsRequiredForFlagCondition returned None" flag_names = [] for i in range(0, count.value): flag_names.append(self._flags_by_index[flags[i]]) @@ -2694,7 +2809,7 @@ class CoreArchitecture(Architecture): class ArchitectureHook(CoreArchitecture): - def __init__(self, base_arch): + def __init__(self, base_arch:'Architecture'): self._base_arch = base_arch super(ArchitectureHook, self).__init__(base_arch.handle) @@ -2728,198 +2843,9 @@ class ArchitectureHook(CoreArchitecture): core.BNFinalizeArchitectureHook(self._base_arch.handle) @property - def base_arch(self): - """ """ + def base_arch(self) -> 'Architecture': return self._base_arch @base_arch.setter - def base_arch(self, value): + def base_arch(self, value:'Architecture') -> None: self._base_arch = value - - -class ReferenceSource(object): - def __init__(self, func, arch, addr): - self._function = func - self._arch = arch - self._address = addr - - def __repr__(self): - if self._arch: - return "" % (self._arch.name, self._address) - else: - return "" % self._address - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self.function, self.arch, self.address) == (other.function, other.arch, other.address) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.address < other.address - - def __gt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.address > other.address - - def __ge__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.address >= other.address - - def __le__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return self.address <= other.address - - def __hash__(self): - return hash((self._function, self._arch, self._address)) - - @property - def function(self): - """ """ - return self._function - - @function.setter - def function(self, value): - self._function = value - - @property - def arch(self): - """ """ - return self._arch - - @arch.setter - def arch(self, value): - self._arch = value - - @property - def address(self): - """ """ - return self._address - - @address.setter - def address(self, value): - self._address = value - - -class TypeFieldReference(object): - def __init__(self, func, arch, addr, size, t): - self._function = func - self._arch = arch - self._address = addr - self._size = size - self._incomingType = t - - def __repr__(self): - if self._arch: - return "" % (self._arch.name, self._address, self._size,\ - self._incomingType) - else: - return "" % (self._address, self._size, self._incomingType) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return (self.function, self.arch, self.address, self._size, self._incomingType) ==\ - (other.function, other.arch, other.address, other.size, other.incomingType) - - def __ne__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - return not (self == other) - - def __lt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address < other.address: - return True - elif self.address > other.address: - return False - else: - return self.size < other.size - - def __gt__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address > other.address: - return True - elif self.address < other.address: - return False - else: - return self.size > other.size - - def __ge__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address > other.address: - return True - elif self.address < other.address: - return False - else: - return self.size >= other.size - - def __le__(self, other): - if not isinstance(other, self.__class__): - return NotImplemented - if self.address < other.address: - return True - elif self.address > other.address: - return False - else: - return self.size <= other.size - - def __hash__(self): - return hash((self._function, self._arch, self._address, self._size, self._incomingType)) - - @property - def function(self): - """ """ - return self._function - - @function.setter - def function(self, value): - self._function = value - - @property - def arch(self): - """ """ - return self._arch - - @arch.setter - def arch(self, value): - self._arch = value - - @property - def address(self): - """ """ - return self._address - - @address.setter - def address(self, value): - self._address = value - - @property - def size(self): - """ """ - return self._size - - @size.setter - def size(self, value): - self._size = value - - @property - def incomingType(self): - """ """ - return self._incomingType - - @size.setter - def incomingType(self, value): - self._incomingType = value -- cgit v1.3.1