diff --git a/disassemblers/ofrak_capstone/ofrak_capstone/disassembler_service_capstone.py b/disassemblers/ofrak_capstone/ofrak_capstone/disassembler_service_capstone.py index 7cde9f7db..942a8eb10 100644 --- a/disassemblers/ofrak_capstone/ofrak_capstone/disassembler_service_capstone.py +++ b/disassemblers/ofrak_capstone/ofrak_capstone/disassembler_service_capstone.py @@ -199,7 +199,35 @@ def _get_cs_mode_flag(cs_disam: CapstoneDisassemblerType): def _asm_fixups(base_mnemonic: str, base_operands: str, isa: InstructionSet) -> Tuple[str, str]: - operands = re.sub(RE_REPRESENT_CONSTANTS_HEX, r"\g<1>0x\g<2>", base_operands) + arm64_vector_hexify_exclusion_mnems = [ + "movi", + "fdiv", + "fmax", + "fmla", + "fmls", + "fmov", + "fmul", + "fmulx", + "fneg", + ] + """ + In AARCH64, vector instructions use numerical constants to reference vectors to perform operations on + These numerical constants shouldn't be converted to hex because keystone will be unable to reassemble them + In every other case we want to do the hex conversion + """ + hex_operand_fixup = lambda base_operands: re.sub( + RE_REPRESENT_CONSTANTS_HEX, r"\g<1>0x\g<2>", base_operands + ) + + if isa is InstructionSet.AARCH64: + if base_mnemonic not in arm64_vector_hexify_exclusion_mnems: + operands = hex_operand_fixup(base_operands) + else: + # do not fixup operands to hex + operands = base_operands + else: + operands = hex_operand_fixup(base_operands) + if isa is InstructionSet.ARM: operands = re.sub(RE_RENAME_FP_TO_R11, r"\1r11\2", operands) diff --git a/disassemblers/ofrak_capstone/ofrak_capstone_test/test_ofrak_capstone.py b/disassemblers/ofrak_capstone/ofrak_capstone_test/test_ofrak_capstone.py index e9e93cb5a..d9418e725 100644 --- a/disassemblers/ofrak_capstone/ofrak_capstone_test/test_ofrak_capstone.py +++ b/disassemblers/ofrak_capstone/ofrak_capstone_test/test_ofrak_capstone.py @@ -27,7 +27,7 @@ RegisterAnalyzerTestCase, RegisterUsageTestPattern, ) -from test_ofrak.constants import ARM32_ARCH +from test_ofrak.constants import ARM32_ARCH, AARCH64_ARCH pytest_plugins = ["pytest_ofrak.fixtures"] @@ -196,13 +196,40 @@ async def _initialize_basic_bloc_resource(self, ofrak) -> Resource: InstructionSetMode.NONE, ), ], - ) + ), + UnpackerTestCase( + "AARCH64", + AARCH64_ARCH, + BasicBlock(0x100, 0x14, InstructionSetMode.NONE, False, None), + unhexlify("00E4006F"), + [ + Instruction( + 0x100, + 4, + "movi v0.2d, #0000000000000000", + "movi", + "v0.2d, #0000000000000000", + InstructionSetMode.NONE, + ) + ], + ), + UnpackerTestCase( + "AARCH64", + AARCH64_ARCH, + BasicBlock(0x100, 0x14, InstructionSetMode.NONE, False, None), + unhexlify("02102E1E"), + [ + Instruction( + 0x100, 4, "fmov s2, #1.00000000", "fmov", "s2, #1.00000000", InstructionSetMode.NONE + ) + ], + ), ] @pytest.mark.parametrize("test_case", BASIC_BLOCK_TEST_CASES, ids=lambda tc: tc.label) async def test_capstone_unpacker(test_case, ofrak_context): - await test_case.run_instruction_analzyer_test_case(ofrak_context) + await test_case.run_instruction_unpacker_test_case(ofrak_context) @pytest.mark.parametrize("test_case", BASIC_BLOCK_TEST_CASES, ids=lambda tc: tc.label) diff --git a/ofrak_core/CHANGELOG.md b/ofrak_core/CHANGELOG.md index c8b76eb43..a9d8765ec 100644 --- a/ofrak_core/CHANGELOG.md +++ b/ofrak_core/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Fixed - Fixed a bug where clicking "Unpack" or "Identify" (for example) too quickly after loading a large resource causes an error that freezes up the whole GUI ([#297](https://github.com/redballoonsecurity/ofrak/pull/297)) - Bump `importlib-metadata` version to fix import errors ([#296](https://github.com/redballoonsecurity/ofrak/pull/296)) +- Fixed a bug in assembler_service_keystone that mishandled AARCH64 vector instructions ## [3.0.0](https://github.com/redballoonsecurity/ofrak/compare/ofrak-v2.2.1...ofrak-v3.0.0) ### Added diff --git a/ofrak_core/test_ofrak/constants.py b/ofrak_core/test_ofrak/constants.py index c103e7fcc..18720f2b5 100644 --- a/ofrak_core/test_ofrak/constants.py +++ b/ofrak_core/test_ofrak/constants.py @@ -27,3 +27,11 @@ Endianness.BIG_ENDIAN, None, ) + +AARCH64_ARCH = ProgramAttributes( + InstructionSet.AARCH64, + None, + BitWidth.BIT_64, + Endianness.LITTLE_ENDIAN, + None, +)