class CodeAnalyzerTests(unittest.TestCase): def setUp(self): self._arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) self._operand_size = self._arch_info.operand_size self._memory = MemoryMock() self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._operand_size) 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._disasm = X86Disassembler() self._ir_translator = X86Translator() self._bb_builder = BasicBlockBuilder(self._disasm, self._memory, self._ir_translator) def test_check_path_satisfiability(self): if VERBOSE: print "[+] Test: test_check_path_satisfiability" # binary : stack1 bin_start_address, bin_end_address = 0x08048ec0, 0x8048f02 binary = "\x55" # 0x08048ec0 : push ebp binary += "\x89\xe5" # 0x08048ec1 : mov ebp,esp binary += "\x83\xec\x60" # 0x08048ec3 : sub esp,0x60 binary += "\x8d\x45\xfc" # 0x08048ec6 : lea eax,[ebp-0x4] binary += "\x89\x44\x24\x08" # 0x08048ec9 : mov DWORD PTR [esp+0x8],eax binary += "\x8d\x45\xac" # 0x08048ecd : lea eax,[ebp-0x54] binary += "\x89\x44\x24\x04" # 0x08048ed0 : mov DWORD PTR [esp+0x4],eax binary += "\xc7\x04\x24\xa8\x5a\x0c\x08" # 0x08048ed4 : mov DWORD PTR [esp],0x80c5aa8 binary += "\xe8\xa0\x0a\x00\x00" # 0x08048edb : call 8049980 <_IO_printf> binary += "\x8d\x45\xac" # 0x08048ee0 : lea eax,[ebp-0x54] binary += "\x89\x04\x24" # 0x08048ee3 : mov DWORD PTR [esp],eax binary += "\xe8\xc5\x0a\x00\x00" # 0x08048ee6 : call 80499b0 <_IO_gets> binary += "\x8b\x45\xfc" # 0x08048eeb : mov eax,DWORD PTR [ebp-0x4] binary += "\x3d\x44\x43\x42\x41" # 0x08048eee : cmp eax,0x41424344 binary += "\x75\x0c" # 0x08048ef3 : jne 8048f01 <main+0x41> binary += "\xc7\x04\x24\xc0\x5a\x0c\x08" # 0x08048ef5 : mov DWORD PTR [esp],0x80c5ac0 binary += "\xe8\x4f\x0c\x00\x00" # 0x08048efc : call 8049b50 <_IO_puts> binary += "\xc9" # 0x08048f01 : leave binary += "\xc3" # 0x08048f02 : ret self._memory.set_base_address(bin_start_address) self._memory.set_content(binary) start = 0x08048ec0 # start = 0x08048ec6 # end = 0x08048efc end = 0x08048f01 registers = { "eax" : GenericRegister("eax", 32, 0xffffd0ec), "ecx" : GenericRegister("ecx", 32, 0x00000001), "edx" : GenericRegister("edx", 32, 0xffffd0e4), "ebx" : GenericRegister("ebx", 32, 0x00000000), "esp" : GenericRegister("esp", 32, 0xffffd05c), "ebp" : GenericRegister("ebp", 32, 0x08049580), "esi" : GenericRegister("esi", 32, 0x00000000), "edi" : GenericRegister("edi", 32, 0x08049620), "eip" : GenericRegister("eip", 32, 0x08048ec0), } flags = { "af" : GenericFlag("af", 0x0), "cf" : GenericFlag("cf", 0x0), "of" : GenericFlag("of", 0x0), "pf" : GenericFlag("pf", 0x1), "sf" : GenericFlag("sf", 0x0), "zf" : GenericFlag("zf", 0x1), } memory = { } bb_list = self._bb_builder.build(bin_start_address, bin_end_address) bb_graph = BasicBlockGraph(bb_list) # bb_graph.save("bb_graph.png") # bb_graph.save("bb_graph_ir.png", print_ir=True) codeAnalyzer = CodeAnalyzer(self._smt_solver, self._smt_translator) codeAnalyzer.set_context(GenericContext(registers, flags, memory)) for bb_path in bb_graph.all_simple_bb_paths(start, end): if VERBOSE: print "[+] Checking path satisfiability :" print " From : %s" % hex(start) print " To : %s" % hex(end) print " Path : %s" % " -> ".join((map(lambda o : hex(o.address), bb_path))) is_sat = codeAnalyzer.check_path_satisfiability(bb_path, start, verbose=False) if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) self.assertTrue(is_sat) if is_sat and VERBOSE: print codeAnalyzer.get_context() if VERBOSE: print ":" * 80 print ""
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 CodeAnalyzerTests(unittest.TestCase): def setUp(self): self._arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) self._operand_size = self._arch_info.operand_size self._memory = MemoryMock() self._smt_solver = SmtSolver() self._smt_translator = SmtTranslator(self._smt_solver, self._operand_size) 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._disasm = X86Disassembler() self._ir_translator = X86Translator() self._bb_builder = BasicBlockBuilder(self._disasm, self._memory, self._ir_translator) def test_check_path_satisfiability(self): if VERBOSE: print "[+] Test: test_check_path_satisfiability" # binary : stack1 bin_start_address, bin_end_address = 0x08048ec0, 0x8048f02 binary = "\x55" # 0x08048ec0 : push ebp binary += "\x89\xe5" # 0x08048ec1 : mov ebp,esp binary += "\x83\xec\x60" # 0x08048ec3 : sub esp,0x60 binary += "\x8d\x45\xfc" # 0x08048ec6 : lea eax,[ebp-0x4] binary += "\x89\x44\x24\x08" # 0x08048ec9 : mov DWORD PTR [esp+0x8],eax binary += "\x8d\x45\xac" # 0x08048ecd : lea eax,[ebp-0x54] binary += "\x89\x44\x24\x04" # 0x08048ed0 : mov DWORD PTR [esp+0x4],eax binary += "\xc7\x04\x24\xa8\x5a\x0c\x08" # 0x08048ed4 : mov DWORD PTR [esp],0x80c5aa8 binary += "\xe8\xa0\x0a\x00\x00" # 0x08048edb : call 8049980 <_IO_printf> binary += "\x8d\x45\xac" # 0x08048ee0 : lea eax,[ebp-0x54] binary += "\x89\x04\x24" # 0x08048ee3 : mov DWORD PTR [esp],eax binary += "\xe8\xc5\x0a\x00\x00" # 0x08048ee6 : call 80499b0 <_IO_gets> binary += "\x8b\x45\xfc" # 0x08048eeb : mov eax,DWORD PTR [ebp-0x4] binary += "\x3d\x44\x43\x42\x41" # 0x08048eee : cmp eax,0x41424344 binary += "\x75\x0c" # 0x08048ef3 : jne 8048f01 <main+0x41> binary += "\xc7\x04\x24\xc0\x5a\x0c\x08" # 0x08048ef5 : mov DWORD PTR [esp],0x80c5ac0 binary += "\xe8\x4f\x0c\x00\x00" # 0x08048efc : call 8049b50 <_IO_puts> binary += "\xc9" # 0x08048f01 : leave binary += "\xc3" # 0x08048f02 : ret self._memory.set_base_address(bin_start_address) self._memory.set_content(binary) start = 0x08048ec0 # start = 0x08048ec6 # end = 0x08048efc end = 0x08048f01 registers = { "eax": GenericRegister("eax", 32, 0xffffd0ec), "ecx": GenericRegister("ecx", 32, 0x00000001), "edx": GenericRegister("edx", 32, 0xffffd0e4), "ebx": GenericRegister("ebx", 32, 0x00000000), "esp": GenericRegister("esp", 32, 0xffffd05c), "ebp": GenericRegister("ebp", 32, 0x08049580), "esi": GenericRegister("esi", 32, 0x00000000), "edi": GenericRegister("edi", 32, 0x08049620), "eip": GenericRegister("eip", 32, 0x08048ec0), } flags = { "af": GenericFlag("af", 0x0), "cf": GenericFlag("cf", 0x0), "of": GenericFlag("of", 0x0), "pf": GenericFlag("pf", 0x1), "sf": GenericFlag("sf", 0x0), "zf": GenericFlag("zf", 0x1), } memory = {} bb_list = self._bb_builder.build(bin_start_address, bin_end_address) bb_graph = BasicBlockGraph(bb_list) # bb_graph.save("bb_graph.png") # bb_graph.save("bb_graph_ir.png", print_ir=True) codeAnalyzer = CodeAnalyzer(self._smt_solver, self._smt_translator) codeAnalyzer.set_context(GenericContext(registers, flags, memory)) for bb_path in bb_graph.all_simple_bb_paths(start, end): if VERBOSE: print "[+] Checking path satisfiability :" print " From : %s" % hex(start) print " To : %s" % hex(end) print " Path : %s" % " -> ".join( (map(lambda o: hex(o.address), bb_path))) is_sat = codeAnalyzer.check_path_satisfiability(bb_path, start, verbose=False) if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) self.assertTrue(is_sat) if is_sat and VERBOSE: print codeAnalyzer.get_context() if VERBOSE: print ":" * 80 print ""
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 X86TranslationTests(unittest.TestCase): def setUp(self): self.trans_mode = FULL_TRANSLATION self.arch_mode = ARCH_X86_MODE_64 self.arch_info = X86ArchitectureInformation(self.arch_mode) self.x86_parser = X86Parser(self.arch_mode) self.x86_translator = X86Translator(self.arch_mode, self.trans_mode) self.smt_solver = SmtSolver() self.smt_translator = SmtTranslator(self.smt_solver, self.arch_info.address_size) self.reil_emulator = ReilEmulator(self.arch_info.address_size) self.reil_emulator.set_arch_registers(self.arch_info.registers_gp) self.reil_emulator.set_arch_registers_size(self.arch_info.register_size) self.reil_emulator.set_reg_access_mapper(self.arch_info.register_access_mapper()) 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) def test_lea(self): asm = ["lea eax, [ebx + 0x100]"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_cld(self): asm = ["cld"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_clc(self): asm = ["clc"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_nop(self): asm = ["nop"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_test(self): asm = ["test eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_not(self): asm = ["not eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_xor(self): asm = ["xor eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_or(self): asm = ["or eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_and(self): asm = ["and eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_cmp(self): asm = ["cmp eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_neg(self): asm = ["neg eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_dec(self): asm = ["dec eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_inc(self): asm = ["inc eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_div(self): asm = ["div ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = { 'rax' : 0x10, 'rbx' : 0x2, 'rdx' : 0x0, 'rflags' : 0x202, } x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_imul(self): asm = ["imul eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_mul(self): asm = ["mul ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_sbb(self): asm = ["sbb eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_sub(self): asm = ["sub eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_adc(self): asm = ["adc eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_add(self): asm = ["add eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_xchg(self): asm = ["xchg eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_movzx(self): asm = ["movzx eax, bx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_mov(self): asm = ["mov eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_shr(self): asm = ["shr eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_shl(self): asm = ["shl eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_sal(self): asm = ["sal eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_sar(self): asm = ["sar eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) x86_instrs[0].address = 0xdeadbeef reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def test_stc(self): asm = ["stc"] x86_instrs = map(self.x86_parser.parse, asm) x86_instrs[0].address = 0xdeadbeef reil_instrs = map(self.x86_translator.translate, x86_instrs) ctx_init = self.__init_context() x86_rv, x86_ctx_out = pyasmjit.execute("\n".join(asm), ctx_init) reil_ctx_out, reil_mem_out = self.reil_emulator.execute( reil_instrs, 0xdeadbeef << 8, context=ctx_init ) reil_ctx_out = self.__fix_reil_flags(reil_ctx_out, x86_ctx_out) self.assertTrue(self.__compare_contexts( ctx_init, x86_ctx_out, reil_ctx_out )) def __init_context(self): return { 'rax' : 0xa, 'rbx' : 0x2, 'rcx' : 0xb, 'rdx' : 0xc, 'rdi' : 0xd, 'rsi' : 0xe, 'rflags' : 0x202, } def __compare_contexts(self, context_init, x86_context, reil_context): match = True fmt = "%s (x86) : %s (%s)" mask = 2**64-1 for reg in sorted(context_init.keys()): if ((2**64-1) & x86_context[reg]) != ((2**64-1) & reil_context[reg]): x86_value = x86_context[reg] & mask reil_value = reil_context[reg] & mask if reg in ['rflags', 'eflags']: x86_flags_str = self.__print_flags(x86_context[reg]) reil_flags_str = self.__print_flags(reil_context[reg]) print ("%s (x86) : %s (%s)" % (reg, hex(x86_value), x86_flags_str)) print ("%s (reil) : %s (%s)" % (reg, hex(reil_value), reil_flags_str)) else: print ("%s (x86) : %s " % (reg, hex(x86_value))) print ("%s (reil) : %s " % (reg, hex(reil_value))) match = False break if not match: self.__print_contexts(context_init, x86_context, reil_context) return match def __print_contexts(self, context_init, x86_context, reil_context): header_fmt = "{0:^8s} : {1:>16s} ?= {2:<16s}" header = header_fmt.format("Register", "x86", "REIL") ruler = "-" * len(header) print(header) print(ruler) fmt = "{0:>8s} : {1:016x} {eq} {2:016x} ({1:>5d} {eq} {2:<5d}) {marker}" mask = 2**64-1 for reg in sorted(context_init.keys()): if (x86_context[reg] & mask) != (reil_context[reg] & mask): eq = "!=" marker = "<" else: eq = "==" marker = "" print fmt.format( reg, (2**64-1) & x86_context[reg], (2**64-1) & reil_context[reg], eq=eq, marker=marker ) def __print_flags(self, flags_reg): # flags flags = { 0 : "cf", # bit 0 2 : "pf", # bit 2 4 : "af", # bit 4 6 : "zf", # bit 6 7 : "sf", # bit 7 11 : "of", # bit 11 10 : "df", # bit 10 } out = "" for bit, flag in flags.items(): if flags_reg & 2**bit: out += flag.upper() + " " else: out += flag.lower() + " " return out[:-1] def __fix_reil_flags(self, reil_context, x86_context): reil_context_out = dict(reil_context) flags_reg = 'eflags' if 'eflags' in reil_context_out else 'rflags' # Remove this when AF and PF are implemented. reil_context_out[flags_reg] |= (x86_context[flags_reg] & 2**4) # AF reil_context_out[flags_reg] |= (x86_context[flags_reg] & 2**2) # PF return reil_context_out
class X86TranslationTests(unittest.TestCase): def setUp(self): self.trans_mode = FULL_TRANSLATION self.arch_mode = ARCH_X86_MODE_64 self.arch_info = X86ArchitectureInformation(self.arch_mode) self.x86_parser = X86Parser(self.arch_mode) self.x86_translator = X86Translator(self.arch_mode, self.trans_mode) self.smt_solver = SmtSolver() self.smt_translator = SmtTranslator(self.smt_solver, self.arch_info.address_size) self.reil_emulator = ReilEmulator(self.arch_info.address_size) self.reil_emulator.set_arch_registers(self.arch_info.registers_gp) self.reil_emulator.set_arch_registers_size(self.arch_info.register_size) self.reil_emulator.set_reg_access_mapper(self.arch_info.register_access_mapper()) 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) def test_lea(self): asm = ["lea eax, [ebx + 0x100]"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_cld(self): asm = ["cld"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_clc(self): asm = ["clc"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_nop(self): asm = ["nop"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_test(self): asm = ["test eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_not(self): asm = ["not eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_xor(self): asm = ["xor eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_or(self): asm = ["or eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_and(self): asm = ["and eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_cmp(self): asm = ["cmp eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_neg(self): asm = ["neg eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_dec(self): asm = ["dec eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_inc(self): asm = ["inc eax"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_div(self): asm = ["div ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = { 'rax' : 0x10, 'rbx' : 0x2, 'rdx' : 0x0, 'rflags' : 0x202, } x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_imul(self): asm = ["imul eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_mul(self): asm = ["mul ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_sbb(self): asm = ["sbb eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_sub(self): asm = ["sub eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_adc(self): asm = ["adc eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_add(self): asm = ["add eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_xchg(self): asm = ["xchg eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_movzx(self): asm = ["movzx eax, bx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_mov(self): asm = ["mov eax, ebx"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_shr(self): asm = ["shr eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_shl(self): asm = ["shl eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_sal(self): asm = ["sal eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def test_sar(self): asm = ["sar eax, 3"] x86_instrs = map(self.x86_parser.parse, asm) x86_instrs[0].address = 0xdeadbeef reil_instrs = map(self.x86_translator.translate, x86_instrs) context_init = self.__init_context() x86_rv, x86_context_out = pyasmjit.execute("\n".join(asm), context_init) reil_context_out, reil_memory_out = self.reil_emulator.execute(reil_instrs, 0xdeadbeef << 8, context=self.__update_flags_from_rflags(context_init)) self.assertTrue(self.__compare_contexts(context_init, x86_context_out, reil_context_out)) def __init_context(self): return { 'rax' : 0xa, 'rbx' : 0x2, 'rcx' : 0xb, 'rdx' : 0xc, 'rdi' : 0xd, 'rsi' : 0xe, 'rflags' : 0x202, } def __compare_contexts(self, context_init, x86_context, reil_context): match = True for reg in sorted(context_init.keys()): if ((2**64-1) & x86_context[reg]) != ((2**64-1) & reil_context[reg]): print ("%s : %s " % (reg, hex((2**64-1) & x86_context[reg]))) print ("%s : %s " % (reg, hex((2**64-1) & reil_context[reg]))) match = False break return match def __print_contexts(self, context_init, x86_context, reil_context): header_fmt = "{0:^8s} : {1:>16s} ?= {2:<16s}" header = header_fmt.format("Register", "x86", "REIL") ruler = "-" * len(header) print(header) print(ruler) for reg in sorted(context_init.keys()): if ((2**64-1) & x86_context[reg]) != ((2**64-1) & reil_context[reg]): eq = "!=" marker = "<" else: eq = "==" marker = "" fmt = "{0:>8s} : {1:016x} {eq} {2:016x} ({1:>5d} {eq} {2:<5d}) {marker}" print fmt.format( reg, (2**64-1) & x86_context[reg], (2**64-1) & reil_context[reg], eq=eq, marker=marker ) def __update_rflags(self, reil_context_out, x86_context_out): reil_context = dict((reg, value) for reg, value in reil_context_out.items() if reg in x86_context_out.keys()) reil_context['rflags'] = 0xffffffff & ( 0x0 << 31 | # Reserved 0x0 << 30 | # Reserved 0x0 << 29 | # Reserved 0x0 << 28 | # Reserved 0x0 << 27 | # Reserved 0x0 << 26 | # Reserved 0x0 << 25 | # Reserved 0x0 << 24 | # Reserved 0x0 << 23 | # Reserved 0x0 << 22 | # Reserved 0x0 << 21 | # ID 0x0 << 20 | # VIP 0x0 << 19 | # VIF 0x0 << 18 | # AC 0x0 << 17 | # VM 0x0 << 16 | # RF 0x0 << 15 | # Reserved 0x0 << 14 | # NT 0x0 << 13 | # IOPL 0x0 << 12 | # IOPL reil_context_out['of'] << 11 | # OF reil_context_out['df'] << 10 | # DF 0x1 << 9 | # IF 0x0 << 8 | # TF reil_context_out['sf'] << 7 | # SF reil_context_out['zf'] << 6 | # ZF 0x0 << 5 | # Reserved # reil_context_out['af'] << 4 | # AF (x86_context_out['rflags'] & 0x10) | # AF 0x0 << 3 | # Reserved # reil_context_out['pf'] << 2 | # PF (x86_context_out['rflags'] & 0x4) | # PF 0x1 << 1 | # Reserved reil_context_out['cf'] << 0 # CF ) return reil_context def __update_flags_from_rflags(self, reil_context): reil_context_out = dict(reil_context) flags_reg = None if 'rflags' in reil_context_out: flags_reg = 'rflags' if 'eflags' in reil_context_out: flags_reg = 'eflags' if flags_reg: reil_context_out['of'] = reil_context_out[flags_reg] & 2**11 # OF reil_context_out['df'] = reil_context_out[flags_reg] & 2**10 # DF reil_context_out['sf'] = reil_context_out[flags_reg] & 2**7 # SF reil_context_out['zf'] = reil_context_out[flags_reg] & 2**6 # ZF reil_context_out['af'] = reil_context_out[flags_reg] & 2**4 # AF reil_context_out['pf'] = reil_context_out[flags_reg] & 2**2 # PF reil_context_out['cf'] = reil_context_out[flags_reg] & 2**0 # CF return reil_context_out
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())