1import logging 2import threading 3 4from angr.errors import AngrError 5from .engine import SuccessorsMixin 6from ..errors import SimConcreteMemoryError, SimConcreteRegisterError 7 8l = logging.getLogger("angr.engines.concrete") 9#l.setLevel(logging.DEBUG) 10 11try: 12 from angr_targets.concrete import ConcreteTarget 13except ImportError: 14 ConcreteTarget = None 15 16 17class SimEngineConcrete(SuccessorsMixin): 18 """ 19 Concrete execution using a concrete target provided by the user. 20 """ 21 def __init__(self, project): 22 if not ConcreteTarget: 23 l.critical("Error, can't find angr_target project") 24 raise AngrError 25 26 l.info("Initializing SimEngineConcrete with ConcreteTarget provided.") 27 super(SimEngineConcrete, self).__init__() 28 self.project = project 29 if isinstance(self.project.concrete_target, ConcreteTarget) and \ 30 self.check_concrete_target_methods(self.project.concrete_target): 31 32 self.target = self.project.concrete_target 33 else: 34 l.warning("Error, you must provide an instance of a ConcreteTarget to initialize a SimEngineConcrete.") 35 self.target = None 36 raise NotImplementedError 37 38 self.segment_registers_already_init = False 39 40 def process_successors(self, successors, extra_stop_points=None, memory_concretize=None, 41 register_concretize=None, timeout=0, *args, **kwargs): 42 43 new_state = self.state 44 # setup the concrete process and resume the execution 45 self.to_engine(new_state, extra_stop_points, memory_concretize, register_concretize, timeout) 46 47 # sync angr with the current state of the concrete process using 48 # the state plugin 49 new_state.concrete.sync() 50 51 successors.engine = "SimEngineConcrete" 52 successors.sort = "SimEngineConcrete" 53 successors.add_successor(new_state, new_state.ip, new_state.solver.true, new_state.unicorn.jumpkind) 54 successors.description = "Concrete Successors" 55 successors.processed = True 56 57 def to_engine(self, state, extra_stop_points, memory_concretize, register_concretize, timeout): 58 """ 59 Handle the concrete execution of the process 60 This method takes care of: 61 1- Set the breakpoints on the addresses provided by the user 62 2- Concretize the symbolic variables and perform the write inside the concrete process 63 3- Continue the program execution. 64 65 :param state: The state with which to execute 66 :param extra_stop_points: list of a addresses where to stop the concrete execution and return to the 67 simulated one 68 :param memory_concretize: list of tuples (address, symbolic variable) that are going to be written 69 in the concrete process memory. 70 :param register_concretize: list of tuples (reg_name, symbolic variable) that are going to be written 71 :param timeout: how long we should wait the concrete target to reach the breakpoint 72 :return: None 73 """ 74 75 state.globals["symbion_timeout"] = False 76 extra_stop_points = [] if extra_stop_points is None else extra_stop_points 77 78 l.debug("Entering in SimEngineConcrete: simulated address %#x concrete address %#x stop points %s", 79 state.addr, self.target.read_register("pc"), map(hex, extra_stop_points)) 80 81 if memory_concretize: 82 l.debug("SimEngineConcrete is concretizing memory variables before resuming the concrete process") 83 84 for sym_var in memory_concretize: 85 sym_var_address = state.solver.eval(sym_var[0]) 86 sym_var_value = state.solver.eval(sym_var[1], cast_to=bytes) 87 l.debug("Concretize memory at address %#x with value %s", sym_var_address, str(sym_var_value)) 88 self.target.write_memory(sym_var_address, sym_var_value, raw=True) 89 90 if register_concretize: 91 l.debug("SimEngineConcrete is concretizing registers variables before resuming the concrete process") 92 for reg in register_concretize: 93 register_name = reg[0] 94 register_value = state.solver.eval(reg[1]) 95 l.debug("Concretize register %s with value %s", register_name, str(register_value)) 96 self.target.write_register(register_name, register_value) 97 98 # Set breakpoint on remote target 99 for stop_point in extra_stop_points: 100 l.debug("Setting breakpoints at %#x", stop_point) 101 self.target.set_breakpoint(stop_point, hardware=True, temporary=True) 102 103 if timeout > 0: 104 l.debug("Found timeout as option, setting it up!") 105 106 def timeout_handler(): 107 self.target.stop() # stop the concrete target now! 108 state.globals["symbion_timeout"] = True # this will end up in the timeout stash 109 110 execution_timer = threading.Timer(timeout, timeout_handler) 111 execution_timer.start() # start the timer! 112 113 # resuming of the concrete process, if the target won't reach the 114 # breakpoint specified by the user the timeout will abort angr execution. 115 l.debug("SimEngineConcrete is resuming the concrete process") 116 self.target.run() 117 l.debug("SimEngineConcrete has successfully resumed the process") 118 119 if state.globals["symbion_timeout"]: 120 l.critical("Timeout has been reached during resuming of concrete process") 121 l.critical("This can be a bad thing ( the ConcreteTarget didn't hit your breakpoint ) or" 122 "just it will take a while.") 123 124 # reset the alarm 125 if timeout > 0: 126 execution_timer.cancel() 127 128 # removing all breakpoints set by the concrete target 129 for stop_point in extra_stop_points: 130 self.target.remove_breakpoint(stop_point) 131 132 # handling the case in which the program stops at a point different than the breakpoints set 133 # by the user. 134 current_pc = self.target.read_register("pc") 135 if current_pc not in extra_stop_points and not state.globals["symbion_timeout"]: 136 l.critical("Stopped at unexpected location inside the concrete process: %#x", current_pc) 137 raise AngrError 138 139 @staticmethod 140 def check_concrete_target_methods(concrete_target): 141 """ 142 Check if the concrete target methods return the correct type of data 143 :return: True if the concrete target is compliant 144 """ 145 entry_point = concrete_target.read_register("pc") 146 if not type(entry_point) is int: 147 l.error("read_register result type is %s, should be <type 'int'>", (type(entry_point))) 148 return False 149 150 mem_read = concrete_target.read_memory(entry_point, 0x4) 151 152 if not type(mem_read) is bytes: 153 l.error("read_memory result type is %s, should be <type 'bytes'>", (type(mem_read))) 154 return False 155 156 try: 157 concrete_target.read_register("not_existent_reg") 158 l.error("read_register should raise a SimConcreteRegisterError when accessing non existent registers") 159 return False 160 161 except SimConcreteRegisterError: 162 l.debug("read_register raise a SimConcreteRegisterError, ok!") 163 164 try: 165 concrete_target.read_memory(0x0, 0x4) 166 l.error("read_memory should raise a SimConcreteMemoryError when accessing non mapped memory") 167 return False 168 169 except SimConcreteMemoryError: 170 l.debug("read_register raise a SimConcreteMemoryError, ok!") 171 172 return True 173