-
Notifications
You must be signed in to change notification settings - Fork 37
/
ct64_angr.py
141 lines (114 loc) · 4.29 KB
/
ct64_angr.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import angr
import cle
import archinfo
import logging
import struct
from .ct64_engine import *
l = logging.getLogger('angr.ct64k')
def load_rom(rom):
return angr.Project(rom, main_opts={'backend': CT64KBlob, 'arch': ArchCT64K(), 'base_addr': 0x1000, 'entry_point': 0x1000})
class ArchCT64K(archinfo.Arch):
def __init__(self, endness=archinfo.Endness.BE):
super(ArchCT64K, self).__init__(endness)
name = 'CT64K'
bits = 16
byte_width = 16
max_inst_bytes = 3
ip_offset = 0
sp_offset = 1
bp_offset = 2
initial_sp = 0x300
sp_diff = 1
register_names = {
0: 'ip',
1: 'sp',
2: 'bp',
}
for i in range(3, 0x10):
register_names[i] = 'sc%X' % i
for i in range(0x10, 0x40):
register_names[i] = 'r%X' % i
for i in range(0x40, 0x100):
register_names[i] = 's%X' % i
registers = {n: (o, 1) for o, n in register_names.items()}
# don't bother; we overwrite registers with memory anyway
#default_register_values = [
# ( 'sp', 0x300, True, 'global' ),
# ( 'bp', 0x300, True, 'global' ),
# ( 'ip', 0x1000, True, 'global' )
#]
class CT64KBlob(cle.backends.blob.Blob):
def _load(self, file_offset, mem_addr, size):
self.os = 'ct64k'
self.binary_stream.seek(file_offset)
string = self.binary_stream.read(size)
memdata = list(struct.unpack('H'*(len(string)//2), string))
self.memory.add_backer(mem_addr - self.linked_base, memdata)
self._max_addr = max(len(memdata) + mem_addr, self._max_addr)
self._min_addr = min(mem_addr, self._min_addr)
self.engine_preset = ct64k_engine_preset
class SimCT64K(angr.SimOS):
def __init__(self, project):
self.peripherals = {
0x200: (hard_200_rd, hard_200_wr),
0x201: (hard_201_rd, hard_201_wr),
}
super(SimCT64K, self).__init__(project, 'ct64k')
def configure_project(self):
pass
def state_blank(self, addr=None, **kwargs):
if addr is None:
addr = 0x1000
permissions_backer = (True, {(0, 0xffff): 7})
state = super(SimCT64K, self).state_blank(addr=addr, permissions_backer=permissions_backer, **kwargs)
state.register_plugin('registers', state.memory)
state.memory.id = 'reg'
state.registers.store(0, addr)
state.registers.store(1, state.arch.initial_sp)
state.registers.store(2, state.arch.initial_sp)
state.inspect.b('reg_read', action=self.hard_checker_rd, when=angr.BP_AFTER)
state.inspect.b('reg_write', action=self.hard_checker_wr, when=angr.BP_AFTER)
return state
def state_entry(self, *args, **kwargs):
state = self.state_blank(*args, **kwargs)
state.memory.store(3, claripy.BVV(0, (0x200 - 3)*16))
state.memory.store(0x300, claripy.BVV(0, (0x1000 - 0x300)*16))
return state
def _hard_checker(self, state, addr):
crange = state.solver.And(addr >= 0x200, addr < 0x300)
if not state.solver.satisfiable(extra_constraints=(crange,)):
return None
try:
addr = state.solver.eval_one(addr)
except angr.SimSolverError:
l.warning("Address %s could touch peripherals but is multivalued", addr)
return None
try:
return self.peripherals[addr]
except KeyError:
l.error("Touching unmapped peripheral address %#x", addr)
return None
def hard_checker_rd(self, state):
p = self._hard_checker(state, state.inspect.reg_read_offset)
if p is None:
return
state.inspect.reg_read_expr = p[0](state)
def hard_checker_wr(self, state):
p = self._hard_checker(state, state.inspect.reg_write_offset)
if p is None:
return
p[1](state, state.inspect.reg_write_expr)
angr.calling_conventions.register_default_cc('CT64K', angr.calling_conventions.SimCCCdecl)
angr.simos.register_simos('ct64k', SimCT64K)
# output
def hard_200_rd(state):
return state.solver.BVV(0, 16)
def hard_200_wr(state, v):
state.posix.fd[1].write_data(v)
# input
def hard_201_rd(state):
r = state.posix.fd[0].read_data(1)[0]
state.solver.add(r < 0x100)
return r
def hard_201_wr(state, v): # pylint: disable=unused-argument
pass