def test_memset(): l.info("concrete src, concrete dst, concrete len") s = SimState(arch="PPC32", mode="symbolic") dst = s.solver.BVV(0, 128) dst_addr = s.solver.BVV(0x1000, 32) char = s.solver.BVV(0x00000041, 32) char2 = s.solver.BVV(0x50505050, 32) length = s.solver.BVS("some_length", 32) s.memory.store(dst_addr, dst) memset(s, arguments=[dst_addr, char, s.solver.BVV(3, 32)]) assert s.solver.eval(s.memory.load(dst_addr, 4)) == 0x41414100 l.debug("Symbolic length") s = SimState(arch="PPC32", mode="symbolic") s.memory.store(dst_addr, dst) length = s.solver.BVS("some_length", 32) s.add_constraints(length < 10) memset(s, arguments=[dst_addr, char2, length]) l.debug("Trying 2") s_two = s.copy() s_two.add_constraints(length == 2) assert s_two.solver.eval(s_two.memory.load(dst_addr, 4)) == 0x50500000 l.debug("Trying 0") s_zero = s.copy() s_zero.add_constraints(length == 0) assert s_zero.solver.eval(s_zero.memory.load(dst_addr, 4)) == 0x00000000 l.debug("Trying 5") s_five = s.copy() s_five.add_constraints(length == 5) assert s_five.solver.eval(s_five.memory.load(dst_addr, 6)) == 0x505050505000
def test_memset(): l.info("concrete src, concrete dst, concrete len") s = SimState(arch="PPC32", mode="symbolic") dst = s.solver.BVV(0, 128) dst_addr = s.solver.BVV(0x1000, 32) char = s.solver.BVV(0x00000041, 32) char2 = s.solver.BVV(0x50505050, 32) length = s.solver.BVS("some_length", 32) s.memory.store(dst_addr, dst) memset(s, arguments=[dst_addr, char, s.solver.BVV(3, 32)]) nose.tools.assert_equal(s.solver.eval(s.memory.load(dst_addr, 4)), 0x41414100) l.debug("Symbolic length") s = SimState(arch="PPC32", mode="symbolic") s.memory.store(dst_addr, dst) length = s.solver.BVS("some_length", 32) memset(s, arguments=[dst_addr, char2, length]) l.debug("Trying 2") s_two = s.copy() s_two.add_constraints(length == 2) nose.tools.assert_equal(s_two.solver.eval(s_two.memory.load(dst_addr, 4)), 0x50500000) l.debug("Trying 0") s_zero = s.copy() s_zero.add_constraints(length == 0) nose.tools.assert_equal(s_zero.solver.eval(s_zero.memory.load(dst_addr, 4)), 0x00000000) l.debug("Trying 5") s_five = s.copy() s_five.add_constraints(length == 5) nose.tools.assert_equal(s_five.solver.eval(s_five.memory.load(dst_addr, 6)), 0x505050505000)
def broken_sprintf(): l.info("concrete src, concrete dst, concrete len") s = SimState(mode="symbolic", arch="PPC32") format_str = s.solver.BVV(0x25640000, 32) format_addr = s.solver.BVV(0x2000, 32) #dst = s.solver.BVV("destination", 128) dst_addr = s.solver.BVV(0x1000, 32) arg = s.solver.BVS("some_number", 32) s.memory.store(format_addr, format_str) sprintf(s, arguments=[dst_addr, format_addr, arg]) for i in range(9): j = random.randint(10**i, 10**(i + 1)) s2 = s.copy() s2.add_constraints(arg == j) #print s2.solver.eval_upto(s2.memory.load(dst_addr, i+2), 2, cast_to=bytes), repr(b"%d\x00" % j) nose.tools.assert_equal( s2.solver.eval_upto(s2.memory.load(dst_addr, i + 2), 2, cast_to=bytes), [b"%d\x00" % j]) s2 = s.copy() s2.add_constraints(arg == 0) #print s2.solver.eval_upto(s2.memory.load(dst_addr, 2), 2, cast_to=bytes), repr(b"%d\x00" % 0) nose.tools.assert_equal( s2.solver.eval_upto(s2.memory.load(dst_addr, 2), 2, cast_to=bytes), [b"%d\x00" % 0])
def test_inline_strlen(): s = SimState(arch="AMD64", mode="symbolic") l.info("fully concrete string") a_str = s.se.BVV(0x41414100, 32) a_addr = s.se.BVV(0x10, 64) s.memory.store(a_addr, a_str, endness="Iend_BE") a_len = strlen(s, arguments=[a_addr]).ret_expr nose.tools.assert_true(s.se.unique(a_len)) nose.tools.assert_equal(s.se.any_int(a_len), 3) l.info("concrete-terminated string") b_str = s.se.Concat(s.se.BVS("mystring", 24), s.se.BVV(0, 8)) b_addr = s.se.BVV(0x20, 64) s.memory.store(b_addr, b_str, endness="Iend_BE") b_len = strlen(s, arguments=[b_addr]).ret_expr nose.tools.assert_equal(s.se.max_int(b_len), 3) nose.tools.assert_items_equal(s.se.any_n_int(b_len, 10), (0, 1, 2, 3)) l.info("fully unconstrained") u_addr = s.se.BVV(0x50, 64) u_len_sp = strlen(s, arguments=[u_addr]) u_len = u_len_sp.ret_expr nose.tools.assert_equal(len(s.se.any_n_int(u_len, 100)), s.libc.buf_symbolic_bytes) nose.tools.assert_equal(s.se.max_int(u_len), s.libc.buf_symbolic_bytes - 1) #print u_len_sp.se.maximum_null #s.add_constraints(u_len < 16) nose.tools.assert_equal( s.se.any_n_int(s.memory.load(0x50 + u_len, 1), 300), [0]) # # This tests if a strlen can influence a symbolic str. # l.info("Trying to influence length.") s = SimState(arch="AMD64", mode="symbolic") str_c = s.se.BVS("some_string", 8 * 16) c_addr = s.se.BVV(0x10, 64) s.memory.store(c_addr, str_c, endness='Iend_BE') c_len = strlen(s, arguments=[c_addr]).ret_expr nose.tools.assert_equal(len(s.se.any_n_int(c_len, 100)), s.libc.buf_symbolic_bytes) nose.tools.assert_equal(s.se.max_int(c_len), s.libc.buf_symbolic_bytes - 1) one_s = s.copy() one_s.add_constraints(c_len == 1) nose.tools.assert_equal(one_s.se.any_str(str_c).index('\x00'), 1) str_test = one_s.memory.load(c_addr, 2, endness='Iend_BE') nose.tools.assert_equal(len(one_s.se.any_n_str(str_test, 300)), 255) for i in range(16): test_s = s.copy() test_s.add_constraints(c_len == i) str_test = test_s.memory.load(c_addr, i + 1, endness='Iend_BE') nose.tools.assert_equal(test_s.se.any_str(str_test).index('\x00'), i) for j in range(i): nose.tools.assert_false( test_s.se.unique(test_s.memory.load(c_addr + j, 1)))
def test_inline_strlen(): s = SimState(arch="AMD64", mode="symbolic") l.info("fully concrete string") a_str = s.solver.BVV(0x41414100, 32) a_addr = s.solver.BVV(0x10, 64) s.memory.store(a_addr, a_str, endness="Iend_BE") a_len = strlen(s, arguments=[a_addr]) assert s.solver.unique(a_len) assert s.solver.eval(a_len) == 3 l.info("concrete-terminated string") b_str = s.solver.Concat(s.solver.BVS("mystring", 24), s.solver.BVV(0, 8)) b_addr = s.solver.BVV(0x20, 64) s.memory.store(b_addr, b_str, endness="Iend_BE") b_len = strlen(s, arguments=[b_addr]) assert s.solver.max_int(b_len) == 3 assert tuple(sorted(s.solver.eval_upto(b_len, 10))) == (0, 1, 2, 3) l.info("fully unconstrained") u_addr = s.solver.BVV(0x50, 64) u_len_sp = strlen(s, arguments=[u_addr]) u_len = u_len_sp assert len(s.solver.eval_upto(u_len, 100)) == s.libc.buf_symbolic_bytes assert s.solver.max_int(u_len) == s.libc.buf_symbolic_bytes-1 #print u_len_sp.solver.maximum_null #s.add_constraints(u_len < 16) assert s.solver.eval_upto(s.memory.load(0x50 + u_len, 1), 300) == [0] # # This tests if a strlen can influence a symbolic str. # l.info("Trying to influence length.") s = SimState(arch="AMD64", mode="symbolic") str_c = s.solver.BVS("some_string", 8*16) c_addr = s.solver.BVV(0x10, 64) s.memory.store(c_addr, str_c, endness='Iend_BE') c_len = strlen(s, arguments=[c_addr]) assert len(s.solver.eval_upto(c_len, 100)) == s.libc.buf_symbolic_bytes assert s.solver.max_int(c_len) == s.libc.buf_symbolic_bytes-1 one_s = s.copy() one_s.add_constraints(c_len == 1) assert one_s.solver.eval(str_c, cast_to=bytes).index(b'\x00') == 1 str_test = one_s.memory.load(c_addr, 2, endness='Iend_BE') assert len(one_s.solver.eval_upto(str_test, 300, cast_to=bytes)) == 255 for i in range(16): test_s = s.copy() test_s.add_constraints(c_len == i) str_test = test_s.memory.load(c_addr, i + 1, endness='Iend_BE') assert test_s.solver.eval(str_test, cast_to=bytes).index(b'\x00') == i for j in range(i): assert not test_s.solver.unique(test_s.memory.load(c_addr+j, 1))
def test_inline_strlen(): s = SimState(arch="AMD64", mode="symbolic") l.info("fully concrete string") a_str = s.solver.BVV(0x41414100, 32) a_addr = s.solver.BVV(0x10, 64) s.memory.store(a_addr, a_str, endness="Iend_BE") a_len = strlen(s, arguments=[a_addr]) nose.tools.assert_true(s.solver.unique(a_len)) nose.tools.assert_equal(s.solver.eval(a_len), 3) l.info("concrete-terminated string") b_str = s.solver.Concat(s.solver.BVS("mystring", 24), s.solver.BVV(0, 8)) b_addr = s.solver.BVV(0x20, 64) s.memory.store(b_addr, b_str, endness="Iend_BE") b_len = strlen(s, arguments=[b_addr]) nose.tools.assert_equal(s.solver.max_int(b_len), 3) nose.tools.assert_sequence_equal(sorted(s.solver.eval_upto(b_len, 10)), (0,1,2,3)) l.info("fully unconstrained") u_addr = s.solver.BVV(0x50, 64) u_len_sp = strlen(s, arguments=[u_addr]) u_len = u_len_sp nose.tools.assert_equal(len(s.solver.eval_upto(u_len, 100)), s.libc.buf_symbolic_bytes) nose.tools.assert_equal(s.solver.max_int(u_len), s.libc.buf_symbolic_bytes-1) #print u_len_sp.solver.maximum_null #s.add_constraints(u_len < 16) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x50 + u_len, 1), 300), [0]) # # This tests if a strlen can influence a symbolic str. # l.info("Trying to influence length.") s = SimState(arch="AMD64", mode="symbolic") str_c = s.solver.BVS("some_string", 8*16) c_addr = s.solver.BVV(0x10, 64) s.memory.store(c_addr, str_c, endness='Iend_BE') c_len = strlen(s, arguments=[c_addr]) nose.tools.assert_equal(len(s.solver.eval_upto(c_len, 100)), s.libc.buf_symbolic_bytes) nose.tools.assert_equal(s.solver.max_int(c_len), s.libc.buf_symbolic_bytes-1) one_s = s.copy() one_s.add_constraints(c_len == 1) nose.tools.assert_equal(one_s.solver.eval(str_c, cast_to=bytes).index(b'\x00'), 1) str_test = one_s.memory.load(c_addr, 2, endness='Iend_BE') nose.tools.assert_equal(len(one_s.solver.eval_upto(str_test, 300, cast_to=bytes)), 255) for i in range(16): test_s = s.copy() test_s.add_constraints(c_len == i) str_test = test_s.memory.load(c_addr, i + 1, endness='Iend_BE') nose.tools.assert_equal(test_s.solver.eval(str_test, cast_to=bytes).index(b'\x00'), i) for j in range(i): nose.tools.assert_false(test_s.solver.unique(test_s.memory.load(c_addr+j, 1)))
def test_strchr(): l.info("concrete haystack and needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVV(0x42, 64) addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) nose.tools.assert_true(s.solver.unique(ss_res)) nose.tools.assert_equal(s.solver.eval(ss_res), 0x11) l.info("concrete haystack, symbolic needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVS("wtf", 64) chr_needle = str_needle[7:0] addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) nose.tools.assert_false(s.solver.unique(ss_res)) nose.tools.assert_equal(len(s.solver.eval_upto(ss_res, 10)), 5) s_match = s.copy() s_nomatch = s.copy() s_match.add_constraints(ss_res != 0) s_nomatch.add_constraints(ss_res == 0) nose.tools.assert_true(s_match.satisfiable()) nose.tools.assert_true(s_nomatch.satisfiable()) nose.tools.assert_equal(len(s_match.solver.eval_upto(chr_needle, 300)), 4) nose.tools.assert_equal(len(s_nomatch.solver.eval_upto(chr_needle, 300)), 252) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(ss_res, 300)), [0x10, 0x11, 0x12, 0x13]) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(chr_needle, 300)), [0x00, 0x41, 0x42, 0x43]) s_match.memory.store(ss_res, s_match.solver.BVV(0x44, 8)) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(s_match.memory.load(0x10, 1), 300)), [0x41, 0x44]) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(s_match.memory.load(0x11, 1), 300)), [0x42, 0x44]) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(s_match.memory.load(0x12, 1), 300)), [0x43, 0x44]) nose.tools.assert_sequence_equal( sorted(s_match.solver.eval_upto(s_match.memory.load(0x13, 1), 300)), [0x00, 0x44])
def run_calloc_multiplies(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(30) sc = s.copy() s.heap.malloc(100) sc.heap.calloc(4, 25) nose.tools.assert_true(same_heap_states(s, sc))
def run_unusable_amount_returns_null(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(0x1000 - 4 * s.heap._chunk_size_t_size) sc = s.copy() p = s.heap.malloc(1) nose.tools.assert_equals(p, 0) nose.tools.assert_true(same_heap_states(s, sc))
def run_realloc_no_space_returns_null(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) p1 = s.heap.malloc(20) sc = s.copy() p2 = s.heap.realloc(p1, 0x2000) nose.tools.assert_equals(p2, 0) nose.tools.assert_true(same_heap_states(s, sc))
def _run_unusable_amount_returns_null(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(0x1000 - 4 * s.heap._chunk_size_t_size) sc = s.copy() p = s.heap.malloc(1) assert p == 0 assert self.same_heap_states(s, sc)
def _run_realloc_no_space_returns_null(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) p1 = s.heap.malloc(20) sc = s.copy() p2 = s.heap.realloc(p1, 0x2000) assert p2 == 0 assert self.same_heap_states(s, sc)
def test_fullpage_write(): s = SimState(arch='AMD64') a = s.se.BVV('A' * 0x2000) s.memory.store(0, a) #assert len(s.memory.mem._pages) == 2 #assert len(s.memory.mem._pages[0].keys()) == 0 #assert len(s.memory.mem._pages[1].keys()) == 0 assert s.memory.load(0, 0x2000) is a assert a.variables != s.memory.load(0x2000, 1).variables s = SimState(arch='AMD64') a = s.se.BVV('A' * 2) s.memory.store(0x1000, a) s.memory.store(0x2000, a) assert a.variables == s.memory.load(0x2000, 1).variables assert a.variables == s.memory.load(0x2001, 1).variables assert a.variables != s.memory.load(0x2002, 1).variables s = SimState(arch='AMD64') x = s.se.BVV('X') a = s.se.BVV('A' * 0x1000) s.memory.store(1, x) s2 = s.copy() s2.memory.store(0, a) assert len(s.memory.changed_bytes(s2.memory)) == 0x1000 s = SimState(arch='AMD64') s.memory._maximum_symbolic_size = 0x2000000 a = s.se.BVS('A', 0x1000000 * 8) s.memory.store(0, a) b = s.memory.load(0, 0x1000000) assert b is a
def _run_calloc_multiplies(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(30) sc = s.copy() s.heap.malloc(100) sc.heap.calloc(4, 25) assert self.same_heap_states(s, sc)
def test_symbolic_write(): s = SimState(arch='AMD64', add_options={o.SYMBOLIC_WRITE_ADDRESSES}) x = s.solver.BVS('x', 64) y = s.solver.BVS('y', 64) a = s.solver.BVV(b'A'*0x10) b = s.solver.BVV(b'B') c = s.solver.BVV(b'C') d = s.solver.BVV(b'D') s.memory.store(0x10, a) s.add_constraints(x >= 0x10, x < 0x20) s.memory.store(x, b) for i in range(0x10, 0x20): assert len(s.solver.eval_upto(s.memory.load(i, 1), 10)) == 2 s.memory.store(x, c) for i in range(0x10, 0x20): assert len(s.solver.eval_upto(s.memory.load(i, 1), 10)) == 2 s2 = s.copy() s2.add_constraints(y >= 0x10, y < 0x20) s2.memory.store(y, d) for i in range(0x10, 0x20): assert len(s2.solver.eval_upto(s2.memory.load(i, 1), 10)) == 3
def test_fullpage_write(): s = SimState(arch='AMD64') a = s.se.BVV('A'*0x2000) s.memory.store(0, a) #assert len(s.memory.mem._pages) == 2 #assert len(s.memory.mem._pages[0].keys()) == 0 #assert len(s.memory.mem._pages[1].keys()) == 0 assert s.memory.load(0, 0x2000) is a assert a.variables != s.memory.load(0x2000, 1).variables s = SimState(arch='AMD64') a = s.se.BVV('A'*2) s.memory.store(0x1000, a) s.memory.store(0x2000, a) assert a.variables == s.memory.load(0x2000, 1).variables assert a.variables == s.memory.load(0x2001, 1).variables assert a.variables != s.memory.load(0x2002, 1).variables s = SimState(arch='AMD64') x = s.se.BVV('X') a = s.se.BVV('A'*0x1000) s.memory.store(1, x) s2 = s.copy() s2.memory.store(0, a) assert len(s.memory.changed_bytes(s2.memory)) == 0x1000 s = SimState(arch='AMD64') s.memory._maximum_symbolic_size = 0x2000000 a = s.se.BVS('A', 0x1000000*8) s.memory.store(0, a) b = s.memory.load(0, 0x1000000) assert b is a
def test_symbolic_write(): s = SimState(arch='AMD64', add_options={o.SYMBOLIC_WRITE_ADDRESSES}) x = s.se.BVS('x', 64) y = s.se.BVS('y', 64) a = s.se.BVV('A' * 0x10) b = s.se.BVV('B') c = s.se.BVV('C') d = s.se.BVV('D') s.memory.store(0x10, a) s.add_constraints(x >= 0x10, x < 0x20) s.memory.store(x, b) for i in range(0x10, 0x20): assert len(s.se.any_n_int(s.memory.load(i, 1), 10)) == 2 s.memory.store(x, c) for i in range(0x10, 0x20): assert len(s.se.any_n_int(s.memory.load(i, 1), 10)) == 2 s2 = s.copy() s2.add_constraints(y >= 0x10, y < 0x20) s2.memory.store(y, d) for i in range(0x10, 0x20): assert len(s2.se.any_n_int(s2.memory.load(i, 1), 10)) == 3
def _run_realloc_near_same_size(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(20) p1 = s.heap.malloc(61) s.heap.malloc(80) sc = s.copy() p2 = s.heap.realloc(p1, 62) assert p1 == p2 assert self.same_heap_states(s, sc)
def run_realloc_near_same_size(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(20) p1 = s.heap.malloc(61) s.heap.malloc(80) sc = s.copy() p2 = s.heap.realloc(p1, 62) nose.tools.assert_equals(p1, p2) nose.tools.assert_true(same_heap_states(s, sc))
def run_free_null_preserves_state(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.heap.malloc(30) p = s.heap.malloc(40) s.heap.malloc(50) s.heap.free(p) s2 = s.copy() s2.heap.free(0) nose.tools.assert_true(same_heap_states(s, s2))
def run_malloc_maximizes_sym_arg(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) sc = s.copy() x = s.solver.BVS("x", 32) s.solver.add(x.UGE(0)) s.solver.add(x.ULE(max_sym_var_val(s))) s.heap.malloc(x) sc.heap.malloc(max_sym_var_val(sc)) nose.tools.assert_true(same_heap_states(s, sc))
def test_inline_strncmp(): l.info("symbolic left, symbolic right, symbolic len") s = SimState(arch="AMD64", mode="symbolic") left = s.solver.BVS("left", 32) left_addr = s.solver.BVV(0x1000, 64) right = s.solver.BVS("right", 32) right_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) s.memory.store(left_addr, left) s.memory.store(right_addr, right) s.add_constraints(strlen(s, arguments=[left_addr]) == 3) s.add_constraints(strlen(s, arguments=[right_addr]) == 0) s.add_constraints(maxlen != 0) c = strncmp(s, arguments=[left_addr, right_addr, maxlen]) s_match = s.copy() s_match.add_constraints(c == 0) nose.tools.assert_false(s_match.satisfiable()) #nose.tools.assert_equal(s_match.solver.min_int(maxlen), 3) s_nomatch = s.copy() s_nomatch.add_constraints(c != 0) nose.tools.assert_true(s_nomatch.satisfiable()) #nose.tools.assert_equal(s_nomatch.solver.max_int(maxlen), 2) l.info("zero-length") s = SimState(arch="AMD64", mode="symbolic") left = s.solver.BVS("left", 32) left_addr = s.solver.BVV(0x1000, 64) right = s.solver.BVS("right", 32) right_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) left_len = strlen(s, arguments=[left_addr]) right_len = strlen(s, arguments=[right_addr]) c = strncmp(s, arguments=[left_addr, right_addr, maxlen]) s.add_constraints(right_len == 0) s.add_constraints(left_len == 0) #s.add_constraints(c == 0) s.add_constraints(maxlen == 0) nose.tools.assert_true(s.satisfiable())
def test_inline_strncmp(): l.info("symbolic left, symbolic right, symbolic len") s = SimState(arch="AMD64", mode="symbolic") left = s.solver.BVS("left", 32) left_addr = s.solver.BVV(0x1000, 64) right = s.solver.BVS("right", 32) right_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) s.memory.store(left_addr, left) s.memory.store(right_addr, right) s.add_constraints(strlen(s, arguments=[left_addr]) == 3) s.add_constraints(strlen(s, arguments=[right_addr]) == 0) s.add_constraints(maxlen != 0) c = strncmp(s, arguments=[left_addr, right_addr, maxlen]) s_match = s.copy() s_match.add_constraints(c == 0) nose.tools.assert_false(s_match.satisfiable()) #nose.tools.assert_equal(s_match.solver.min_int(maxlen), 3) s_nomatch = s.copy() s_nomatch.add_constraints(c != 0) nose.tools.assert_true(s_nomatch.satisfiable()) #nose.tools.assert_equal(s_nomatch.solver.max_int(maxlen), 2) l.info("zero-length") s = SimState(arch="AMD64", mode="symbolic") left = s.solver.BVS("left", 32) left_addr = s.solver.BVV(0x1000, 64) right = s.solver.BVS("right", 32) right_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) left_len = strlen(s, arguments=[left_addr]) right_len = strlen(s, arguments=[right_addr]) c = strncmp(s, arguments=[left_addr, right_addr, maxlen]) s.add_constraints(right_len == 0) s.add_constraints(left_len == 0) #s.add_constraints(c == 0) s.add_constraints(maxlen == 0) nose.tools.assert_true(s.satisfiable())
def run_needs_space_for_metadata(arch): s = SimState(arch=arch, plugins={ 'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000) }) sc = s.copy() p1 = s.heap.malloc(0x1000) nose.tools.assert_equal(p1, 0) nose.tools.assert_true(same_heap_states(s, sc))
def run_needs_space_for_metadata(arch): s = SimState(arch=arch, plugins={ 'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000) }) sc = s.copy() p1 = s.heap.malloc(0x1000) assert p1 == 0 assert same_heap_states(s, sc)
def run_calloc_no_space_returns_null(arch): s = SimState(arch=arch, plugins={ 'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000) }) sc = s.copy() p1 = s.heap.calloc(0x500, 4) assert p1 == 0 assert same_heap_states(s, sc)
def run_calloc_clears(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) s.memory.store(0xd0000000 + 2 * s.heap._chunk_size_t_size, s.solver.BVV(-1, 100 * 8)) sc = s.copy() p1 = s.heap.calloc(6, 5) p2 = sc.heap.malloc(30) v1 = s.memory.load(p1, 30) v2 = sc.memory.load(p2, 30) nose.tools.assert_true(s.solver.is_true(v1 == 0)) nose.tools.assert_true(sc.solver.is_true(v2 == -1))
def _run_free_maximizes_sym_arg(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) p = s.heap.malloc(50) sc = s.copy() x = s.solver.BVS("x", 32) s.solver.add(x.UGE(0)) s.solver.add(x.ULE(p)) s.heap.free(x) sc.heap.free(p) assert self.same_heap_states(s, sc)
def test_strchr(): l.info("concrete haystack and needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVV(0x42, 64) addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) nose.tools.assert_true(s.solver.unique(ss_res)) nose.tools.assert_equal(s.solver.eval(ss_res), 0x11) l.info("concrete haystack, symbolic needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVS("wtf", 64) chr_needle = str_needle[7:0] addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) nose.tools.assert_false(s.solver.unique(ss_res)) nose.tools.assert_equal(len(s.solver.eval_upto(ss_res, 10)), 5) s_match = s.copy() s_nomatch = s.copy() s_match.add_constraints(ss_res != 0) s_nomatch.add_constraints(ss_res == 0) nose.tools.assert_true(s_match.satisfiable()) nose.tools.assert_true(s_nomatch.satisfiable()) nose.tools.assert_equal(len(s_match.solver.eval_upto(chr_needle, 300)), 4) nose.tools.assert_equal(len(s_nomatch.solver.eval_upto(chr_needle, 300)), 252) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(ss_res, 300)), [ 0x10, 0x11, 0x12, 0x13 ]) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(chr_needle, 300)), [ 0x00, 0x41, 0x42, 0x43 ]) s_match.memory.store(ss_res, s_match.solver.BVV(0x44, 8)) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(s_match.memory.load(0x10, 1), 300)), [ 0x41, 0x44 ]) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(s_match.memory.load(0x11, 1), 300)), [ 0x42, 0x44 ]) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(s_match.memory.load(0x12, 1), 300)), [ 0x43, 0x44 ]) nose.tools.assert_sequence_equal(sorted(s_match.solver.eval_upto(s_match.memory.load(0x13, 1), 300)), [ 0x00, 0x44 ]) return
def test_store_simplification(): state = SimState(arch='X86') state.regs.esp = state.se.BVS('stack_pointer', 32) state.regs.ebp = state.se.BVS('base_pointer', 32) state.regs.eax = state.se.BVS('base_eax', 32) irsb = pyvex.IRSB('PT]\xc2\x10\x00', 0x4000, state.arch) sim_successors = SimEngineVEX().process(state.copy(), irsb) exit_state = sim_successors.all_successors[0] nose.tools.assert_true(claripy.backends.z3.is_true(exit_state.regs.ebp == state.regs.esp - 4))
def test_store_simplification(): state = SimState(arch='X86') state.regs.esp = state.solver.BVS('stack_pointer', 32) state.regs.ebp = state.solver.BVS('base_pointer', 32) state.regs.eax = state.solver.BVS('base_eax', 32) irsb = pyvex.IRSB(b'PT]\xc2\x10\x00', 0x4000, state.arch) sim_successors = HeavyVEXMixin(None).process(state.copy(), irsb=irsb) exit_state = sim_successors.all_successors[0] nose.tools.assert_true(claripy.backends.z3.is_true(exit_state.regs.ebp == state.regs.esp - 4))
def test_strchr(): l.info("concrete haystack and needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVV(0x42, 64) addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) assert s.solver.unique(ss_res) assert s.solver.eval(ss_res) == 0x11 l.info("concrete haystack, symbolic needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVS("wtf", 64) chr_needle = str_needle[7:0] addr_haystack = s.solver.BVV(0x10, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") ss_res = strchr(s, arguments=[addr_haystack, str_needle]) assert not s.solver.unique(ss_res) assert len(s.solver.eval_upto(ss_res, 10)) == 5 s_match = s.copy() s_nomatch = s.copy() s_match.add_constraints(ss_res != 0) s_nomatch.add_constraints(ss_res == 0) assert s_match.satisfiable() assert s_nomatch.satisfiable() assert len(s_match.solver.eval_upto(chr_needle, 300)) == 4 assert len(s_nomatch.solver.eval_upto(chr_needle, 300)) == 252 assert sorted(s_match.solver.eval_upto(ss_res, 300)) == [ 0x10, 0x11, 0x12, 0x13 ] assert sorted(s_match.solver.eval_upto(chr_needle, 300)) == [ 0x00, 0x41, 0x42, 0x43 ] s_match.memory.store(ss_res, s_match.solver.BVV(0x44, 8)) assert sorted(s_match.solver.eval_upto(s_match.memory.load(0x10, 1), 300)) == [ 0x41, 0x44 ] assert sorted(s_match.solver.eval_upto(s_match.memory.load(0x11, 1), 300)) == [ 0x42, 0x44 ] assert sorted(s_match.solver.eval_upto(s_match.memory.load(0x12, 1), 300)) == [ 0x43, 0x44 ] assert sorted(s_match.solver.eval_upto(s_match.memory.load(0x13, 1), 300)) == [ 0x00, 0x44 ]
def run_calloc_maximizes_sym_arg(arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) sc = s.copy() x = s.solver.BVS("x", 32) s.solver.add(x.UGE(0)) s.solver.add(x.ULE(20)) y = s.solver.BVS("y", 32) s.solver.add(y.UGE(0)) s.solver.add(y.ULE(6)) s.heap.calloc(x, y) sc.heap.calloc(20, 6) nose.tools.assert_true(same_heap_states(s, sc))
def test_store_simplification(): state = SimState(arch="X86") state.regs.esp = state.solver.BVS("stack_pointer", 32) state.regs.ebp = state.solver.BVS("base_pointer", 32) state.regs.eax = state.solver.BVS("base_eax", 32) irsb = pyvex.IRSB(b"PT]\xc2\x10\x00", 0x4000, state.arch) sim_successors = HeavyVEXMixin(None).process(state.copy(), irsb=irsb) exit_state = sim_successors.all_successors[0] assert claripy.backends.z3.is_true(exit_state.regs.ebp == state.regs.esp - 4)
def test_mmap_base_copy(): state = SimState(arch="AMD64", mode="symbolic") mmap_base = 0x12345678 state.libc.mmap_base = mmap_base # Sanity check nose.tools.assert_equal(state.libc.mmap_base, mmap_base) state_copy = state.copy() nose.tools.assert_equal(state_copy.libc.mmap_base, mmap_base)
def test_mmap_base_copy(): state = SimState(arch="AMD64", mode="symbolic") mmap_base = 0x12345678 state.heap.mmap_base = mmap_base # Sanity check assert state.heap.mmap_base == mmap_base state_copy = state.copy() assert state_copy.heap.mmap_base == mmap_base
def _run_realloc_maximizes_sym_arg(self, arch): s = SimState(arch=arch, plugins={'heap': SimHeapPTMalloc(heap_base=0xd0000000, heap_size=0x1000)}) p = s.heap.malloc(50) sc = s.copy() x = s.solver.BVS("x", 32) s.solver.add(x.UGE(0)) s.solver.add(x.ULE(p)) y = s.solver.BVS("y", 32) s.solver.add(y.UGE(0)) s.solver.add(y.ULE(self.max_sym_var_val(s))) s.heap.realloc(x, y) sc.heap.realloc(p, self.max_sym_var_val(sc)) assert self.same_heap_states(s, sc)
def broken_sprintf(): l.info("concrete src, concrete dst, concrete len") s = SimState(mode="symbolic", arch="PPC32") format_str = s.solver.BVV(0x25640000, 32) format_addr = s.solver.BVV(0x2000, 32) #dst = s.solver.BVV("destination", 128) dst_addr = s.solver.BVV(0x1000, 32) arg = s.solver.BVS("some_number", 32) s.memory.store(format_addr, format_str) sprintf(s, arguments=[dst_addr, format_addr, arg]) for i in range(9): j = random.randint(10**i, 10**(i+1)) s2 = s.copy() s2.add_constraints(arg == j) #print s2.solver.eval_upto(s2.memory.load(dst_addr, i+2), 2, cast_to=bytes), repr(b"%d\x00" % j) nose.tools.assert_equal(s2.solver.eval_upto(s2.memory.load(dst_addr, i+2), 2, cast_to=bytes), [b"%d\x00" % j]) s2 = s.copy() s2.add_constraints(arg == 0) #print s2.solver.eval_upto(s2.memory.load(dst_addr, 2), 2, cast_to=bytes), repr(b"%d\x00" % 0) nose.tools.assert_equal(s2.solver.eval_upto(s2.memory.load(dst_addr, 2), 2, cast_to=bytes), [b"%d\x00" % 0])
def test_state_merge_3way(): a = SimState(arch='AMD64', mode='symbolic') b = a.copy() c = a.copy() conds = [ a.solver.BoolS('cond_0'), a.solver.BoolS('cond_1') ] a.add_constraints(conds[0]) b.add_constraints(a.solver.Not(conds[0]), conds[1]) c.add_constraints(a.solver.Not(conds[0]), a.solver.Not(conds[1])) a.memory.store(0x400000, a.solver.BVV(8, 32)) b.memory.store(0x400000, b.solver.BVV(9, 32)) c.memory.store(0x400000, c.solver.BVV(10, 32)) m, _, _ = a.merge(b) m, _, _ = m.merge(c) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 8,)) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 9,)) assert m.satisfiable(extra_constraints=(m.memory.load(0x400000, 4) == 10,))
def test_state_merge_static(): # With abstract memory # Aligned memory merging a = SimState(arch='AMD64', mode='static') addr = a.se.ValueSet(32, 'global', 0, 8) a.memory.store(addr, a.se.BVV(42, 32)) # Clear a_locs, so further writes will not try to merge with value 42 a.memory.regions['global']._alocs = { } b = a.copy() c = a.copy() a.memory.store(addr, a.se.BVV(50, 32), endness='Iend_LE') b.memory.store(addr, a.se.BVV(60, 32), endness='Iend_LE') c.memory.store(addr, a.se.BVV(70, 32), endness='Iend_LE') merged, _, _ = a.merge(b, c) actual = claripy.backends.vsa.convert(merged.memory.load(addr, 4)) expected = claripy.backends.vsa.convert(a.se.SI(bits=32, stride=10, lower_bound=50, upper_bound=70)) nose.tools.assert_true(actual.identical(expected))
def test_fullpage_write(): if os.environ.get("APPVEYOR", "false").lower() == "true": # Skip as AppVeyor boxes do not have enough memory to run this test raise nose.SkipTest() s = SimState(arch='AMD64') a = s.solver.BVV(b'A'*0x2000) s.memory.store(0, a) #assert len(s.memory.mem._pages) == 2 #assert len(s.memory.mem._pages[0].keys()) == 0 #assert len(s.memory.mem._pages[1].keys()) == 0 assert s.memory.load(0, 0x2000) is a assert a.variables != s.memory.load(0x2000, 1).variables s = SimState(arch='AMD64') a = s.solver.BVV(b'A'*2) s.memory.store(0x1000, a) s.memory.store(0x2000, a) assert a.variables == s.memory.load(0x2000, 1).variables assert a.variables == s.memory.load(0x2001, 1).variables assert a.variables != s.memory.load(0x2002, 1).variables s = SimState(arch='AMD64') x = s.solver.BVV(b'X') a = s.solver.BVV(b'A'*0x1000) s.memory.store(1, x) s2 = s.copy() s2.memory.store(0, a) assert len(s.memory.changed_bytes(s2.memory)) == 0x1000 s = SimState(arch='AMD64') s.memory._maximum_symbolic_size = 0x2000000 a = s.solver.BVS('A', 0x1000000*8) s.memory.store(0, a) b = s.memory.load(0, 0x1000000) assert b is a
def test_state_merge(): a = SimState(arch='AMD64', mode='symbolic') a.memory.store(1, a.se.BVV(42, 8)) b = a.copy() c = b.copy() a.memory.store(2, a.memory.load(1, 1)+1) b.memory.store(2, b.memory.load(1, 1)*2) c.memory.store(2, c.memory.load(1, 1)/2) # make sure the byte at 1 is right nose.tools.assert_equal(a.se.eval(a.memory.load(1, 1)), 42) nose.tools.assert_equal(b.se.eval(b.memory.load(1, 1)), 42) nose.tools.assert_equal(c.se.eval(c.memory.load(1, 1)), 42) # make sure the byte at 2 is right nose.tools.assert_equal(a.se.eval(a.memory.load(2, 1)), 43) nose.tools.assert_equal(b.se.eval(b.memory.load(2, 1)), 84) nose.tools.assert_equal(c.se.eval(c.memory.load(2, 1)), 21) # the byte at 2 should be unique for all before the merge nose.tools.assert_true(a.se.unique(a.memory.load(2, 1))) nose.tools.assert_true(b.se.unique(b.memory.load(2, 1))) nose.tools.assert_true(c.se.unique(c.memory.load(2, 1))) logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.DEBUG) m, merge_conditions, merging_occurred = a.merge(b, c) logging.getLogger('angr.state_plugins.symbolic_memory').setLevel(logging.WARNING) nose.tools.assert_true(merging_occurred) #nose.tools.assert_equals(sorted(m.se.eval_upto(merge_flag, 10)), [ 0,1,2 ]) assert len(merge_conditions) == 3 # the byte at 2 should now *not* be unique for a nose.tools.assert_false(m.se.unique(m.memory.load(2, 1))) nose.tools.assert_true(a.se.unique(a.memory.load(2, 1))) nose.tools.assert_true(b.se.unique(b.memory.load(2, 1))) nose.tools.assert_true(c.se.unique(c.memory.load(2, 1))) # the byte at 2 should have the three values nose.tools.assert_items_equal(m.se.eval_upto(m.memory.load(2, 1), 10), (43, 84, 21)) # we should be able to select them by adding constraints a_a = m.copy() a_a.add_constraints(merge_conditions[0]) nose.tools.assert_true(a_a.se.unique(a_a.memory.load(2, 1))) nose.tools.assert_equal(a_a.se.eval(a_a.memory.load(2, 1)), 43) a_b = m.copy() a_b.add_constraints(merge_conditions[1]) nose.tools.assert_true(a_b.se.unique(a_b.memory.load(2, 1))) nose.tools.assert_equal(a_b.se.eval(a_b.memory.load(2, 1)), 84) a_c = m.copy() a_c.add_constraints(merge_conditions[2]) nose.tools.assert_true(a_c.se.unique(a_c.memory.load(2, 1))) nose.tools.assert_equal(a_c.se.eval(a_c.memory.load(2, 1)), 21) # test different sets of plugins a = SimState(arch='AMD64', mode='symbolic') nose.tools.assert_true(a.has_plugin('memory')) nose.tools.assert_true(a.has_plugin('registers')) nose.tools.assert_false(a.has_plugin('libc')) b = a.copy() a.get_plugin('libc') nose.tools.assert_true(a.has_plugin('libc')) nose.tools.assert_false(b.has_plugin('libc')) c = a.copy().merge(b.copy())[0] d = b.copy().merge(a.copy())[0] nose.tools.assert_true(c.has_plugin('libc')) nose.tools.assert_true(d.has_plugin('libc')) # test merging posix with different open files a = SimState(arch='AMD64', mode='symbolic') b = a.copy() a.posix.get_file(3) nose.tools.assert_equal(len(a.posix.files), 4) nose.tools.assert_equal(len(b.posix.files), 3) c = a.copy().merge(b.copy())[0] d = b.copy().merge(a.copy())[0] nose.tools.assert_equal(len(c.posix.files), 4) nose.tools.assert_equal(len(d.posix.files), 4)
def test_memory(): initial_memory = { 0: b'A', 1: b'A', 2: b'A', 3: b'A', 10: b'B' } s = SimState(arch="AMD64", memory_backer=initial_memory, add_options={o.REVERSE_MEMORY_NAME_MAP, o.REVERSE_MEMORY_HASH_MAP}) _concrete_memory_tests(s) # concrete address and partially symbolic result expr = s.memory.load(2, 4) expr = s.memory.load(2, 4) expr = s.memory.load(2, 4) expr = s.memory.load(2, 4) nose.tools.assert_true(s.solver.symbolic(expr)) nose.tools.assert_false(s.solver.unique(expr)) nose.tools.assert_greater_equal(s.solver.eval(expr), 0x41410000) nose.tools.assert_less_equal(s.solver.eval(expr), 0x41420000) nose.tools.assert_equal(s.solver.min_int(expr), 0x41410000) nose.tools.assert_equal(s.solver.max_int(expr), 0x4141ffff) # concrete address and concrete result expr = s.memory.load(0, 4) # Returns: a z3 BVS representing 0x41414141 nose.tools.assert_false(s.solver.symbolic(expr)) nose.tools.assert_equal(s.solver.eval(expr), 0x41414141) # symbolicize v = s.memory.make_symbolic("asdf", 0, length=4) nose.tools.assert_equal(v.size(), 32) nose.tools.assert_true(s.solver.unique(v)) nose.tools.assert_equal(s.solver.eval(v), 0x41414141) expr = s.memory.load(0, 4) # Returns: a z3 BVS representing 0x41414141 nose.tools.assert_true(s.solver.symbolic(expr)) nose.tools.assert_equal(s.solver.eval(expr), 0x41414141) nose.tools.assert_true(s.solver.unique(expr)) c = s.solver.BVS('condition', 8) expr = s.memory.load(10, 1, condition=c==1, fallback=s.solver.BVV(b'X')) nose.tools.assert_equal(s.solver.eval_upto(expr, 10, cast_to=bytes, extra_constraints=[c==1]), [ b'B' ]) nose.tools.assert_equal(s.solver.eval_upto(expr, 10, cast_to=bytes, extra_constraints=[c!=1]), [ b'X' ]) x = s.solver.BVS('ref_test', 16, explicit_name=True) s.memory.store(0x1000, x) s.memory.store(0x2000, x) nose.tools.assert_equal(set(s.memory.addrs_for_name('ref_test')), {0x1000,0x1001,0x2000,0x2001}) nose.tools.assert_equal(set(s.memory.addrs_for_hash(hash(x))), {0x1000, 0x1001, 0x2000, 0x2001}) s2 = s.copy() y = s2.solver.BVS('ref_test2', 16, explicit_name=True) s2.memory.store(0x2000, y) assert s2.memory.load(0x2000, 2) is y assert s.memory.load(0x2000, 2) is x nose.tools.assert_equal(set(s.memory.addrs_for_name('ref_test')), {0x1000,0x1001,0x2000,0x2001}) nose.tools.assert_equal(set(s.memory.addrs_for_hash(hash(x))), {0x1000,0x1001,0x2000,0x2001}) nose.tools.assert_equal(set(s2.memory.addrs_for_name('ref_test')), {0x1000, 0x1001}) nose.tools.assert_equal(set(s2.memory.addrs_for_hash(hash(x))), {0x1000, 0x1001}) nose.tools.assert_equal(set(s2.memory.addrs_for_name('ref_test2')), {0x2000, 0x2001}) nose.tools.assert_equal(set(s2.memory.addrs_for_hash(hash(y))), {0x2000, 0x2001}) s.memory.store(0x3000, s.solver.BVS('replace_old', 32, explicit_name=True)) s.memory.store(0x3001, s.solver.BVV(b'AB')) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_old')), {0x3000, 0x3003}) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x3001, 2), 10, cast_to=bytes), [b"AB"]) n = s.solver.BVS('replace_new', 32, explicit_name=True) c = s.solver.BVS('replace_cool', 32, explicit_name=True) mo = s.memory.memory_objects_for_name('replace_old') nose.tools.assert_equal(len(mo), 1) s.memory.replace_memory_object(next(iter(mo)), n) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_old')), set()) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_new')), {0x3000, 0x3003}) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x3001, 2), 10, cast_to=bytes), [b"AB"]) s.memory.store(0x4000, s.solver.If(n == 0, n+10, n+20)) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_new')), {0x3000, 0x3003, 0x4000, 0x4001, 0x4002, 0x4003}) s.memory.replace_all(n, c) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_old')), set()) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_new')), set()) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_cool')), {0x3000, 0x3003, 0x4000, 0x4001, 0x4002, 0x4003}) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x3001, 2), 10, cast_to=bytes), [b"AB"]) z = s.solver.BVV(0, 32) s.memory.replace_all(c, z) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_old')), set()) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_new')), set()) nose.tools.assert_equal(set(s.memory.addrs_for_name('replace_cool')), set()) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x3001, 2), 10, cast_to=bytes), [b"AB"]) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x3000, 4), 10), [0x00414200]) nose.tools.assert_equal(s.solver.eval_upto(s.memory.load(0x4000, 4), 10), [0x0000000a]) # symbolic length x = s.solver.BVV(0x11223344, 32) y = s.solver.BVV(0xAABBCCDD, 32) n = s.solver.BVS('size', 32) s.memory.store(0x5000, x) s.memory.store(0x5000, y, size=n) nose.tools.assert_equal(set(s.solver.eval_upto(s.memory.load(0x5000, 4), 10)), { 0x11223344, 0xAA223344, 0xAABB3344, 0xAABBCC44, 0xAABBCCDD }) s1 = s.copy() s1.add_constraints(n == 1) nose.tools.assert_equal(set(s1.solver.eval_upto(s1.memory.load(0x5000, 4), 10)), { 0xAA223344 }) s4 = s.copy() s4.add_constraints(n == 4) nose.tools.assert_equal(set(s4.solver.eval_upto(s4.memory.load(0x5000, 4), 10)), { 0xAABBCCDD }) # condition without fallback x = s.solver.BVV(0x11223344, 32) y = s.solver.BVV(0xAABBCCDD, 32) c = s.solver.BVS('condition', 32) s.memory.store(0x6000, x) s.memory.store(0x6000, y, condition=c==1) nose.tools.assert_equal(set(s.solver.eval_upto(s.memory.load(0x6000, 4), 10)), { 0x11223344, 0xAABBCCDD }) s0 = s.copy() s0.add_constraints(c == 0) nose.tools.assert_equal(set(s0.solver.eval_upto(s0.memory.load(0x6000, 4), 10)), { 0x11223344 }) s1 = s.copy() s1.add_constraints(c == 1) nose.tools.assert_equal(set(s1.solver.eval_upto(s1.memory.load(0x6000, 4), 10)), { 0xAABBCCDD }) # condition with symbolic size x = s.solver.BVV(0x11223344, 32) y = s.solver.BVV(0xAABBCCDD, 32) c = s.solver.BVS('condition', 32) n = s.solver.BVS('size', 32) s.memory.store(0x8000, x) s.memory.store(0x8000, y, condition=c==1, size=n) s0 = s.copy() s0.add_constraints(c == 0) nose.tools.assert_equal(set(s0.solver.eval_upto(s0.memory.load(0x8000, 4), 10)), { 0x11223344 }) s1 = s.copy() s1.add_constraints(c == 1) nose.tools.assert_equal(set(s1.solver.eval_upto(s1.memory.load(0x8000, 4), 10)), { 0x11223344, 0xAA223344, 0xAABB3344, 0xAABBCC44, 0xAABBCCDD })
def test_cased_store(): initial_memory = { 0: b'A', 1: b'A', 2: b'A', 3: b'A' } so = SimState(arch="AMD64", memory_backer=initial_memory) # sanity check nose.tools.assert_equal(so.solver.eval_upto(so.memory.load(0, 4), 2, cast_to=bytes), [b'AAAA']) # the values values = [ None, so.solver.BVV(b'B'), so.solver.BVV(b'CC'), so.solver.BVV(b'DDD'), so.solver.BVV(b'EEEE') ] # try the write s = so.copy() x = s.solver.BVS('x', 32) s.memory.store_cases(0, values, [ x == i for i in range(len(values)) ]) for i,v in enumerate(values): v = b'' if v is None else s.solver.eval(v, cast_to=bytes) w = s.solver.eval_upto(s.memory.load(0, 4), 2, cast_to=bytes, extra_constraints=[x==i]) nose.tools.assert_equal(w, [v.ljust(4, b'A')]) # and now with a fallback y = s.solver.BVS('y', 32) s.memory.store_cases(0, values, [ y == i for i in range(len(values)) ], fallback=s.solver.BVV(b'XXXX')) for i,v in enumerate(values): v = b'' if v is None else s.solver.eval(v, cast_to=bytes) w = s.solver.eval_upto(s.memory.load(0, 4), 2, cast_to=bytes, extra_constraints=[y==i]) nose.tools.assert_equal(w, [v.ljust(4, b'X')]) # and now with endness y = s.solver.BVS('y', 32) s.memory.store_cases(0, values, [ y == i for i in range(len(values)) ], fallback=s.solver.BVV(b'XXXX'), endness="Iend_LE") for i,v in enumerate(values): v = b'' if v is None else s.solver.eval(v, cast_to=bytes) w = s.solver.eval_upto(s.memory.load(0, 4), 2, cast_to=bytes, extra_constraints=[y==i]) print(w, v.rjust(4, b'X')) nose.tools.assert_equal(w, [v.rjust(4, b'X')]) # and write all Nones s = so.copy() z = s.solver.BVS('z', 32) s.memory.store_cases(0, [ None, None, None ], [ z == 0, z == 1, z == 2]) for i in range(len(values)): w = s.solver.eval_upto(s.memory.load(0, 4), 2, cast_to=bytes, extra_constraints=[z==i]) nose.tools.assert_equal(w, [b'AAAA']) # and all Nones with a fallback u = s.solver.BVS('w', 32) s.memory.store_cases(0, [ None, None, None ], [ u == 0, u == 1, u == 2], fallback=s.solver.BVV(b'WWWW')) for i,v in enumerate(values): w = s.solver.eval_upto(s.memory.load(0, 4), 2, cast_to=bytes, extra_constraints=[u==i]) nose.tools.assert_equal(w, [b'WWWW']) # and all identical values s = so.copy() #t = s.solver.BVS('t', 32) s.memory.store_cases(0, [ s.solver.BVV(b'AA'), s.solver.BVV(b'AA'), s.solver.BVV(b'AA') ], [ u == 0, u == 1, u == 2], fallback=s.solver.BVV(b'AA')) r = s.memory.load(0, 2) nose.tools.assert_equal(r.op, 'BVV') nose.tools.assert_equal(s.solver.eval_upto(r, 2, cast_to=bytes), [b'AA']) # and all identical values, with varying fallback s = so.copy() #t = s.solver.BVS('t', 32) s.memory.store_cases(0, [ s.solver.BVV(b'AA'), s.solver.BVV(b'AA'), s.solver.BVV(b'AA') ], [ u == 0, u == 1, u == 2], fallback=s.solver.BVV(b'XX')) r = s.memory.load(0, 2) nose.tools.assert_equal(sorted(s.solver.eval_upto(r, 3, cast_to=bytes)), [b'AA', b'XX']) # and some identical values s = so.copy() #q = s.solver.BVS('q', 32) values = [ b'AA', b'BB', b'AA' ] s.memory.store_cases(0, [ s.solver.BVV(v) for v in values ], [ u == i for i in range(len(values))], fallback=s.solver.BVV(b'XX')) r = s.memory.load(0, 2) for i,v in enumerate(values + [b'XX']): w = s.solver.eval_upto(s.memory.load(0, 2), 2, cast_to=bytes, extra_constraints=[u==i]) nose.tools.assert_equal(w, [(values+[b'XX'])[i]])
def test_abstract_memory(): initial_memory = {0: b'A', 1: b'B', 2: b'C', 3: b'D'} s = SimState(mode='static', arch="AMD64", memory_backer=initial_memory, add_options={o.ABSTRACT_SOLVER, o.ABSTRACT_MEMORY}) se = s.se def to_vs(region, offset): return s.solver.VS(s.arch.bits, region, 0, offset) # Load a single-byte constant from global region expr = s.memory.load(to_vs('global', 2), 1) nose.tools.assert_equal(s.solver.eval(expr), 0x43) nose.tools.assert_equal(s.solver.max_int(expr), 0x43) nose.tools.assert_equal(s.solver.min_int(expr), 0x43) # Store a single-byte constant to global region s.memory.store(to_vs('global', 1), s.solver.BVV(b'D'), 1) expr = s.memory.load(to_vs('global', 1), 1) nose.tools.assert_equal(s.solver.eval(expr), 0x44) # Store a single-byte StridedInterval to global region si_0 = s.solver.BVS('unnamed', 8, 10, 20, 2) s.memory.store(to_vs('global', 4), si_0) # Load the single-byte StridedInterval from global region expr = s.memory.load(to_vs('global', 4), 1) nose.tools.assert_equal(s.solver.min_int(expr), 10) nose.tools.assert_equal(s.solver.max_int(expr), 20) nose.tools.assert_equal(s.solver.eval_upto(expr, 100), [10, 12, 14, 16, 18, 20]) # Store a two-byte StridedInterval object to global region si_1 = s.solver.BVS('unnamed', 16, 10, 20, 2) s.memory.store(to_vs('global', 5), si_1) # Load the two-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 5), 2) nose.tools.assert_true(claripy.backends.vsa.identical(expr, si_1)) # Store a four-byte StridedInterval object to global region si_2 = s.solver.BVS('unnamed', 32, 8000, 9000, 2) s.memory.store(to_vs('global', 7), si_2) # Load the four-byte StridedInterval object from global region expr = s.memory.load(to_vs('global', 7), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 8000, 9000, 2))) # Test default values s.options.remove(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 100), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0, 0))) # Test default values (symbolic) s.options.add(o.SYMBOLIC_INITIAL_VALUES) expr = s.memory.load(to_vs('global', 104), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, 0, 0xffffffff, 1))) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 32, -0x80000000, 0x7fffffff, 1))) # # Merging # # Merging two one-byte values s.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x10, 0x10, 0)) a = s.copy() a.memory.store(to_vs('function_merge', 0), s.solver.BVS('unnamed', 8, 0x20, 0x20, 0)) b = s.merge(a)[0] expr = b.memory.load(to_vs('function_merge', 0), 1) nose.tools.assert_true(claripy.backends.vsa.identical(expr, s.solver.BVS('unnamed', 8, 0x10, 0x20, 0x10))) # | MO(value_0) | # | MO(value_1) | # 0x20 0x24 # Merge one byte in value_0/1 means merging the entire MemoryObject a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100000, upper_bound=0x100000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x100001, upper_bound=0x100001)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=1, lower_bound=0x100000, upper_bound=0x100001))) c_mem = c.memory.regions['function_merge'].memory.mem object_set = {c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]} nose.tools.assert_equal(len(object_set), 1) a = s.copy() a.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x200000)) b = s.copy() b.memory.store(to_vs('function_merge', 0x20), se.SI(bits=32, stride=0, lower_bound=0x300000, upper_bound=0x300000)) c = a.merge(b)[0] expr = c.memory.load(to_vs('function_merge', 0x20), 4) nose.tools.assert_true(claripy.backends.vsa.identical(expr, se.SI(bits=32, stride=0x100000, lower_bound=0x100000, upper_bound=0x300000))) object_set = {c_mem[0x20], c_mem[0x20], c_mem[0x22], c_mem[0x23]} nose.tools.assert_equal(len(object_set), 1) # # Widening # a = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=2) b = s.solver.SI(bits=32, stride=1, lower_bound=1, upper_bound=3) a = a.reversed b = b.reversed
class BlockState(object): def __init__(self, project, addr, state=None, taint_region=None): self.project = project self.addr = addr self.block_addr = addr self.taint_region = taint_region self.state = state self.tempstore = None self.tags = [] self.write_targets = [] if self.state is None: self.state = SimState(arch=project.arch, mode='symbolic', special_memory_filler=lambda name, bits, _state: BiHead(claripy.BVV(0, bits), claripy.BVV(0, bits)), add_options={sim_options.ABSTRACT_MEMORY, sim_options.SPECIAL_MEMORY_FILL} ) self.state.scratch.ins_addr = 0 if project.arch.name.startswith('ARM'): it = self.state.regs.itstate it.taints['it'] = True self.state.regs.itstate = it def copy(self, newaddr): return BlockState(self.project, newaddr, state=self.state.copy(), taint_region=self.taint_region) def get_reg(self, offset, ty): if isinstance(ty, int): ty = 'Ity_I%d' % ty size = vexutils.extract_int(ty) val = self.state.registers.load(offset, size//8) if ty.startswith('Ity_F'): val = val.raw_to_fp() return val def put_reg(self, offset, val): self.state.registers.store(offset, val) def get_tmp(self, tmpnum): return self.tempstore.read(tmpnum) def put_tmp(self, tmpnum, val): self.tempstore.write(tmpnum, val) def get_mem(self, addr, ty): if isinstance(ty, int): ty = 'Ity_I%d' % ty size = vexutils.extract_int(ty) addr_vs = self.state.solver.VS(bits=self.state.arch.bits, region=addr.taints['pointer'] if addr.taints['pointer'] else 'global', val=addr.as_unsigned) val = self.state.memory.load(addr_vs, size//8, endness=self.state.arch.memory_endness) if ty.startswith('Ity_F'): val = val.raw_to_fp() return val def put_mem(self, addr, val): if not addr.taints['pointer']: return # don't store anything to memory that's not an accounted-for region addr_vs = self.state.solver.VS(bits=self.state.arch.bits, region=addr.taints['pointer'], val=addr.as_unsigned) self.state.scratch.ins_addr += 1 self.state.memory.store(addr_vs, val, endness=self.state.arch.memory_endness) self.write_targets.append((addr_vs, val.length//8)) def access(self, addr_expression, access_type): if addr_expression.taints['pointer'] != self.taint_region: return self.tags.append(('ACCESS', PendingBinaryData.make_bindata(addr_expression, self.addr, access_type))) def alloc(self, addr_expression): self.tags.append(('ALLOC', PendingBinaryData.make_bindata(addr_expression, self.addr, 0))) def handle_irsb(self, block): self.tempstore = TempStore(block.tyenv) for stmt_idx, stmt in enumerate(block.statements): path = ['statements', stmt_idx] self.handle_statement(stmt, block.tyenv, path) def handle_statement(self, stmt, tyenv, path): if stmt.tag in ('Ist_NoOp', 'Ist_AbiHint', 'Ist_MBE'): pass elif stmt.tag == 'Ist_IMark': self.addr = stmt.addr + stmt.delta elif stmt.tag == 'Ist_Exit': self.handle_expression(stmt.dst, tyenv, path + ['dst']) # Let the cfg take care of control flow! elif stmt.tag == 'Ist_WrTmp': expression = self.handle_expression(stmt.data, tyenv, path + ['data']) self.put_tmp(stmt.tmp, expression) elif stmt.tag == 'Ist_Store': expression = self.handle_expression(stmt.data, tyenv, path + ['data']) address = self.handle_expression(stmt.addr, tyenv, path + ['addr']) self.put_mem(address, expression) self.access(address, ACCESS_WRITE) self.access(expression, ACCESS_POINTER) elif stmt.tag == 'Ist_Put': expression = self.handle_expression(stmt.data, tyenv, path + ['data']) self.put_reg(stmt.offset, expression) if stmt.offset == self.project.arch.sp_offset: if not expression.taints['concrete']: l.warning("This function appears to use alloca(). Abort.") raise FidgetAnalysisFailure self.alloc(expression) elif stmt.tag == 'Ist_LoadG': # Conditional loads. Lots of bullshit. addr_expression = self.handle_expression(stmt.addr, tyenv, path + ['addr']) self.access(addr_expression, ACCESS_READ) # load the actual data data_expression = self.get_mem(addr_expression, stmt.cvt_types[0]) # it then needs a type conversion applied to it conv_diff = vexutils.extract_int(stmt.cvt_types[1]) - vexutils.extract_int(stmt.cvt_types[0]) if conv_diff != 0: concrete = data_expression.taints['concrete'] deps = data_expression.taints['deps'] if 'S' in stmt.cvt: data_expression = data_expression.sign_extend(conv_diff) else: data_expression = data_expression.zero_extend(conv_diff) data_expression.taints['concrete'] = concrete data_expression.taints['deps'] = deps self.put_tmp(stmt.dst, data_expression) self.handle_expression(stmt.guard, tyenv, path + ['guard']) self.handle_expression(stmt.alt, tyenv, path + ['alt']) elif stmt.tag == 'Ist_StoreG': # Conditional store addr_expr = self.handle_expression(stmt.addr, tyenv, path + ['addr']) value_expr = self.handle_expression(stmt.data, tyenv, path + ['data']) self.handle_expression(stmt.guard, tyenv, path + ['guard']) self.put_mem(addr_expr, value_expr) self.access(addr_expr, ACCESS_WRITE) self.access(value_expr, ACCESS_POINTER) elif stmt.tag == 'Ist_PutI': # haha no self.handle_expression(stmt.data, tyenv, path + ['data']) elif stmt.tag == 'Ist_CAS': # HA ha no if stmt.oldLo != 4294967295: self.tempstore.default(stmt.oldLo) if stmt.oldHi != 4294967295: self.tempstore.default(stmt.oldHi) elif stmt.tag == 'Ist_Dirty': # hahAHAHAH NO if stmt.tmp != 4294967295: self.tempstore.default(stmt.tmp) else: raise FidgetUnsupportedError("Unknown vex instruction???", stmt) def handle_expression(self, expr, tyenv, path): size = expr.result_size(tyenv) if not expr.tag.startswith('Ico_') else expr.size ty = expr.result_type(tyenv) if not expr.tag.startswith('Ico_') else expr.type addr = self.addr if expr.tag == 'Iex_Get': return self.get_reg(expr.offset, ty) elif expr.tag == 'Iex_RdTmp': return self.get_tmp(expr.tmp) elif expr.tag == 'Iex_Load': addr_expression = self.handle_expression(expr.addr, tyenv, path + ['addr']) self.access(addr_expression, ACCESS_READ) return self.get_mem(addr_expression, ty) elif expr.tag == 'Iex_Const' or expr.tag.startswith('Ico_'): if expr.tag == 'Iex_Const': expr = expr.con if 'F' in ty: if size == 32: values = BiHead( claripy.FPV(expr.value, claripy.fp.FSORT_FLOAT), claripy.FPS('%x_%d' % (addr, path[1]), claripy.fp.FSORT_FLOAT) ) elif size == 64: values = BiHead( claripy.FPV(expr.value, claripy.fp.FSORT_DOUBLE), claripy.FPS('%x_%d' % (addr, path[1]), claripy.fp.FSORT_DOUBLE) ) else: raise FidgetUnsupportedError("Why is there a FP const of size %d" % size) else: values = BiHead( claripy.BVV(expr.value, size), claripy.BVS('%x_%d' % (addr, path[1]), size) ) values.taints['deps'].append(PendingBinaryData(self.project, self.addr, values, path)) values.taints['concrete'] = True values.taints['concrete_root'] = True return values elif expr.tag == 'Iex_ITE': false_expr = self.handle_expression(expr.iffalse, tyenv, path + ['iffalse']) truth_expr = self.handle_expression(expr.iftrue, tyenv, path + ['iftrue']) values = truth_expr if truth_expr.taints['pointer'] else false_expr cond_expr = self.handle_expression(expr.cond, tyenv, path + ['cond']) if not cond_expr.taints['it']: values.taints['concrete'] = false_expr.taints['concrete'] and truth_expr.taints['concrete'] values.taints['it'] = false_expr.taints['it'] or truth_expr.taints['it'] return values elif expr.tag in ('Iex_Unop','Iex_Binop','Iex_Triop','Iex_Qop'): args = [] for i, sub_expr in enumerate(expr.args): arg = self.handle_expression(sub_expr, tyenv, path + ['args', i]) if expr.op.startswith('Iop_Mul') or expr.op.startswith('Iop_And') \ or (i == 0 and expr.op in ROUNDING_IROPS): if arg.taints['concrete_root']: arg = BiHead(arg.cleanval, arg.cleanval) arg.taints['concrete'] = True args.append(arg) try: values = BiHead( operations[expr.op].calculate(*(x.cleanval for x in args)), operations[expr.op].calculate(*(x.dirtyval for x in args)) ) except SimOperationError: l.exception("SimOperationError while running op '%s', returning null", expr.op) return BiHead.default(ty) except KeyError: l.error("Unsupported operation '%s', returning null", expr.op) return BiHead.default(ty) else: # propogate the taints correctly values.taints['concrete'] = True for arg in args: values.taints['deps'].extend(arg.taints['deps']) values.taints['concrete'] = values.taints['concrete'] and arg.taints['concrete'] values.taints['it'] = values.taints['it'] or arg.taints['it'] if expr.op.startswith('Iop_Add') or expr.op.startswith('Iop_And') or \ expr.op.startswith('Iop_Or') or expr.op.startswith('Iop_Xor'): t1 = args[0].taints['pointer'] t2 = args[1].taints['pointer'] values.taints['pointer'] = (t1 if t1 else t2) if (bool(t1) ^ bool(t2)) else False elif expr.op.startswith('Iop_Sub'): t1 = args[0].taints['pointer'] t2 = args[1].taints['pointer'] values.taints['pointer'] = t1 if t1 and not t2 else False return values elif expr.tag == 'Iex_CCall': values = BiHead.default(ty) for i, expr in enumerate(expr.args): arg = self.handle_expression(expr, tyenv, path + ['args', i]) values.taints['it'] = values.taints['it'] or arg.taints['it'] return values elif expr.tag == 'Iex_GetI': return BiHead.default(ty) else: raise FidgetUnsupportedError('Unknown expression tag ({:#x}): {!r}'.format(addr, expr.tag)) def end(self, clean=False): for name in self.project.arch.default_symbolic_registers: offset = self.project.arch.registers[name][0] if offset in (self.project.arch.sp_offset, self.project.arch.bp_offset, self.project.arch.ip_offset): continue if name == 'r7' and self.project.arch.name.startswith('ARM') and self.addr & 1 == 1: continue # values remaining in registers at end-of-block are pointers! Probably. value = getattr(self.state.regs, name) if value.taints['already_pointered']: continue self.access(value, ACCESS_POINTER) value.taints['already_pointered'] = True if value.taints['concrete'] and not value.taints['pointer']: # Don't let nonpointer values persist between block states value = BiHead(value.cleanval, value.cleanval) self.state.registers.store(offset, value) # If a call, scrub the return-value register if clean: self.state.registers.store(self.state.arch.ret_offset, BiHead(claripy.BVV(0, self.state.arch.bits), claripy.BVV(0, self.state.arch.bits))) # Don't let nonpointer vales persist between block state... in memory! for addr, size in self.write_targets: value = self.state.memory.load(addr, size, endness=self.state.arch.memory_endness) if not value.taints['pointer']: replacement = BiHead(value.cleanval, value.cleanval) self.state.scratch.ins_addr += 1 self.state.memory.store(addr, replacement, endness=self.state.arch.memory_endness)
def broken_inline_strstr(): l.info("concrete haystack and needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVV(0x42430000, 32) addr_haystack = s.solver.BVV(0x10, 64) addr_needle = s.solver.BVV(0xb0, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") s.memory.store(addr_needle, str_needle, endness="Iend_BE") ss_res = strstr(s, arguments=[addr_haystack, addr_needle]) nose.tools.assert_true(s.solver.unique(ss_res)) nose.tools.assert_equal(s.solver.eval(ss_res), 0x11) l.info("concrete haystack, symbolic needle") s = SimState(arch="AMD64", mode="symbolic") str_haystack = s.solver.BVV(0x41424300, 32) str_needle = s.solver.BVS("wtf", 32) addr_haystack = s.solver.BVV(0x10, 64) addr_needle = s.solver.BVV(0xb0, 64) s.memory.store(addr_haystack, str_haystack, endness="Iend_BE") s.memory.store(addr_needle, str_needle, endness="Iend_BE") ss_res = strstr(s, arguments=[addr_haystack, addr_needle]) nose.tools.assert_false(s.solver.unique(ss_res)) nose.tools.assert_equal(len(s.solver.eval_upto(ss_res, 10)), 4) s_match = s.copy() s_nomatch = s.copy() s_match.add_constraints(ss_res != 0) s_nomatch.add_constraints(ss_res == 0) match_needle = str_needle[31:16] nose.tools.assert_equal(len(s_match.solver.eval_upto(match_needle, 300)), 259) nose.tools.assert_equal(len(s_match.solver.eval_upto(str_needle, 10)), 10) l.info("symbolic haystack, symbolic needle") s = SimState(arch="AMD64", mode="symbolic") s.libc.buf_symbolic_bytes = 5 addr_haystack = s.solver.BVV(0x10, 64) addr_needle = s.solver.BVV(0xb0, 64) len_needle = strlen(s, arguments=[addr_needle]) ss_res = strstr(s, arguments=[addr_haystack, addr_needle]) nose.tools.assert_false(s.solver.unique(ss_res)) nose.tools.assert_equal(len(s.solver.eval_upto(ss_res, 100)), s.libc.buf_symbolic_bytes) s_match = s.copy() s_nomatch = s.copy() s_match.add_constraints(ss_res != 0) s_nomatch.add_constraints(ss_res == 0) match_cmp = strncmp(s_match, arguments=[ss_res, addr_needle, len_needle]) nose.tools.assert_sequence_equal(s_match.solver.eval_upto(match_cmp, 10), [0]) r_mm = strstr(s_match, arguments=[addr_haystack, addr_needle]) s_match.add_constraints(r_mm == 0) nose.tools.assert_false(s_match.satisfiable()) nose.tools.assert_true(s_nomatch.satisfiable()) s_nss = s_nomatch.copy() nomatch_ss = strstr(s_nss, arguments=[addr_haystack, addr_needle]) s_nss.add_constraints(nomatch_ss != 0) nose.tools.assert_false(s_nss.satisfiable())
def test_memcpy(): l.info("concrete src, concrete dst, concrete len") l.debug("... full copy") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVV(0x42424242, 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) memcpy(s, arguments=[dst_addr, src_addr, s.solver.BVV(4, 64)]) new_dst = s.memory.load(dst_addr, 4, endness='Iend_BE') nose.tools.assert_equal(s.solver.eval_upto(new_dst, 2, cast_to=bytes), [ b"BBBB" ]) l.info("giant copy") s = SimState(arch="AMD64", mode="symbolic", remove_options=angr.options.simplification) s.memory._maximum_symbolic_size = 0x2000000 size = s.solver.BVV(0x1000000, 64) dst_addr = s.solver.BVV(0x2000000, 64) src_addr = s.solver.BVV(0x4000000, 64) memcpy(s, arguments=[dst_addr, src_addr, size]) nose.tools.assert_is(s.memory.load(dst_addr, size), s.memory.load(src_addr, size)) l.debug("... partial copy") s = SimState(arch="AMD64", mode="symbolic") s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) memcpy(s, arguments=[dst_addr, src_addr, s.solver.BVV(2, 64)]) new_dst = s.memory.load(dst_addr, 4, endness='Iend_BE') nose.tools.assert_equal(s.solver.eval_upto(new_dst, 2, cast_to=bytes), [ b"BBAA" ]) l.info("symbolic src, concrete dst, concrete len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) # make sure it copies it all memcpy(s, arguments=[dst_addr, src_addr, s.solver.BVV(4, 64)]) nose.tools.assert_true(s.satisfiable()) s.add_constraints(src != s.memory.load(dst_addr, 4)) nose.tools.assert_false(s.satisfiable()) l.info("symbolic src, concrete dst, symbolic len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) cpylen = s.solver.BVS("len", 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) memcpy(s, arguments=[dst_addr, src_addr, cpylen]) result = s.memory.load(dst_addr, 4, endness='Iend_BE') # make sure it copies it all s1 = s.copy() s1.add_constraints(cpylen == 1) nose.tools.assert_true(s1.solver.unique(s1.memory.load(dst_addr+1, 3))) nose.tools.assert_equal(len(s1.solver.eval_upto(s1.memory.load(dst_addr, 1), 300)), 256) s2 = s.copy() s2.add_constraints(cpylen == 2) nose.tools.assert_equal(len(s2.solver.eval_upto(result[31:24], 300)), 256) nose.tools.assert_equal(len(s2.solver.eval_upto(result[23:16], 300)), 256) nose.tools.assert_equal(s2.solver.eval_upto(result[15:0], 300, cast_to=bytes), [ b'AA' ]) l.info("concrete src, concrete dst, symbolic len") dst = s2.solver.BVV(0x41414141, 32) dst_addr = s2.solver.BVV(0x1000, 64) src = s2.solver.BVV(0x42424242, 32) src_addr = s2.solver.BVV(0x2000, 64) s = SimState(arch="AMD64", mode="symbolic") s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) cpylen = s.solver.BVS("len", 64) s.add_constraints(s.solver.ULE(cpylen, 4)) memcpy(s, arguments=[dst_addr, src_addr, cpylen]) new_dst = s.memory.load(dst_addr, 4, endness='Iend_BE') nose.tools.assert_sequence_equal(sorted(s.solver.eval_upto(new_dst, 300, cast_to=bytes)), [ b'AAAA', b'BAAA', b'BBAA', b'BBBA', b'BBBB' ])
def test_memcmp(): l.info("concrete src, concrete dst, concrete len") l.debug("... full cmp") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVV(0x42424242, 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) r = memcmp(s, arguments=[dst_addr, src_addr, s.solver.BVV(4, 64)]) nose.tools.assert_true(s.satisfiable()) s_pos = s.copy() s_pos.add_constraints(r.SGE(0)) nose.tools.assert_false(s_pos.satisfiable()) s_neg = s.copy() s_neg.add_constraints(r.SLT(0)) nose.tools.assert_true(s_neg.satisfiable()) l.debug("... zero cmp") s = SimState(arch="AMD64", mode="symbolic") s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) r = memcmp(s, arguments=[dst_addr, src_addr, s.solver.BVV(0, 64)]) nose.tools.assert_equal(s.solver.eval_upto(r, 2), [ 0 ]) l.info("symbolic src, concrete dst, concrete len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) # make sure it copies it all r = memcmp(s, arguments=[dst_addr, src_addr, s.solver.BVV(4, 64)]) s_match = s.copy() s_match.add_constraints(r == 0) m = s_match.memory.load(src_addr, 4) nose.tools.assert_equal(s_match.solver.eval_upto(m, 2), [0x41414141]) s_nomatch = s.copy() s_nomatch.add_constraints(r != 0) m = s_nomatch.memory.load(src_addr, 4) nose.tools.assert_false(s_nomatch.solver.solution(m, 0x41414141)) l.info("symbolic src, concrete dst, symbolic len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414141, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) cmplen = s.solver.BVS("len", 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) r = memcmp(s, arguments=[dst_addr, src_addr, cmplen]) # look at effects of different lengths s1 = s.copy() s1.add_constraints(cmplen == 1) s1.add_constraints(r == 0) l.debug("... simplifying") s1.solver._solver.simplify() l.debug("... solving") nose.tools.assert_equal(s1.solver.eval_upto(src[31:24], 2), [ 0x41 ]) nose.tools.assert_false(s1.solver.unique(src[31:16])) l.debug("... solved") s2 = s.copy() s2.add_constraints(cmplen == 2) s2.add_constraints(r == 0) nose.tools.assert_equal(s2.solver.eval_upto(s2.memory.load(src_addr, 2), 2), [ 0x4141 ]) nose.tools.assert_false(s2.solver.unique(s2.memory.load(src_addr, 3))) s2u = s.copy() s2u.add_constraints(cmplen == 2) s2u.add_constraints(r == 1) nose.tools.assert_false(s2u.solver.solution(s2u.memory.load(src_addr, 2), 0x4141))
def test_strncpy(): l.info("concrete src, concrete dst, concrete len") l.debug("... full copy") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414100, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVV(0x42420000, 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) strncpy(s, arguments=[dst_addr, src_addr, s.solver.BVV(3, 64)]) new_dst = s.memory.load(dst_addr, 4, endness='Iend_BE') nose.tools.assert_equal(s.solver.eval(new_dst, cast_to=bytes), b"BB\x00\x00") l.debug("... partial copy") s = SimState(arch="AMD64", mode="symbolic") s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) strncpy(s, arguments=[dst_addr, src_addr, s.solver.BVV(2, 64)]) new_dst = s.memory.load(dst_addr, 4, endness='Iend_BE') nose.tools.assert_equal(s.solver.eval_upto(new_dst, 2, cast_to=bytes), [ b"BBA\x00" ]) l.info("symbolic src, concrete dst, concrete len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414100, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) # make sure it copies it all s.add_constraints(strlen(s, arguments=[src_addr]) == 2) # sanity check s_false = s.copy() s_false.add_constraints(strlen(s_false, arguments=[src_addr]) == 3) nose.tools.assert_false(s_false.satisfiable()) strncpy(s, arguments=[dst_addr, src_addr, 3]) nose.tools.assert_true(s.satisfiable()) c = strcmp(s, arguments=[dst_addr, src_addr]) nose.tools.assert_sequence_equal(s.solver.eval_upto(c, 10), [0]) l.info("symbolic src, concrete dst, symbolic len") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414100, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVS("src", 32) src_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) # make sure it copies it all s.add_constraints(strlen(s, arguments=[src_addr]) == 2) strncpy(s, arguments=[dst_addr, src_addr, maxlen]) c = strcmp(s, arguments=[dst_addr, src_addr]) s_match = s.copy() s_match.add_constraints(c == 0) nose.tools.assert_equal(s_match.solver.min_int(maxlen), 3) s_nomatch = s.copy() s_nomatch.add_constraints(c != 0) nose.tools.assert_equal(s_nomatch.solver.max_int(maxlen), 2) l.info("concrete src, concrete dst, symbolic len") l.debug("... full copy") s = SimState(arch="AMD64", mode="symbolic") dst = s.solver.BVV(0x41414100, 32) dst_addr = s.solver.BVV(0x1000, 64) src = s.solver.BVV(0x42420000, 32) src_addr = s.solver.BVV(0x2000, 64) maxlen = s.solver.BVS("len", 64) s.memory.store(dst_addr, dst) s.memory.store(src_addr, src) strncpy(s, arguments=[dst_addr, src_addr, maxlen]) r = s.memory.load(dst_addr, 4, endness='Iend_BE') #print repr(r.solver.eval_upto(r, 10, cast_to=bytes)) nose.tools.assert_sequence_equal(sorted(s.solver.eval_upto(r, 10, cast_to=bytes)), [ b"AAA\x00", b'BAA\x00', b'BB\x00\x00', b'BBA\x00' ] )
def test_inline_strcmp(): s = SimState(arch="AMD64", mode="symbolic") str_a = s.solver.BVV(0x41414100, 32) str_b = s.solver.BVS("mystring", 32) a_addr = s.solver.BVV(0x10, 64) b_addr = s.solver.BVV(0xb0, 64) s.memory.store(a_addr, str_a, endness="Iend_BE") s.memory.store(b_addr, str_b, endness="Iend_BE") s_cmp = s.copy() cmpres = strcmp(s_cmp, arguments=[a_addr, b_addr]) s_match = s_cmp.copy() s_nomatch = s_cmp.copy() s_match.add_constraints(cmpres == 0) s_nomatch.add_constraints(cmpres != 0) nose.tools.assert_true(s_match.solver.unique(str_b)) nose.tools.assert_false(s_nomatch.solver.unique(str_b)) nose.tools.assert_equal(s_match.solver.eval(str_b, cast_to=bytes), b"AAA\x00") s_ncmp = s.copy() ncmpres = strncmp(s_ncmp, arguments=[a_addr, b_addr, s.solver.BVV(2, s.arch.bits)]) s_match = s_ncmp.copy() s_nomatch = s_ncmp.copy() s_match.add_constraints(ncmpres == 0) s_nomatch.add_constraints(ncmpres != 0) nose.tools.assert_false(s_match.solver.unique(str_b)) nose.tools.assert_true(s_match.solver.unique(s_match.memory.load(b_addr, 2))) nose.tools.assert_equal(len(s_match.solver.eval_upto(s_match.memory.load(b_addr, 3), 300)), 256) nose.tools.assert_false(s_nomatch.solver.unique(str_b)) l.info("concrete a, symbolic b") s = SimState(arch="AMD64", mode="symbolic") str_a = s.solver.BVV(0x41424300, 32) str_b = s.solver.BVS("mystring", 32) a_addr = s.solver.BVV(0x10, 64) b_addr = s.solver.BVV(0xb0, 64) s.memory.store(a_addr, str_a, endness="Iend_BE") s.memory.store(b_addr, str_b, endness="Iend_BE") s_cmp = s.copy() cmpres = strncmp(s_cmp, arguments=[a_addr, b_addr, s.solver.BVV(2, s_cmp.arch.bits)]) s_match = s_cmp.copy() s_nomatch = s_cmp.copy() s_match.add_constraints(cmpres == 0) s_nomatch.add_constraints(cmpres != 0) nose.tools.assert_true(s_match.solver.solution(str_b, 0x41420000)) nose.tools.assert_true(s_match.solver.solution(str_b, 0x41421234)) nose.tools.assert_true(s_match.solver.solution(str_b, 0x41424300)) nose.tools.assert_false(s_nomatch.solver.solution(str_b, 0x41420000)) nose.tools.assert_false(s_nomatch.solver.solution(str_b, 0x41421234)) nose.tools.assert_false(s_nomatch.solver.solution(str_b, 0x41424300)) l.info("symbolic a, symbolic b") s = SimState(arch="AMD64", mode="symbolic") a_addr = s.solver.BVV(0x10, 64) b_addr = s.solver.BVV(0xb0, 64) s_cmp = s.copy() cmpres = strcmp(s_cmp, arguments=[a_addr, b_addr]) s_match = s_cmp.copy() s_nomatch = s_cmp.copy() s_match.add_constraints(cmpres == 0) s_nomatch.add_constraints(cmpres != 0) m_res = strcmp(s_match, arguments=[a_addr, b_addr]) s_match.add_constraints(m_res != 0) nm_res = strcmp(s_nomatch, arguments=[a_addr, b_addr]) s_nomatch.add_constraints(nm_res == 0) nose.tools.assert_false(s_match.satisfiable()) nose.tools.assert_false(s_match.satisfiable())