def setUp(self): self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM) self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size) self._ir_emulator = ReilEmulator(self._arch_info) self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper) self._smt_translator.set_arch_registers_size(self._arch_info.registers_size) self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info) self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info) self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info)
class ArmGadgetClassifierTests(unittest.TestCase): def setUp(self): self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM) self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size) self._ir_emulator = ReilEmulator(self._arch_info) self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper) self._smt_translator.set_arch_registers_size(self._arch_info.registers_size) self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info) self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info) self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info) def _find_and_classify_gadgets(self, binary): g_finder = GadgetFinder(ArmDisassembler(architecture_mode=ARCH_ARM_MODE_ARM), bytearray(binary), ArmTranslator(), ARCH_ARM, ARCH_ARM_MODE_ARM) g_candidates = g_finder.find(0x00000000, len(binary), instrs_depth=4) g_classified = self._g_classifier.classify(g_candidates[0]) # Debug: # self._print_candidates(g_candidates) # self._print_classified(g_classified) return g_candidates, g_classified def test_move_register_1(self): # testing : dst_reg <- src_reg binary = b"\x04\x00\xa0\xe1" # 0x00 : (4) mov r0, r4 binary += b"\x31\xff\x2f\xe1" # 0x04 : (4) blx r1 g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertTrue(ReilRegisterOperand("r14", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_move_register_2(self): # testing : dst_reg <- src_reg binary = b"\x00\x00\x84\xe2" # 0x00 : (4) add r0, r4, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) # TODO: test_move_register_n: mul r0, r4, #1 def test_load_constant_1(self): # testing : dst_reg <- constant binary = b"\x0a\x20\xa0\xe3" # 0x00 : (4) mov r2, #10 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(10, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_2(self): # testing : dst_reg <- constant binary = b"\x02\x20\x42\xe0" # 0x00 : (4) sub r2, r2, r2 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_3(self): # testing : dst_reg <- constant binary = b"\x02\x20\x22\xe0" # 0x00 : (4) eor r2, r2, r2 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_4(self): # testing : dst_reg <- constant binary = b"\x00\x20\x02\xe2" # 0x00 : (4) and r2, r2, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_5(self): # testing : dst_reg <- constant binary = b"\x00\x20\x02\xe2" # and r2, r2, #0 binary += b"\x21\x20\x82\xe3" # orr r2, r2, #33 binary += b"\x1e\xff\x2f\xe1" # bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(33, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_add_1(self): # testing : dst_reg <- src1_reg + src2_reg binary = b"\x08\x00\x84\xe0" # 0x00 : (4) add r0, r4, r8 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.Arithmetic) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_sub_1(self): # testing : dst_reg <- src1_reg + src2_reg binary = b"\x08\x00\x44\xe0" # 0x00 : (4) sub r0, r4, r8 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.Arithmetic) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "-") self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_memory_1(self): # testing : dst_reg <- m[src_reg] binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4 + 0x33] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) # TODO: ARM's ldr rd, [rn, r2] is not a valid classification right now def test_store_memory_1(self): # testing : dst_reg <- m[src_reg] binary = b"\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.StoreMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_store_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x84\xe5" # 0x00 : (4) str r3, [r4 + 0x33] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.StoreMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_load_add_1(self): # testing : dst_reg <- dst_reg + mem[src_reg] binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_load_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = b"\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += b"\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_store_add_1(self): # testing : m[dst_reg] <- m[dst_reg] + src_reg binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += b"\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_store_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = b"\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += b"\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += b"\x22\x30\x84\xe5" # 0x00 : (4) str r3, [r4, 0x22] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def _print_candidates(self, candidates): print("Candidates :") for gadget in candidates: print(gadget) print("-" * 10) def _print_classified(self, classified): print("Classified :") for gadget in classified: print(gadget) print(gadget.type) print("-" * 10)
class ArmGadgetClassifierTests(unittest.TestCase): def setUp(self): self._arch_info = ArmArchitectureInformation(ARCH_ARM_MODE_ARM) self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size) self._ir_emulator = ReilEmulator(self._arch_info) self._smt_translator.set_arch_alias_mapper(self._arch_info.alias_mapper) self._smt_translator.set_arch_registers_size(self._arch_info.registers_size) self._code_analyzer = CodeAnalyzer(self._smt_solver, self._smt_translator, self._arch_info) self._g_classifier = GadgetClassifier(self._ir_emulator, self._arch_info) self._g_verifier = GadgetVerifier(self._code_analyzer, self._arch_info) def _find_and_classify_gadgets(self, binary): g_finder = GadgetFinder(ArmDisassembler(architecture_mode=ARCH_ARM_MODE_ARM), bytearray(binary), ArmTranslator(), ARCH_ARM, ARCH_ARM_MODE_ARM) g_candidates = g_finder.find(0x00000000, len(binary), instrs_depth=4) g_classified = self._g_classifier.classify(g_candidates[0]) # Debug: # self._print_candidates(g_candidates) # self._print_classified(g_classified) return g_candidates, g_classified def test_move_register_1(self): # testing : dst_reg <- src_reg binary = b"\x04\x00\xa0\xe1" # 0x00 : (4) mov r0, r4 binary += b"\x31\xff\x2f\xe1" # 0x04 : (4) blx r1 g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_move_register_2(self): # testing : dst_reg <- src_reg binary = b"\x00\x00\x84\xe2" # 0x00 : (4) add r0, r4, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.MoveRegister) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) # TODO: test_move_register_n: mul r0, r4, #1 def test_load_constant_1(self): # testing : dst_reg <- constant binary = b"\x0a\x20\xa0\xe3" # 0x00 : (4) mov r2, #10 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(10, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_2(self): # testing : dst_reg <- constant binary = b"\x02\x20\x42\xe0" # 0x00 : (4) sub r2, r2, r2 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_3(self): # testing : dst_reg <- constant binary = b"\x02\x20\x22\xe0" # 0x00 : (4) eor r2, r2, r2 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_4(self): # testing : dst_reg <- constant binary = b"\x00\x20\x02\xe2" # 0x00 : (4) and r2, r2, #0 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_constant_5(self): # testing : dst_reg <- constant binary = b"\x00\x20\x02\xe2" # and r2, r2, #0 binary += b"\x21\x20\x82\xe3" # orr r2, r2, #33 binary += b"\x1e\xff\x2f\xe1" # bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadConstant) self.assertEqual(g_classified[0].sources, [ReilImmediateOperand(33, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertFalse(ReilRegisterOperand("r2", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_add_1(self): # testing : dst_reg <- src1_reg + src2_reg binary = b"\x08\x00\x84\xe0" # 0x00 : (4) add r0, r4, r8 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.Arithmetic) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_sub_1(self): # testing : dst_reg <- src1_reg + src2_reg binary = b"\x08\x00\x44\xe0" # 0x00 : (4) sub r0, r4, r8 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.Arithmetic) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "-") self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_memory_1(self): # testing : dst_reg <- m[src_reg] binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_load_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4 + 0x33] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.LoadMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) # TODO: ARM's ldr rd, [rn, r2] is not a valid classification right now def test_store_memory_1(self): # testing : dst_reg <- m[src_reg] binary = b"\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.StoreMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_store_memory_2(self): # testing : dst_reg <- m[src_reg + offset] binary = b"\x33\x30\x84\xe5" # 0x00 : (4) str r3, [r4 + 0x33] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 1) self.assertEqual(g_classified[0].type, GadgetType.StoreMemory) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEqual(len(g_classified[0].modified_registers), 0) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_load_add_1(self): # testing : dst_reg <- dst_reg + mem[src_reg] binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_load_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = b"\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += b"\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticLoad) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_store_add_1(self): # testing : m[dst_reg] <- m[dst_reg] + src_reg binary = b"\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += b"\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += b"\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def test_arithmetic_store_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = b"\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += b"\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += b"\x22\x30\x84\xe5" # 0x00 : (4) str r3, [r4, 0x22] binary += b"\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEqual(len(g_candidates), 1) self.assertEqual(len(g_classified), 2) self.assertEqual(g_classified[0].type, GadgetType.ArithmeticStore) self.assertEqual(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32)]) self.assertEqual(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEqual(g_classified[0].operation, "+") self.assertEqual(len(g_classified[0].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[0].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[0].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[0])) def _print_candidates(self, candidates): print("Candidates :") for gadget in candidates: print(gadget) print("-" * 10) def _print_classified(self, classified): print("Classified :") for gadget in classified: print(gadget) print(gadget.type) print("-" * 10)
def barf_classify(gadget_map, printout=True): arch_mode = ARCH_X86_MODE_32 arch_info = X86ArchitectureInformation(arch_mode) translator = X86Translator(arch_mode) instruction_parser = X86Parser(arch_mode) ir_emulator = ReilEmulator(arch_info) classifier = GadgetClassifier(ir_emulator, arch_info) raw_gadgets = {} typed_gadgets = [] for _, gadget in gadget_map.items(): # Translation cycle: from my emulator to BARF representation classifiable = False barf_instr_list = [] for _, instr in gadget.instructions.items(): # Parse a ROPInstruction into the BARF representation of an x86 instruction barf_instr = instruction_parser.parse("{} {}".format( instr.mnemonic, instr.op_str)) barf_instr.address = instr.address try: # Translate an x86 instruction into a list of REIL instructions reil_transl_instrs = translator.translate(barf_instr) barf_instr.ir_instrs = reil_transl_instrs classifiable = True except TranslationError: classifiable = False finally: barf_instr_list.append(barf_instr) # Classification of the gadgets barf_g = RawGadget(barf_instr_list) raw_gadgets[barf_g.address] = barf_g if classifiable: classified = classifier.classify(barf_g) for tg in classified: typed_gadgets.append(tg) if printout: print_gadgets_raw(list(raw_gadgets.values()), sys.stdout, 'addr', True, 'Raw Gadgets', False) verified = [] unverified = [] solver = Z3Solver() translator = SmtTranslator(solver, arch_info.address_size) code_analyzer = CodeAnalyzer(solver, translator, arch_info) verifier = GadgetVerifier(code_analyzer, arch_info) for tg in typed_gadgets: if verifier.verify(tg): verified.append(tg) else: unverified.append(tg) print_gadgets_typed(verified, sys.stdout, arch_info.address_size, 'Verified classification') print_gadgets_typed(unverified, sys.stdout, arch_info.address_size, 'Unverified classification') for tg in typed_gadgets: if tg.address in raw_gadgets: raw_gadgets.pop(tg.address) print_gadgets_raw(list(raw_gadgets.values()), sys.stdout, 'addr', False, 'Not classified', False) return {tg.address: tg for tg in typed_gadgets}