def __init__ (self, binary): self.elf = elffile.ELFFile(binary) if self.elf.elfclass == 32: self.arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) if self.elf.elfclass == 64: self.arch_info = X86ArchitectureInformation(ARCH_X86_MODE_64) self.emulator = ReilEmulator(self.arch_info.address_size) self.emulator.set_arch_registers(self.arch_info.registers_gp) self.emulator.set_arch_registers_size(self.arch_info.register_size) self.emulator.set_reg_access_mapper(self.arch_info.register_access_mapper()) self.classifier = GadgetClassifier(self.emulator, self.arch_info) self.smt_solver = SmtSolver() self.smt_translator = SmtTranslator(self.smt_solver, self.arch_info.address_size) self.smt_translator.set_reg_access_mapper(self.arch_info.register_access_mapper()) self.smt_translator.set_arch_registers_size(self.arch_info.register_size) self.code_analyzer = CodeAnalyzer(self.smt_solver, self.smt_translator) self.gadgets = {} self.classified_gadgets = {} self.regset = RegSet(self) self.ccf = CCFlag(self) self.ams = ArithmeticStore(self) self.memstr = MemoryStore(self) self.reil_translator = X86Translator(architecture_mode=self.arch_info.architecture_mode, translation_mode=FULL_TRANSLATION)
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 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_32) self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size) self._ir_emulator = ReilEmulator(self._arch_info.address_size) self._ir_emulator.set_arch_registers(self._arch_info.registers_gp_all) self._ir_emulator.set_arch_registers_size( self._arch_info.registers_size) self._ir_emulator.set_reg_access_mapper(self._arch_info.alias_mapper) self._smt_translator.set_reg_access_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._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(), binary, ArmTranslator(translation_mode=LITE_TRANSLATION), ARCH_ARM, ARCH_ARM_MODE_32) 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 = "\x04\x00\xa0\xe1" # 0x00 : (4) mov r0, r4 binary += "\x31\xff\x2f\xe1" # 0x04 : (4) blx r1 g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[0].type, GadgetType.MoveRegister) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(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 = "\x00\x00\x84\xe2" # 0x00 : (4) add r0, r4, #0 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.MoveRegister) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(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 = "\x0a\x20\xa0\xe3" # 0x00 : (4) mov r2, #10 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(10, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x02\x20\x42\xe0" # 0x00 : (4) sub r2, r2, r2 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x02\x20\x22\xe0" # 0x00 : (4) eor r2, r2, r2 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x00\x20\x02\xe2" # 0x00 : (4) and r2, r2, #0 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x00\x20\x02\xe2" # and r2, r2, #0 binary += "\x21\x20\x82\xe3" # orr r2, r2, #33 binary += "\x1e\xff\x2f\xe1" # bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(33, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x08\x00\x84\xe0" # 0x00 : (4) add r0, r4, r8 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.Arithmetic) self.assertEquals( g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[0].operation, "+") self.assertEquals(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 = "\x08\x00\x44\xe0" # 0x00 : (4) sub r0, r4, r8 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.Arithmetic) self.assertEquals( g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[0].operation, "-") self.assertEquals(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 = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadMemory) self.assertEquals( g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEquals(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 = "\x33\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4 + 0x33] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadMemory) self.assertEquals( g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEquals(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 = "\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.StoreMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEquals( g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(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 = "\x33\x30\x84\xe5" # 0x00 : (4) str r3, [r4 + 0x33] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.StoreMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEquals( g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEquals(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 = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticLoad) self.assertEquals(g_classified[1].sources, [ ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32) ]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse( ReilRegisterOperand("r0", 32) in g_classified[1].modified_registers) self.assertTrue( ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_load_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = "\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += "\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticLoad) self.assertEquals(g_classified[1].sources, [ ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32) ]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse( ReilRegisterOperand("r0", 32) in g_classified[1].modified_registers) self.assertTrue( ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_store_add_1(self): # testing : m[dst_reg] <- m[dst_reg] + src_reg binary = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += "\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticStore) self.assertEquals(g_classified[1].sources, [ ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32) ]) self.assertEquals( g_classified[1].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse( ReilRegisterOperand("r4", 32) in g_classified[1].modified_registers) self.assertTrue( ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_store_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = "\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += "\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += "\x22\x30\x84\xe5" # 0x00 : (4) str r3, [r4, 0x22] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticStore) self.assertEquals(g_classified[1].sources, [ ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32) ]) self.assertEquals( g_classified[1].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse( ReilRegisterOperand("r4", 32) in g_classified[1].modified_registers) self.assertTrue( ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) 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_32) self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._arch_info.address_size) self._ir_emulator = ReilEmulator(self._arch_info.address_size) self._ir_emulator.set_arch_registers(self._arch_info.registers_gp_all) self._ir_emulator.set_arch_registers_size(self._arch_info.registers_size) self._ir_emulator.set_reg_access_mapper(self._arch_info.alias_mapper) self._smt_translator.set_reg_access_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._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(), binary, ArmTranslator(translation_mode=LITE_TRANSLATION), ARCH_ARM, ARCH_ARM_MODE_32) 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 = "\x04\x00\xa0\xe1" # 0x00 : (4) mov r0, r4 binary += "\x31\xff\x2f\xe1" # 0x04 : (4) blx r1 g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[0].type, GadgetType.MoveRegister) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(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 = "\x00\x00\x84\xe2" # 0x00 : (4) add r0, r4, #0 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.MoveRegister) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(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 = "\x0a\x20\xa0\xe3" # 0x00 : (4) mov r2, #10 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(10, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x02\x20\x42\xe0" # 0x00 : (4) sub r2, r2, r2 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x02\x20\x22\xe0" # 0x00 : (4) eor r2, r2, r2 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x00\x20\x02\xe2" # 0x00 : (4) and r2, r2, #0 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x00\x20\x02\xe2" # and r2, r2, #0 binary += "\x21\x20\x82\xe3" # orr r2, r2, #33 binary += "\x1e\xff\x2f\xe1" # bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadConstant) self.assertEquals(g_classified[0].sources, [ReilImmediateOperand(33, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r2", 32)]) self.assertEquals(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 = "\x08\x00\x84\xe0" # 0x00 : (4) add r0, r4, r8 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.Arithmetic) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[0].operation, "+") self.assertEquals(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 = "\x08\x00\x44\xe0" # 0x00 : (4) sub r0, r4, r8 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.Arithmetic) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilRegisterOperand("r8", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[0].operation, "-") self.assertEquals(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 = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEquals(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 = "\x33\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4 + 0x33] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.LoadMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r3", 32)]) self.assertEquals(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 = "\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.StoreMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(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 = "\x33\x30\x84\xe5" # 0x00 : (4) str r3, [r4 + 0x33] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 1) self.assertEquals(g_classified[0].type, GadgetType.StoreMemory) self.assertEquals(g_classified[0].sources, [ReilRegisterOperand("r3", 32)]) self.assertEquals(g_classified[0].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x33, 32)]) self.assertEquals(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 = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticLoad) self.assertEquals(g_classified[1].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[1].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_load_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = "\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += "\x03\x00\x80\xe0" # 0x00 : (4) add r0, r0, r3 binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticLoad) self.assertEquals(g_classified[1].sources, [ReilRegisterOperand("r0", 32), ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r0", 32) in g_classified[1].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_store_add_1(self): # testing : m[dst_reg] <- m[dst_reg] + src_reg binary = "\x00\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4] binary += "\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += "\x00\x30\x84\xe5" # 0x00 : (4) str r3, [r4] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticStore) self.assertEquals(g_classified[1].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32), ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x0, 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[1].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) def test_arithmetic_store_add_2(self): # testing : dst_reg <- dst_reg + mem[src_reg + offset] binary = "\x22\x30\x94\xe5" # 0x00 : (4) ldr r3, [r4, 0x22] binary += "\x03\x30\x80\xe0" # 0x00 : (4) add r3, r0, r3 binary += "\x22\x30\x84\xe5" # 0x00 : (4) str r3, [r4, 0x22] binary += "\x1e\xff\x2f\xe1" # 0x04 : (4) bx lr g_candidates, g_classified = self._find_and_classify_gadgets(binary) self.assertEquals(len(g_candidates), 1) self.assertEquals(len(g_classified), 2) self.assertEquals(g_classified[1].type, GadgetType.ArithmeticStore) self.assertEquals(g_classified[1].sources, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32), ReilRegisterOperand("r0", 32)]) self.assertEquals(g_classified[1].destination, [ReilRegisterOperand("r4", 32), ReilImmediateOperand(0x22, 32)]) self.assertEquals(g_classified[1].operation, "+") self.assertEquals(len(g_classified[1].modified_registers), 1) self.assertFalse(ReilRegisterOperand("r4", 32) in g_classified[1].modified_registers) self.assertTrue(ReilRegisterOperand("r3", 32) in g_classified[1].modified_registers) self.assertTrue(self._g_verifier.verify(g_classified[1])) 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 GadgetTools(): def __init__ (self, binary): self.elf = elffile.ELFFile(binary) if self.elf.elfclass == 32: self.arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) if self.elf.elfclass == 64: self.arch_info = X86ArchitectureInformation(ARCH_X86_MODE_64) self.emulator = ReilEmulator(self.arch_info.address_size) self.emulator.set_arch_registers(self.arch_info.registers_gp) self.emulator.set_arch_registers_size(self.arch_info.register_size) self.emulator.set_reg_access_mapper(self.arch_info.register_access_mapper()) self.classifier = GadgetClassifier(self.emulator, self.arch_info) self.smt_solver = SmtSolver() self.smt_translator = SmtTranslator(self.smt_solver, self.arch_info.address_size) self.smt_translator.set_reg_access_mapper(self.arch_info.register_access_mapper()) self.smt_translator.set_arch_registers_size(self.arch_info.register_size) self.code_analyzer = CodeAnalyzer(self.smt_solver, self.smt_translator) self.gadgets = {} self.classified_gadgets = {} self.regset = RegSet(self) self.ccf = CCFlag(self) self.ams = ArithmeticStore(self) self.memstr = MemoryStore(self) self.reil_translator = X86Translator(architecture_mode=self.arch_info.architecture_mode, translation_mode=FULL_TRANSLATION) def find_gadgets(self, max_instr=10, max_bytes=15): logging.info('searching gadgets in binary..') for s in self.elf.iter_sections(): if (s.header.sh_type == 'SHT_PROGBITS') and (s.header.sh_flags & 0x4): sz = s.header.sh_size base = s.header.sh_addr mem = Memory(lambda x, y : s.data()[x - base], None) gfinder = GadgetFinder(X86Disassembler(architecture_mode=self.arch_info.architecture_mode), mem, self.reil_translator) logging.info("searching gadgets in section " + s.name + "...") for g in gfinder.find(base, base + sz - 1, max_instr, max_bytes): ret = g.instrs[-1].asm_instr if not isinstance(ret, Ret): continue if len(ret.operands) > 0 and ret.operands[0].immediate > 0x10: continue self.gadgets[g.address] = g logging.info("found {0} gadgets".format(len(self.gadgets))) def classify_gadgets(self): #setting 0 to cf flags to avoid impossible random value invalidates results rflags = self.classifier.set_reg_init({'cf': 0}) for g in self.gadgets.itervalues(): tgs = self.classifier.classify(g) for tg in tgs: if tg.type not in self.classified_gadgets: self.classified_gadgets[tg.type] = [] self.classified_gadgets[tg.type].append(tg) def find_reg_set_gadgets(self): self.regset.add(self.gadgets.itervalues()) def read_carrier_flag(self, g): self.emulator.reset() regs_init = utils.make_random_regs_context(self.arch_info) self.emulator.execute_lite(g.get_ir_instrs(), regs_init) return 'eflags' in self.emulator.registers def find_arithmetic_mem_set_gadgets(self): self.ams.add(self.classified_gadgets[GadgetType.ArithmeticStore]) def get_stack_slide_chunk(self, slide): #TODO not use only pop gadgets and chain more slide if we wan't longer slide return self.regset.get_slide_stack_chunk(slide) def get_ret_func_chunk(self, args, address): """Return a chainable chunk that return to address and set up args or registers as if a function was called with args. Args: args (list): the list of args to setup as function arguments address (int): the address where to return """ if self.arch_info.architecture_size == 64: if len(args) > 6: raise BaseException("chunk for calling a function whit more of six args isn't implemented") args_regs = ['rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9'] regs_values = {args_regs[i] : a for i, a in enumerate(args)} regs_c = self.regset.get_chunk(regs_values) ret_c = PayloadChunk("", self.arch_info, address) return PayloadChunk.get_general_chunk([regs_c, ret_c]) if self.arch_info.architecture_size == 32: slide_c = self.regset.get_slide_stack_chunk(len(args) * 4) print slide_c ret_c = RetToAddress32(args, address, self.arch_info) print ret_c return PayloadChunk.get_general_chunk([ret_c, slide_c]) def get_mem_set_libc_read_chunk(self, location, fd, size, read_address): if self.arch_info.architecture_size == 64: print "TO IMPLEMENT" return if self.arch_info.architecture_size == 32: slide_chunk = self.regset.get_slide_stack_chunk(4 * 3) pl_chunk = MemSetLibcRead32(location, fd, size, read_address, self.arch_info) return PayloadChunk.get_general_chunk([pl_chunk, slide_chunk]) def build_mem_add(self, location, offset, size, mem_pre = None): return self.ams.get_memory_add_chunk(location, offset, size, mem_pre) def check_mem_side_effects_and_stack_end(self, g, regs_init, location, size): stack_reg = 'esp' if (self.arch_info.architecture_size == 64): stack_reg = 'rsp' stack_base = 0x50 regs_init[stack_reg] = stack_base #TODO fix try and execute (zero div in mv where finding ccf) try: cregs, mem_final = self.emulator.execute_lite(g.get_ir_instrs(), regs_init) except: pass mem_side_effects = [] for addr in mem_final.get_addresses(): if addr in [location + i for i in xrange(size/8)]: continue sp, vp = mem_final.try_read_prev(addr, 8) sn, vn = mem_final.try_read(addr, 8) #quick fix. We should disting between reading from stack and read side effetcs if sn and not sp and (addr >= stack_base - abs(stack_base - cregs[stack_reg]) and addr <= stack_base + abs(stack_base - cregs[stack_reg])): continue if (sp and sn and vp != vn) or (sn and not sp) : mem_side_effects.append(addr) return mem_side_effects, cregs[stack_reg] - stack_base - self.arch_info.address_size / 8 def find_memory_store(self): self.mem_set_gadgets = {} if not GadgetType.StoreMemory in self.classified_gadgets: return self.memstr.add(self.classified_gadgets[GadgetType.StoreMemory]) def find_ccfs(self): self.ccf.add(self.gadgets.values())