1import nose
2import angr
3
4import os
5test_location = os.path.join(os.path.dirname(os.path.realpath(str(__file__))), '..', '..', 'binaries', 'tests')
6
7arch_data = { # (steps, [hit addrs], finished)
8    'x86_64':  (330, (0x1021c20, 0x1021980, 0x1021be0, 0x4004b0, 0x400440, 0x400570), True),
9    'i386':    (425, (0x90198e0, 0x90195c0, 0x9019630, 0x90198a0, 0x8048370, 0x80482f8, 0x8048440, 0x804846D, 0x8048518), True),
10    'ppc':     (381,  (0x11022f50, 0x11022eb0, 0x10000340, 0x100002e8, 0x1000053C, 0x1000063C), True),
11    'ppc64':   (372, (0x11047490, 0x100003fc, 0x10000368, 0x10000654, 0x10000770), True),
12    'mips':    (363, (0x1016f20, 0x400500, 0x400470, 0x400640, 0x400750), True),
13    'mips64':  (390, (0x12103b828, 0x120000870, 0x1200007e0, 0x120000A80, 0x120000B68), True),
14    'armel':   (370, (0x10154b8, 0x1108244, 0x83a8, 0x8348, 0x84b0, 0x84E4, 0x85E8), True),
15    'aarch64': (370, (0x1020b04, 0x400430, 0x4003b8, 0x400538, 0x400570, 0x40062C), True),
16}
17
18def emulate(arch, binary, use_sim_procs, steps, hit_addrs, finished):
19    p = angr.Project(os.path.join(test_location, arch, binary), use_sim_procedures=use_sim_procs, rebase_granularity=0x1000000, load_debug_info=False)
20    state = p.factory.full_init_state(args=['./test_arrays'], add_options={angr.options.STRICT_PAGE_ACCESS, angr.options.ENABLE_NX, angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY, angr.options.USE_SYSTEM_TIMES})
21
22    pg = p.factory.simulation_manager(state, resilience=True)
23    pg2 = pg.run(until=lambda lpg: len(lpg.active) != 1)
24
25    is_finished = False
26    if len(pg2.active) > 0:
27        state = pg2.active[0]
28    elif len(pg2.deadended) > 0:
29        state = pg2.deadended[0]
30        is_finished = True
31    elif len(pg2.errored) > 0:
32        state = pg2.errored[0].state # ErroredState object!
33    else:
34        raise ValueError("The result does not contain a state we can use for this test?")
35
36    nose.tools.assert_greater_equal(state.history.depth, steps)
37
38    # this is some wonky control flow that asserts that the items in hit_addrs appear in the state in order.
39    trace = state.history.bbl_addrs.hardcopy
40    reqs = list(hit_addrs)
41    while len(reqs) > 0:
42        req = reqs.pop(0)
43        while True:
44            nose.tools.assert_greater(len(trace), 0)
45            trace_head = trace.pop(0)
46            if trace_head == req:
47                break
48            nose.tools.assert_not_in(trace_head, reqs)
49
50    if finished:
51        nose.tools.assert_true(is_finished)
52
53def test_emulation():
54    for arch in arch_data:
55        steps, hit_addrs, finished = arch_data[arch]
56        yield emulate, arch, 'test_arrays', False, steps, hit_addrs, finished
57
58def test_windows():
59    yield emulate, 'i386', 'test_arrays.exe', True, 41, [], False # blocked on GetLastError or possibly dynamic loading
60
61def test_locale():
62    p = angr.Project(os.path.join(test_location, 'i386', 'isalnum'), use_sim_procedures=False)
63    state = p.factory.full_init_state(args=['./isalnum'], add_options={angr.options.STRICT_PAGE_ACCESS})
64    pg = p.factory.simulation_manager(state)
65    pg2 = pg.run(until=lambda lpg: len(lpg.active) != 1,
66                  step_func=lambda lpg: lpg if len(lpg.active) == 1 else lpg.prune()
67                 )
68    nose.tools.assert_equal(len(pg2.active), 0)
69    nose.tools.assert_equal(len(pg2.deadended), 1)
70    nose.tools.assert_equal(pg2.deadended[0].history.events[-1].type, 'terminate')
71    nose.tools.assert_equal(pg2.deadended[0].history.events[-1].objects['exit_code']._model_concrete.value, 0)
72
73
74if __name__ == '__main__':
75    #emulate('armel', 'test_arrays', False, *arch_data['armel'])
76    #import sys; sys.exit()
77    for func, a, b, c, d, e, f in test_windows():
78        print(a, b)
79        func(a, b, c, d, e, f)
80    print('locale')
81    test_locale()
82    for func, a, b, c, d, e, f in test_emulation():
83        print(a, b)
84        func(a, b, c, d, e, f)
85