3737import agc
3838import angrpt
3939import dwarf
40+ import explore
4041from globals_deep import SimStateDeepGlobals
4142import griffin
4243import hooks
4344import plugins .detectors
4445import plugins .hooks
46+ import plugins .explorers
4547import reporting
4648import taint
4749import xed
@@ -108,6 +110,20 @@ def parse_args():
108110 help = 'Save reports as JSON files to provided directory' )
109111 parser .add_option_group (group_analysis )
110112
113+ group_explore = OptionGroup (parser , 'Explore Options' )
114+ group_explore .add_option ('--explore' , action = 'store_true' , default = False ,
115+ help = 'Explore paths near the traced path for additional bugs' )
116+ group_explore .add_option ('--explore-after' , action = 'store' , type = 'str' , default = None ,
117+ help = 'Explore after given time, even if end of trace has not been reached '
118+ '(supports suffixes: s/m/h, defaults to m)' )
119+ group_explore .add_option ('--explore-db' , action = 'store' , default = None ,
120+ help = 'Use database so explorers can share data across sessions (supported: '
121+ 'Redis - redis://111.222.333.444:6379/0)' )
122+ group_explore .add_option ('--explore-plugins' , action = 'store' , type = 'str' , default = None ,
123+ help = 'Comma seperated list of explorer plugins to use, by module name '
124+ '(example: "arg_max,loop_bounds")' )
125+ parser .add_option_group (group_explore )
126+
111127 group_logging = OptionGroup (parser , 'Logging Options' )
112128 group_logging .add_option ('-l' , '--logging' , action = 'store' , type = 'int' , default = 20 ,
113129 help = 'Log level [10-50] (default: 20 - Info)' )
@@ -572,6 +588,10 @@ def set_log_levels(options):
572588 for module in list (plugins .detectors .loaded .values ()):
573589 logging .getLogger (module .__name__ ).setLevel (options .logging )
574590
591+ # explorer plugins
592+ for module in list (plugins .explorers .loaded .values ()):
593+ logging .getLogger (module .__name__ ).setLevel (options .logging )
594+
575595def get_predecessor (tech , index ):
576596 """Helper function to get predecessors by index, ignoring None elements.
577597
@@ -848,6 +868,19 @@ def main():
848868
849869 set_log_levels (options )
850870
871+ # input validation
872+ if options .explore_after :
873+ if not options .explore :
874+ options .explore = True # user clearly intends to explore
875+ explore_delta = parse_timedelta (options .explore_after , default_suffix = 'm' )
876+ if explore_delta is None :
877+ log .error ("Invalid value for --explore-after: %s" % options .explore_after )
878+ return
879+ if explore_delta < 1 :
880+ log .error ("Value for --explore-after must be positive: %d" % explore_delta )
881+ return
882+ options .explore_after = explore_delta
883+
851884 trace_dir = args [0 ]
852885 input_trace_candidates = ['trace.griffin' , 'trace.griffin.gz' ]
853886 input_trace = None
@@ -955,7 +988,7 @@ def main():
955988
956989 # initialize the starting state, exploration technique and simulation manager
957990 tech = angrpt .Tracer (bb_seq , start_address = regs ['rip' ])
958- init_state , init_env = parse_entry_state_json (proj , trace_dir , snapshot_dir , False ,
991+ init_state , init_env = parse_entry_state_json (proj , trace_dir , snapshot_dir , options . explore ,
959992 options .override_max_argv )
960993 simgr = proj .factory .simgr (init_state )
961994
@@ -1062,13 +1095,19 @@ def main():
10621095 raise CriticalMemoryException ('Memory critically low' )
10631096
10641097 analysis_duration = (datetime .now () - analysis_start_time ).total_seconds ()
1098+ if options .explore_after and analysis_duration > options .explore_after :
1099+ log .warning ("Analysis timeout reached, moving to exploration early" )
1100+ break
10651101
10661102 except KeyboardInterrupt :
10671103 log .warning ("Received interrupt, cleaning up..." )
1104+ options .explore = False # forcibly disable exploration
10681105 except (CriticalMemoryException , MemoryError ):
10691106 log .error ("Memory critically low, halting analysis" )
1107+ options .explore = False
10701108 except AssertionError :
10711109 log .error ("Failed assertion: %s" % format_exc ())
1110+ options .explore = False
10721111 except angr .errors .AngrTracerError as ex :
10731112 log .error ("Angr stopped early: %s" % str (ex ))
10741113
@@ -1086,17 +1125,112 @@ def main():
10861125 log .error ("Stopped here: (symbolic)" )
10871126 except KeyboardInterrupt :
10881127 log .warning ("Received interrupt, cleaning up..." )
1128+ options .explore = False # forcibly disable exploration
10891129
10901130 # update reports
10911131 log .info ("Updating reports with root cause analysis" )
10921132 try :
10931133 reports = analyze (simgr , bb_seq )
10941134 except KeyboardInterrupt :
10951135 log .warning ("Received interrupt, cleaning up..." )
1136+ options .explore = False # forcibly disable exploration
1137+
1138+ ################################################
1139+ ### PHASE 2: Optionally Explore Nearby Paths ###
1140+ ################################################
1141+
1142+ try :
1143+ if options .explore :
1144+ log .info ("Starting explorers" )
1145+ # backup list of predecessors for original trace
1146+ orig_preds = simgr ._techniques [0 ].predecessors .copy ()
1147+ # we no longer need the tracer exploration technique
1148+ simgr .remove_technique (tech )
1149+ assert len (simgr ._techniques ) == 0
1150+
1151+ # filter for if user wants us to only use a subset of plugins
1152+ allowed_explorers = None
1153+ if options .explore_plugins :
1154+ allowed_explorers = options .explore_plugins .split (',' )
1155+
1156+ for explorer in list (plugins .explorers .loaded .values ()):
1157+ e_short_name = explorer .__name__ .split ('.' )[- 1 ]
1158+ if not (allowed_explorers is None or e_short_name in allowed_explorers ):
1159+ log .info ("Skipping explorer %s at user's request" % e_short_name )
1160+ continue
10961161
1162+ log .debug ("Invoking explorer: %s" % e_short_name )
1163+
1164+ # reactivate detectors because this is a new exploration
1165+ for detector in list (plugins .detectors .loaded .values ()):
1166+ detector .active = True
1167+
1168+ try :
1169+ explorer_tech = explorer .explorer (orig_preds , bb_seq , options )
1170+ simgr .use_technique (explorer_tech )
1171+ except KeyboardInterrupt :
1172+ # let the outer try-except catch these
1173+ raise ex
1174+ except :
1175+ log .error ("Uncaught exception while trying to setup explorer: %s" % format_exc ())
1176+ buggy_plugins .add (explorer .__name__ )
1177+ continue
1178+
1179+ mem_mgr .enable ()
1180+ # step until explorer is complete
1181+ while not simgr .complete ():
1182+ try :
1183+ simgr .step ()
1184+ except (KeyboardInterrupt , CriticalMemoryException , MemoryError ) as ex :
1185+ # let the outer try-except catch these
1186+ raise ex
1187+ except ReferenceError :
1188+ # something is wrong with the active state, drop it, all explorers are
1189+ # designed to react robustly to an empty active stash
1190+ simgr .drop (stash = 'active' )
1191+ except :
1192+ log .error ("Uncaught exception raised by explorer plugin: %s" % format_exc ())
1193+ log .error ("Stopping explorer and moving on" )
1194+ buggy_plugins .add (explorer .__name__ )
1195+ break
1196+
1197+ if not hasattr (simgr ._techniques [0 ], 'predecessors' ):
1198+ log .error ("Detectors rely on explorers maintaining predecessors, which is missing, cannot continue" )
1199+ buggy_plugins .add (explorer .__name__ )
1200+ break
1201+
1202+ if len (simgr .stashes ['active' ]) > 0 :
1203+ if len (simgr .stashes ['active' ]) > 1 :
1204+ log .warn ("Explorer created %d active states, most detectors only examine one" % len (simgr .stashes ['active' ]))
1205+
1206+ check_for_vulns (simgr , proj )
1207+ # this is a bit excessive, but because we don't know when an explorer is going to rewind
1208+ # we have to check for new states to analyze after each step so simgr._techniques[0].predecessors
1209+ # remains accurate
1210+ analyze (simgr , bb_seq , reports )
1211+
1212+ if psutil .virtual_memory ().available <= min_memory :
1213+ mem_mgr .reap_predecessors ()
1214+ if psutil .virtual_memory ().available <= crit_memory :
1215+ raise CriticalMemoryException ('Memory critically low' )
1216+
1217+ # cleanup explorer
1218+ log .debug ("Explorer %s complete" % explorer .__name__ )
1219+ mem_mgr .disable ()
1220+ simgr .remove_technique (explorer_tech )
1221+ assert len (simgr ._techniques ) == 0
1222+
1223+ except KeyboardInterrupt :
1224+ log .warning ("Received interrupt, cleaning up..." )
1225+ mem_mgr .disable ()
1226+ except (CriticalMemoryException , MemoryError ):
1227+ log .error ("Memory critically low, halting analysis" )
1228+ mem_mgr .disable ()
1229+ except AssertionError :
1230+ log .error ("Failed assertion: %s" % format_exc ())
10971231
10981232 ################################
1099- ### PHASE 2 : Final Reporting ###
1233+ ### PHASE 3 : Final Reporting ###
11001234 ################################
11011235
11021236 log .info ("** Analysis complete, final results **" )
0 commit comments