@@ -29,10 +29,28 @@ def __init__(self, chain_builder):
2929 self .hard_chain_cache = None
3030 # Estimate of how difficult it is to set each register.
3131 self ._reg_weights = None
32+ self ._reg_setting_dict = None
33+
34+ def _insert_to_reg_dict (self , gs ):
35+ for rb in gs :
36+ for reg in rb .popped_regs :
37+ self ._reg_setting_dict [reg ].append (rb )
38+ for reg in self ._reg_setting_dict :
39+ lst = self ._reg_setting_dict [reg ]
40+ self ._reg_setting_dict [reg ] = sorted (lst , key = lambda x : x .stack_change )
3241
3342 def update (self ):
3443 self ._reg_setting_gadgets = self .filter_gadgets (self .chain_builder .gadgets )
3544
45+ # update reg_setting_dict
46+ self ._reg_setting_dict = defaultdict (list )
47+ for g in self ._reg_setting_gadgets :
48+ if not g .self_contained :
49+ continue
50+ for reg in g .popped_regs :
51+ self ._reg_setting_dict [reg ].append (g )
52+ self ._insert_to_reg_dict ([]) # sort reg dict
53+
3654 reg_pops = Counter ()
3755 for gadget in self ._reg_setting_gadgets :
3856 reg_pops .update (gadget .popped_regs )
@@ -43,7 +61,43 @@ def update(self):
4361
4462 self .hard_chain_cache = {}
4563
46- ## now we have a functional RegSetter, check whether we can do better
64+ def advanced_update (self ):
65+ # now we have a functional RegSetter, check whether we can do better
66+
67+ # first, TODO: see whether we can use reg_mover to set hard-registers
68+
69+ # second, see whether we can use non-self-contained gadgets to reduce stack-change requirements
70+ # TODO: currently, we only support jmp_reg gadgets
71+ new_rop_blocks = set ()
72+ for gadget in self ._reg_setting_gadgets :
73+ if gadget .self_contained :
74+ continue
75+ if gadget .has_conditional_branch :
76+ continue
77+ if gadget .transit_type != 'jmp_reg' :
78+ continue
79+ stack_change = gadget .stack_change
80+ if gadget .pc_reg not in self ._reg_setting_dict :
81+ continue
82+ pc_setter = self ._reg_setting_dict [gadget .pc_reg ][0 ]
83+ pc_setter_sc = pc_setter .stack_change
84+
85+ for reg in gadget .popped_regs :
86+ if gadget .pc_reg not in self ._reg_setting_dict :
87+ continue
88+ total_sc = stack_change + pc_setter_sc
89+ reg_sc = self ._reg_setting_dict [reg ][0 ].stack_change if reg in self ._reg_setting_dict else 0xffffffff
90+ if total_sc > reg_sc :
91+ continue
92+
93+ assert isinstance (pc_setter , RopGadget )
94+ try :
95+ chain = self ._build_reg_setting_chain ([pc_setter , gadget ], None , {}, total_sc )
96+ rb = RopBlock .from_chain (chain )
97+ new_rop_blocks .add (rb )
98+ except RopException :
99+ pass
100+ self ._insert_to_reg_dict (new_rop_blocks )
47101
48102 def verify (self , chain , preserve_regs , registers ):
49103 """
@@ -80,6 +134,17 @@ def verify(self, chain, preserve_regs, registers):
80134 pc_var = set (state .regs .pc .variables ).pop ()
81135 return pc_var .startswith ("next_pc" )
82136
137+ def _mixins_to_gadgets (self , mixins ):
138+ gadgets = []
139+ for mixin in mixins :
140+ if isinstance (mixin , RopGadget ):
141+ gadgets .append (mixin )
142+ elif isinstance (mixin , RopBlock ):
143+ gadgets += mixin ._gadgets
144+ else :
145+ raise
146+ return gadgets
147+
83148 def run (self , modifiable_memory_range = None , preserve_regs = None , max_length = 10 , ** registers ):
84149 if len (registers ) == 0 :
85150 return RopChain (self .project , None , badbytes = self .badbytes )
@@ -99,6 +164,7 @@ def run(self, modifiable_memory_range=None, preserve_regs=None, max_length=10, *
99164 l .debug ("building reg_setting chain with chain:\n %s" , chain_str )
100165 stack_change = sum (x .stack_change for x in gadgets )
101166 try :
167+ gadgets = self ._mixins_to_gadgets (gadgets )
102168 chain = self ._build_reg_setting_chain (gadgets , modifiable_memory_range ,
103169 registers , stack_change )
104170 chain ._concretize_chain_values (timeout = len (chain ._values )* 3 )
@@ -155,12 +221,9 @@ def _tuple_to_gadgets(data, reg_tuple):
155221 @staticmethod
156222 def _verify_chain (chain , regs ):
157223 """
158- make sure the new chain can control the registers
224+ make sure the new chain does not do bad memory accesses
159225 """
160226 g = chain [- 1 ]
161- if g .transit_type == 'jmp_reg' :
162- return g .pc_reg in regs
163-
164227 # make sure all memory access can be forced to happen on valid addresses
165228 # don't need to consider constant addr or addr popped from stack
166229 for mem_access in g .mem_reads + g .mem_writes + g .mem_changes :
@@ -195,7 +258,7 @@ def find_candidate_chains_graph_search(self, modifiable_memory_range=None, use_p
195258 partial_controllers = self ._get_sufficient_partial_controllers (registers )
196259
197260 # filter reg setting gadgets
198- gadgets = set ( g for g in self ._reg_setting_gadgets if g . self_contained )
261+ gadgets = self ._find_relevant_gadgets ( ** registers )
199262 for s in partial_controllers .values ():
200263 gadgets .update (s )
201264 gadgets = list (gadgets )
@@ -395,11 +458,15 @@ def _check_if_sufficient_partial_control(self, gadget, reg, value):
395458 def _find_relevant_gadgets (self , ** registers ):
396459 """
397460 find gadgets that may pop/load/change requested registers
398- exclude gadgets that do symbolic memory access
399461 """
400- gadgets = set ({})
462+ gadgets = set ()
463+
464+ # this step will add crafted rop_blocks as well
465+ for reg in registers :
466+ gadgets .update (self ._reg_setting_dict [reg ])
467+
401468 for g in self ._reg_setting_gadgets :
402- if g . has_symbolic_access () :
469+ if not g . self_contained :
403470 continue
404471 for reg in registers :
405472 if reg in g .popped_regs :
@@ -683,6 +750,7 @@ def _same_effect(self, g1, g2):
683750 def filter_gadgets (self , gadgets ):
684751 """
685752 process gadgets based on their effects
753+ exclude gadgets that do symbolic memory access
686754 """
687755 bests = set ()
688756 gadgets = set (gadgets )
@@ -693,4 +761,5 @@ def filter_gadgets(self, gadgets):
693761 bests = bests .union (self ._filter_gadgets (equal_class ))
694762
695763 gadgets -= equal_class
764+ bests = set (g for g in bests if not g .has_symbolic_access ())
696765 return bests
0 commit comments