class ReilParserTests(unittest.TestCase): def setUp(self): self._parser = ReilParser() def test_add(self): instrs = ["str [eax, EMPTY, t0]"] instrs += ["str [ebx, EMPTY, t1]"] instrs += ["add [t0, t1, t2]"] instrs += ["str [t2, EMPTY, eax]"] instrs_parse = self._parser.parse(instrs) self.assertEqual(str(instrs_parse[0]), "str [UNK eax, EMPTY, UNK t0]") self.assertEqual(str(instrs_parse[1]), "str [UNK ebx, EMPTY, UNK t1]") self.assertEqual(str(instrs_parse[2]), "add [UNK t0, UNK t1, UNK t2]") self.assertEqual(str(instrs_parse[3]), "str [UNK t2, EMPTY, UNK eax]") def test_parse_operand_size(self): instrs = ["str [DWORD eax, EMPTY, DWORD t0]"] instrs += ["str [eax, EMPTY, DWORD t0]"] instrs += ["str [eax, EMPTY, t0]"] instrs_parse = self._parser.parse(instrs) self.assertEqual(instrs_parse[0].operands[0].size, 32) self.assertEqual(instrs_parse[0].operands[1].size, 0) self.assertEqual(instrs_parse[0].operands[2].size, 32) self.assertEqual(instrs_parse[1].operands[0].size, None) self.assertEqual(instrs_parse[1].operands[1].size, 0) self.assertEqual(instrs_parse[1].operands[2].size, 32) self.assertEqual(instrs_parse[2].operands[0].size, None) self.assertEqual(instrs_parse[2].operands[1].size, 0) self.assertEqual(instrs_parse[2].operands[2].size, None)
class ReilEmulatorTests(unittest.TestCase): def setUp(self): self._arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) self._emulator = ReilEmulator(self._arch_info) self._asm_parser = X86Parser() self._reil_parser = ReilParser() self._translator = X86Translator() def test_add(self): asm_instrs = self._asm_parser.parse("add eax, ebx") self.__set_address(0xdeadbeef, [asm_instrs]) reil_instrs = self._translator.translate(asm_instrs) regs_initial = { "eax": 0x1, "ebx": 0x2, } regs_final, _ = self._emulator.execute_lite(reil_instrs, context=regs_initial) self.assertEqual(regs_final["eax"], 0x3) self.assertEqual(regs_final["ebx"], 0x2) def test_loop(self): # 0x08048060 : b8 00 00 00 00 mov eax,0x0 # 0x08048065 : bb 0a 00 00 00 mov ebx,0xa # 0x0804806a : 83 c0 01 add eax,0x1 # 0x0804806d : 83 eb 01 sub ebx,0x1 # 0x08048070 : 83 fb 00 cmp ebx,0x0 # 0x08048073 : 75 f5 jne 0x0804806a asm_instrs_str = [(0x08048060, "mov eax,0x0", 5)] asm_instrs_str += [(0x08048065, "mov ebx,0xa", 5)] asm_instrs_str += [(0x0804806a, "add eax,0x1", 3)] asm_instrs_str += [(0x0804806d, "sub ebx,0x1", 3)] asm_instrs_str += [(0x08048070, "cmp ebx,0x0", 3)] asm_instrs_str += [(0x08048073, "jne 0x0804806a", 2)] asm_instrs = [] for addr, asm, size in asm_instrs_str: asm_instr = self._asm_parser.parse(asm) asm_instr.address = addr asm_instr.size = size asm_instrs.append(asm_instr) reil_instrs = self.__translate(asm_instrs) regs_final, _ = self._emulator.execute(reil_instrs, start=0x08048060 << 8) self.assertEqual(regs_final["eax"], 0xa) self.assertEqual(regs_final["ebx"], 0x0) def test_mov(self): asm_instrs = [self._asm_parser.parse("mov eax, 0xdeadbeef")] asm_instrs += [self._asm_parser.parse("mov al, 0x12")] asm_instrs += [self._asm_parser.parse("mov ah, 0x34")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self._translator.translate(asm_instrs[0]) reil_instrs += self._translator.translate(asm_instrs[1]) reil_instrs += self._translator.translate(asm_instrs[2]) regs_initial = { "eax": 0xffffffff, } regs_final, _ = self._emulator.execute_lite(reil_instrs, context=regs_initial) self.assertEqual(regs_final["eax"], 0xdead3412) def test_pre_hanlder(self): def pre_hanlder(emulator, instruction, parameter): paramter.append(True) asm = ["mov eax, ebx"] x86_instrs = map(self._asm_parser.parse, asm) self.__set_address(0xdeadbeef, x86_instrs) reil_instrs = map(self._translator.translate, x86_instrs) paramter = [] self._emulator.set_instruction_pre_handler(pre_hanlder, paramter) reil_ctx_out, reil_mem_out = self._emulator.execute_lite( reil_instrs[0]) self.assertTrue(len(paramter) > 0) def test_post_hanlder(self): def post_hanlder(emulator, instruction, parameter): paramter.append(True) asm = ["mov eax, ebx"] x86_instrs = map(self._asm_parser.parse, asm) self.__set_address(0xdeadbeef, x86_instrs) reil_instrs = map(self._translator.translate, x86_instrs) paramter = [] self._emulator.set_instruction_post_handler(post_hanlder, paramter) reil_ctx_out, reil_mem_out = self._emulator.execute_lite( reil_instrs[0]) self.assertTrue(len(paramter) > 0) def test_zero_division_error_1(self): asm_instrs = [self._asm_parser.parse("div ebx")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self._translator.translate(asm_instrs[0]) regs_initial = { "eax": 0x2, "edx": 0x2, "ebx": 0x0, } self.assertRaises(ReilCpuZeroDivisionError, self._emulator.execute_lite, reil_instrs, context=regs_initial) def test_zero_division_error_2(self): instrs = ["mod [DWORD eax, DWORD ebx, DWORD t0]"] reil_instrs = self._reil_parser.parse(instrs) reil_instrs[0].address = 0xdeadbeef00 regs_initial = { "eax": 0x2, "ebx": 0x0, } self.assertRaises(ReilCpuZeroDivisionError, self._emulator.execute_lite, reil_instrs, context=regs_initial) def test_invalid_address_error_1(self): asm_instrs = [self._asm_parser.parse("jmp eax")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self.__translate(asm_instrs) regs_initial = { "eax": 0xffffffff, } self.assertRaises(ReilCpuInvalidAddressError, self._emulator.execute, reil_instrs, start=0xdeadbeef << 8, registers=regs_initial) def test_invalid_address_error_2(self): asm_instrs = [self._asm_parser.parse("mov eax, 0xdeadbeef")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self.__translate(asm_instrs) regs_initial = { "eax": 0xffffffff, } self.assertRaises(ReilCpuInvalidAddressError, self._emulator.execute, reil_instrs, start=0xdeadbef0 << 8, registers=regs_initial) # Auxiliary methods # ======================================================================== # def __set_address(self, address, asm_instrs): addr = address for asm_instr in asm_instrs: asm_instr.address = addr addr += 1 def __translate(self, asm_instrs): instr_container = ReilContainer() asm_instr_last = None instr_seq_prev = None for asm_instr in asm_instrs: instr_seq = ReilSequence() for reil_instr in self._translator.translate(asm_instr): instr_seq.append(reil_instr) if instr_seq_prev: instr_seq_prev.next_sequence_address = instr_seq.address instr_container.add(instr_seq) instr_seq_prev = instr_seq if instr_seq_prev: if asm_instr_last: instr_seq_prev.next_sequence_address = ( asm_instr_last.address + asm_instr_last.size) << 8 # instr_container.dump() return instr_container
class SmtTranslatorTests(unittest.TestCase): def setUp(self): self._address_size = 32 self._parser = ReilParser() self._solver = SmtSolver() self._translator = SmtTranslator(self._solver, self._address_size) def test_add_reg_reg(self): if VERBOSE: print "\n[+] Test: test_add_reg_reg" # add eax, ebx instrs = self._parser.parse([ "add [eax, ebx, t0]", "str [t0, e, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("eax")) == 42, self._solver.mkBitVec(32, self._translator.get_init_name("eax")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("ebx")) print "~" * 80 self.assertEqual(is_sat, True) def test_add_reg_mem(self): if VERBOSE: print "\n[+] Test: test_add_reg_mem" # add eax, [ebx] instrs = self._parser.parse([ "ldm [ebx, EMPTY, t0]", "add [eax, t0, t1]", "str [t1, EMPTY, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[1].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("eax")) == 42, self._solver.mkBitVec(32, self._translator.get_init_name("eax")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("ebx")) print "~" * 80 self.assertEqual(is_sat, True) def test_add_mem_reg(self): if VERBOSE: print "\n[+] Test: test_add_mem_reg" # add [eax], ebx instrs = self._parser.parse([ "ldm [eax, EMPTY, t0]", "add [t0, ebx, t1]", "stm [t1, EMPTY, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[1].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[2].size = 32 self._solver.reset() # add constrains mem = self._translator.get_memory() eax = self._solver.mkBitVec(32, "eax_0") constraint = (mem[eax] != 42) if VERBOSE: print "constraint : %s" % constraint self._solver.add(constraint) # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ mem[eax] == 42, self._solver.mkBitVec(32, self._translator.get_init_name("t0")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("ebx")) print " t0 : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("t0")) print " [eax] : 0x%08x" % self._solver.getvalue(mem[eax]) print "~" * 80 self.assertEqual(is_sat, True) def test_add_mem_reg_2(self): if VERBOSE: print "\n[+] Test: test_add_mem_reg_2" # add [eax + 0x1000], ebx instrs = self._parser.parse([ "add [eax, 0x1000, t0]", "ldm [t0, e, t1]", "add [t1, ebx, t2]", "stm [t2, e, t0]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[1].size = 32 instrs[2].operands[2].size = 32 instrs[3].operands[0].size = 32 instrs[3].operands[2].size = 32 self._solver.reset() # add constrains mem = self._translator.get_memory() eax = self._solver.mkBitVec(32, "eax_0") off = BitVec(32, "#x%08x" % 0x1000) constraint = (mem[eax + off] != 42) if VERBOSE: print "constraint : %s" % constraint self._solver.add(constraint) # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ mem[eax + off] == 42, self._solver.mkBitVec(32, self._translator.get_init_name("t1")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("ebx")) print " t0 : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("t0")) print " t1 : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("t1")) print " [eax + off] : 0x%08x" % self._solver.getvalue(mem[eax + off]) print "~" * 80 self.assertEqual(is_sat, True) def test_mul(self): if VERBOSE: print "\n[+] Test: test_mul" instrs = self._parser.parse([ "mul [0x0, 0x1, t0]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 # TODO: Ver esto, el tam del output deberia ser 64 instrs[0].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t0")) == 0, self._solver.mkBitVec(32, self._translator.get_init_name("t0")) != 0, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " t0 : 0x%08x" % self._solver.getvaluebyname(self._translator.get_curr_name("t0")) print "~" * 80 self.assertEqual(is_sat, True) def test_sext_1(self): instr = self._parser.parse(["sext [WORD 0xffff, EMPTY, DWORD t1]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) != 0xffffffff, ] self._solver.add(constraints[0]) self.assertEqual(self._solver.check(), 'unsat') def test_sext_2(self): instr = self._parser.parse(["sext [WORD 0x7fff, EMPTY, DWORD t1]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) != 0x00007fff, ] self._solver.add(constraints[0]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_left_1(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD 16, QWORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(64, self._translator.get_curr_name("t2")) != 0x0000ffffffff0000, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_left_2(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD 16, DWORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(32, self._translator.get_curr_name("t2")) != 0xffff0000, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_left_3(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD 16, WORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(16, self._translator.get_curr_name("t2")) != 0x0000, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_right_1(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD -16, QWORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(64, self._translator.get_curr_name("t2")) != 0x000000000000ffff, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_right_2(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD -16, DWORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(32, self._translator.get_curr_name("t2")) != 0x0000ffff, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat') def test_bsh_right_3(self): instr = self._parser.parse(["bsh [DWORD t1, DWORD -16, WORD t2]"]) self._solver.reset() smt_expr = self._translator.translate(instr[0]) self._solver.add(smt_expr[0]) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t1")) == 0xffffffff, self._solver.mkBitVec(16, self._translator.get_curr_name("t2")) != 0xffff, ] self._solver.add(constraints[0]) self._solver.add(constraints[1]) self.assertEqual(self._solver.check(), 'unsat')
class ReilEmulatorTests(unittest.TestCase): def setUp(self): self._arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) self._emulator = ReilEmulator(self._arch_info) self._asm_parser = X86Parser() self._reil_parser = ReilParser() self._translator = X86Translator() def test_add(self): asm_instrs = self._asm_parser.parse("add eax, ebx") self.__set_address(0xdeadbeef, [asm_instrs]) reil_instrs = self._translator.translate(asm_instrs) regs_initial = { "eax" : 0x1, "ebx" : 0x2, } regs_final, _ = self._emulator.execute_lite( reil_instrs, context=regs_initial ) self.assertEqual(regs_final["eax"], 0x3) self.assertEqual(regs_final["ebx"], 0x2) def test_loop(self): # 0x08048060 : b8 00 00 00 00 mov eax,0x0 # 0x08048065 : bb 0a 00 00 00 mov ebx,0xa # 0x0804806a : 83 c0 01 add eax,0x1 # 0x0804806d : 83 eb 01 sub ebx,0x1 # 0x08048070 : 83 fb 00 cmp ebx,0x0 # 0x08048073 : 75 f5 jne 0x0804806a asm_instrs_str = [(0x08048060, "mov eax,0x0", 5)] asm_instrs_str += [(0x08048065, "mov ebx,0xa", 5)] asm_instrs_str += [(0x0804806a, "add eax,0x1", 3)] asm_instrs_str += [(0x0804806d, "sub ebx,0x1", 3)] asm_instrs_str += [(0x08048070, "cmp ebx,0x0", 3)] asm_instrs_str += [(0x08048073, "jne 0x0804806a", 2)] asm_instrs = [] for addr, asm, size in asm_instrs_str: asm_instr = self._asm_parser.parse(asm) asm_instr.address = addr asm_instr.size = size asm_instrs.append(asm_instr) reil_instrs = self.__translate(asm_instrs) regs_final, _ = self._emulator.execute( reil_instrs, start=0x08048060 << 8 ) self.assertEqual(regs_final["eax"], 0xa) self.assertEqual(regs_final["ebx"], 0x0) def test_mov(self): asm_instrs = [self._asm_parser.parse("mov eax, 0xdeadbeef")] asm_instrs += [self._asm_parser.parse("mov al, 0x12")] asm_instrs += [self._asm_parser.parse("mov ah, 0x34")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self._translator.translate(asm_instrs[0]) reil_instrs += self._translator.translate(asm_instrs[1]) reil_instrs += self._translator.translate(asm_instrs[2]) regs_initial = { "eax" : 0xffffffff, } regs_final, _ = self._emulator.execute_lite(reil_instrs, context=regs_initial) self.assertEqual(regs_final["eax"], 0xdead3412) def test_pre_hanlder(self): def pre_hanlder(emulator, instruction, parameter): paramter.append(True) asm = ["mov eax, ebx"] x86_instrs = map(self._asm_parser.parse, asm) self.__set_address(0xdeadbeef, x86_instrs) reil_instrs = map(self._translator.translate, x86_instrs) paramter = [] self._emulator.set_instruction_pre_handler(pre_hanlder, paramter) reil_ctx_out, reil_mem_out = self._emulator.execute_lite( reil_instrs[0] ) self.assertTrue(len(paramter) > 0) def test_post_hanlder(self): def post_hanlder(emulator, instruction, parameter): paramter.append(True) asm = ["mov eax, ebx"] x86_instrs = map(self._asm_parser.parse, asm) self.__set_address(0xdeadbeef, x86_instrs) reil_instrs = map(self._translator.translate, x86_instrs) paramter = [] self._emulator.set_instruction_post_handler(post_hanlder, paramter) reil_ctx_out, reil_mem_out = self._emulator.execute_lite( reil_instrs[0] ) self.assertTrue(len(paramter) > 0) def test_zero_division_error_1(self): asm_instrs = [self._asm_parser.parse("div ebx")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self._translator.translate(asm_instrs[0]) regs_initial = { "eax" : 0x2, "edx" : 0x2, "ebx" : 0x0, } self.assertRaises(ReilCpuZeroDivisionError, self._emulator.execute_lite, reil_instrs, context=regs_initial) def test_zero_division_error_2(self): instrs = ["mod [DWORD eax, DWORD ebx, DWORD t0]"] reil_instrs = self._reil_parser.parse(instrs) regs_initial = { "eax" : 0x2, "ebx" : 0x0, } self.assertRaises(ReilCpuZeroDivisionError, self._emulator.execute_lite, reil_instrs, context=regs_initial) def test_invalid_address_error_1(self): asm_instrs = [self._asm_parser.parse("jmp eax")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self.__translate(asm_instrs) regs_initial = { "eax" : 0xffffffff, } self.assertRaises(ReilCpuInvalidAddressError, self._emulator.execute, reil_instrs, start=0xdeadbeef << 8, registers=regs_initial) def test_invalid_address_error_2(self): asm_instrs = [self._asm_parser.parse("mov eax, 0xdeadbeef")] self.__set_address(0xdeadbeef, asm_instrs) reil_instrs = self.__translate(asm_instrs) regs_initial = { "eax" : 0xffffffff, } self.assertRaises(ReilCpuInvalidAddressError, self._emulator.execute, reil_instrs, start=0xdeadbef0 << 8, registers=regs_initial) # Auxiliary methods # ======================================================================== # def __set_address(self, address, asm_instrs): addr = address for asm_instr in asm_instrs: asm_instr.address = addr addr += 1 def __translate(self, asm_instrs): instr_container = ReilContainer() asm_instr_last = None instr_seq_prev = None for asm_instr in asm_instrs: instr_seq = ReilSequence() for reil_instr in self._translator.translate(asm_instr): instr_seq.append(reil_instr) if instr_seq_prev: instr_seq_prev.next_sequence_address = instr_seq.address instr_container.add(instr_seq) instr_seq_prev = instr_seq if instr_seq_prev: if asm_instr_last: instr_seq_prev.next_sequence_address = (asm_instr_last.address + asm_instr_last.size) << 8 # instr_container.dump() return instr_container
class SmtTranslatorTests(unittest.TestCase): def setUp(self): self._address_size = 32 self._parser = ReilParser() self._solver = SmtSolver() self._translator = SmtTranslator(self._solver, self._address_size) self._arch_info = X86ArchitectureInformation(ARCH_X86_MODE_32) self._translator.set_arch_alias_mapper(self._arch_info.alias_mapper) self._translator.set_arch_registers_size( self._arch_info.registers_size) # Arithmetic Instructions def test_translate_add_1(self): # Same size operands. instr = self._parser.parse(["add [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvadd t0_0 t1_0))") def test_translate_add_2(self): # Destination operand larger than source operands. instr = self._parser.parse(["add [BYTE t0, BYTE t1, WORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual( form[0].value, "(= t2_1 (bvadd ((_ zero_extend 8) t0_0) ((_ zero_extend 8) t1_0)))" ) def test_translate_add_3(self): # Destination operand smaller than source operands. instr = self._parser.parse(["add [WORD t0, WORD t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 ((_ extract 7 0) (bvadd t0_0 t1_0)))") def test_translate_add_4(self): # Mixed source operands. instr = self._parser.parse(["add [BYTE t0, BYTE 0x12, WORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual( form[0].value, "(= t2_1 (bvadd ((_ zero_extend 8) t0_0) ((_ zero_extend 8) #x12)))" ) def test_translate_sub(self): instr = self._parser.parse(["sub [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvsub t0_0 t1_0))") def test_translate_mul(self): instr = self._parser.parse(["mul [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvmul t0_0 t1_0))") def test_translate_div(self): instr = self._parser.parse(["div [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvudiv t0_0 t1_0))") def test_translate_mod(self): instr = self._parser.parse(["mod [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvurem t0_0 t1_0))") def test_translate_bsh(self): instr = self._parser.parse(["bsh [DWORD t0, DWORD t1, DWORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual( form[0].value, "(= t2_1 (ite (bvsge t1_0 #x00000000) (bvshl t0_0 t1_0) (bvlshr t0_0 (bvneg t1_0))))" ) # Bitwise Instructions def test_translate_and(self): instr = self._parser.parse(["and [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvand t0_0 t1_0))") def test_translate_or(self): instr = self._parser.parse(["or [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvor t0_0 t1_0))") def test_translate_xor(self): instr = self._parser.parse(["xor [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvxor t0_0 t1_0))") # Data Transfer Instructions def test_translate_ldm(self): instr = self._parser.parse(["ldm [DWORD t0, empty, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= (select MEM_0 (bvadd t0_0 #x00000000)) t2_1)") def test_translate_stm(self): instr = self._parser.parse(["stm [BYTE t0, empty, DWORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual( form[0].value, "(= MEM_1 (store MEM_0 (bvadd t2_0 #x00000000) t0_0))") def test_translate_str(self): instr = self._parser.parse(["str [BYTE t0, empty, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 t0_0)") # Conditional Instructions def test_translate_bisz(self): instr = self._parser.parse(["bisz [DWORD t0, empty, DWORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual( form[0].value, "(= t2_1 (ite (= t0_0 #x00000000) #x00000001 #x00000000))") def test_translate_jcc(self): instr = self._parser.parse(["jcc [BIT t0, empty, DWORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(not (= t0_0 #b0))") # Other Instructions def test_translate_undef(self): instr = self._parser.parse(["undef [empty, empty, DWORD t2]"])[0] with self.assertRaises(Exception) as context: self._translator.translate(instr) self.assertTrue("Unsupported instruction : UNDEF" in context.exception) def test_translate_unkn(self): instr = self._parser.parse(["unkn [empty, empty, empty]"])[0] with self.assertRaises(Exception) as context: self._translator.translate(instr) self.assertTrue("Unsupported instruction : UNKN" in context.exception) def test_translate_nop(self): instr = self._parser.parse(["nop [empty, empty, empty]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 0) # Extensions def test_translate_sext(self): instr = self._parser.parse(["sext [BYTE t0, empty, WORD t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 ((_ sign_extend 8) t0_0))") def test_translate_sdiv(self): instr = self._parser.parse(["sdiv [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvsdiv t0_0 t1_0))") def test_translate_smod(self): instr = self._parser.parse(["smod [BYTE t0, BYTE t1, BYTE t2]"])[0] form = self._translator.translate(instr) self.assertEqual(len(form), 1) self.assertEqual(form[0].value, "(= t2_1 (bvsmod t0_0 t1_0))")
class SmtTranslatorTests(unittest.TestCase): def setUp(self): self._address_size = 32 self._parser = ReilParser() self._solver = SmtSolver() self._translator = SmtTranslator(self._solver, self._address_size) def test_add_reg_reg(self): if VERBOSE: print "\n[+] Test: test_add_reg_reg" # add eax, ebx instrs = self._parser.parse([ "add [eax, ebx, t0]", "str [t0, e, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("eax")) == 42, self._solver.mkBitVec(32, self._translator.get_init_name("eax")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("ebx")) print "~" * 80 self.assertEqual(is_sat, True) def test_add_reg_mem(self): if VERBOSE: print "\n[+] Test: test_add_reg_mem" # add eax, [ebx] instrs = self._parser.parse([ "ldm [ebx, EMPTY, t0]", "add [eax, t0, t1]", "str [t1, EMPTY, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[1].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("eax")) == 42, self._solver.mkBitVec(32, self._translator.get_init_name("eax")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("ebx")) print "~" * 80 self.assertEqual(is_sat, True) def test_add_mem_reg(self): if VERBOSE: print "\n[+] Test: test_add_mem_reg" # add [eax], ebx instrs = self._parser.parse([ "ldm [eax, EMPTY, t0]", "add [t0, ebx, t1]", "stm [t1, EMPTY, eax]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[1].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[2].size = 32 self._solver.reset() # add constrains mem = self._translator.get_memory() eax = self._solver.mkBitVec(32, "eax_0") constraint = (mem[eax] != 42) if VERBOSE: print "constraint : %s" % constraint self._solver.add(constraint) # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ mem[eax] == 42, self._solver.mkBitVec(32, self._translator.get_init_name("t0")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("ebx")) print " t0 : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("t0")) print " [eax] : 0x%08x" % self._solver.getvalue(mem[eax]) print "~" * 80 self.assertEqual(is_sat, True) def test_add_mem_reg_2(self): if VERBOSE: print "\n[+] Test: test_add_mem_reg_2" # add [eax + 0x1000], ebx instrs = self._parser.parse([ "add [eax, 0x1000, t0]", "ldm [t0, e, t1]", "add [t1, ebx, t2]", "stm [t2, e, t0]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 instrs[0].operands[2].size = 32 instrs[1].operands[0].size = 32 instrs[1].operands[2].size = 32 instrs[2].operands[0].size = 32 instrs[2].operands[1].size = 32 instrs[2].operands[2].size = 32 instrs[3].operands[0].size = 32 instrs[3].operands[2].size = 32 self._solver.reset() # add constrains mem = self._translator.get_memory() eax = self._solver.mkBitVec(32, "eax_0") off = BitVec(32, "#x%08x" % 0x1000) constraint = (mem[eax + off] != 42) if VERBOSE: print "constraint : %s" % constraint self._solver.add(constraint) # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ mem[eax + off] == 42, self._solver.mkBitVec(32, self._translator.get_init_name("t1")) != 42, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " eax : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("eax")) print " ebx : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("ebx")) print " t0 : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("t0")) print " t1 : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("t1")) print " [eax + off] : 0x%08x" % self._solver.getvalue( mem[eax + off]) print "~" * 80 self.assertEqual(is_sat, True) def test_mul(self): if VERBOSE: print "\n[+] Test: test_mul" instrs = self._parser.parse([ "mul [0x0, 0x1, t0]", ]) instrs[0].operands[0].size = 32 instrs[0].operands[1].size = 32 # TODO: Ver esto, el tam del output deberia ser 64 instrs[0].operands[2].size = 32 self._solver.reset() # translate instructions to formulae if VERBOSE: print "[+] Instructions:" for instr in instrs: trans = self._translator.translate(instr) if trans is not None: self._solver.add(trans) print " %-20s -> %-20s" % (instr, trans) # add constrains constraints = [ self._solver.mkBitVec(32, self._translator.get_curr_name("t0")) == 0, self._solver.mkBitVec(32, self._translator.get_init_name("t0")) != 0, ] if VERBOSE: print "[+] Constraints :" for i, constr in enumerate(constraints): self._solver.add(constr) print " %2d : %s" % (i, constr) # check satisfiability is_sat = self._solver.check() == 'sat' if VERBOSE: print "[+] Satisfiability : %s" % str(is_sat) if is_sat: print " t0 : 0x%08x" % self._solver.getvaluebyname( self._translator.get_curr_name("t0")) print "~" * 80 self.assertEqual(is_sat, True)