-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathexplore.py
167 lines (140 loc) · 2.93 KB
/
explore.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/local/bin/python
#
# Various helper functions for explorations
#
#----------------------------------------------------------------------
# Check the python version
import sys
assert sys.version_info[0] >= 3 or "Need" == "Python v3"
#----------------------------------------------------------------------
def gain(p, cpu, adr, follow_calls = True):
"""
How many instructions would we gain by starting disassembly at adr ?
"""
while p.run():
pass;
ccpu = cpu.clone(follow_calls)
ccpu.disass(adr)
while p.run():
pass
assert cpu.fails != None
dx = dict()
for i in ccpu.ins:
# We only care for new stuff
if i in cpu.ins:
continue
j = ccpu.ins[i]
# If they are OK, we return them
if j.status == "OK":
dx[i] = j
continue
# If they failed, propagate up
if j.status == "fail":
j.disass = cpu
cpu.ins[i] = j
continue
if ccpu.fails != 0:
return None
return dx
def best_place_to_start(p, cpu, lo=None, hi=None):
"""
Try to find the instruction that causes most other instructions
to be disassembled.
Returns a list of (adr, #ins) tupples.
"""
while p.run():
pass;
best = 0
cand = None
bdict = dict()
lp = 0
lx = list()
for g in p.t.gaps():
g = list(g)
if lo != None:
if lo >= g[1]:
continue
if g[0] < lo:
g[0] = lo
if hi != None:
if hi <= g[0]:
continue
if g[1] > hi:
g[1] = hi
i = g[0]
while i < g[1]:
if i >> 12 != lp:
print("..." + p.m.afmt(i), "cands:", len(lx))
lp = i >> 12
if i in cpu.ins:
i = cpu.ins[i].hi
continue
if cpu.bm.tst(i):
i += 1
continue
if i in bdict:
i = bdict[i].hi
continue
xx = True
this = gain(p, cpu, i, xx)
if this == None:
xx = False
this = gain(p, cpu, i, xx)
if this != None:
l = len(this)
if l > 0:
lx.append((i,l, xx))
if l > best:
print("Best so far: ", p.m.afmt(i), l)
sys.stdout.flush()
best = l
cand = i
bdict =this
i += 1
lx = sorted(lx, key=lambda x: -x[1])
return lx
#----------------------------------------------------------------------
#
def brute_force(p, cpu, lo=None, hi=None, max = None):
"""
Disassemble as much as possible, with as few pivot points as
possible. Pivot instructions are marked with a lcmt.
"""
n = 0
lx = best_place_to_start(p, cpu, lo, hi)
if len(lx) == 0:
return
cand = lx[0][0]
j = lx[0][1]
while True:
print("Doing", p.m.afmt(cand), "gain", j, "list", len(lx))
x = cpu.disass(cand)
x.lcmt("<==== Brute Force Discovery #%d" % n)
while p.run():
pass;
n += 1
if max != None and n >= max:
break
lx = sorted(lx, key=lambda x: -x[1])
best = 0
cand = None
ly = list()
for j in lx:
i,n,k = j
if n <= best:
ly.append(j)
continue
this = gain(p, cpu, i)
if this == None:
continue
l = len(this)
if l <= 0:
continue
ly.append((i,l, None))
if l > best:
best = l
cand = i
if cand == None:
break
lx = ly
j = best