diff options
| author | Peter LaFosse <peter@vector35.com> | 2018-04-04 14:11:55 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2018-04-04 14:11:55 -0400 |
| commit | d990d5ebf56eb0f1a7d96e98577cb9ace9dac19d (patch) | |
| tree | 752649d87db23f95a59384f5325b94b734e1c27b /python | |
| parent | 1eb3683b3a1ee0d263267b1e84957fadea7fadaa (diff) | |
| parent | fa716fe2da53a4f136380b1f60197bd197b2793a (diff) | |
Merging with dev
Diffstat (limited to 'python')
| -rw-r--r-- | python/architecture.py | 1916 | ||||
| -rw-r--r-- | python/basicblock.py | 23 | ||||
| -rw-r--r-- | python/binaryview.py | 30 | ||||
| -rw-r--r-- | python/callingconvention.py | 91 | ||||
| -rw-r--r-- | python/examples/arch_hook.py | 16 | ||||
| -rw-r--r-- | python/examples/nes.py | 28 | ||||
| -rw-r--r-- | python/function.py | 391 | ||||
| -rw-r--r-- | python/interaction.py | 2 | ||||
| -rw-r--r-- | python/lowlevelil.py | 720 | ||||
| -rw-r--r-- | python/mediumlevelil.py | 47 | ||||
| -rw-r--r-- | python/platform.py | 2 | ||||
| -rw-r--r-- | python/plugin.py | 219 | ||||
| -rw-r--r-- | python/scriptingprovider.py | 4 | ||||
| -rw-r--r-- | python/types.py | 17 |
14 files changed, 2938 insertions, 568 deletions
diff --git a/python/architecture.py b/python/architecture.py index a893c1d4..c5f87ec6 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -44,7 +44,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) result = [] for i in xrange(0, count.value): - result.append(Architecture(archs[i])) + result.append(CoreArchitecture._from_cache(archs[i])) core.BNFreeArchitectureList(archs) return result @@ -54,7 +54,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) try: for i in xrange(0, count.value): - yield Architecture(archs[i]) + yield CoreArchitecture._from_cache(archs[i]) finally: core.BNFreeArchitectureList(archs) @@ -63,7 +63,7 @@ class _ArchitectureMetaClass(type): arch = core.BNGetArchitectureByName(name) if arch is None: raise KeyError("'%s' is not a valid architecture" % str(name)) - return Architecture(arch) + return CoreArchitecture._from_cache(arch) def register(cls): startup._init_plugins() @@ -120,232 +120,266 @@ class Architecture(object): global_regs = [] flags = [] flag_write_types = [] + semantic_flag_classes = [] + semantic_flag_groups = [] flag_roles = {} flags_required_for_flag_condition = {} + flags_required_for_semantic_flag_group = {} + flag_conditions_for_semantic_flag_group = {} flags_written_by_flag_write_type = {} + semantic_class_for_flag_write_type = {} + reg_stacks = {} + intrinsics = {} __metaclass__ = _ArchitectureMetaClass next_address = 0 - def __init__(self, handle=None): - if handle is not None: - 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, - core.BNGetArchitectureStackPointerRegister(self.handle)) - self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle, - core.BNGetArchitectureLinkRegister(self.handle)) + def __init__(self): + startup._init_plugins() - count = ctypes.c_ulonglong() - regs = core.BNGetAllArchitectureRegisters(self.handle, count) - self.__dict__["regs"] = {} - for i in xrange(0, count.value): - name = core.BNGetArchitectureRegisterName(self.handle, regs[i]) - info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) - full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) - self.regs[name] = function.RegisterInfo(full_width_reg, info.size, info.offset, - ImplicitRegisterExtend(info.extend), regs[i]) - core.BNFreeRegisterList(regs) + if self.__class__.opcode_display_length > self.__class__.max_instr_length: + self.__class__.opcode_display_length = self.__class__.max_instr_length - count = ctypes.c_ulonglong() - flags = core.BNGetAllArchitectureFlags(self.handle, count) - self._flags = {} - self._flags_by_index = {} - self.__dict__["flags"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureFlagName(self.handle, flags[i]) - self._flags[name] = flags[i] - self._flags_by_index[flags[i]] = name - self.flags.append(name) - core.BNFreeRegisterList(flags) + self._cb = core.BNCustomArchitecture() + self._cb.context = 0 + self._cb.init = self._cb.init.__class__(self._init) + self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness) + self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) + self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size) + self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) + self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) + self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) + self._cb.getAssociatedArchitectureByAddress = \ + self._cb.getAssociatedArchitectureByAddress.__class__(self._get_associated_arch_by_address) + self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info) + self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text) + self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text) + self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__( + self._get_instruction_low_level_il) + self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) + self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) + self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) + self._cb.getSemanticFlagClassName = self._cb.getSemanticFlagClassName.__class__(self._get_semantic_flag_class_name) + self._cb.getSemanticFlagGroupName = self._cb.getSemanticFlagGroupName.__class__(self._get_semantic_flag_group_name) + self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers) + self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers) + self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags) + self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types) + self._cb.getAllSemanticFlagClasses = self._cb.getAllSemanticFlagClasses.__class__(self._get_all_semantic_flag_classes) + self._cb.getAllSemanticFlagGroups = self._cb.getAllSemanticFlagGroups.__class__(self._get_all_semantic_flag_groups) + self._cb.getFlagRole = self._cb.getFlagRole.__class__(self._get_flag_role) + self._cb.getFlagsRequiredForFlagCondition = self._cb.getFlagsRequiredForFlagCondition.__class__( + self._get_flags_required_for_flag_condition) + self._cb.getFlagsRequiredForSemanticFlagGroup = self._cb.getFlagsRequiredForSemanticFlagGroup.__class__( + self._get_flags_required_for_semantic_flag_group) + self._cb.getFlagConditionsForSemanticFlagGroup = self._cb.getFlagConditionsForSemanticFlagGroup.__class__( + self._get_flag_conditions_for_semantic_flag_group) + self._cb.freeFlagConditionsForSemanticFlagGroup = self._cb.freeFlagConditionsForSemanticFlagGroup.__class__( + self._free_flag_conditions_for_semantic_flag_group) + self._cb.getFlagsWrittenByFlagWriteType = self._cb.getFlagsWrittenByFlagWriteType.__class__( + self._get_flags_written_by_flag_write_type) + self._cb.getSemanticClassForFlagWriteType = self._cb.getSemanticClassForFlagWriteType.__class__( + self._get_semantic_class_for_flag_write_type) + self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__( + self._get_flag_write_low_level_il) + self._cb.getFlagConditionLowLevelIL = self._cb.getFlagConditionLowLevelIL.__class__( + self._get_flag_condition_low_level_il) + self._cb.getSemanticFlagGroupLowLevelIL = self._cb.getSemanticFlagGroupLowLevelIL.__class__( + self._get_semantic_flag_group_low_level_il) + self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) + self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info) + self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( + self._get_stack_pointer_register) + self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) + self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) + self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__(self._get_register_stack_name) + self._cb.getAllRegisterStacks = self._cb.getAllRegisterStacks.__class__(self._get_all_register_stacks) + self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__(self._get_register_stack_info) + self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__(self._get_intrinsic_name) + self._cb.getAllIntrinsics = self._cb.getAllIntrinsics.__class__(self._get_all_intrinsics) + self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__(self._get_intrinsic_inputs) + self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__(self._free_name_and_type_list) + self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__(self._get_intrinsic_outputs) + self._cb.freeTypeList = self._cb.freeTypeList.__class__(self._free_type_list) + self._cb.assemble = self._cb.assemble.__class__(self._assemble) + self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( + self._is_never_branch_patch_available) + self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__( + self._is_always_branch_patch_available) + self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__( + self._is_invert_branch_patch_available) + self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__( + self._is_skip_and_return_zero_patch_available) + self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__( + self._is_skip_and_return_value_patch_available) + self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop) + self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch) + self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) + self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value) - count = ctypes.c_ulonglong() - types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) - self._flag_write_types = {} - self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = [] - for i in xrange(0, count.value): - name = core.BNGetArchitectureFlagWriteTypeName(self.handle, types[i]) - self._flag_write_types[name] = types[i] - self._flag_write_types_by_index[types[i]] = name - self.flag_write_types.append(name) - core.BNFreeRegisterList(types) + 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._flag_roles = {} - self.__dict__["flag_roles"] = {} - for flag in self.__dict__["flags"]: - role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag])) - self.__dict__["flag_roles"][flag] = role - self._flag_roles[self._flags[flag]] = role + self._all_regs = {} + self._full_width_regs = {} + self._regs_by_index = {} + self.__dict__["regs"] = self.__class__.regs + reg_index = 0 - self._flags_required_for_flag_condition = {} - self.__dict__["flags_required_for_flag_condition"] = {} - for cond in LowLevelILFlagCondition: - count = ctypes.c_ulonglong() - flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, count) - flag_indexes = [] - flag_names = [] - for i in xrange(0, count.value): - flag_indexes.append(flags[i]) - flag_names.append(self._flags_by_index[flags[i]]) - core.BNFreeRegisterList(flags) - self._flags_required_for_flag_condition[cond] = flag_indexes - self.__dict__["flags_required_for_flag_condition"][cond] = flag_names + # 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] + 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 + 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 + 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 - self._flags_written_by_flag_write_type = {} - self.__dict__["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) - flag_indexes = [] - flag_names = [] - for i in xrange(0, count.value): - flag_indexes.append(flags[i]) - 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 + for reg in self.regs: + info = self.regs[reg] + 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 + 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 + 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] - count = ctypes.c_ulonglong() - regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) - self.__dict__["global_regs"] = [] - for i in xrange(0, count.value): - self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) - core.BNFreeRegisterList(regs) - else: - startup._init_plugins() + self._flags = {} + self._flags_by_index = {} + self.__dict__["flags"] = self.__class__.flags + flag_index = 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 - if self.__class__.opcode_display_length > self.__class__.max_instr_length: - self.__class__.opcode_display_length = self.__class__.max_instr_length + self._flag_write_types = {} + self._flag_write_types_by_index = {} + self.__dict__["flag_write_types"] = self.__class__.flag_write_types + write_type_index = 0 + 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 - self._cb = core.BNCustomArchitecture() - self._cb.context = 0 - self._cb.init = self._cb.init.__class__(self._init) - self._cb.getEndianness = self._cb.getEndianness.__class__(self._get_endianness) - self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) - self._cb.getDefaultIntegerSize = self._cb.getDefaultIntegerSize.__class__(self._get_default_integer_size) - self._cb.getInstructionAlignment = self._cb.getInstructionAlignment.__class__(self._get_instruction_alignment) - self._cb.getMaxInstructionLength = self._cb.getMaxInstructionLength.__class__(self._get_max_instruction_length) - self._cb.getOpcodeDisplayLength = self._cb.getOpcodeDisplayLength.__class__(self._get_opcode_display_length) - self._cb.getAssociatedArchitectureByAddress = \ - self._cb.getAssociatedArchitectureByAddress.__class__(self._get_associated_arch_by_address) - self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__(self._get_instruction_info) - self._cb.getInstructionText = self._cb.getInstructionText.__class__(self._get_instruction_text) - self._cb.freeInstructionText = self._cb.freeInstructionText.__class__(self._free_instruction_text) - self._cb.getInstructionLowLevelIL = self._cb.getInstructionLowLevelIL.__class__( - self._get_instruction_low_level_il) - self._cb.getRegisterName = self._cb.getRegisterName.__class__(self._get_register_name) - self._cb.getFlagName = self._cb.getFlagName.__class__(self._get_flag_name) - self._cb.getFlagWriteTypeName = self._cb.getFlagWriteTypeName.__class__(self._get_flag_write_type_name) - self._cb.getFullWidthRegisters = self._cb.getFullWidthRegisters.__class__(self._get_full_width_registers) - self._cb.getAllRegisters = self._cb.getAllRegisters.__class__(self._get_all_registers) - self._cb.getAllFlags = self._cb.getAllRegisters.__class__(self._get_all_flags) - self._cb.getAllFlagWriteTypes = self._cb.getAllRegisters.__class__(self._get_all_flag_write_types) - self._cb.getFlagRole = self._cb.getFlagRole.__class__(self._get_flag_role) - self._cb.getFlagsRequiredForFlagCondition = self._cb.getFlagsRequiredForFlagCondition.__class__( - self._get_flags_required_for_flag_condition) - self._cb.getFlagsWrittenByFlagWriteType = self._cb.getFlagsWrittenByFlagWriteType.__class__( - self._get_flags_written_by_flag_write_type) - self._cb.getFlagWriteLowLevelIL = self._cb.getFlagWriteLowLevelIL.__class__( - self._get_flag_write_low_level_il) - self._cb.getFlagConditionLowLevelIL = self._cb.getFlagConditionLowLevelIL.__class__( - self._get_flag_condition_low_level_il) - self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) - self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__(self._get_register_info) - self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__( - self._get_stack_pointer_register) - self._cb.getLinkRegister = self._cb.getLinkRegister.__class__(self._get_link_register) - self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_registers) - self._cb.assemble = self._cb.assemble.__class__(self._assemble) - self._cb.isNeverBranchPatchAvailable = self._cb.isNeverBranchPatchAvailable.__class__( - self._is_never_branch_patch_available) - self._cb.isAlwaysBranchPatchAvailable = self._cb.isAlwaysBranchPatchAvailable.__class__( - self._is_always_branch_patch_available) - self._cb.isInvertBranchPatchAvailable = self._cb.isInvertBranchPatchAvailable.__class__( - self._is_invert_branch_patch_available) - self._cb.isSkipAndReturnZeroPatchAvailable = self._cb.isSkipAndReturnZeroPatchAvailable.__class__( - self._is_skip_and_return_zero_patch_available) - self._cb.isSkipAndReturnValuePatchAvailable = self._cb.isSkipAndReturnValuePatchAvailable.__class__( - self._is_skip_and_return_value_patch_available) - self._cb.convertToNop = self._cb.convertToNop.__class__(self._convert_to_nop) - self._cb.alwaysBranch = self._cb.alwaysBranch.__class__(self._always_branch) - self._cb.invertBranch = self._cb.invertBranch.__class__(self._invert_branch) - self._cb.skipAndReturnValue = self._cb.skipAndReturnValue.__class__(self._skip_and_return_value) + self._semantic_flag_classes = {} + self._semantic_flag_classes_by_index = {} + self.__dict__["semantic_flag_classes"] = self.__class__.semantic_flag_classes + semantic_class_index = 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 - self._all_regs = {} - self._full_width_regs = {} - self._regs_by_index = {} - self.__dict__["regs"] = self.__class__.regs - reg_index = 0 - for reg in self.regs: - info = self.regs[reg] - 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 - 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 - 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._semantic_flag_groups = {} + self._semantic_flag_groups_by_index = {} + self.__dict__["semantic_flag_groups"] = self.__class__.semantic_flag_groups + semantic_group_index = 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 - self._flags = {} - self._flags_by_index = {} - self.__dict__["flags"] = self.__class__.flags - flag_index = 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 + self._flag_roles = {} + self.__dict__["flag_roles"] = 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._flag_write_types = {} - self._flag_write_types_by_index = {} - self.__dict__["flag_write_types"] = self.__class__.flag_write_types - write_type_index = 0 - 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 + self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition - self._flag_roles = {} - self.__dict__["flag_roles"] = 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._flags_required_by_semantic_flag_group = {} + self.__dict__["flags_required_for_semantic_flag_group"] = self.__class__.flags_required_for_semantic_flag_group + for group in self.__class__.flags_required_for_semantic_flag_group: + flags = [] + 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._flags_required_for_flag_condition = {} - self.__dict__["flags_required_for_flag_condition"] = self.__class__.flags_required_for_flag_condition - for cond in self.__class__.flags_required_for_flag_condition: - flags = [] - for flag in self.__class__.flags_required_for_flag_condition[cond]: - flags.append(self._flags[flag]) - self._flags_required_for_flag_condition[cond] = flags + self._flag_conditions_for_semantic_flag_group = {} + self.__dict__["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]: + if sem_class is None: + class_cond[0] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] + else: + class_cond[self._semantic_flag_classes[sem_class]] = self.__class__.flag_conditions_for_semantic_flag_group[group][sem_class] + 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 - 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]: - flags.append(self._flags[flag]) - self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags + self._flags_written_by_flag_write_type = {} + self.__dict__["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]: + flags.append(self._flags[flag]) + self._flags_written_by_flag_write_type[self._flag_write_types[write_type]] = flags - self.__dict__["global_regs"] = self.__class__.global_regs + self._semantic_class_for_flag_write_type = {} + self.__dict__["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: + sem_class_index = self._semantic_flag_classes[sem_class] + else: + 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._pending_reg_lists = {} - self._pending_token_lists = {} + self._intrinsics = {} + self._intrinsics_by_index = {} + self.__dict__["intrinsics"] = self.__class__.intrinsics + intrinsic_index = 0 + for intrinsic in self.__class__.intrinsics.keys(): + if intrinsic not in self._intrinsics: + info = self.__class__.intrinsics[intrinsic] + for i in xrange(0, len(info.inputs)): + if isinstance(info.inputs[i], types.Type): + info.inputs[i] = function.IntrinsicInput(info.inputs[i]) + elif isinstance(info.inputs[i], tuple): + info.inputs[i] = function.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 + + self._pending_reg_lists = {} + self._pending_token_lists = {} + self._pending_condition_lists = {} + self._pending_name_and_type_lists = {} + self._pending_type_lists = {} def __eq__(self, value): if not isinstance(value, Architecture): @@ -405,49 +439,49 @@ class Architecture(object): def _get_endianness(self, ctxt): try: - return self.__class__.endianness + return self.endianness except: log.log_error(traceback.format_exc()) return Endianness.LittleEndian def _get_address_size(self, ctxt): try: - return self.__class__.address_size + return self.address_size except: log.log_error(traceback.format_exc()) return 8 def _get_default_integer_size(self, ctxt): try: - return self.__class__.default_int_size + return self.default_int_size except: log.log_error(traceback.format_exc()) return 4 def _get_instruction_alignment(self, ctxt): try: - return self.__class__.instr_alignment + return self.instr_alignment except: log.log_error(traceback.format_exc()) return 1 def _get_max_instruction_length(self, ctxt): try: - return self.__class__.max_instr_length + return self.max_instr_length except: log.log_error(traceback.format_exc()) return 16 def _get_opcode_display_length(self, ctxt): try: - return self.__class__.opcode_display_length + return self.opcode_display_length except: log.log_error(traceback.format_exc()) return 8 def _get_associated_arch_by_address(self, ctxt, addr): try: - result, new_addr = self.perform_get_associated_arch_by_address(addr[0]) + result, new_addr = self.get_associated_arch_by_address(addr[0]) addr[0] = new_addr return ctypes.cast(result.handle, ctypes.c_void_p).value except: @@ -458,7 +492,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(max_len) ctypes.memmove(buf, data, max_len) - info = self.perform_get_instruction_info(buf.raw, addr) + info = self.get_instruction_info(buf.raw, addr) if info is None: return False result[0].length = info.length @@ -484,7 +518,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length[0]) ctypes.memmove(buf, data, length[0]) - info = self.perform_get_instruction_text(buf.raw, addr) + info = self.get_instruction_text(buf.raw, addr) if info is None: return False tokens = info[0] @@ -524,7 +558,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length[0]) ctypes.memmove(buf, data, length[0]) - result = self.perform_get_instruction_low_level_il(buf.raw, addr, + result = self.get_instruction_low_level_il(buf.raw, addr, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))) if result is None: return False @@ -561,6 +595,24 @@ class Architecture(object): log.log_error(traceback.format_exc()) return core.BNAllocString("") + def _get_semantic_flag_class_name(self, ctxt, sem_class): + try: + if sem_class in self._semantic_flag_classes_by_index: + return core.BNAllocString(self._semantic_flag_classes_by_index[sem_class]) + return core.BNAllocString("") + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return core.BNAllocString("") + + def _get_semantic_flag_group_name(self, ctxt, sem_group): + try: + if sem_group in self._semantic_flag_groups_by_index: + return core.BNAllocString(self._semantic_flag_groups_by_index[sem_group]) + return core.BNAllocString("") + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return core.BNAllocString("") + def _get_full_width_registers(self, ctxt, count): try: regs = self._full_width_regs.values() @@ -608,11 +660,11 @@ class Architecture(object): def _get_all_flag_write_types(self, ctxt, count): try: - types = self._flag_write_types_by_index.keys() - count[0] = len(types) - type_buf = (ctypes.c_uint * len(types))() - for i in xrange(0, len(types)): - type_buf[i] = types[i] + write_types = self._flag_write_types_by_index.keys() + count[0] = len(write_types) + type_buf = (ctypes.c_uint * len(write_types))() + for i in xrange(0, len(write_types)): + type_buf[i] = write_types[i] result = ctypes.cast(type_buf, ctypes.c_void_p) self._pending_reg_lists[result.value] = (result, type_buf) return result.value @@ -621,19 +673,73 @@ class Architecture(object): count[0] = 0 return None - def _get_flag_role(self, ctxt, flag): + def _get_all_semantic_flag_classes(self, ctxt, count): + try: + sem_classes = self._semantic_flag_classes_by_index.keys() + count[0] = len(sem_classes) + class_buf = (ctypes.c_uint * len(sem_classes))() + for i in xrange(0, len(sem_classes)): + class_buf[i] = sem_classes[i] + result = ctypes.cast(class_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, class_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_all_semantic_flag_groups(self, ctxt, count): try: - if flag in self._flag_roles: - return self._flag_roles[flag] + sem_groups = self._semantic_flag_groups_by_index.keys() + count[0] = len(sem_groups) + group_buf = (ctypes.c_uint * len(sem_groups))() + for i in xrange(0, len(sem_groups)): + group_buf[i] = sem_groups[i] + result = ctypes.cast(group_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, group_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + 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_flags_required_for_flag_condition(self, ctxt, cond, sem_class, count): + 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 + flag_names = self.get_flags_required_for_flag_condition(cond, sem_class) + flags = [] + for name in flag_names: + flags.append(self._flags[name]) + count[0] = len(flags) + flag_buf = (ctypes.c_uint * len(flags))() + for i in xrange(0, len(flags)): + flag_buf[i] = flags[i] + result = ctypes.cast(flag_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, flag_buf) + return result.value except KeyError: log.log_error(traceback.format_exc()) + count[0] = 0 return None - def _get_flags_required_for_flag_condition(self, ctxt, cond, count): + def _get_flags_required_for_semantic_flag_group(self, ctxt, sem_group, count): try: - if cond in self._flags_required_for_flag_condition: - flags = self._flags_required_for_flag_condition[cond] + if sem_group in self._flags_required_by_semantic_flag_group: + flags = self._flags_required_by_semantic_flag_group[sem_group] else: flags = [] count[0] = len(flags) @@ -643,11 +749,41 @@ class Architecture(object): result = ctypes.cast(flag_buf, ctypes.c_void_p) self._pending_reg_lists[result.value] = (result, flag_buf) return result.value - except KeyError: + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_flag_conditions_for_semantic_flag_group(self, ctxt, sem_group, count): + try: + if sem_group in self._flag_conditions_for_semantic_flag_group: + class_cond = self._flag_conditions_for_semantic_flag_group[sem_group] + else: + class_cond = {} + count[0] = len(class_cond) + cond_buf = (core.BNFlagConditionForSemanticClass * len(class_cond))() + i = 0 + for class_index in class_cond.keys(): + cond_buf[i].semanticClass = class_index + cond_buf[i].condition = class_cond[class_index] + i += 1 + result = ctypes.cast(cond_buf, ctypes.c_void_p) + self._pending_condition_lists[result.value] = (result, cond_buf) + return result.value + except (KeyError, OSError): log.log_error(traceback.format_exc()) count[0] = 0 return None + def _free_flag_conditions_for_semantic_flag_group(self, ctxt, conditions): + try: + buf = ctypes.cast(conditions, ctypes.c_void_p) + if buf.value not in self._pending_condition_lists: + raise ValueError("freeing condition list that wasn't allocated") + del self._pending_condition_lists[buf.value] + except (ValueError, KeyError): + log.log_error(traceback.format_exc()) + def _get_flags_written_by_flag_write_type(self, ctxt, write_type, count): try: if write_type in self._flags_written_by_flag_write_type: @@ -666,6 +802,16 @@ class Architecture(object): count[0] = 0 return None + def _get_semantic_class_for_flag_write_type(self, ctxt, write_type): + try: + if write_type in self._semantic_class_for_flag_write_type: + return self._semantic_class_for_flag_write_type[write_type] + else: + return 0 + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return 0 + def _get_flag_write_low_level_il(self, ctxt, op, size, write_type, flag, operands, operand_count, il): try: write_type_name = None @@ -680,15 +826,31 @@ class Architecture(object): operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) else: operand_list.append(lowlevelil.ILRegister(self, operands[i].reg)) - return self.perform_get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list, + return self.get_flag_write_low_level_il(op, size, write_type_name, flag_name, operand_list, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index except (KeyError, OSError): log.log_error(traceback.format_exc()) return False - def _get_flag_condition_low_level_il(self, ctxt, cond, il): + def _get_flag_condition_low_level_il(self, ctxt, cond, sem_class, il): try: - return self.perform_get_flag_condition_low_level_il(cond, + if sem_class in self._semantic_flag_classes_by_index: + sem_class_name = self._semantic_flag_classes_by_index[sem_class] + else: + sem_class_name = None + return self.get_flag_condition_low_level_il(cond, sem_class_name, + lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index + except OSError: + log.log_error(traceback.format_exc()) + return 0 + + def _get_semantic_flag_group_low_level_il(self, ctxt, sem_group, il): + try: + if sem_group in self._semantic_flag_groups_by_index: + sem_group_name = self._semantic_flag_groups_by_index[sem_group] + else: + sem_group_name = None + return self.get_semantic_flag_group_low_level_il(sem_group_name, lowlevelil.LowLevelILFunction(self, core.BNNewLowLevelILFunctionReference(il))).index except OSError: log.log_error(traceback.format_exc()) @@ -711,7 +873,7 @@ class Architecture(object): result[0].size = 0 result[0].extend = ImplicitRegisterExtend.NoExtend return - info = self.__class__.regs[self._regs_by_index[reg]] + info = self.regs[self._regs_by_index[reg]] result[0].fullWidthRegister = self._all_regs[info.full_width_reg] result[0].offset = info.offset result[0].size = info.size @@ -728,26 +890,50 @@ class Architecture(object): def _get_stack_pointer_register(self, ctxt): try: - return self._all_regs[self.__class__.stack_pointer] + return self._all_regs[self.stack_pointer] except KeyError: log.log_error(traceback.format_exc()) return 0 def _get_link_register(self, ctxt): try: - if self.__class__.link_reg is None: + if self.link_reg is None: return 0xffffffff - return self._all_regs[self.__class__.link_reg] + return self._all_regs[self.link_reg] except KeyError: log.log_error(traceback.format_exc()) return 0 def _get_global_registers(self, ctxt, count): try: - count[0] = len(self.__class__.global_regs) - reg_buf = (ctypes.c_uint * len(self.__class__.global_regs))() - for i in xrange(0, len(self.__class__.global_regs)): - reg_buf[i] = self._all_regs[self.__class__.global_regs[i]] + count[0] = len(self.global_regs) + reg_buf = (ctypes.c_uint * len(self.global_regs))() + for i in xrange(0, len(self.global_regs)): + reg_buf[i] = self._all_regs[self.global_regs[i]] + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_register_stack_name(self, ctxt, reg_stack): + try: + if reg_stack in self._reg_stacks_by_index: + return core.BNAllocString(self._reg_stacks_by_index[reg_stack]) + return core.BNAllocString("") + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return core.BNAllocString("") + + def _get_all_register_stacks(self, ctxt, count): + try: + regs = self._reg_stacks_by_index.keys() + count[0] = len(regs) + reg_buf = (ctypes.c_uint * len(regs))() + for i in xrange(0, len(regs)): + reg_buf[i] = regs[i] result = ctypes.cast(reg_buf, ctypes.c_void_p) self._pending_reg_lists[result.value] = (result, reg_buf) return result.value @@ -756,9 +942,125 @@ class Architecture(object): count[0] = 0 return None + def _get_register_stack_info(self, ctxt, reg_stack, result): + try: + if reg_stack not in self._reg_stacks_by_index: + result[0].firstStorageReg = 0 + result[0].firstTopRelativeReg = 0 + result[0].storageCount = 0 + result[0].topRelativeCount = 0 + result[0].stackTopReg = 0 + return + info = self.reg_stacks[self._reg_stacks_by_index[reg_stack]] + result[0].firstStorageReg = self._all_regs[info.storage_regs[0]] + result[0].storageCount = len(info.storage_regs) + if len(info.top_relative_regs) > 0: + result[0].firstTopRelativeReg = self._all_regs[info.top_relative_regs[0]] + result[0].topRelativeCount = len(info.top_relative_regs) + else: + result[0].firstTopRelativeReg = 0 + result[0].topRelativeCount = 0 + result[0].stackTopReg = self._all_regs[info.stack_top_reg] + except KeyError: + log.log_error(traceback.format_exc()) + result[0].firstStorageReg = 0 + result[0].firstTopRelativeReg = 0 + result[0].storageCount = 0 + result[0].topRelativeCount = 0 + result[0].stackTopReg = 0 + + def _get_intrinsic_name(self, ctxt, intrinsic): + try: + if intrinsic in self._intrinsics_by_index: + return core.BNAllocString(self._intrinsics_by_index[intrinsic][0]) + return core.BNAllocString("") + except (KeyError, OSError): + log.log_error(traceback.format_exc()) + return core.BNAllocString("") + + def _get_all_intrinsics(self, ctxt, count): + try: + regs = self._intrinsics_by_index.keys() + count[0] = len(regs) + reg_buf = (ctypes.c_uint * len(regs))() + for i in xrange(0, len(regs)): + reg_buf[i] = regs[i] + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except KeyError: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _get_intrinsic_inputs(self, ctxt, intrinsic, count): + try: + if intrinsic in self._intrinsics_by_index: + inputs = self._intrinsics_by_index[intrinsic][1].inputs + count[0] = len(inputs) + input_buf = (core.BNNameAndType * len(inputs))() + for i in xrange(0, len(inputs)): + input_buf[i].name = inputs[i].name + input_buf[i].type = core.BNNewTypeReference(inputs[i].type.handle) + input_buf[i].typeConfidence = inputs[i].type.confidence + result = ctypes.cast(input_buf, ctypes.c_void_p) + self._pending_name_and_type_lists[result.value] = (result, input_buf, len(inputs)) + return result.value + count[0] = 0 + return None + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _free_name_and_type_list(self, ctxt, buf_raw, length): + try: + buf = ctypes.cast(buf_raw, ctypes.c_void_p) + if buf.value not in self._pending_name_and_type_lists: + raise ValueError("freeing name and type list that wasn't allocated") + name_and_types = self._pending_name_and_type_lists[buf.value][1] + count = self._pending_name_and_type_lists[buf.value][2] + for i in xrange(0, count): + core.BNFreeType(name_and_types[i].type) + del self._pending_name_and_type_lists[buf.value] + except (ValueError, KeyError): + log.log_error(traceback.format_exc()) + + def _get_intrinsic_outputs(self, ctxt, intrinsic, count): + try: + if intrinsic in self._intrinsics_by_index: + outputs = self._intrinsics_by_index[intrinsic][1].outputs + count[0] = len(outputs) + output_buf = (core.BNTypeWithConfidence * len(outputs))() + for i in xrange(0, len(outputs)): + output_buf[i].type = core.BNNewTypeReference(outputs[i].handle) + output_buf[i].confidence = outputs[i].confidence + result = ctypes.cast(output_buf, ctypes.c_void_p) + self._pending_type_lists[result.value] = (result, output_buf, len(outputs)) + return result.value + count[0] = 0 + return None + except: + log.log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _free_type_list(self, ctxt, buf_raw, length): + try: + buf = ctypes.cast(buf_raw, ctypes.c_void_p) + if buf.value not in self._pending_type_lists: + raise ValueError("freeing type list that wasn't allocated") + types = self._pending_type_lists[buf.value][1] + count = self._pending_type_lists[buf.value][2] + for i in xrange(0, count): + core.BNFreeType(types[i].type) + del self._pending_type_lists[buf.value] + except (ValueError, KeyError): + log.log_error(traceback.format_exc()) + def _assemble(self, ctxt, code, addr, result, errors): try: - data, error_str = self.perform_assemble(code, addr) + data, error_str = self.assemble(code, addr) errors[0] = core.BNAllocString(str(error_str)) if data is None: return False @@ -776,7 +1078,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_never_branch_patch_available(buf.raw, addr) + return self.is_never_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -785,7 +1087,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_always_branch_patch_available(buf.raw, addr) + return self.is_always_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -794,7 +1096,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_invert_branch_patch_available(buf.raw, addr) + return self.is_invert_branch_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -803,7 +1105,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_skip_and_return_zero_patch_available(buf.raw, addr) + return self.is_skip_and_return_zero_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -812,7 +1114,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - return self.perform_is_skip_and_return_value_patch_available(buf.raw, addr) + return self.is_skip_and_return_value_patch_available(buf.raw, addr) except: log.log_error(traceback.format_exc()) return False @@ -821,7 +1123,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_convert_to_nop(buf.raw, addr) + result = self.convert_to_nop(buf.raw, addr) if result is None: return False result = str(result) @@ -837,7 +1139,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_always_branch(buf.raw, addr) + result = self.always_branch(buf.raw, addr) if result is None: return False result = str(result) @@ -853,7 +1155,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_invert_branch(buf.raw, addr) + result = self.invert_branch(buf.raw, addr) if result is None: return False result = str(result) @@ -869,7 +1171,7 @@ class Architecture(object): try: buf = ctypes.create_string_buffer(length) ctypes.memmove(buf, data, length) - result = self.perform_skip_and_return_value(buf.raw, addr, value) + result = self.skip_and_return_value(buf.raw, addr, value) if result is None: return False result = str(result) @@ -882,27 +1184,15 @@ class Architecture(object): return False def perform_get_associated_arch_by_address(self, addr): + """ + Deprecated method provided for compatibility. Architecture plugins should override ``get_associated_arch_by_address``. + """ return self, addr @abc.abstractmethod def perform_get_instruction_info(self, data, addr): """ - ``perform_get_instruction_info`` implements a method which interpretes the bytes passed in ``data`` as an - :py:Class:`InstructionInfo` object. The InstructionInfo object should have the length of the current instruction. - If the instruction is a branch instruction the method should add a branch of the proper type: - - ===================== =================================================== - BranchType Description - ===================== =================================================== - UnconditionalBranch Branch will always be taken - FalseBranch False branch condition - TrueBranch True branch condition - CallDestination Branch is a call instruction (Branch with Link) - FunctionReturn Branch returns from a function - SystemCall System call instruction - IndirectBranch Branch destination is a memory address or register - UnresolvedBranch Call instruction that isn't - ===================== =================================================== + Deprecated method provided for compatibility. Architecture plugins should override ``get_instruction_info``. :param str data: bytes to decode :param int addr: virtual address of the byte to be decoded @@ -914,8 +1204,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_instruction_text(self, data, addr): """ - ``perform_get_instruction_text`` implements a method which interpretes the bytes passed in ``data`` as a - list of :py:class:`InstructionTextToken` objects. + Deprecated method provided for compatibility. Architecture plugins should override ``get_instruction_text``. :param str data: bytes to decode :param int addr: virtual address of the byte to be decoded @@ -927,10 +1216,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_instruction_low_level_il(self, data, addr, il): """ - ``perform_get_instruction_low_level_il`` implements a method to interpret the bytes passed in ``data`` to - low-level IL instructions. The il instructions must be appended to the :py:class:`LowLevelILFunction`. - - .. note:: Architecture subclasses should implement this method. + Deprecated method provided for compatibility. Architecture plugins should override ``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`` @@ -942,8 +1228,7 @@ class Architecture(object): @abc.abstractmethod def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): """ - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``get_flag_write_low_level_il``. :param LowLevelILOperation op: :param int size: @@ -959,28 +1244,32 @@ class Architecture(object): 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, il): + def perform_get_flag_condition_low_level_il(self, cond, sem_class, il): """ - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``get_flag_condition_low_level_il``. - :param LowLevelILFlagCondition cond: - :param LowLevelILFunction 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, il) + return self.get_default_flag_condition_low_level_il(cond, sem_class, il) @abc.abstractmethod - def perform_assemble(self, code, addr): + def perform_get_semantic_flag_group_low_level_il(self, sem_group, il): """ - ``perform_assemble`` implements a method to convert the string of assembly instructions ``code`` loaded at - virtual address ``addr`` to the byte representation of those instructions. This can be done by simply shelling - out to an assembler like yasm or llvm-mc, since this method isn't performance sensitive. + Deprecated method provided for compatibility. Architecture plugins should override ``get_semantic_flag_group_low_level_il``. - .. note:: Architecture subclasses should implement this method. - .. note :: It is important that the assembler used accepts a syntax identical to the one emitted by the \ - disassembler. This will prevent confusing the user. - .. warning:: This method should never be called directly. + :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 ``assemble``. :param str code: string representation of the instructions to be assembled :param int addr: virtual address that the instructions will be loaded at @@ -992,8 +1281,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_never_branch_patch_available(self, data, addr): """ - ``perform_is_never_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a branch instruction that can be made to never branch. + Deprecated method provided for compatibility. Architecture plugins should override ``is_never_branch_patch_available``. .. note:: Architecture subclasses should implement this method. .. warning:: This method should never be called directly. @@ -1008,11 +1296,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_always_branch_patch_available(self, data, addr): """ - ``perform_is_always_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a conditional branch that can be made unconditional. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``is_always_branch_patch_available``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1024,11 +1308,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_invert_branch_patch_available(self, data, addr): """ - ``perform_is_invert_branch_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a conditional branch which can be inverted. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``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 @@ -1039,13 +1319,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_skip_and_return_zero_patch_available(self, data, addr): """ - ``perform_is_skip_and_return_zero_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a *call-like* instruction which can made into instructions - that are equivilent to "return 0". For example if ``data`` was the x86 instruction ``call eax`` which could be - converted into ``xor eax,eax`` thus this function would return True. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``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 @@ -1057,13 +1331,7 @@ class Architecture(object): @abc.abstractmethod def perform_is_skip_and_return_value_patch_available(self, data, addr): """ - ``perform_is_skip_and_return_value_patch_available`` implements a check to determine if the instruction represented by - the bytes contained in ``data`` at address addr is a *call-like* instruction which can made into instructions - that are equivilent to "return 0". For example if ``data`` was the x86 instruction ``call 0xdeadbeef`` which could be - converted into ``mov eax, 42`` thus this function would return True. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``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 @@ -1075,10 +1343,7 @@ class Architecture(object): @abc.abstractmethod def perform_convert_to_nop(self, data, addr): """ - ``perform_convert_to_nop`` implements a method which returns a nop sequence of len(data) bytes long. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``convert_to_nop``. :param str data: bytes at virtual address ``addr`` :param int addr: the virtual address of the instruction to be patched @@ -1090,11 +1355,7 @@ class Architecture(object): @abc.abstractmethod def perform_always_branch(self, data, addr): """ - ``perform_always_branch`` implements a method which converts the branch represented by the bytes in ``data`` to - at ``addr`` to an unconditional branch. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``always_branch``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1106,11 +1367,7 @@ class Architecture(object): @abc.abstractmethod def perform_invert_branch(self, data, addr): """ - ``perform_invert_branch`` implements a method which inverts the branch represented by the bytes in ``data`` to - at ``addr``. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``invert_branch``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1122,12 +1379,7 @@ class Architecture(object): @abc.abstractmethod def perform_skip_and_return_value(self, data, addr, value): """ - ``perform_skip_and_return_value`` implements a method which converts a *call-like* instruction represented by - the bytes in ``data`` at ``addr`` to one or more instructions that are equivilent to a function returning a - value. - - .. note:: Architecture subclasses should implement this method. - .. warning:: This method should never be called directly. + Deprecated method provided for compatibility. Architecture plugins should override ``skip_and_return_value``. :param str data: bytes to be checked :param int addr: the virtual address of the instruction to be patched @@ -1137,76 +1389,70 @@ class Architecture(object): """ return None + def perform_get_flag_role(self, flag, sem_class): + """ + Deprecated method provided for compatibility. Architecture plugins should override ``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 ``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): - new_addr = ctypes.c_ulonglong() - new_addr.value = addr - result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) - return Architecture(handle = result), new_addr.value + return self.perform_get_associated_arch_by_address(addr) def get_instruction_info(self, data, addr): """ ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address ``addr`` with data ``data``. + .. note:: Architecture subclasses should implement this method. + .. note :: The instruction info object should always set the InstructionInfo.length to the instruction length, \ and the branches of the proper types shoulde be added if the instruction is a branch. + If the instruction is a branch instruction architecture plugins should add a branch of the proper type: + + ===================== =================================================== + BranchType Description + ===================== =================================================== + UnconditionalBranch Branch will always be taken + FalseBranch False branch condition + TrueBranch True branch condition + CallDestination Branch is a call instruction (Branch with Link) + FunctionReturn Branch returns from a function + SystemCall System call instruction + IndirectBranch Branch destination is a memory address or register + UnresolvedBranch Branch destination is an unknown address + ===================== =================================================== + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :return: the InstructionInfo for the current instruction :rtype: InstructionInfo """ - info = core.BNInstructionInfo() - data = str(data) - 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 = function.InstructionInfo() - result.length = info.length - result.arch_transition_by_target_addr = info.archTransitionByTargetAddr - result.branch_delay = info.branchDelay - for i in xrange(0, info.branchCount): - target = info.branchTarget[i] - if info.branchArch[i]: - arch = Architecture(info.branchArch[i]) - else: - arch = None - result.add_branch(BranchType(info.branchType[i]), target, arch) - return result + return self.perform_get_instruction_info(data, addr) def get_instruction_text(self, data, addr): """ ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual address ``addr`` with data ``data``. + .. note:: Architecture subclasses should implement this method. + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` :param int addr: virtual address of bytes in ``data`` :return: an InstructionTextToken list for the current instruction :rtype: list(InstructionTextToken) """ - data = str(data) - count = ctypes.c_ulonglong() - length = ctypes.c_ulonglong() - length.value = len(data) - 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 = [] - for i in xrange(0, count.value): - token_type = InstructionTextTokenType(tokens[i].type) - text = tokens[i].text - value = tokens[i].value - size = tokens[i].size - operand = tokens[i].operand - context = tokens[i].context - confidence = tokens[i].confidence - address = tokens[i].address - result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - core.BNFreeInstructionText(tokens, count.value) - return result, length.value + return self.perform_get_instruction_text(data, addr) def get_instruction_low_level_il_instruction(self, bv, addr): il = lowlevelil.LowLevelILFunction(self) @@ -1222,19 +1468,15 @@ class Architecture(object): This is used to analyze arbitrary data at an address, if you are working with an existing binary, you likely want to be using ``Function.get_low_level_il_at``. + .. note:: Architecture subclasses should implement this method. + :param str 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 """ - data = str(data) - 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) - return length.value + return self.perform_get_instruction_low_level_il(data, addr, il) def get_low_level_il_from_bytes(self, data, addr): """ @@ -1264,6 +1506,23 @@ class Architecture(object): """ return core.BNGetArchitectureRegisterName(self.handle, reg) + def get_reg_stack_name(self, reg_stack): + """ + ``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 + """ + return 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) + if result == 0xffffffff: + return None + return self.get_reg_stack_name(result) + def get_flag_name(self, flag): """ ``get_flag_name`` gets a flag name from a flag number. @@ -1281,6 +1540,13 @@ class Architecture(object): return reg.index return reg + def get_reg_stack_index(self, reg_stack): + if isinstance(reg_stack, str): + return self.reg_stacks[reg_stack].index + elif isinstance(reg_stack, lowlevelil.ILRegisterStack): + return reg_stack.index + return reg_stack + def get_flag_index(self, flag): if isinstance(flag, str): return self._flags[flag] @@ -1288,6 +1554,69 @@ class Architecture(object): return flag.index return flag + def get_semantic_flag_class_index(self, sem_class): + if sem_class is None: + return 0 + elif isinstance(sem_class, str): + return self._semantic_flag_classes[sem_class] + elif isinstance(sem_class, lowlevelil.ILSemanticFlagClass): + return sem_class.index + return sem_class + + def get_semantic_flag_class_name(self, class_index): + """ + ``get_semantic_flag_class_name`` gets the name of a semantic flag class from the index. + + :param int _index: class_index + :return: the name of the semantic flag class + :rtype: str + """ + if not isinstance(class_index, (int, long)): + 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): + 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): + """ + ``get_semantic_flag_group_name`` gets the name of a semantic flag group from the index. + + :param int group_index: group_index + :return: the name of the semantic flag group + :rtype: str + """ + if not isinstance(group_index, (int, long)): + 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): + """ + ``get_intrinsic_name`` gets an intrinsic name from an intrinsic number. + + :param int intrinsic: intrinsic number + :return: the corresponding intrinsic string + :rtype: str + """ + return core.BNGetArchitectureIntrinsicName(self.handle, intrinsic) + + def get_intrinsic_index(self, intrinsic): + if isinstance(intrinsic, str): + return self._intrinsics[intrinsic] + elif isinstance(intrinsic, lowlevelil.ILIntrinsic): + return intrinsic.index + return intrinsic + def get_flag_write_type_name(self, write_type): """ ``get_flag_write_type_name`` gets the flag write type name for the given flag. @@ -1318,6 +1647,37 @@ class Architecture(object): """ return self._flag_write_types[write_type] + def get_semantic_flag_class_by_name(self, sem_class): + """ + ``get_semantic_flag_class_by_name`` gets the semantic flag class index by name. + + :param int sem_class: semantic flag class + :return: semantic flag class index + :rtype: str + """ + return self._semantic_flag_classes[sem_class] + + def get_semantic_flag_group_by_name(self, sem_group): + """ + ``get_semantic_flag_group_by_name`` gets the semantic flag group index by name. + + :param int sem_group: semantic flag group + :return: semantic flag group index + :rtype: str + """ + return self._semantic_flag_groups[sem_group] + + def get_flag_role(self, flag, sem_class = None): + """ + ``get_flag_role`` gets the role of a given flag. + + :param int flag: flag + :param int sem_class: optional semantic flag class + :return: flag role + :rtype: FlagRole + """ + return self.perform_get_flag_role(flag, sem_class) + def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): """ :param LowLevelILOperation op: @@ -1328,20 +1688,7 @@ class Architecture(object): :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - flag = self.get_flag_index(flag) - operand_list = (core.BNRegisterOrConstant * len(operands))() - for i in xrange(len(operands)): - if isinstance(operands[i], str): - operand_list[i].constant = False - operand_list[i].reg = self.regs[operands[i]].index - elif isinstance(operands[i], lowlevelil.ILRegister): - operand_list[i].constant = False - operand_list[i].reg = operands[i].index - else: - operand_list[i].constant = True - operand_list[i].value = operands[i] - return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagWriteLowLevelIL(self.handle, op, size, - self._flag_write_types[write_type], flag, operand_list, len(operand_list), il.handle)) + return self.perform_get_flag_write_low_level_il(op, size, write_type, flag, operands, il) def get_default_flag_write_low_level_il(self, op, size, role, operands, il): """ @@ -1367,21 +1714,35 @@ class Architecture(object): 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, il): + def get_flag_condition_low_level_il(self, cond, sem_class, 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.perform_get_flag_condition_low_level_il(cond, sem_class, il) + + def get_default_flag_condition_low_level_il(self, cond, sem_class, il): """ :param LowLevelILFlagCondition cond: :param LowLevelILFunction il: + :param str sem_class: :rtype: LowLevelILExpr """ - return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, il.handle)) + class_index = self.get_semantic_flag_class_index(sem_class) + return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, class_index, il.handle)) - def get_default_flag_condition_low_level_il(self, cond, il): + def get_semantic_flag_group_low_level_il(self, sem_group, il): """ - :param LowLevelILFlagCondition cond: + :param str sem_group: :param LowLevelILFunction il: :rtype: LowLevelILExpr """ - return lowlevelil.LowLevelILExpr(core.BNGetDefaultArchitectureFlagConditionLowLevelIL(self.handle, cond, il.handle)) + return self.perform_get_semantic_flag_group_low_level_il(sem_group, il) + + 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_modified_regs_on_write(self, reg): """ @@ -1405,6 +1766,648 @@ class Architecture(object): ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the byte representation of those instructions. + .. note:: Architecture subclasses should implement this method. + + Architecture plugins can override this method to provide assembler functionality. This can be done by + simply shelling out to an assembler like yasm or llvm-mc, since this method isn't performance sensitive. + + .. note :: It is important that the assembler used accepts a syntax identical to the one emitted by the \ + disassembler. This will prevent confusing the user. + + :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) + :Example: + + >>> arch.assemble("je 10") + ('\\x0f\\x84\\x04\\x00\\x00\\x00', '') + >>> + """ + return self.perform_assemble(code, addr) + + def is_never_branch_patch_available(self, data, addr): + """ + ``is_never_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to **never branch**. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction 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 + :Example: + + >>> arch.is_never_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_never_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + return self.perform_is_never_branch_patch_available(data, addr) + + def is_always_branch_patch_available(self, data, addr): + """ + ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be made to + **always branch**. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction 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 + :Example: + + >>> arch.is_always_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_always_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + return self.perform_is_always_branch_patch_available(data, addr) + + def is_invert_branch_patch_available(self, data, addr): + """ + ``is_always_branch_patch_available`` determines if the instruction ``data`` at ``addr`` can be inverted. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction 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 + :Example: + + >>> arch.is_invert_branch_patch_available(arch.assemble("je 10")[0], 0) + True + >>> arch.is_invert_branch_patch_available(arch.assemble("nop")[0], 0) + False + >>> + """ + return self.perform_is_invert_branch_patch_available(data, addr) + + def is_skip_and_return_zero_patch_available(self, data, addr): + """ + ``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*. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction 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 + :Example: + + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call 0")[0], 0) + True + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call eax")[0], 0) + True + >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("jmp eax")[0], 0) + False + >>> + """ + return self.perform_is_skip_and_return_zero_patch_available(data, addr) + + def is_skip_and_return_value_patch_available(self, data, addr): + """ + ``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*. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction 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 + :Example: + + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("call 0")[0], 0) + True + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("jmp eax")[0], 0) + False + >>> + """ + return self.perform_is_skip_and_return_value_patch_available(data, addr) + + def convert_to_nop(self, data, addr): + """ + ``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. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) worth of no-operation instructions + :rtype: str + :Example: + + >>> arch.convert_to_nop("\\x00\\x00", 0) + '\\x90\\x90' + >>> + """ + return self.perform_convert_to_nop(data, addr) + + def always_branch(self, data, addr): + """ + ``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. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> bytes = arch.always_branch(arch.assemble("je 10")[0], 0) + >>> arch.get_instruction_text(bytes, 0) + (['nop '], 1L) + >>> arch.get_instruction_text(bytes[1:], 0) + (['jmp ', '0x9'], 5L) + >>> + """ + return self.perform_always_branch(data, addr) + + def invert_branch(self, data, addr): + """ + ``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. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("je 10")[0], 0), 0) + (['jne ', '0xa'], 6L) + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("jo 10")[0], 0), 0) + (['jno ', '0xa'], 6L) + >>> arch.get_instruction_text(arch.invert_branch(arch.assemble("jge 10")[0], 0), 0) + (['jl ', '0xa'], 6L) + >>> + """ + return self.perform_invert_branch(data, addr) + + def skip_and_return_value(self, data, addr, value): + """ + ``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*. + + .. note:: Architecture subclasses should implement this method. + + :param str data: bytes for the instruction to be converted + :param int addr: the virtual address of the instruction to be patched + :return: string containing len(data) which always branches to the same location as the provided instruction + :rtype: str + :Example: + + >>> arch.get_instruction_text(arch.skip_and_return_value(arch.assemble("call 10")[0], 0, 0), 0) + (['mov ', 'eax', ', ', '0x0'], 5L) + >>> + """ + return self.perform_skip_and_return_value(data, addr, value) + + def is_view_type_constant_defined(self, type_name, const_name): + """ + + :param str type_name: the BinaryView type name of the constant to query + :param str const_name: the constant name to query + :rtype: None + :Example: + + >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) + >>> arch.is_view_type_constant_defined("ELF", "R_COPY") + True + >>> arch.is_view_type_constant_defined("ELF", "NOT_THERE") + False + >>> + """ + return core.BNIsBinaryViewTypeArchitectureConstantDefined(self.handle, type_name, const_name) + + def get_view_type_constant(self, type_name, const_name, default_value=0): + """ + ``get_view_type_constant`` retrieves the view type constant for the given type_name and const_name. + + :param str type_name: the BinaryView type name of the constant to be retrieved + :param str const_name: the constant name to retrieved + :param int value: optional default value if the type_name is not present. default value is zero. + :return: The BinaryView type constant or the default_value if not found + :rtype: int + :Example: + + >>> ELF_RELOC_COPY = 5 + >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) + >>> arch.get_view_type_constant("ELF", "R_COPY") + 5L + >>> arch.get_view_type_constant("ELF", "NOT_HERE", 100) + 100L + """ + return core.BNGetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, default_value) + + def set_view_type_constant(self, type_name, const_name, value): + """ + ``set_view_type_constant`` creates a new binaryview type constant. + + :param str type_name: the BinaryView type name of the constant to be registered + :param str const_name: the constant name to register + :param int value: the value of the constant + :rtype: None + :Example: + + >>> ELF_RELOC_COPY = 5 + >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) + >>> + """ + core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) + + def register_calling_convention(self, cc): + """ + ``register_calling_convention`` registers a new calling convention for the Architecture. + + :param CallingConvention cc: CallingConvention object to be registered + :rtype: None + """ + core.BNRegisterCallingConvention(self.handle, cc.handle) + + +_architecture_cache = {} +class CoreArchitecture(Architecture): + def __init__(self, handle): + 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, + core.BNGetArchitectureStackPointerRegister(self.handle)) + + link_reg = core.BNGetArchitectureLinkRegister(self.handle) + if link_reg == 0xffffffff: + self.__dict__["link_reg"] = None + else: + self.__dict__["link_reg"] = core.BNGetArchitectureRegisterName(self.handle, link_reg) + + count = ctypes.c_ulonglong() + regs = core.BNGetAllArchitectureRegisters(self.handle, count) + self._all_regs = {} + self._regs_by_index = {} + self._full_width_regs = {} + self.__dict__["regs"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureRegisterName(self.handle, regs[i]) + info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) + full_width_reg = core.BNGetArchitectureRegisterName(self.handle, info.fullWidthRegister) + self.regs[name] = function.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 xrange(0, count.value): + info = core.BNGetArchitectureRegisterInfo(self.handle, regs[i]) + full_width_reg = 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) + self._flags = {} + self._flags_by_index = {} + self.__dict__["flags"] = [] + for i in xrange(0, count.value): + name = core.BNGetArchitectureFlagName(self.handle, flags[i]) + self._flags[name] = flags[i] + self._flags_by_index[flags[i]] = name + self.flags.append(name) + core.BNFreeRegisterList(flags) + + count = ctypes.c_ulonglong() + write_types = core.BNGetAllArchitectureFlagWriteTypes(self.handle, count) + self._flag_write_types = {} + self._flag_write_types_by_index = {} + self.__dict__["flag_write_types"] = [] + for i in xrange(0, count.value): + name = 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) + core.BNFreeRegisterList(write_types) + + count = ctypes.c_ulonglong() + sem_classes = core.BNGetAllArchitectureSemanticFlagClasses(self.handle, count) + self._semantic_flag_classes = {} + self._semantic_flag_classes_by_index = {} + self.__dict__["semantic_flag_classes"] = [] + for i in xrange(0, count.value): + name = 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) + core.BNFreeRegisterList(sem_classes) + + count = ctypes.c_ulonglong() + sem_groups = core.BNGetAllArchitectureSemanticFlagGroups(self.handle, count) + self._semantic_flag_groups = {} + self._semantic_flag_groups_by_index = {} + self.__dict__["semantic_flag_groups"] = [] + for i in xrange(0, count.value): + name = 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"]: + role = FlagRole(core.BNGetArchitectureFlagRole(self.handle, self._flags[flag], 0)) + self.__dict__["flag_roles"][flag] = role + self._flag_roles[self._flags[flag]] = role + + self.__dict__["flags_required_for_flag_condition"] = {} + for cond in LowLevelILFlagCondition: + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, 0, count) + flag_names = [] + for i in xrange(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_by_semantic_flag_group = {} + self.__dict__["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) + flag_indexes = [] + flag_names = [] + for i in xrange(0, count.value): + flag_indexes.append(flags[i]) + 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._flag_conditions_for_semantic_flag_group = {} + self.__dict__["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) + class_index_cond = {} + class_cond = {} + for i in xrange(0, count.value): + class_index_cond[conditions[i].semanticClass] = conditions[i].condition + if conditions[i].semanticClass == 0: + class_cond[None] = conditions[i].condition + elif conditions[i].semanticClass in self._semantic_flag_classes_by_index: + 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._flags_written_by_flag_write_type = {} + self.__dict__["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) + flag_indexes = [] + flag_names = [] + for i in xrange(0, count.value): + flag_indexes.append(flags[i]) + 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._semantic_class_for_flag_write_type = {} + self.__dict__["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]) + if sem_class == 0: + sem_class_name = None + 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 + + count = ctypes.c_ulonglong() + regs = core.BNGetArchitectureGlobalRegisters(self.handle, count) + self.__dict__["global_regs"] = [] + for i in xrange(0, count.value): + self.global_regs.append(core.BNGetArchitectureRegisterName(self.handle, regs[i])) + core.BNFreeRegisterList(regs) + + count = ctypes.c_ulonglong() + regs = core.BNGetAllArchitectureRegisterStacks(self.handle, count) + self._all_reg_stacks = {} + self._reg_stacks_by_index = {} + self.__dict__["reg_stacks"] = {} + for i in xrange(0, count.value): + name = core.BNGetArchitectureRegisterStackName(self.handle, regs[i]) + info = core.BNGetArchitectureRegisterStackInfo(self.handle, regs[i]) + storage = [] + for j in xrange(0, info.storageCount): + storage.append(core.BNGetArchitectureRegisterName(self.handle, info.firstStorageReg + j)) + top_rel = [] + for j in xrange(0, info.topRelativeCount): + top_rel.append(core.BNGetArchitectureRegisterName(self.handle, info.firstTopRelativeReg + j)) + top = core.BNGetArchitectureRegisterName(self.handle, info.stackTopReg) + self.reg_stacks[name] = function.RegisterStackInfo(storage, top_rel, 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 xrange(0, count.value): + name = core.BNGetArchitectureIntrinsicName(self.handle, intrinsics[i]) + input_count = ctypes.c_ulonglong() + inputs = core.BNGetArchitectureIntrinsicInputs(self.handle, intrinsics[i], input_count) + input_list = [] + for j in xrange(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(function.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) + output_list = [] + for j in xrange(0, 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] = function.IntrinsicInfo(input_list, output_list) + self._intrinsics[name] = intrinsics[i] + self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name]) + core.BNFreeRegisterList(intrinsics) + global _architecture_cache + _architecture_cache[ctypes.addressof(handle.contents)] = self + + @classmethod + def _from_cache(cls, handle): + global _architecture_cache + return _architecture_cache.get(ctypes.addressof(handle.contents)) or cls(handle) + + def get_associated_arch_by_address(self, addr): + 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): + """ + ``get_instruction_info`` returns an InstructionInfo object for the instruction at the given virtual address + ``addr`` with data ``data``. + + .. note :: The instruction info object should always set the InstructionInfo.length to the instruction length, \ + and the branches of the proper types shoulde be added if the instruction is a branch. + + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param int addr: virtual address of bytes in ``data`` + :return: the InstructionInfo for the current instruction + :rtype: InstructionInfo + """ + info = core.BNInstructionInfo() + data = str(data) + 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 = function.InstructionInfo() + result.length = info.length + result.arch_transition_by_target_addr = info.archTransitionByTargetAddr + result.branch_delay = info.branchDelay + for i in xrange(0, info.branchCount): + target = info.branchTarget[i] + if info.branchArch[i]: + arch = CoreArchitecture._from_cache(info.branchArch[i]) + else: + arch = None + result.add_branch(BranchType(info.branchType[i]), target, arch) + return result + + def get_instruction_text(self, data, addr): + """ + ``get_instruction_text`` returns a list of InstructionTextToken objects for the instruction at the given virtual + address ``addr`` with data ``data``. + + :param str data: max_instruction_length bytes from the binary at virtual address ``addr`` + :param int addr: virtual address of bytes in ``data`` + :return: an InstructionTextToken list for the current instruction + :rtype: list(InstructionTextToken) + """ + data = str(data) + count = ctypes.c_ulonglong() + length = ctypes.c_ulonglong() + length.value = len(data) + 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 = [] + for i in xrange(0, count.value): + token_type = InstructionTextTokenType(tokens[i].type) + text = tokens[i].text + value = tokens[i].value + size = tokens[i].size + operand = tokens[i].operand + context = tokens[i].context + confidence = tokens[i].confidence + address = tokens[i].address + result.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) + core.BNFreeInstructionText(tokens, count.value) + return result, length.value + + def get_instruction_low_level_il(self, data, addr, il): + """ + ``get_instruction_low_level_il`` appends LowLevelILExpr objects to ``il`` for the instruction at the given + virtual address ``addr`` with data ``data``. + + This is used to analyze arbitrary data at an address, if you are working with an existing binary, you likely + want to be using ``Function.get_low_level_il_at``. + + :param str 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 + """ + data = str(data) + 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) + return length.value + + def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + """ + :param LowLevelILOperation op: + :param int size: + :param str write_type: + :param list(str or int) operands: a list of either items that are either string register names or constant \ + integer values + :param LowLevelILFunction il: + :rtype: LowLevelILExpr + """ + flag = self.get_flag_index(flag) + operand_list = (core.BNRegisterOrConstant * len(operands))() + for i in xrange(len(operands)): + if isinstance(operands[i], str): + operand_list[i].constant = False + operand_list[i].reg = self.regs[operands[i]].index + elif isinstance(operands[i], lowlevelil.ILRegister): + operand_list[i].constant = False + operand_list[i].reg = operands[i].index + else: + operand_list[i].constant = True + operand_list[i].value = operands[i] + 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): + """ + :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 + """ + class_index = self.get_semantic_flag_class_index(sem_class) + return lowlevelil.LowLevelILExpr(core.BNGetArchitectureFlagConditionLowLevelIL(self.handle, cond, + class_index, il.handle)) + + def get_semantic_flag_group_low_level_il(self, sem_group, il): + """ + :param str sem_group: + :param LowLevelILFunction il: + :rtype: LowLevelILExpr + """ + 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): + """ + ``assemble`` converts the string of assembly instructions ``code`` loaded at virtual address ``addr`` to the + byte representation of those instructions. + :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 @@ -1511,7 +2514,7 @@ class Architecture(object): def is_skip_and_return_value_patch_available(self, data, addr): """ - ``is_skip_and_return_zero_patch_available`` determines if the instruction ``data`` at ``addr`` is a *call-like* + ``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*. :param str data: bytes for the instruction to be checked @@ -1520,9 +2523,9 @@ class Architecture(object): :rtype: bool :Example: - >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("call 0")[0], 0) + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("call 0")[0], 0) True - >>> arch.is_skip_and_return_zero_patch_available(arch.assemble("jmp eax")[0], 0) + >>> arch.is_skip_and_return_value_patch_available(arch.assemble("jmp eax")[0], 0) False >>> """ @@ -1634,67 +2637,62 @@ class Architecture(object): ctypes.memmove(result, buf, len(data)) return result.raw - def is_view_type_constant_defined(self, type_name, const_name): - """ - - :param str type_name: the BinaryView type name of the constant to query - :param str const_name: the constant name to query - :rtype: None - :Example: - - >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) - >>> arch.is_view_type_constant_defined("ELF", "R_COPY") - True - >>> arch.is_view_type_constant_defined("ELF", "NOT_THERE") - False - >>> + def get_flag_role(self, flag, sem_class = None): """ - return core.BNIsBinaryViewTypeArchitectureConstantDefined(self.handle, type_name, const_name) + ``get_flag_role`` gets the role of a given flag. - def get_view_type_constant(self, type_name, const_name, default_value=0): + :param int flag: flag + :param int sem_class: optional semantic flag class + :return: flag role + :rtype: FlagRole """ - ``get_view_type_constant`` retrieves the view type constant for the given type_name and const_name. - - :param str type_name: the BinaryView type name of the constant to be retrieved - :param str const_name: the constant name to retrieved - :param int value: optional default value if the type_name is not present. default value is zero. - :return: The BinaryView type constant or the default_value if not found - :rtype: int - :Example: - - >>> ELF_RELOC_COPY = 5 - >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) - >>> arch.get_view_type_constant("ELF", "R_COPY") - 5L - >>> arch.get_view_type_constant("ELF", "NOT_HERE", 100) - 100L - """ - return core.BNGetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, default_value) + 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 set_view_type_constant(self, type_name, const_name, value): - """ - ``set_view_type_constant`` creates a new binaryview type constant. + def get_flags_required_for_flag_condition(self, cond, sem_class = None): + sem_class = self.get_semantic_flag_class_index(sem_class) + count = ctypes.c_ulonglong() + flags = core.BNGetArchitectureFlagsRequiredForFlagCondition(self.handle, cond, sem_class, count) + flag_names = [] + for i in xrange(0, count.value): + flag_names.append(self._flags_by_index[flags[i]]) + core.BNFreeRegisterList(flags) + return flag_names - :param str type_name: the BinaryView type name of the constant to be registered - :param str const_name: the constant name to register - :param int value: the value of the constant - :rtype: None - :Example: - >>> ELF_RELOC_COPY = 5 - >>> arch.set_view_type_constant("ELF", "R_COPY", ELF_RELOC_COPY) - >>> - """ - core.BNSetBinaryViewTypeArchitectureConstant(self.handle, type_name, const_name, value) +class ArchitectureHook(CoreArchitecture): + def __init__(self, base_arch): + self.base_arch = base_arch + super(ArchitectureHook, self).__init__(base_arch.handle) - def register_calling_convention(self, cc): - """ - ``register_calling_convention`` registers a new calling convention for the Architecture. + # To improve performance of simpler hooks, use null callback for functions that are not being overridden + if self.get_associated_arch_by_address.__code__ == CoreArchitecture.get_associated_arch_by_address.__code__: + self._cb.getAssociatedArchitectureByAddress = self._cb.getAssociatedArchitectureByAddress.__class__() + if self.get_instruction_info.__code__ == CoreArchitecture.get_instruction_info.__code__: + self._cb.getInstructionInfo = self._cb.getInstructionInfo.__class__() + if self.get_instruction_text.__code__ == CoreArchitecture.get_instruction_text.__code__: + self._cb.getInstructionText = self._cb.getInstructionText.__class__() + if self.__class__.stack_pointer is None: + self._cb.getStackPointerRegister = self._cb.getStackPointerRegister.__class__() + if self.__class__.link_reg is None: + self._cb.getLinkRegister = self._cb.getLinkRegister.__class__() + if len(self.__class__.regs) == 0: + self._cb.getRegisterInfo = self._cb.getRegisterInfo.__class__() + self._cb.getRegisterName = self._cb.getRegisterName.__class__() + if len(self.__class__.reg_stacks) == 0: + self._cb.getRegisterStackName = self._cb.getRegisterStackName.__class__() + self._cb.getRegisterStackInfo = self._cb.getRegisterStackInfo.__class__() + if len(self.__class__.intrinsics) == 0: + self._cb.getIntrinsicName = self._cb.getIntrinsicName.__class__() + self._cb.getIntrinsicInputs = self._cb.getIntrinsicInputs.__class__() + self._cb.freeNameAndTypeList = self._cb.freeNameAndTypeList.__class__() + self._cb.getIntrinsicOutputs = self._cb.getIntrinsicOutputs.__class__() + self._cb.freeTypeList = self._cb.freeTypeList.__class__() - :param CallingConvention cc: CallingConvention object to be registered - :rtype: None - """ - core.BNRegisterCallingConvention(self.handle, cc.handle) + def register(self): + self.__class__._registered_cb = self._cb + self.handle = core.BNRegisterArchitectureHook(self.base_arch.handle, self._cb) class ReferenceSource(object): diff --git a/python/basicblock.py b/python/basicblock.py index 8e64c1c1..4dc783c3 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -100,7 +100,7 @@ class BasicBlock(object): arch = core.BNGetBasicBlockArchitecture(self.handle) if arch is None: return None - self._arch = architecture.Architecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property @@ -256,6 +256,21 @@ class BasicBlock(object): def highlight(self, value): self.set_user_highlight(value) + @property + def is_il(self): + """Whether the basic block contains IL""" + return core.BNIsILBasicBlock(self.handle) + + @property + def is_low_level_il(self): + """Whether the basic block contains Low Level IL""" + return core.BNIsLowLevelILBasicBlock(self.handle) + + @property + def is_medium_level_il(self): + """Whether the basic block contains Medium Level IL""" + return core.BNIsMediumLevelILBasicBlock(self.handle) + @classmethod def get_iterated_dominance_frontier(self, blocks): if len(blocks) == 0: @@ -322,6 +337,10 @@ class BasicBlock(object): result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(self, 'il_function'): + il_instr = self.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -333,7 +352,7 @@ class BasicBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(function.DisassemblyTextLine(addr, tokens)) + result.append(function.DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result diff --git a/python/binaryview.py b/python/binaryview.py index 19bff9e5..0b090a9a 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -65,6 +65,9 @@ class BinaryDataNotification(object): def function_updated(self, view, func): pass + def function_update_requested(self, view, func): + pass + def data_var_added(self, view, var): pass @@ -105,7 +108,8 @@ class StringReference(object): class AnalysisCompletionEvent(object): """ The ``AnalysisCompletionEvent`` object provides an asynchronous mechanism for receiving - callbacks when analysis is complete. + callbacks when analysis is complete. The callback runs once. A completion event must be added + for each new analysis in order to be notified of each analysis completion. :Example: >>> def on_complete(self): @@ -180,6 +184,7 @@ class BinaryDataNotificationCallbacks(object): self._cb.functionAdded = self._cb.functionAdded.__class__(self._function_added) self._cb.functionRemoved = self._cb.functionRemoved.__class__(self._function_removed) self._cb.functionUpdated = self._cb.functionUpdated.__class__(self._function_updated) + self._cb.functionUpdateRequested = self._cb.functionUpdateRequested.__class__(self._function_update_requested) self._cb.dataVariableAdded = self._cb.dataVariableAdded.__class__(self._data_var_added) self._cb.dataVariableRemoved = self._cb.dataVariableRemoved.__class__(self._data_var_removed) self._cb.dataVariableUpdated = self._cb.dataVariableUpdated.__class__(self._data_var_updated) @@ -230,6 +235,12 @@ class BinaryDataNotificationCallbacks(object): except: log.log_error(traceback.format_exc()) + def _function_update_requested(self, ctxt, view, func): + try: + self.notify.function_update_requested(self.view, function.Function(self.view, core.BNNewFunctionReference(func))) + except: + log.log_error(traceback.format_exc()) + def _data_var_added(self, ctxt, view, var): try: address = var[0].address @@ -400,7 +411,7 @@ class BinaryViewType(object): arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) if arch is None: return None - return architecture.Architecture(arch) + return architecture.CoreArchitecture._from_cache(arch) def register_platform(self, ident, arch, plat): core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) @@ -857,7 +868,7 @@ class BinaryView(object): arch = core.BNGetDefaultArchitecture(self.handle) if arch is None: return None - return architecture.Architecture(handle=arch) + return architecture.CoreArchitecture._from_cache(handle=arch) @arch.setter def arch(self, value): @@ -1054,6 +1065,15 @@ class BinaryView(object): result = core.BNGetGlobalPointerValue(self.handle) return function.RegisterValue(self.arch, result.value, confidence = result.confidence) + @property + def max_function_size_for_analysis(self): + """Maximum size of function (sum of basic block sizes in bytes) for auto analysis""" + return core.BNGetMaxFunctionSizeForAnalysis(self.handle) + + @max_function_size_for_analysis.setter + def max_function_size_for_analysis(self, size): + core.BNSetMaxFunctionSizeForAnalysis(self.handle, size) + def __len__(self): return int(core.BNGetViewLength(self.handle)) @@ -2146,6 +2166,8 @@ class BinaryView(object): """ if plat is None: plat = self.platform + if plat is None: + return None func = core.BNGetAnalysisFunction(self.handle, plat.handle, addr) if func is None: return None @@ -2240,7 +2262,7 @@ class BinaryView(object): else: func = None if refs[i].arch: - arch = architecture.Architecture(refs[i].arch) + arch = architecture.CoreArchitecture._from_cache(refs[i].arch) else: arch = None addr = refs[i].addr diff --git a/python/callingconvention.py b/python/callingconvention.py index e72475c9..e3ec7261 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -28,6 +28,7 @@ import log import types import function import binaryview +from enums import VariableSourceType class CallingConvention(object): @@ -68,11 +69,13 @@ class CallingConvention(object): self._cb.getImplicitlyDefinedRegisters = self._cb.getImplicitlyDefinedRegisters.__class__(self._get_implicitly_defined_regs) self._cb.getIncomingRegisterValue = self._cb.getIncomingRegisterValue.__class__(self._get_incoming_reg_value) self._cb.getIncomingFlagValue = self._cb.getIncomingFlagValue.__class__(self._get_incoming_flag_value) + self._cb.getIncomingVariableForParameterVariable = self._cb.getIncomingVariableForParameterVariable.__class__(self._get_incoming_var_for_parameter_var) + self._cb.getParameterVariableForIncomingVariable = self._cb.getParameterVariableForIncomingVariable.__class__(self._get_parameter_var_for_incoming_var) self.handle = core.BNCreateCallingConvention(arch.handle, name, self._cb) self.__class__._registered_calling_conventions.append(self) else: self.handle = handle - self.arch = architecture.Architecture(core.BNGetCallingConventionArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(self.handle)) self.__dict__["name"] = core.BNGetCallingConventionName(self.handle) self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle) self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle) @@ -301,6 +304,42 @@ class CallingConvention(object): result[0].state = api_obj.state result[0].value = api_obj.value + def _get_incoming_var_for_parameter_var(self, ctxt, in_var, func, result): + try: + if func is None: + func_obj = None + else: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage) + out_var = self.perform_get_incoming_var_for_parameter_var(in_var_obj, func_obj) + result[0].type = out_var.source_type + result[0].index = out_var.index + result[0].storage = out_var.storage + except: + log.log_error(traceback.format_exc()) + result[0].type = in_var[0].type + result[0].index = in_var[0].index + result[0].storage = in_var[0].storage + + def _get_parameter_var_for_incoming_var(self, ctxt, in_var, func, result): + try: + if func is None: + func_obj = None + else: + func_obj = function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), + core.BNNewFunctionReference(func)) + in_var_obj = function.Variable(func_obj, in_var[0].type, in_var[0].index, in_var[0].storage) + out_var = self.perform_get_parameter_var_for_incoming_var(in_var_obj, func_obj) + result[0].type = out_var.source_type + result[0].index = out_var.index + result[0].storage = out_var.storage + except: + log.log_error(traceback.format_exc()) + result[0].type = in_var[0].type + result[0].index = in_var[0].index + result[0].storage = in_var[0].storage + def __repr__(self): return "<calling convention: %s %s>" % (self.arch.name, self.name) @@ -308,11 +347,34 @@ class CallingConvention(object): return self.name def perform_get_incoming_reg_value(self, reg, func): + reg_stack = self.arch.get_reg_stack_for_reg(reg) + if reg_stack is not None: + if reg == self.arch.reg_stacks[reg_stack].stack_top_reg: + return function.RegisterValue.constant(0) return function.RegisterValue() def perform_get_incoming_flag_value(self, reg, func): return function.RegisterValue() + def perform_get_incoming_var_for_parameter_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_buf) + name = None + if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType): + name = func.arch.get_reg_name(out_var.storage) + return function.Variable(func, out_var.type, out_var.index, out_var.storage, name) + + def perform_get_parameter_var_for_incoming_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_buf) + return function.Variable(func, out_var.type, out_var.index, out_var.storage) + def with_confidence(self, confidence): return CallingConvention(self.arch, handle = core.BNNewCallingConventionReference(self.handle), confidence = confidence) @@ -330,3 +392,30 @@ class CallingConvention(object): if func is not None: func_handle = func.handle return function.RegisterValue(self.arch, core.BNGetIncomingFlagValue(self.handle, reg_num, func_handle)) + + def get_incoming_var_for_parameter_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + if func is None: + func_obj = None + else: + func_obj = func.handle + out_var = core.BNGetIncomingVariableForParameterVariable(self.handle, in_buf, func_obj) + name = None + if (func is not None) and (out_var.type == VariableSourceType.RegisterVariableSourceType): + name = func.arch.get_reg_name(out_var.storage) + return function.Variable(func, out_var.type, out_var.index, out_var.storage, name) + + def get_parameter_var_for_incoming_var(self, in_var, func): + in_buf = core.BNVariable() + in_buf.type = in_var.source_type + in_buf.index = in_var.index + in_buf.storage = in_var.storage + if func is None: + func_obj = None + else: + func_obj = func.handle + out_var = core.BNGetParameterVariableForIncomingVariable(self.handle, in_buf, func_obj) + return function.Variable(func, out_var.type, out_var.index, out_var.storage) diff --git a/python/examples/arch_hook.py b/python/examples/arch_hook.py new file mode 100644 index 00000000..452bd2b6 --- /dev/null +++ b/python/examples/arch_hook.py @@ -0,0 +1,16 @@ +from binaryninja.architecture import Architecture, ArchitectureHook + +class X86ReturnHook(ArchitectureHook): + def get_instruction_text(self, data, addr): + # Call the original implementation's method by calling the superclass + result, length = super(X86ReturnHook, self).get_instruction_text(data, addr) + + # Patch the name of the 'retn' instruction to 'ret' + if len(result) > 0 and result[0].text == 'retn': + result[0].text = 'ret' + + return result, length + +# Install the hook by constructing it with the desired architecture to hook, then registering it +X86ReturnHook(Architecture['x86']).register() + diff --git a/python/examples/nes.py b/python/examples/nes.py index 39544c9f..00451abd 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -423,7 +423,7 @@ class M6502(Architecture): return instr, operand, length, value - def perform_get_instruction_info(self, data, addr): + def get_instruction_info(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -445,7 +445,7 @@ class M6502(Architecture): result.add_branch(BranchType.FalseBranch, addr + 2) return result - def perform_get_instruction_text(self, data, addr): + def get_instruction_text(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -455,7 +455,7 @@ class M6502(Architecture): tokens += OperandTokens[operand](value) return tokens, length - def perform_get_instruction_low_level_il(self, data, addr, il): + def get_instruction_low_level_il(self, data, addr, il): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None @@ -470,48 +470,48 @@ class M6502(Architecture): return length - def perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): if flag == 'c': if (op == LowLevelILOperation.LLIL_SUB) or (op == LowLevelILOperation.LLIL_SBB): # Subtraction carry flag is inverted from the commom implementation return il.not_expr(0, self.get_default_flag_write_low_level_il(op, size, FlagRole.CarryFlagRole, operands, il)) # Other operations use a normal carry flag return self.get_default_flag_write_low_level_il(op, size, FlagRole.CarryFlagRole, operands, il) - return Architecture.perform_get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il) + return Architecture.get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il) - def perform_is_never_branch_patch_available(self, data, addr): + def is_never_branch_patch_available(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return True return False - def perform_is_invert_branch_patch_available(self, data, addr): + def is_invert_branch_patch_available(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return True return False - def perform_is_always_branch_patch_available(self, data, addr): + def is_always_branch_patch_available(self, data, addr): return False - def perform_is_skip_and_return_zero_patch_available(self, data, addr): + def is_skip_and_return_zero_patch_available(self, data, addr): return (data[0] == "\x20") and (len(data) == 3) - def perform_is_skip_and_return_value_patch_available(self, data, addr): + def is_skip_and_return_value_patch_available(self, data, addr): return (data[0] == "\x20") and (len(data) == 3) - def perform_convert_to_nop(self, data, addr): + def convert_to_nop(self, data, addr): return "\xea" * len(data) - def perform_never_branch(self, data, addr): + def never_branch(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return "\xea" * len(data) return None - def perform_invert_branch(self, data, addr): + def invert_branch(self, data, addr): if (data[0] == "\x10") or (data[0] == "\x30") or (data[0] == "\x50") or (data[0] == "\x70") or (data[0] == "\x90") or (data[0] == "\xb0") or (data[0] == "\xd0") or (data[0] == "\xf0"): return chr(ord(data[0]) ^ 0x20) + data[1:] return None - def perform_skip_and_return_value(self, data, addr, value): + def skip_and_return_value(self, data, addr, value): if (data[0] != "\x20") or (len(data) != 3): return None return "\xa9" + chr(value & 0xff) + "\xea" diff --git a/python/function.py b/python/function.py index 58bee8f4..6db44e6d 100644 --- a/python/function.py +++ b/python/function.py @@ -26,7 +26,8 @@ import ctypes import _binaryninjacore as core from enums import (FunctionGraphType, BranchType, SymbolType, InstructionTextTokenType, HighlightStandardColor, HighlightColorStyle, RegisterValueType, ImplicitRegisterExtend, - DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType) + DisassemblyOption, IntegerDisplayType, InstructionTextTokenContext, VariableSourceType, + FunctionAnalysisSkipOverride) import architecture import platform import highlight @@ -51,11 +52,11 @@ class LookupTableEntry(object): class RegisterValue(object): def __init__(self, arch = None, value = None, confidence = types.max_confidence): + self.is_constant = False if value is None: self.type = RegisterValueType.UndeterminedValue else: self.type = RegisterValueType(value.state) - self.is_constant = False if value.state == RegisterValueType.EntryValue: self.arch = arch if arch is not None: @@ -103,6 +104,54 @@ class RegisterValue(object): result.value = self.value return result + @classmethod + def undetermined(self): + return RegisterValue() + + @classmethod + def entry_value(self, arch, reg): + result = RegisterValue() + result.type = RegisterValueType.EntryValue + result.arch = arch + result.reg = reg + return result + + @classmethod + def constant(self, value): + result = RegisterValue() + result.type = RegisterValueType.ConstantValue + result.value = value + result.is_constant = True + return result + + @classmethod + def constant_ptr(self, value): + result = RegisterValue() + result.type = RegisterValueType.ConstantPointerValue + result.value = value + result.is_constant = True + return result + + @classmethod + def stack_frame_offset(self, offset): + result = RegisterValue() + result.type = RegisterValueType.StackFrameOffset + result.offset = offset + return result + + @classmethod + def imported_address(self, value): + result = RegisterValue() + result.type = RegisterValueType.ImportedAddressValue + result.value = value + return result + + @classmethod + def return_address(self): + result = RegisterValue() + result.type = RegisterValueType.ReturnAddressValue + return result + class ValueRange(object): def __init__(self, start, end, step): @@ -177,9 +226,9 @@ class PossibleValueSet(object): if self.type == RegisterValueType.LookupTableValue: return "<table: %s>" % ', '.join([repr(i) for i in self.table]) if self.type == RegisterValueType.InSetOfValues: - return "<in %s>" % repr(self.values) + return "<in set(%s)>" % '[{}]'.format(', '.join(hex(i) for i in self.values)) if self.type == RegisterValueType.NotInSetOfValues: - return "<not in %s>" % repr(self.values) + return "<not in set(%s)>" % '[{}]'.format(', '.join(hex(i) for i in self.values)) if self.type == RegisterValueType.ReturnAddressValue: return "<return address>" return "<undetermined>" @@ -219,14 +268,15 @@ class Variable(object): var.storage = storage self.identifier = core.BNToVariableIdentifier(var) - if name is None: - name = core.BNGetVariableName(func.handle, var) - if var_type is None: - var_type_conf = core.BNGetVariableType(func.handle, var) - if var_type_conf.type: - var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence) - else: - var_type = None + if func is not None: + if name is None: + name = core.BNGetVariableName(func.handle, var) + if var_type is None: + var_type_conf = core.BNGetVariableType(func.handle, var) + if var_type_conf.type: + var_type = types.Type(var_type_conf.type, platform = func.platform, confidence = var_type_conf.confidence) + else: + var_type = None self.name = name self.type = var_type @@ -370,7 +420,7 @@ class Function(object): arch = core.BNGetFunctionArchitecture(self.handle) if arch is None: return None - self._arch = architecture.Architecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property @@ -378,7 +428,7 @@ class Function(object): """Function platform (read-only)""" if self._platform: return self._platform - else: + else: plat = core.BNGetFunctionPlatform(self.handle) if plat is None: return None @@ -485,7 +535,7 @@ class Function(object): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) - core.BNFreeVariableList(v, count.value) + core.BNFreeVariableNameAndTypeList(v, count.value) return result @property @@ -498,7 +548,7 @@ class Function(object): result.append(Variable(self, v[i].var.type, v[i].var.index, v[i].var.storage, v[i].name, types.Type(handle = core.BNNewTypeReference(v[i].type), platform = self.platform, confidence = v[i].typeConfidence))) result.sort(key = lambda x: x.identifier) - core.BNFreeVariableList(v, count.value) + core.BNFreeVariableNameAndTypeList(v, count.value) return result @property @@ -508,7 +558,7 @@ class Function(object): branches = core.BNGetIndirectBranches(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.Architecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -558,6 +608,30 @@ class Function(object): core.BNSetUserFunctionReturnType(self.handle, type_conf) @property + def return_regs(self): + """Registers that are used for the return value""" + result = core.BNGetFunctionReturnRegisters(self.handle) + reg_set = [] + for i in xrange(0, result.count): + reg_set.append(self.arch.get_reg_name(result.regs[i])) + regs = types.RegisterSet(reg_set, confidence = result.confidence) + core.BNFreeRegisterSet(result) + return regs + + @return_regs.setter + def return_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetUserFunctionReturnRegisters(self.handle, regs) + + @property def calling_convention(self): """Calling convention used by the function""" result = core.BNGetFunctionCallingConvention(self.handle) @@ -641,6 +715,35 @@ class Function(object): core.BNSetUserFunctionStackAdjustment(self.handle, sc) @property + def reg_stack_adjustments(self): + """Number of entries removed from each register stack after return""" + count = ctypes.c_ulonglong() + adjust = core.BNGetFunctionRegisterStackAdjustments(self.handle, count) + result = {} + for i in xrange(0, count.value): + name = self.arch.get_reg_stack_name(adjust[i].regStack) + value = types.RegisterStackAdjustmentWithConfidence(adjust[i].adjustment, + confidence = adjust[i].confidence) + result[name] = value + core.BNFreeRegisterStackAdjustments(adjust) + return result + + @reg_stack_adjustments.setter + def reg_stack_adjustments(self, value): + adjust = (core.BNRegisterStackAdjustment * len(value))() + i = 0 + for reg_stack in value.keys(): + adjust[i].regStack = self.arch.get_reg_stack_index(reg_stack) + if isinstance(value[reg_stack], types.RegisterStackAdjustmentWithConfidence): + adjust[i].adjustment = value[reg_stack].value + adjust[i].confidence = value[reg_stack].confidence + else: + adjust[i].adjustment = value[reg_stack] + adjust[i].confidence = types.max_confidence + i += 1 + core.BNSetUserFunctionRegisterStackAdjustments(self.handle, adjust, len(value)) + + @property def clobbered_regs(self): """Registers that are modified by this function""" result = core.BNGetFunctionClobberedRegisters(self.handle) @@ -648,7 +751,7 @@ class Function(object): for i in xrange(0, result.count): reg_set.append(self.arch.get_reg_name(result.regs[i])) regs = types.RegisterSet(reg_set, confidence = result.confidence) - core.BNFreeClobberedRegisters(result) + core.BNFreeRegisterSet(result) return regs @clobbered_regs.setter @@ -715,6 +818,32 @@ class Function(object): for i in block: yield i + @property + def too_large(self): + """Whether the function is too large to automatically perform analysis (read-only)""" + return core.BNIsFunctionTooLarge(self.handle) + + @property + def analysis_skipped(self): + """Whether automatic analysis was skipped for this function""" + return core.BNIsFunctionAnalysisSkipped(self.handle) + + @analysis_skipped.setter + def analysis_skipped(self, skip): + if skip: + core.BNSetFunctionAnalysisSkipOverride(self.handle, FunctionAnalysisSkipOverride.AlwaysSkipFunctionAnalysis) + else: + core.BNSetFunctionAnalysisSkipOverride(self.handle, FunctionAnalysisSkipOverride.NeverSkipFunctionAnalysis) + + @property + def analysis_skip_override(self): + """Override for skipping of automatic analysis""" + return FunctionAnalysisSkipOverride(core.BNGetFunctionAnalysisSkipOverride(self.handle)) + + @analysis_skip_override.setter + def analysis_skip_override(self, override): + core.BNSetFunctionAnalysisSkipOverride(self.handle, override) + def __iter__(self): count = ctypes.c_ulonglong() blocks = core.BNGetFunctionBasicBlockList(self.handle, count) @@ -1013,7 +1142,7 @@ class Function(object): branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.Architecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.CoreArchitecture._from_cache(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1055,6 +1184,18 @@ class Function(object): type_conf.confidence = value.confidence core.BNSetAutoFunctionReturnType(self.handle, type_conf) + def set_auto_return_regs(self, value): + regs = core.BNRegisterSetWithConfidence() + regs.regs = (ctypes.c_uint * len(value))() + regs.count = len(value) + for i in xrange(0, len(value)): + regs.regs[i] = self.arch.get_reg_index(value[i]) + if hasattr(value, 'confidence'): + regs.confidence = value.confidence + else: + regs.confidence = types.max_confidence + core.BNSetAutoFunctionReturnRegisters(self.handle, regs) + def set_auto_calling_convention(self, value): conv_conf = core.BNCallingConventionWithConfidence() if value is None: @@ -1112,6 +1253,20 @@ class Function(object): sc.confidence = types.max_confidence core.BNSetAutoFunctionStackAdjustment(self.handle, sc) + def set_auto_reg_stack_adjustments(self, value): + adjust = (core.BNRegisterStackAdjustment * len(value))() + i = 0 + for reg_stack in value.keys(): + adjust[i].regStack = self.arch.get_reg_stack_index(reg_stack) + if isinstance(value[reg_stack], types.RegisterStackAdjustmentWithConfidence): + adjust[i].adjustment = value[reg_stack].value + adjust[i].confidence = value[reg_stack].confidence + else: + adjust[i].adjustment = value[reg_stack] + adjust[i].confidence = types.max_confidence + i += 1 + core.BNSetAutoFunctionRegisterStackAdjustments(self.handle, adjust, len(value)) + def set_auto_clobbered_regs(self, value): regs = core.BNRegisterSetWithConfidence() regs.regs = (ctypes.c_uint * len(value))() @@ -1325,6 +1480,94 @@ class Function(object): result = core.BNGetFunctionRegisterValueAtExit(self.handle, self.arch.get_reg_index(reg)) return RegisterValue(self.arch, result.value, confidence = result.confidence) + def set_auto_call_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + if not isinstance(adjust, types.SizeWithConfidence): + adjust = types.SizeWithConfidence(adjust) + core.BNSetAutoCallStackAdjustment(self.handle, arch.handle, addr, adjust.value, adjust.confidence) + + def set_auto_call_reg_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + adjust_buf = (core.BNRegisterStackAdjustment * len(adjust))() + i = 0 + for reg_stack in adjust.keys(): + adjust_buf[i].regStack = arch.get_reg_stack_index(reg_stack) + value = adjust[reg_stack] + if not isinstance(value, types.RegisterStackAdjustmentWithConfidence): + value = types.RegisterStackAdjustmentWithConfidence(value) + adjust_buf[i].adjustment = value.value + adjust_buf[i].confidence = value.confidence + i += 1 + core.BNSetAutoCallRegisterStackAdjustment(self.handle, arch.handle, addr, adjust_buf, len(adjust)) + + def set_auto_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, adjust, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + if not isinstance(adjust, types.RegisterStackAdjustmentWithConfidence): + adjust = types.RegisterStackAdjustmentWithConfidence(adjust) + core.BNSetAutoCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack, + adjust.value, adjust.confidence) + + def set_call_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + if not isinstance(adjust, types.SizeWithConfidence): + adjust = types.SizeWithConfidence(adjust) + core.BNSetUserCallStackAdjustment(self.handle, arch.handle, addr, adjust.value, adjust.confidence) + + def set_call_reg_stack_adjustment(self, addr, adjust, arch=None): + if arch is None: + arch = self.arch + adjust_buf = (core.BNRegisterStackAdjustment * len(adjust))() + i = 0 + for reg_stack in adjust.keys(): + adjust_buf[i].regStack = arch.get_reg_stack_index(reg_stack) + value = adjust[reg_stack] + if not isinstance(value, types.RegisterStackAdjustmentWithConfidence): + value = types.RegisterStackAdjustmentWithConfidence(value) + adjust_buf[i].adjustment = value.value + adjust_buf[i].confidence = value.confidence + i += 1 + core.BNSetUserCallRegisterStackAdjustment(self.handle, arch.handle, addr, adjust_buf, len(adjust)) + + def set_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, adjust, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + if not isinstance(adjust, types.RegisterStackAdjustmentWithConfidence): + adjust = types.RegisterStackAdjustmentWithConfidence(adjust) + core.BNSetUserCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack, + adjust.value, adjust.confidence) + + def get_call_stack_adjustment(self, addr, arch=None): + if arch is None: + arch = self.arch + result = core.BNGetCallStackAdjustment(self.handle, arch.handle, addr) + return types.SizeWithConfidence(result.value, confidence = result.confidence) + + def get_call_reg_stack_adjustment(self, addr, arch=None): + if arch is None: + arch = self.arch + count = ctypes.c_ulonglong() + adjust = core.BNGetCallRegisterStackAdjustment(self.handle, arch.handle, addr, count) + result = {} + for i in xrange(0, count.value): + result[arch.get_reg_stack_name(adjust[i].regStack)] = types.RegisterStackAdjustmentWithConfidence( + adjust[i].adjustment, confidence = adjust[i].confidence) + core.BNFreeRegisterStackAdjustments(adjust) + return result + + def get_call_reg_stack_adjustment_for_reg_stack(self, addr, reg_stack, arch=None): + if arch is None: + arch = self.arch + reg_stack = arch.get_reg_stack_index(reg_stack) + adjust = core.BNGetCallRegisterStackAdjustmentForRegisterStack(self.handle, arch.handle, addr, reg_stack) + result = types.RegisterStackAdjustmentWithConfidence(adjust.adjustment, confidence = adjust.confidence) + return result + class AdvancedFunctionAnalysisDataRequestor(object): def __init__(self, func = None): @@ -1355,9 +1598,10 @@ class AdvancedFunctionAnalysisDataRequestor(object): class DisassemblyTextLine(object): - def __init__(self, addr, tokens): + def __init__(self, addr, tokens, il_instr = None): self.address = addr self.tokens = tokens + self.il_instruction = il_instr def __str__(self): result = "" @@ -1382,8 +1626,9 @@ class FunctionGraphEdge(object): class FunctionGraphBlock(object): - def __init__(self, handle): + def __init__(self, handle, graph): self.handle = handle + self.graph = graph def __del__(self): core.BNFreeFunctionGraphBlock(self.handle) @@ -1402,13 +1647,22 @@ class FunctionGraphBlock(object): def basic_block(self): """Basic block associated with this part of the function graph (read-only)""" block = core.BNGetFunctionGraphBasicBlock(self.handle) - func = core.BNGetBasicBlockFunction(block) - if func is None: + func_handle = core.BNGetBasicBlockFunction(block) + if func_handle is None: core.BNFreeBasicBlock(block) - block = None + return None + + view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) + func = Function(view, func_handle) + + if core.BNIsLowLevelILBasicBlock(block): + block = lowlevelil.LowLevelILBasicBlock(view, block, + lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) + elif core.BNIsMediumLevelILBasicBlock(block): + block = mediumlevelil.MediumLevelILBasicBlock(view, block, + mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) else: - block = basicblock.BasicBlock(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), block) - core.BNFreeFunction(func) + block = basicblock.BasicBlock(view, block) return block @property @@ -1417,7 +1671,7 @@ class FunctionGraphBlock(object): arch = core.BNGetFunctionGraphBlockArchitecture(self.handle) if arch is None: return None - return architecture.Architecture(arch) + return architecture.CoreArchitecture._from_cache(arch) @property def start(self): @@ -1454,9 +1708,14 @@ class FunctionGraphBlock(object): """Function graph block list of lines (read-only)""" count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1468,7 +1727,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(DisassemblyTextLine(addr, tokens)) + result.append(DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result @@ -1513,9 +1772,14 @@ class FunctionGraphBlock(object): def __iter__(self): count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block try: for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1527,7 +1791,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - yield DisassemblyTextLine(addr, tokens) + yield DisassemblyTextLine(addr, tokens, il_instr) finally: core.BNFreeDisassemblyTextLines(lines, count.value) @@ -1615,11 +1879,16 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result @property + def has_blocks(self): + """Whether the function graph has at least one block (read-only)""" + return core.BNFunctionGraphHasBlocks(self.handle) + + @property def width(self): """Function graph width (read-only)""" return core.BNGetFunctionGraphWidth(self.handle) @@ -1649,6 +1918,32 @@ class FunctionGraph(object): def settings(self): return DisassemblySettings(core.BNGetFunctionGraphSettings(self.handle)) + @property + def is_il(self): + return core.BNIsILFunctionGraph(self.handle) + + @property + def is_low_level_il(self): + return core.BNIsLowLevelILFunctionGraph(self.handle) + + @property + def is_medium_level_il(self): + return core.BNIsMediumLevelILFunctionGraph(self.handle) + + @property + def il_function(self): + if self.is_low_level_il: + il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle) + if not il_func: + return None + return lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) + if self.is_medium_level_il: + il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle) + if not il_func: + return None + return mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) + return None + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -1663,7 +1958,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) try: for i in xrange(0, count.value): - yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i])) + yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self) finally: core.BNFreeFunctionGraphBlockList(blocks, count.value) @@ -1706,7 +2001,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result @@ -1739,6 +2034,38 @@ class RegisterInfo(object): return "<reg: size %d, offset %d in %s%s>" % (self.size, self.offset, self.full_width_reg, extend) +class RegisterStackInfo(object): + def __init__(self, storage_regs, top_relative_regs, stack_top_reg, index=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 "<reg stack: %d regs, stack top in %s>" % (len(self.storage_regs), self.stack_top_reg) + + +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 "<input: %s>" % str(self.type) + return "<input: %s %s>" % (str(self.type), self.name) + + +class IntrinsicInfo(object): + def __init__(self, inputs, outputs, index=None): + self.inputs = inputs + self.outputs = outputs + self.index = index + + def __repr__(self): + return "<intrinsic: %s -> %s>" % (repr(self.inputs), repr(self.outputs)) + + class InstructionBranch(object): def __init__(self, branch_type, target = 0, arch = None): self.type = branch_type diff --git a/python/interaction.py b/python/interaction.py index 96cac42d..4f6ed67d 100644 --- a/python/interaction.py +++ b/python/interaction.py @@ -121,7 +121,7 @@ class IntegerField(object): class AddressField(object): """ ``AddressField`` prompts the user for an address. By passing the optional view and current_address parameters - offsets can be used instead of just an address. Th reslut is stored as in int in self.result. + offsets can be used instead of just an address. The result is stored as in int in self.result. Note: This API currenlty functions differently on the command line, as the view and current_address are disregarded. Additionally where as in the ui the result defaults to hexidecimal on the command line 0x must be diff --git a/python/lowlevelil.py b/python/lowlevelil.py index dfc5af5f..ab6170a5 100644 --- a/python/lowlevelil.py +++ b/python/lowlevelil.py @@ -26,6 +26,7 @@ from .enums import LowLevelILOperation, LowLevelILFlagCondition, InstructionText import function import basicblock import mediumlevelil +import struct class LowLevelILLabel(object): @@ -61,6 +62,26 @@ class ILRegister(object): return self.info == other.info +class ILRegisterStack(object): + def __init__(self, arch, reg_stack): + self.arch = arch + self.index = reg_stack + self.name = self.arch.get_reg_stack_name(self.index) + + @property + def info(self): + return self.arch.reg_stacks[self.name] + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.info == other.info + + class ILFlag(object): def __init__(self, arch, flag): self.arch = arch @@ -78,6 +99,57 @@ class ILFlag(object): return self.name +class ILSemanticFlagClass(object): + def __init__(self, arch, sem_class): + self.arch = arch + self.index = sem_class + self.name = self.arch.get_semantic_flag_class_name(self.index) + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.index == other.index + + +class ILSemanticFlagGroup(object): + def __init__(self, arch, sem_group): + self.arch = arch + self.index = sem_group + self.name = self.arch.get_semantic_flag_group_name(self.index) + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.index == other.index + + +class ILIntrinsic(object): + def __init__(self, arch, intrinsic): + self.arch = arch + self.index = intrinsic + self.name = self.arch.get_intrinsic_name(self.index) + if self.name in self.arch.intrinsics: + self.inputs = self.arch.intrinsics[self.name].inputs + self.outputs = self.arch.intrinsics[self.name].outputs + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __eq__(self, other): + return self.index == other.index + + class SSARegister(object): def __init__(self, reg, version): self.reg = reg @@ -87,6 +159,15 @@ class SSARegister(object): return "<ssa %s version %d>" % (repr(self.reg), self.version) +class SSARegisterStack(object): + def __init__(self, reg_stack, version): + self.reg_stack = reg_stack + self.version = version + + def __repr__(self): + return "<ssa %s version %d>" % (repr(self.reg_stack), self.version) + + class SSAFlag(object): def __init__(self, flag, version): self.flag = flag @@ -96,6 +177,15 @@ class SSAFlag(object): return "<ssa %s version %d>" % (repr(self.flag), self.version) +class SSARegisterOrFlag(object): + def __init__(self, reg_or_flag, version): + self.reg_or_flag = reg_or_flag + self.version = version + + def __repr__(self): + return "<ssa %s version %d>" % (repr(self.reg_or_flag), self.version) + + class LowLevelILOperationAndSize(object): def __init__(self, operation, size): self.operation = operation @@ -118,14 +208,22 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_NOP: [], LowLevelILOperation.LLIL_SET_REG: [("dest", "reg"), ("src", "expr")], LowLevelILOperation.LLIL_SET_REG_SPLIT: [("hi", "reg"), ("lo", "reg"), ("src", "expr")], + LowLevelILOperation.LLIL_SET_REG_STACK_REL: [("stack", "reg_stack"), ("dest", "expr"), ("src", "expr")], + LowLevelILOperation.LLIL_REG_STACK_PUSH: [("stack", "reg_stack"), ("src", "expr")], LowLevelILOperation.LLIL_SET_FLAG: [("dest", "flag"), ("src", "expr")], LowLevelILOperation.LLIL_LOAD: [("src", "expr")], LowLevelILOperation.LLIL_STORE: [("dest", "expr"), ("src", "expr")], LowLevelILOperation.LLIL_PUSH: [("src", "expr")], LowLevelILOperation.LLIL_POP: [], LowLevelILOperation.LLIL_REG: [("src", "reg")], + LowLevelILOperation.LLIL_REG_SPLIT: [("hi", "reg"), ("lo", "reg")], + LowLevelILOperation.LLIL_REG_STACK_REL: [("stack", "reg_stack"), ("src", "expr")], + LowLevelILOperation.LLIL_REG_STACK_POP: [("stack", "reg_stack")], + LowLevelILOperation.LLIL_REG_STACK_FREE_REG: [("dest", "reg")], + LowLevelILOperation.LLIL_REG_STACK_FREE_REL: [("stack", "reg_stack"), ("dest", "expr")], LowLevelILOperation.LLIL_CONST: [("constant", "int")], LowLevelILOperation.LLIL_CONST_PTR: [("constant", "int")], + LowLevelILOperation.LLIL_FLOAT_CONST: [("constant", "float")], LowLevelILOperation.LLIL_FLAG: [("src", "flag")], LowLevelILOperation.LLIL_FLAG_BIT: [("src", "flag"), ("bit", "int")], LowLevelILOperation.LLIL_ADD: [("left", "expr"), ("right", "expr")], @@ -146,13 +244,13 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_MULU_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_MULS_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_DIVU: [("left", "expr"), ("right", "expr")], - LowLevelILOperation.LLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVU_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_DIVS: [("left", "expr"), ("right", "expr")], - LowLevelILOperation.LLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_DIVS_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_MODU: [("left", "expr"), ("right", "expr")], - LowLevelILOperation.LLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODU_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_MODS: [("left", "expr"), ("right", "expr")], - LowLevelILOperation.LLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_MODS_DP: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_NEG: [("src", "expr")], LowLevelILOperation.LLIL_NOT: [("src", "expr")], LowLevelILOperation.LLIL_SX: [("src", "expr")], @@ -161,12 +259,13 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_JUMP: [("dest", "expr")], LowLevelILOperation.LLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")], LowLevelILOperation.LLIL_CALL: [("dest", "expr")], - LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int")], + LowLevelILOperation.LLIL_CALL_STACK_ADJUST: [("dest", "expr"), ("stack_adjustment", "int"), ("reg_stack_adjustments", "reg_stack_adjust")], LowLevelILOperation.LLIL_RET: [("dest", "expr")], LowLevelILOperation.LLIL_NORET: [], LowLevelILOperation.LLIL_IF: [("condition", "expr"), ("true", "int"), ("false", "int")], LowLevelILOperation.LLIL_GOTO: [("dest", "int")], - LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond")], + LowLevelILOperation.LLIL_FLAG_COND: [("condition", "cond"), ("semantic_class", "sem_class")], + LowLevelILOperation.LLIL_FLAG_GROUP: [("semantic_group", "sem_group")], LowLevelILOperation.LLIL_CMP_E: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_CMP_NE: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], @@ -181,17 +280,49 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_BOOL_TO_INT: [("src", "expr")], LowLevelILOperation.LLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_SYSCALL: [], + LowLevelILOperation.LLIL_INTRINSIC: [("output", "reg_or_flag_list"), ("intrinsic", "intrinsic"), ("param", "expr")], + LowLevelILOperation.LLIL_INTRINSIC_SSA: [("output", "reg_or_flag_ssa_list"), ("intrinsic", "intrinsic"), ("param", "expr")], LowLevelILOperation.LLIL_BP: [], LowLevelILOperation.LLIL_TRAP: [("vector", "int")], LowLevelILOperation.LLIL_UNDEF: [], LowLevelILOperation.LLIL_UNIMPL: [], LowLevelILOperation.LLIL_UNIMPL_MEM: [("src", "expr")], + LowLevelILOperation.LLIL_FADD: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FSUB: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FMUL: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FDIV: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FSQRT: [("src", "expr")], + LowLevelILOperation.LLIL_FNEG: [("src", "expr")], + LowLevelILOperation.LLIL_FABS: [("src", "expr")], + LowLevelILOperation.LLIL_FLOAT_TO_INT: [("src", "expr")], + LowLevelILOperation.LLIL_INT_TO_FLOAT: [("src", "expr")], + LowLevelILOperation.LLIL_FLOAT_CONV: [("src", "expr")], + LowLevelILOperation.LLIL_ROUND_TO_INT: [("src", "expr")], + LowLevelILOperation.LLIL_FLOOR: [("src", "expr")], + LowLevelILOperation.LLIL_CEIL: [("src", "expr")], + LowLevelILOperation.LLIL_FTRUNC: [("src", "expr")], + LowLevelILOperation.LLIL_FCMP_E: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_NE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_LT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_LE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_GE: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_GT: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_O: [("left", "expr"), ("right", "expr")], + LowLevelILOperation.LLIL_FCMP_UO: [("left", "expr"), ("right", "expr")], LowLevelILOperation.LLIL_SET_REG_SSA: [("dest", "reg_ssa"), ("src", "expr")], LowLevelILOperation.LLIL_SET_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("dest", "reg"), ("src", "expr")], LowLevelILOperation.LLIL_SET_REG_SPLIT_SSA: [("hi", "expr"), ("lo", "expr"), ("src", "expr")], + LowLevelILOperation.LLIL_SET_REG_STACK_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr"), ("src", "expr")], + LowLevelILOperation.LLIL_SET_REG_STACK_ABS_SSA: [("stack", "expr"), ("dest", "reg"), ("src", "expr")], LowLevelILOperation.LLIL_REG_SPLIT_DEST_SSA: [("dest", "reg_ssa")], + LowLevelILOperation.LLIL_REG_STACK_DEST_SSA: [("src", "reg_stack_ssa_dest_and_src")], LowLevelILOperation.LLIL_REG_SSA: [("src", "reg_ssa")], LowLevelILOperation.LLIL_REG_SSA_PARTIAL: [("full_reg", "reg_ssa"), ("src", "reg")], + LowLevelILOperation.LLIL_REG_SPLIT_SSA: [("hi", "reg_ssa"), ("lo", "reg_ssa")], + LowLevelILOperation.LLIL_REG_STACK_REL_SSA: [("stack", "reg_stack_ssa"), ("src", "expr"), ("top", "expr")], + LowLevelILOperation.LLIL_REG_STACK_ABS_SSA: [("stack", "reg_stack_ssa"), ("src", "reg")], + LowLevelILOperation.LLIL_REG_STACK_FREE_REL_SSA: [("stack", "expr"), ("dest", "expr"), ("top", "expr")], + LowLevelILOperation.LLIL_REG_STACK_FREE_ABS_SSA: [("stack", "expr"), ("dest", "reg")], LowLevelILOperation.LLIL_SET_FLAG_SSA: [("dest", "flag_ssa"), ("src", "expr")], LowLevelILOperation.LLIL_FLAG_SSA: [("src", "flag_ssa")], LowLevelILOperation.LLIL_FLAG_BIT_SSA: [("src", "flag_ssa"), ("bit", "int")], @@ -199,10 +330,11 @@ class LowLevelILInstruction(object): LowLevelILOperation.LLIL_SYSCALL_SSA: [("output", "expr"), ("stack", "expr"), ("param", "expr")], LowLevelILOperation.LLIL_CALL_OUTPUT_SSA: [("dest_memory", "int"), ("dest", "reg_ssa_list")], LowLevelILOperation.LLIL_CALL_STACK_SSA: [("src", "reg_ssa"), ("src_memory", "int")], - LowLevelILOperation.LLIL_CALL_PARAM_SSA: [("src", "reg_ssa_list")], + LowLevelILOperation.LLIL_CALL_PARAM: [("src", "expr_list")], LowLevelILOperation.LLIL_LOAD_SSA: [("src", "expr"), ("src_memory", "int")], LowLevelILOperation.LLIL_STORE_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src_memory", "int"), ("src", "expr")], LowLevelILOperation.LLIL_REG_PHI: [("dest", "reg_ssa"), ("src", "reg_ssa_list")], + LowLevelILOperation.LLIL_REG_STACK_PHI: [("dest", "reg_stack_ssa"), ("src", "reg_stack_ssa_list")], LowLevelILOperation.LLIL_FLAG_PHI: [("dest", "flag_ssa"), ("src", "flag_ssa_list")], LowLevelILOperation.LLIL_MEM_PHI: [("dest_memory", "int"), ("src_memory", "int_list")] } @@ -229,20 +361,50 @@ class LowLevelILInstruction(object): name, operand_type = operand if operand_type == "int": value = instr.operands[i] + elif operand_type == "float": + if instr.size == 4: + value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0] + elif instr.size == 8: + value = struct.unpack("d", struct.pack("Q", instr.operands[i]))[0] + else: + value = instr.operands[i] elif operand_type == "expr": value = LowLevelILInstruction(func, instr.operands[i]) elif operand_type == "reg": value = ILRegister(func.arch, instr.operands[i]) + elif operand_type == "reg_stack": + value = ILRegisterStack(func.arch, instr.operands[i]) + elif operand_type == "intrinsic": + value = ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "reg_ssa": reg = ILRegister(func.arch, instr.operands[i]) i += 1 value = SSARegister(reg, instr.operands[i]) + elif operand_type == "reg_stack_ssa": + reg_stack = ILRegisterStack(func.arch, instr.operands[i]) + i += 1 + value = SSARegisterStack(reg_stack, instr.operands[i]) + elif operand_type == "reg_stack_ssa_dest_and_src": + reg_stack = ILRegisterStack(func.arch, instr.operands[i]) + i += 1 + value = SSARegisterStack(reg_stack, instr.operands[i]) + i += 1 + self.operands.append(value) + self.dest = value + value = SSARegisterStack(reg_stack, instr.operands[i]) elif operand_type == "flag": value = ILFlag(func.arch, instr.operands[i]) elif operand_type == "flag_ssa": flag = ILFlag(func.arch, instr.operands[i]) i += 1 value = SSAFlag(flag, instr.operands[i]) + elif operand_type == "sem_class": + if instr.operands[i] == 0: + value = None + else: + value = ILSemanticFlagClass(func.arch, instr.operands[i]) + elif operand_type == "sem_group": + value = ILSemanticFlagGroup(func.arch, instr.operands[i]) elif operand_type == "cond": value = LowLevelILFlagCondition(instr.operands[i]) elif operand_type == "int_list": @@ -250,29 +412,83 @@ class LowLevelILInstruction(object): operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value): - value.append(operand_list[i]) + for j in xrange(count.value): + value.append(operand_list[j]) + core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "expr_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value): + value.append(LowLevelILInstruction(func, operand_list[j])) + core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_or_flag_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value): + if (operand_list[j] & (1 << 32)) != 0: + value.append(ILFlag(func.arch, operand_list[j] & 0xffffffff)) + else: + value.append(ILRegister(func.arch, operand_list[j] & 0xffffffff)) core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "reg_ssa_list": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value / 2): - reg = operand_list[i * 2] - reg_version = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + reg = operand_list[j * 2] + reg_version = operand_list[(j * 2) + 1] value.append(SSARegister(ILRegister(func.arch, reg), reg_version)) core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_stack_ssa_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value / 2): + reg_stack = operand_list[j * 2] + reg_version = operand_list[(j * 2) + 1] + value.append(SSARegisterStack(ILRegisterStack(func.arch, reg_stack), reg_version)) + core.BNLowLevelILFreeOperandList(operand_list) elif operand_type == "flag_ssa_list": count = ctypes.c_ulonglong() operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) i += 1 value = [] - for i in xrange(count.value / 2): - flag = operand_list[i * 2] - flag_version = operand_list[(i * 2) + 1] + for j in xrange(count.value / 2): + flag = operand_list[j * 2] + flag_version = operand_list[(j * 2) + 1] value.append(SSAFlag(ILFlag(func.arch, flag), flag_version)) core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_or_flag_ssa_list": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = [] + for j in xrange(count.value / 2): + if (operand_list[j * 2] & (1 << 32)) != 0: + reg_or_flag = ILFlag(func.arch, operand_list[j * 2] & 0xffffffff) + else: + reg_or_flag = ILRegister(func.arch, operand_list[j * 2] & 0xffffffff) + reg_version = operand_list[(j * 2) + 1] + value.append(SSARegisterOrFlag(reg_or_flag, reg_version)) + core.BNLowLevelILFreeOperandList(operand_list) + elif operand_type == "reg_stack_adjust": + count = ctypes.c_ulonglong() + operand_list = core.BNLowLevelILGetOperandList(func.handle, self.expr_index, i, count) + i += 1 + value = {} + for j in xrange(count.value / 2): + reg_stack = operand_list[j * 2] + adjust = operand_list[(j * 2) + 1] + if adjust & 0x80000000: + adjust |= ~0x80000000 + value[func.arch.get_reg_stack_name(reg_stack)] = adjust + core.BNLowLevelILFreeOperandList(operand_list) self.operands.append(value) self.__dict__[name] = value i += 1 @@ -710,6 +926,38 @@ class LowLevelILFunction(object): lo = self.arch.get_reg_index(lo) return self.expr(LowLevelILOperation.LLIL_SET_REG_SPLIT, hi, lo, value.index, size = size, flags = flags) + def set_reg_stack_top_relative(self, size, reg_stack, entry, value, flags = 0): + """ + ``set_reg_stack_top_relative`` sets the top-relative entry ``entry`` of size ``size`` in register + stack ``reg_stack`` to the expression ``value`` + + :param int size: size of the register parameter in bytes + :param str reg_stack: the register stack name + :param LowLevelILExpr entry: an expression for which stack entry to set + :param LowLevelILExpr value: an expression to set the entry to + :param str flags: which flags are set by this operation + :return: The expression ``reg_stack[entry] = value`` + :rtype: LowLevelILExpr + """ + reg_stack = self.arch.get_reg_stack_index(reg_stack) + return self.expr(LowLevelILOperation.LLIL_SET_REG_STACK_REL, reg_stack, entry.index, value.index, + size = size, flags = flags) + + def reg_stack_push(self, size, reg_stack, value, flags = 0): + """ + ``reg_stack_push`` pushes the expression ``value`` of size ``size`` onto the top of the register + stack ``reg_stack`` + + :param int size: size of the register parameter in bytes + :param str reg_stack: the register stack name + :param LowLevelILExpr value: an expression to push + :param str flags: which flags are set by this operation + :return: The expression ``reg_stack.push(value)`` + :rtype: LowLevelILExpr + """ + reg_stack = self.arch.get_reg_stack_index(reg_stack) + return self.expr(LowLevelILOperation.LLIL_REG_STACK_PUSH, reg_stack, value.index, size = size, flags = flags) + def set_flag(self, flag, value): """ ``set_flag`` sets the flag ``flag`` to the LowLevelILExpr ``value`` @@ -723,7 +971,7 @@ class LowLevelILFunction(object): def load(self, size, addr): """ - ``laod`` Reads ``size`` bytes from the expression ``addr`` + ``load`` Reads ``size`` bytes from the expression ``addr`` :param int size: number of bytes to read :param LowLevelILExpr addr: the expression to read memory from @@ -768,7 +1016,7 @@ class LowLevelILFunction(object): def reg(self, size, reg): """ - ``reg`` returns a register of size ``size`` with name ``name`` + ``reg`` returns a register of size ``size`` with name ``reg`` :param int size: the size of the register in bytes :param str reg: the name of the register @@ -778,6 +1026,47 @@ class LowLevelILFunction(object): reg = self.arch.get_reg_index(reg) return self.expr(LowLevelILOperation.LLIL_REG, reg, size=size) + def reg_split(self, size, hi, lo): + """ + ``reg_split`` combines registers of size ``size`` with names ``hi`` and ``lo`` + + :param int size: the size of the register in bytes + :param str hi: register holding high part of value + :param str lo: register holding low part of value + :return: The expression ``hi:lo`` + :rtype: LowLevelILExpr + """ + hi = self.arch.get_reg_index(hi) + lo = self.arch.get_reg_index(lo) + return self.expr(LowLevelILOperation.LLIL_REG_SPLIT, hi, lo, size=size) + + def reg_stack_top_relative(self, size, reg_stack, entry): + """ + ``reg_stack_top_relative`` returns a register stack entry of size ``size`` at top-relative + location ``entry`` in register stack with name ``reg_stack`` + + :param int size: the size of the register in bytes + :param str reg_stack: the name of the register stack + :param LowLevelILExpr entry: an expression for which stack entry to fetch + :return: The expression ``reg_stack[entry]`` + :rtype: LowLevelILExpr + """ + reg_stack = self.arch.get_reg_stack_index(reg_stack) + return self.expr(LowLevelILOperation.LLIL_REG_STACK_REL, reg_stack, entry.index, size=size) + + def reg_stack_pop(self, size, reg_stack): + """ + ``reg_stack_pop`` returns the top entry of size ``size`` in register stack with name ``reg_stack``, and + removes the entry from the stack + + :param int size: the size of the register in bytes + :param str reg_stack: the name of the register stack + :return: The expression ``reg_stack.pop`` + :rtype: LowLevelILExpr + """ + reg_stack = self.arch.get_reg_stack_index(reg_stack) + return self.expr(LowLevelILOperation.LLIL_REG_STACK_POP, reg_stack, size=size) + def const(self, size, value): """ ``const`` returns an expression for the constant integer ``value`` with size ``size`` @@ -800,6 +1089,38 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_CONST_PTR, value, size=size) + def float_const_raw(self, size, value): + """ + ``float_const_raw`` returns an expression for the constant raw binary floating point + value ``value`` with size ``size`` + + :param int size: the size of the constant in bytes + :param int value: integer value for the raw binary representation of the constant + :return: A constant expression of given value and size + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, value, size=size) + + def float_const_single(self, value): + """ + ``float_const_single`` returns an expression for the single precision floating point value ``value`` + + :param float value: float value for the constant + :return: A constant expression of given value and size + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, struct.unpack("I", struct.pack("f", value))[0], size=4) + + def float_const_double(self, value): + """ + ``float_const_double`` returns an expression for the double precision floating point value ``value`` + + :param float value: float value for the constant + :return: A constant expression of given value and size + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOAT_CONST, struct.unpack("Q", struct.pack("d", value))[0], size=8) + def flag(self, reg): """ ``flag`` returns a flag expression for the given flag name. @@ -1059,7 +1380,7 @@ class LowLevelILFunction(object): :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``muls.dp.<size>{<flags>}(a, b)`` + :return: The expression ``mulu.dp.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ return self.expr(LowLevelILOperation.LLIL_MULU_DP, a.index, b.index, size=size, flags=flags) @@ -1078,21 +1399,20 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) - def div_double_prec_signed(self, size, hi, lo, b, flags=None): + def div_double_prec_signed(self, size, a, b, flags=None): """ - ``div_double_prec_signed`` signed double precision divide using expression ``hi`` and expression ``lo`` as a + ``div_double_prec_signed`` signed double precision divide using expression ``a`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. :param int size: the size of the result in bytes - :param LowLevelILExpr hi: high LHS expression - :param LowLevelILExpr lo: low LHS expression + :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``divs.dp.<size>{<flags>}(hi:lo, b)`` + :return: The expression ``divs.dp.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVS_DP, a.index, b.index, size=size, flags=flags) def div_unsigned(self, size, a, b, flags=None): """ @@ -1103,26 +1423,25 @@ class LowLevelILFunction(object): :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``divs.<size>{<flags>}(a, b)`` + :return: The expression ``divu.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_DIVS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVU, a.index, b.index, size=size, flags=flags) - def div_double_prec_unsigned(self, size, hi, lo, b, flags=None): + def div_double_prec_unsigned(self, size, a, b, flags=None): """ - ``div_double_prec_unsigned`` unsigned double precision divide using expression ``hi`` and expression ``lo`` as + ``div_double_prec_unsigned`` unsigned double precision divide using expression ``a`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. :param int size: the size of the result in bytes - :param LowLevelILExpr hi: high LHS expression - :param LowLevelILExpr lo: low LHS expression + :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``divs.dp.<size>{<flags>}(hi:lo, b)`` + :return: The expression ``divu.dp.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_DIVS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_DIVU_DP, a.index, b.index, size=size, flags=flags) def mod_signed(self, size, a, b, flags=None): """ @@ -1138,21 +1457,20 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) - def mod_double_prec_signed(self, size, hi, lo, b, flags=None): + def mod_double_prec_signed(self, size, a, b, flags=None): """ - ``mod_double_prec_signed`` signed double precision modulus using expression ``hi`` and expression ``lo`` as a single + ``mod_double_prec_signed`` signed double precision modulus using expression ``a`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. :param int size: the size of the result in bytes - :param LowLevelILExpr hi: high LHS expression - :param LowLevelILExpr lo: low LHS expression + :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``mods.dp.<size>{<flags>}(hi:lo, b)`` + :return: The expression ``mods.dp.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODS_DP, a.index, b.index, size=size, flags=flags) def mod_unsigned(self, size, a, b, flags=None): """ @@ -1166,23 +1484,22 @@ class LowLevelILFunction(object): :return: The expression ``modu.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_MODS, a.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODU, a.index, b.index, size=size, flags=flags) - def mod_double_prec_unsigned(self, size, hi, lo, b, flags=None): + def mod_double_prec_unsigned(self, size, a, b, flags=None): """ - ``mod_double_prec_unsigned`` unsigned double precision modulus using expression ``hi`` and expression ``lo`` as + ``mod_double_prec_unsigned`` unsigned double precision modulus using expression ``a`` as a single double precision register by expression ``b`` potentially setting flags ``flags`` and returning an expression of ``size`` bytes. :param int size: the size of the result in bytes - :param LowLevelILExpr hi: high LHS expression - :param LowLevelILExpr lo: low LHS expression + :param LowLevelILExpr a: LHS expression :param LowLevelILExpr b: RHS expression :param str flags: optional, flags to set - :return: The expression ``modu.dp.<size>{<flags>}(hi:lo, b)`` + :return: The expression ``modu.dp.<size>{<flags>}(a, b)`` :rtype: LowLevelILExpr """ - return self.expr(LowLevelILOperation.LLIL_MODS_DP, hi.index, lo.index, b.index, size=size, flags=flags) + return self.expr(LowLevelILOperation.LLIL_MODU_DP, a.index, b.index, size=size, flags=flags) def neg_expr(self, size, value, flags=None): """ @@ -1226,7 +1543,7 @@ class LowLevelILFunction(object): :param int size: the size of the result in bytes :param LowLevelILExpr value: the expression to zero extend - :return: The expression ``sx.<size>(value)`` + :return: The expression ``zx.<size>(value)`` :rtype: LowLevelILExpr """ return self.expr(LowLevelILOperation.LLIL_ZX, value.index, size=size, flags=flags) @@ -1295,11 +1612,12 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_NORET) - def flag_condition(self, cond): + def flag_condition(self, cond, sem_class = None): """ ``flag_condition`` returns a flag_condition expression for the given LowLevelILFlagCondition :param LowLevelILFlagCondition cond: Flag condition expression to retrieve + :param str sem_class: Optional semantic flag class :return: A flag_condition expression :rtype: LowLevelILExpr """ @@ -1307,7 +1625,19 @@ class LowLevelILFunction(object): cond = LowLevelILFlagCondition[cond] elif isinstance(cond, LowLevelILFlagCondition): cond = cond.value - return self.expr(LowLevelILOperation.LLIL_FLAG_COND, cond) + class_index = self.arch.get_semantic_flag_class_index(sem_class) + return self.expr(LowLevelILOperation.LLIL_FLAG_COND, cond, class_index) + + def flag_group(self, sem_group): + """ + ``flag_group`` returns a flag_group expression for the given semantic flag group + + :param str sem_group: Semantic flag group to access + :return: A flag_group expression + :rtype: LowLevelILExpr + """ + group = self.arch.get_semantic_flag_group_index(sem_group) + return self.expr(LowLevelILOperation.LLIL_FLAG_GROUP, group) def compare_equal(self, size, a, b): """ @@ -1451,6 +1781,25 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_SYSCALL) + def intrinsic(self, outputs, intrinsic, params, flags=None): + """ + ``intrinsic`` return an intrinsic expression. + + :return: an intrinsic expression. + :rtype: LowLevelILExpr + """ + output_list = [] + for output in outputs: + if isinstance(output, ILFlag): + output_list.append((1 << 32) | output.index) + else: + output_list.append(output.index) + param_list = [] + for param in params: + param_list.append(param.index) + return self.expr(LowLevelILOperation.LLIL_INTRINSIC, len(outputs), self.add_operand_list(output_list), + self.arch.get_intrinsic_index(intrinsic), len(params), self.add_operand_list(param_list), flags = flags) + def breakpoint(self): """ ``breakpoint`` returns a processor breakpoint expression. @@ -1501,6 +1850,280 @@ class LowLevelILFunction(object): """ return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr.index, size = size) + def float_add(self, size, a, b, flags=None): + """ + ``float_add`` adds floating point expression ``a`` to expression ``b`` potentially setting flags ``flags`` + and returning an expression of ``size`` bytes. + + :param int size: the size of the result in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``fadd.<size>{<flags>}(a, b)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FADD, a.index, b.index, size=size, flags=flags) + + def float_sub(self, size, a, b, flags=None): + """ + ``float_sub`` subtracts floating point expression ``b`` from expression ``a`` potentially setting flags ``flags`` + and returning an expression of ``size`` bytes. + + :param int size: the size of the result in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``fsub.<size>{<flags>}(a, b)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FSUB, a.index, b.index, size=size, flags=flags) + + def float_mult(self, size, a, b, flags=None): + """ + ``float_mult`` multiplies floating point expression ``a`` by expression ``b`` potentially setting flags ``flags`` + and returning an expression of ``size`` bytes. + + :param int size: the size of the result in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``fmul.<size>{<flags>}(a, b)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FMUL, a.index, b.index, size=size, flags=flags) + + def float_div(self, size, a, b, flags=None): + """ + ``float_div`` divides floating point expression ``a`` by expression ``b`` potentially setting flags ``flags`` + and returning an expression of ``size`` bytes. + + :param int size: the size of the result in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``fdiv.<size>{<flags>}(a, b)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FDIV, a.index, b.index, size=size, flags=flags) + + def float_sqrt(self, size, value, flags=None): + """ + ``float_sqrt`` returns square root of floating point expression ``value`` of size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``sqrt.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FSQRT, value.index, size=size, flags=flags) + + def float_neg(self, size, value, flags=None): + """ + ``float_neg`` returns sign negation of floating point expression ``value`` of size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``fneg.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FNEG, value.index, size=size, flags=flags) + + def float_abs(self, size, value, flags=None): + """ + ``float_abs`` returns absolute value of floating point expression ``value`` of size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``fabs.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FABS, value.index, size=size, flags=flags) + + def float_to_int(self, size, value, flags=None): + """ + ``float_to_int`` returns integer value of floating point expression ``value`` of size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``int.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOAT_TO_INT, value.index, size=size, flags=flags) + + def int_to_float(self, size, value, flags=None): + """ + ``int_to_float`` returns floating point value of integer expression ``value`` of size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``float.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_INT_TO_FLOAT, value.index, size=size, flags=flags) + + def float_convert(self, size, value, flags=None): + """ + ``int_to_float`` converts floating point value of expression ``value`` to size ``size`` potentially setting flags + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``fconvert.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOAT_CONV, value.index, size=size, flags=flags) + + def round_to_int(self, size, value, flags=None): + """ + ``round_to_int`` rounds a floating point value to the nearest integer + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``roundint.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_ROUND_TO_INT, value.index, size=size, flags=flags) + + def floor(self, size, value, flags=None): + """ + ``floor`` rounds a floating point value to an integer towards negative infinity + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``roundint.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FLOOR, value.index, size=size, flags=flags) + + def ceil(self, size, value, flags=None): + """ + ``ceil`` rounds a floating point value to an integer towards positive infinity + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``roundint.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_CEIL, value.index, size=size, flags=flags) + + def float_trunc(self, size, value, flags=None): + """ + ``float_trunc`` rounds a floating point value to an integer towards zero + + :param int size: the size of the result in bytes + :param LowLevelILExpr value: the expression to negate + :param str flags: optional, flags to set + :return: The expression ``roundint.<size>{<flags>}(value)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FTRUNC, value.index, size=size, flags=flags) + + def float_compare_equal(self, size, a, b): + """ + ``float_compare_equal`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is equal to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f== b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_E, a.index, b.index) + + def float_compare_not_equal(self, size, a, b): + """ + ``float_compare_not_equal`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is not equal to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f!= b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_NE, a.index, b.index) + + def float_compare_less_than(self, size, a, b): + """ + ``float_compare_less_than`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is less than to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f< b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_LT, a.index, b.index) + + def float_compare_less_equal(self, size, a, b): + """ + ``float_compare_less_equal`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is less than or equal to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f<= b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_LE, a.index, b.index) + + def float_compare_greater_equal(self, size, a, b): + """ + ``float_compare_greater_equal`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is greater than or equal to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f>= b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_GE, a.index, b.index) + + def float_compare_greater_than(self, size, a, b): + """ + ``float_compare_greater_than`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is greater than or equal to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``a f> b`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_GT, a.index, b.index) + + def float_compare_unordered(self, size, a, b): + """ + ``float_compare_unordered`` returns floating point comparison expression of size ``size`` checking if + expression ``a`` is unordered relative to expression ``b`` + + :param int size: the size of the operands in bytes + :param LowLevelILExpr a: LHS expression + :param LowLevelILExpr b: RHS expression + :param str flags: flags to set + :return: The expression ``is_unordered(a, b)`` + :rtype: LowLevelILExpr + """ + return self.expr(LowLevelILOperation.LLIL_FCMP_UO, a.index, b.index) + def goto(self, label): """ ``goto`` returns a goto expression which jumps to the provided LowLevelILLabel. @@ -1736,6 +2359,7 @@ class LowLevelILBasicBlock(basicblock.BasicBlock): def __hash__(self): return hash((self.start, self.end, self.il_function)) + def LLIL_TEMP(n): return n | 0x80000000 diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py index 6f5515bb..caf19e8e 100644 --- a/python/mediumlevelil.py +++ b/python/mediumlevelil.py @@ -27,6 +27,7 @@ import function import basicblock import lowlevelil import types +import struct class SSAVariable(object): @@ -85,10 +86,12 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_STORE_STRUCT: [("dest", "expr"), ("offset", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_VAR: [("src", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [("src", "var"), ("offset", "int")], + MediumLevelILOperation.MLIL_VAR_SPLIT: [("high", "var"), ("low", "var")], MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [("src", "var"), ("offset", "int")], MediumLevelILOperation.MLIL_CONST: [("constant", "int")], MediumLevelILOperation.MLIL_CONST_PTR: [("constant", "int")], + MediumLevelILOperation.MLIL_FLOAT_CONST: [("constant", "float")], MediumLevelILOperation.MLIL_IMPORT: [("constant", "int")], MediumLevelILOperation.MLIL_ADD: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_ADC: [("left", "expr"), ("right", "expr"), ("carry", "expr")], @@ -108,13 +111,13 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_MULU_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MULS_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_DIVU: [("left", "expr"), ("right", "expr")], - MediumLevelILOperation.MLIL_DIVU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVU_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_DIVS: [("left", "expr"), ("right", "expr")], - MediumLevelILOperation.MLIL_DIVS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_DIVS_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODU: [("left", "expr"), ("right", "expr")], - MediumLevelILOperation.MLIL_MODU_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODU_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_MODS: [("left", "expr"), ("right", "expr")], - MediumLevelILOperation.MLIL_MODS_DP: [("hi", "expr"), ("lo", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_MODS_DP: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_NEG: [("src", "expr")], MediumLevelILOperation.MLIL_NOT: [("src", "expr")], MediumLevelILOperation.MLIL_SX: [("src", "expr")], @@ -147,9 +150,35 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_SYSCALL_UNTYPED: [("output", "expr"), ("params", "expr"), ("stack", "expr")], MediumLevelILOperation.MLIL_BP: [], MediumLevelILOperation.MLIL_TRAP: [("vector", "int")], + MediumLevelILOperation.MLIL_INTRINSIC: [("output", "var_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + MediumLevelILOperation.MLIL_INTRINSIC_SSA: [("output", "var_ssa_list"), ("intrinsic", "intrinsic"), ("params", "expr_list")], + MediumLevelILOperation.MLIL_FREE_VAR_SLOT: [("dest", "var")], + MediumLevelILOperation.MLIL_FREE_VAR_SLOT_SSA: [("prev", "var_ssa_dest_and_src")], MediumLevelILOperation.MLIL_UNDEF: [], MediumLevelILOperation.MLIL_UNIMPL: [], MediumLevelILOperation.MLIL_UNIMPL_MEM: [("src", "expr")], + MediumLevelILOperation.MLIL_FADD: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FSUB: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FMUL: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FDIV: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FSQRT: [("src", "expr")], + MediumLevelILOperation.MLIL_FNEG: [("src", "expr")], + MediumLevelILOperation.MLIL_FABS: [("src", "expr")], + MediumLevelILOperation.MLIL_FLOAT_TO_INT: [("src", "expr")], + MediumLevelILOperation.MLIL_INT_TO_FLOAT: [("src", "expr")], + MediumLevelILOperation.MLIL_FLOAT_CONV: [("src", "expr")], + MediumLevelILOperation.MLIL_ROUND_TO_INT: [("src", "expr")], + MediumLevelILOperation.MLIL_FLOOR: [("src", "expr")], + MediumLevelILOperation.MLIL_CEIL: [("src", "expr")], + MediumLevelILOperation.MLIL_FTRUNC: [("src", "expr")], + MediumLevelILOperation.MLIL_FCMP_E: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_NE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_LT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_LE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_GE: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_GT: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_O: [("left", "expr"), ("right", "expr")], + MediumLevelILOperation.MLIL_FCMP_UO: [("left", "expr"), ("right", "expr")], MediumLevelILOperation.MLIL_SET_VAR_SSA: [("dest", "var_ssa"), ("src", "expr")], MediumLevelILOperation.MLIL_SET_VAR_SSA_FIELD: [("prev", "var_ssa_dest_and_src"), ("offset", "int"), ("src", "expr")], MediumLevelILOperation.MLIL_SET_VAR_SPLIT_SSA: [("high", "var_ssa"), ("low", "var_ssa"), ("src", "expr")], @@ -159,6 +188,7 @@ class MediumLevelILInstruction(object): MediumLevelILOperation.MLIL_VAR_SSA_FIELD: [("src", "var_ssa"), ("offset", "int")], MediumLevelILOperation.MLIL_VAR_ALIASED: [("src", "var_ssa")], MediumLevelILOperation.MLIL_VAR_ALIASED_FIELD: [("src", "var_ssa"), ("offset", "int")], + MediumLevelILOperation.MLIL_VAR_SPLIT_SSA: [("high", "var_ssa"), ("low", "var_ssa")], MediumLevelILOperation.MLIL_CALL_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr_list"), ("src_memory", "int")], MediumLevelILOperation.MLIL_CALL_UNTYPED_SSA: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")], MediumLevelILOperation.MLIL_SYSCALL_SSA: [("output", "expr"), ("params", "expr_list"), ("src_memory", "int")], @@ -192,8 +222,17 @@ class MediumLevelILInstruction(object): name, operand_type = operand if operand_type == "int": value = instr.operands[i] + elif operand_type == "float": + if instr.size == 4: + value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0] + elif instr.size == 8: + value = struct.unpack("d", struct.pack("Q", instr.operands[i]))[0] + else: + value = instr.operands[i] elif operand_type == "expr": value = MediumLevelILInstruction(func, instr.operands[i]) + elif operand_type == "intrinsic": + value = lowlevelil.ILIntrinsic(func.arch, instr.operands[i]) elif operand_type == "var": value = function.Variable.from_identifier(self.function.source_function, instr.operands[i]) elif operand_type == "var_ssa": diff --git a/python/platform.py b/python/platform.py index 5e63d836..a79e3b9a 100644 --- a/python/platform.py +++ b/python/platform.py @@ -105,7 +105,7 @@ class Platform(object): else: self.handle = handle self.__dict__["name"] = core.BNGetPlatformName(self.handle) - self.arch = architecture.Architecture(core.BNGetPlatformArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(self.handle)) def __del__(self): core.BNFreePlatform(self.handle) diff --git a/python/plugin.py b/python/plugin.py index e0054d86..c6cd9fc0 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -30,6 +30,8 @@ import filemetadata import binaryview import function import log +import lowlevelil +import mediumlevelil class PluginCommandContext(object): @@ -38,6 +40,7 @@ class PluginCommandContext(object): self.address = 0 self.length = 0 self.function = None + self.instruction = None class _PluginCommandMetaClass(type): @@ -118,6 +121,50 @@ class PluginCommand(object): log.log_error(traceback.format_exc()) @classmethod + def _low_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _low_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + + @classmethod def _default_is_valid(cls, view, is_valid): try: if is_valid is None: @@ -167,6 +214,62 @@ class PluginCommand(object): return False @classmethod + def _low_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _low_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod def register(cls, name, description, action, is_valid = None): """ ``register`` Register a plugin @@ -243,6 +346,82 @@ class PluginCommand(object): core.BNRegisterPluginCommandForFunction(name, description, action_obj, is_valid_obj, None) @classmethod + def register_for_low_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_function`` Register a plugin to be called with a low level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_low_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_instruction`` Register a plugin to be called with a low level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILInstruction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_function`` Register a plugin to be called with a medium level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_instruction`` Register a plugin to be called with a medium level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILInstruction(name, description, action_obj, is_valid_obj, None) + + @classmethod def get_valid_list(cls, context): """Dict of registered plugins""" commands = cls.list @@ -275,6 +454,36 @@ class PluginCommand(object): if not self.command.functionIsValid: return True return self.command.functionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.lowLevelILFunctionIsValid: + return True + return self.command.lowLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, lowlevelil.LowLevelILInstruction): + return False + if not self.command.lowLevelILInstructionIsValid: + return True + return self.command.lowLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.mediumLevelILFunctionIsValid: + return True + return self.command.mediumLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, mediumlevelil.MediumLevelILInstruction): + return False + if not self.command.mediumLevelILInstructionIsValid: + return True + return self.command.mediumLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) return False def execute(self, context): @@ -288,6 +497,16 @@ class PluginCommand(object): self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length) elif self.command.type == PluginCommandType.FunctionPluginCommand: self.command.functionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + self.command.lowLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + self.command.lowLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + self.command.mediumLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + self.command.mediumLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) def __repr__(self): return "<PluginCommand: %s>" % self.name diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index c92c249a..e7838748 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -540,7 +540,7 @@ class PythonScriptingInstance(ScriptingInstance): self.locals["current_address"] = self.active_addr self.locals["here"] = self.active_addr self.locals["current_selection"] = (self.active_selection_begin, self.active_selection_end) - if self.active_func == None: + if self.active_func is None: self.locals["current_llil"] = None self.locals["current_mlil"] = None else: @@ -556,6 +556,8 @@ class PythonScriptingInstance(ScriptingInstance): elif self.locals["current_address"] != self.active_addr: if not self.active_view.file.navigate(self.active_view.file.view, self.locals["current_address"]): sys.stderr.write("Address 0x%x is not valid for the current view\n" % self.locals["current_address"]) + if self.active_view is not None: + self.active_view.update_analysis() except: traceback.print_exc() finally: diff --git a/python/types.py b/python/types.py index f5279047..42ed7ddd 100644 --- a/python/types.py +++ b/python/types.py @@ -641,7 +641,7 @@ class Type(object): return core.BNGenerateAutoDemangledTypeId(name) @classmethod - def get_auto_demanged_type_id_source(self): + def get_auto_demangled_type_id_source(self): return core.BNGetAutoDemangledTypeIdSource() def with_confidence(self, confidence): @@ -687,6 +687,21 @@ class SizeWithConfidence(object): return self.value +class RegisterStackAdjustmentWithConfidence(object): + def __init__(self, value, confidence = max_confidence): + self.value = value + self.confidence = confidence + + def __str__(self): + return str(self.value) + + def __repr__(self): + return repr(self.value) + + def __int__(self): + return self.value + + class RegisterSet(object): def __init__(self, reg_list, confidence = max_confidence): self.regs = reg_list |
