diff options
| author | rose <47357290+rose4096@users.noreply.github.com> | 2022-05-20 13:30:17 -0400 |
|---|---|---|
| committer | rose <47357290+rose4096@users.noreply.github.com> | 2022-05-31 12:47:49 -0400 |
| commit | 6df2db145bdcc7e541c71d5843d270ecebbd6143 (patch) | |
| tree | 27d14a802655e31c9f593c37fb64fe8ad90bd276 | |
| parent | d03f3e58fcdd548c788eeff51d7507e07ed799ed (diff) | |
Increase coverage of architecture.py
| -rw-r--r-- | python/binaryview.py | 2 | ||||
| -rw-r--r-- | suite/api_test.py | 32 | ||||
| -rw-r--r-- | suite/testcommon.py | 143 |
3 files changed, 152 insertions, 25 deletions
diff --git a/python/binaryview.py b/python/binaryview.py index fdd03f37..9ce51386 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -274,7 +274,7 @@ class AnalysisCompletionEvent: del self.__class__._pending_analysis_completion_events[id(self)] try: arg_offset = inspect.ismethod(self.callback) - callback_spec = inspect.getargspec(self.callback) + callback_spec = inspect.getfullargspec(self.callback) if len(callback_spec.args) > arg_offset: self.callback(self) # type: ignore else: diff --git a/suite/api_test.py b/suite/api_test.py index 5b087034..7291b8c1 100644 --- a/suite/api_test.py +++ b/suite/api_test.py @@ -2989,3 +2989,35 @@ class TestBinaryViewType(unittest.TestCase): with BinaryViewType.get_view_of_file(filename) as bv: assert bvt2.is_valid_for_data(bv.parent_view) assert isinstance(bvt2.parse(bv.parent_view), BinaryView) + + +class TestArchitecture(TestWithBinaryView): + def test_available_patches_x86(self): + x86 = binaryninja.Architecture["x86"] + + je_0 = x86.assemble("je 0") + call_0 = x86.assemble("call 0") + jmp_eax = x86.assemble("jmp eax") + + assert x86.is_never_branch_patch_available(je_0, 0) == True + assert x86.is_never_branch_patch_available(call_0, 0) == False + + assert x86.is_always_branch_patch_available(je_0, 0) == True + assert x86.is_always_branch_patch_available(call_0, 0) == False + + assert x86.is_invert_branch_patch_available(je_0, 0) == True + assert x86.is_invert_branch_patch_available(call_0, 0) == False + + assert x86.is_skip_and_return_zero_patch_available(call_0, 0) == True + assert x86.is_skip_and_return_zero_patch_available(jmp_eax, 0) == False + + assert x86.is_skip_and_return_value_patch_available(call_0, 0) == True + assert x86.is_skip_and_return_value_patch_available(jmp_eax, 0) == False + + assert x86.convert_to_nop(je_0, 0) == b'\x90\x90\x90\x90\x90\x90' + assert x86.always_branch(je_0, 0) == b'\x90\xe9\xfa\xff\xff\xff' + assert x86.invert_branch(je_0, 0) == b'\x0f\x85\xfa\xff\xff\xff' + assert x86.skip_and_return_value(je_0, 0, 0) == b'\xb8\x00\x00\x00\x00\x90' + + def test_available_typelibs(self): + assert len(self.bv.arch.type_libraries) > 0 diff --git a/suite/testcommon.py b/suite/testcommon.py index 788e0f39..99e9c6b9 100644 --- a/suite/testcommon.py +++ b/suite/testcommon.py @@ -559,36 +559,131 @@ class TestBuilder(Builder): return result def test_Architecture(self): - """Architecture failure""" - if not os.path.exists(os.path.join(os.path.expanduser("~"), '.binaryninja', 'plugins', 'nes.py')): - return [""] - + """Architectures produced different results""" retinfo = [] - file_name = os.path.join(os.path.dirname(__file__), self.test_store, "..", "pwnadventurez.nes") - bv = binja.BinaryViewType["NES Bank 0"].open(file_name) - for i in bv.platform.arch.calling_conventions: - retinfo.append("Custom arch calling convention: " + str(i)) - for i in bv.platform.arch.full_width_regs: - retinfo.append("Custom arch full width reg: " + str(i)) + flag_reg0 = binja.FlagName("reg0") + reg_reg0 = binja.RegisterName("reg0") + reg_fwidthreg0 = binja.RegisterName("fwidth_reg0") + stack_reg0 = binja.RegisterStackName("reg0") + semgrp_flggrp0 = binja.SemanticGroupName("flggrp0") + semcls_cls0 = binja.SemanticClassName("cls0") - reg = binja.RegisterValue() - retinfo.append("Reg entry value: " + str(reg.entry_value(bv.platform.arch, 'x'))) - retinfo.append("Reg constant: " + str(reg.constant(0xfe))) - retinfo.append("Reg constant pointer: " + str(reg.constant_ptr(0xcafebabe))) - retinfo.append("Reg stack frame offset: " + str(reg.stack_frame_offset(0x10))) - retinfo.append("Reg imported address: " + str(reg.imported_address(0xdeadbeef))) - retinfo.append("Reg return address: " + str(reg.return_address())) + class ArchTest(binja.Architecture): + name = "ArchTest" + address_size = -1 + default_int_size = -1 + instr_alignment = -1 + opcode_display_length = 1 + max_instr_length = -1 + regs = { + reg_reg0: binja.RegisterInfo(reg_reg0, 2) + } + stack_pointer = "reg0" + flags = [flag_reg0, binja.FlagName("reg0_flg")] + flag_write_types = [binja.FlagWriteTypeName("*")] + flag_roles = { + flag_reg0: binja.FlagRole.SpecialFlagRole, + "reg0_flg": "SpecialFlagRole" + } + flags_required_for_flag_condition = { + binja.LowLevelILFlagCondition.LLFC_UGE: [flag_reg0] + } + flags_written_by_flag_write_type = { + "*": ["reg0"] + } + full_width_regs = { + reg_fwidthreg0: binja.RegisterInfo(reg_fwidthreg0, 3) + } + reg_stacks = { + stack_reg0: binja.RegisterStackInfo([stack_reg0], [stack_reg0], stack_reg0, 0) + } + semantic_flag_groups = { + semgrp_flggrp0: 0 + } + flags_required_by_semantic_flag_group = { + semgrp_flggrp0: [0] + } + flags_required_for_semantic_flag_group = { + semgrp_flggrp0: [flag_reg0] + } + semantic_flag_classes = { + semcls_cls0: 0 + } + # flag_conditions_for_semantic_flag_group = { + # semgrp_flggrp0: semcls_cls0 + # } - bv.update_analysis_and_wait() - for func in bv.functions: - for bb in func.low_level_il.basic_blocks: - for ins in bb: - retinfo.append("Instruction info: " + str(bv.platform.arch.get_instruction_info(0x10, ins.address))) - retinfo.append("Instruction test: " + str(bv.platform.arch.get_instruction_text(0x10, ins.address))) - retinfo.append("Instruction: " + str(ins)) + def get_instruction_text(self, data, addr): + return [binja.InstructionTextToken(binja.InstructionTextTokenType.TextToken, "not hooked")], 1 + + class EmptyArch(binja.Architecture): + pass + + ArchTest.register() + + try: + EmptyArch.register() + assert False # Registering an empty arch should fail (this code should not be reached) + except: + pass + + at = binja.Architecture['ArchTest'] + + assert len(at.type_libraries) == 0 + + assert at.can_assemble == False + assert binja.Architecture['x86'].can_assemble == True + + for arch in binja.Architecture: + retinfo.append(f"Arch calling convention: {arch.calling_conventions}") + retinfo.append(f"Arch regs: {arch.regs}") + retinfo.append(f"Arch full width regs: {arch.full_width_regs}") + retinfo.append(f"Arch standalone platform: {arch.standalone_platform}") + retinfo.append(f"Arch repr: {repr(arch)}") + retinfo.append(f"Arch endianness: {arch.endianness}") + retinfo.append(f"Arch address size: {arch.address_size}") + retinfo.append(f"Arch default int size: {arch.default_int_size}") + retinfo.append(f"Arch instr alignment: {arch.instr_alignment}") + retinfo.append(f"Arch max instr length: {arch.max_instr_length}") + retinfo.append(f"Arch opcode display length: {arch.opcode_display_length}") + retinfo.append(f"Arch stack pointer: {arch.stack_pointer}") + retinfo.append(f"Arch link reg: {arch.link_reg}") + retinfo.append(f"Arch & address: {arch.get_associated_arch_by_address(0)}") + + assert binja.Architecture['x86'] == binja.Architecture['x86'] + assert binja.Architecture['x86'] != binja.Architecture['x86_64'] return retinfo + def test_ArchitectureHook(self): + class ArchTestHook(binja.ArchitectureHook): + def get_instruction_text(self, data, addr): + return [binja.InstructionTextToken(binja.InstructionTextTokenType.TextToken, "hooked")], 1 + + class ArchTestHook2(binja.ArchitectureHook): + pass + + at = binja.Architecture["ArchTest"] + instr_text = at.get_instruction_text(b'\x00', 1) + + ArchTestHook(at).register() + instr_text_hooked = at.get_instruction_text(b'\x00', 1) + + # Register empty hook + ArchTestHook2(at).register() + + assert instr_text != instr_text_hooked + assert instr_text == instr_text + + ath2 = ArchTestHook2(at) + assert ath2.base_arch == at + ath2.base_arch = binja.Architecture["x86"] + assert ath2.base_arch == binja.Architecture["x86"] + ath2.base_arch = at + assert ath2.base_arch == at + return [f"{at}"] + + def test_Function(self): """Function produced different result""" inttype = binja.Type.int(4) |
