4
4
from collections import defaultdict
5
5
from functools import cmp_to_key
6
6
7
+ import claripy
7
8
from angr .errors import SimUnsatError
8
9
9
10
10
11
from .. import rop_utils
11
12
from ..rop_chain import RopChain
12
13
from ..errors import RopException
14
+ from ..rop_value import RopValue
13
15
14
16
l = logging .getLogger ("angrop.chain_builder.reg_setter" )
15
17
@@ -32,6 +34,11 @@ def _contain_badbyte(self, ptr):
32
34
"""
33
35
check if a pointer contains any bad byte
34
36
"""
37
+ if isinstance (ptr , RopValue ):
38
+ if ptr .symbolic :
39
+ return False
40
+ else :
41
+ ptr = ptr .concreted
35
42
raw_bytes = struct .pack (self .project .arch .struct_fmt (), ptr )
36
43
if any (x in raw_bytes for x in self ._badbytes ):
37
44
return True
@@ -46,7 +53,13 @@ def verify(self, chain, registers):
46
53
for reg , val in registers .items ():
47
54
chain_str = '\n -----\n ' .join ([str (self .project .factory .block (g .addr ).capstone )for g in chain ._gadgets ])
48
55
bv = getattr (state .regs , reg )
49
- if bv .symbolic or state .solver .eval (bv != val ):
56
+ for act in state .history .actions .hardcopy :
57
+ if act .type != "mem" :
58
+ continue
59
+ if act .addr .ast .variables :
60
+ l .exception ("memory access outside stackframe\n %s\n " , chain_str )
61
+ return False
62
+ if bv .symbolic or state .solver .eval (bv != val .data ):
50
63
l .exception ("Somehow angrop thinks \n %s\n can be used for the chain generation." , chain_str )
51
64
return False
52
65
return True
@@ -60,9 +73,10 @@ def run(self, modifiable_memory_range=None, use_partial_controllers=False, **re
60
73
if unknown_regs :
61
74
raise RopException ("unknown registers: %s" % unknown_regs )
62
75
63
- # load from cache
64
- #reg_tuple = tuple(sorted(registers.keys()))
65
- #chains = self._chain_cache[reg_tuple]
76
+ # cast values to RopValue
77
+ for x in registers :
78
+ registers [x ] = rop_utils .cast_rop_value (registers [x ], self .project )
79
+
66
80
chains = []
67
81
68
82
gadgets = self ._find_relevant_gadgets (** registers )
@@ -168,19 +182,20 @@ def _find_add_chain(self, gadgets, reg, val):
168
182
"""
169
183
find one chain to set one single register to a specific value using concrete values only through add/dec
170
184
"""
185
+ val = rop_utils .cast_rop_value (val , self .project )
171
186
concrete_setter_gadgets = [ x for x in gadgets if reg in x .concrete_regs ]
172
187
delta_gadgets = [ x for x in gadgets if len (x .reg_dependencies ) == 1 and reg in x .reg_dependencies \
173
188
and len (x .reg_dependencies [reg ]) == 1 and reg in x .reg_dependencies [reg ]]
174
189
for g1 in concrete_setter_gadgets :
175
190
for g2 in delta_gadgets :
176
191
try :
177
- chain = self ._build_reg_setting_chain ([g1 , g2 ], False ,
178
- {reg : val }, g1 .stack_change + g2 .stack_change , [] )
192
+ chain = self ._build_reg_setting_chain ([g1 , g2 ], False , # pylint:disable=too-many-function-args
193
+ {reg : val }, g1 .stack_change + g2 .stack_change )
179
194
state = chain .exec ()
180
195
bv = state .registers .load (reg )
181
196
if bv .symbolic :
182
197
continue
183
- if state .solver .eval (bv == val ):
198
+ if state .solver .eval (bv == val . data ):
184
199
return [g1 , g2 ]
185
200
except Exception :# pylint:disable=broad-except
186
201
pass
@@ -193,16 +208,16 @@ def _find_all_candidate_chains(self, gadgets, **registers):
193
208
TODO: handle moves
194
209
"""
195
210
# get the list of regs that cannot be popped (call it hard_regs)
196
- hard_regs = [reg for reg , val in registers .items () if type ( val ) == int and self ._contain_badbyte (val )]
211
+ hard_regs = [reg for reg , val in registers .items () if self ._contain_badbyte (val )]
197
212
if len (hard_regs ) > 1 :
198
213
l .error ("too many registers contain bad bytes! bail out! %s" , registers )
199
214
return []
200
215
201
216
# if hard_regs exists, try to use concrete values to craft the value
202
217
hard_chain = []
203
- if hard_regs :
218
+ if hard_regs and not registers [ hard_regs [ 0 ]]. symbolic :
204
219
reg = hard_regs [0 ]
205
- val = registers [reg ]
220
+ val = registers [reg ]. concreted
206
221
key = (reg , val )
207
222
if key in self .hard_chain_cache :
208
223
hard_chain = self .hard_chain_cache [key ]
@@ -294,8 +309,13 @@ def _build_reg_setting_chain(self, gadgets, modifiable_memory_range, register_di
294
309
295
310
# constrain the final registers
296
311
rebase_state = test_symbolic_state .copy ()
312
+ var_dict = {}
297
313
for r , v in register_dict .items ():
298
- test_symbolic_state .add_constraints (state .registers .load (r ) == v )
314
+ var = claripy .BVS (r , self .project .arch .bits )
315
+ var_name = var ._encoded_name .decode ()
316
+ var_dict [var_name ] = v
317
+ test_symbolic_state .add_constraints (state .registers .load (r ) == var )
318
+ test_symbolic_state .add_constraints (var == v .data )
299
319
300
320
# constrain the "filler" values
301
321
if self ._roparg_filler is not None :
@@ -323,7 +343,19 @@ def _build_reg_setting_chain(self, gadgets, modifiable_memory_range, register_di
323
343
chain .add_gadget (gadgets [0 ])
324
344
gadgets = gadgets [1 :]
325
345
else :
326
- chain .add_value (sym_word , needs_rebase = False )
346
+ # propagate the initial RopValue provided by users to preserve info like rebase
347
+ var = sym_word
348
+ for c in test_symbolic_state .solver .constraints :
349
+ if len (c .variables ) != 2 : # it is always xx == yy
350
+ continue
351
+ if not sym_word .variables .intersection (c .variables ):
352
+ continue
353
+ var_name = set (c .variables - sym_word .variables ).pop ()
354
+ if var_name not in var_dict :
355
+ continue
356
+ var = var_dict [var_name ]
357
+ break
358
+ chain .add_value (var , needs_rebase = False )
327
359
328
360
if len (gadgets ) > 0 :
329
361
raise RopException ("Didnt find all gadget addresses, something must've broke" )
@@ -377,7 +409,7 @@ def _find_reg_setting_gadgets(self, modifiable_memory_range=None, use_partial_co
377
409
search_regs = set (registers )
378
410
379
411
if modifiable_memory_range is not None and len (modifiable_memory_range ) != 2 :
380
- raise Exception ("modifiable_memory_range should be a tuple (low, high)" )
412
+ raise RopException ("modifiable_memory_range should be a tuple (low, high)" )
381
413
382
414
# find gadgets with sufficient partial control
383
415
partial_controllers = {}
0 commit comments