def prune_snapshots(self): '''Prune available snapshots according to the pruning politics''' self.logger.info("Parsing and prunning snapshots: strategy %s, " \ "with %d elements keeped each time", config.prune_strategy, config.prune_keep) trace = Trace() ignored = None # Prune depending on the strategy if config.prune_strategy == "branch": ignored = 0 already_keeped = {} # path -> seen number for snapshot in self.trace_iter: # TODO use abi if self.avoid_null and snapshot.output_reg["RAX"] == 0: ignored += 1 continue path = frozenset(snapshot.paths.edges()) current = already_keeped.get(path, 0) if current < config.prune_keep: # not enough sample of this current snapshot branch coverage trace.append(snapshot) else: ignored += 1 already_keeped[path] = current + 1 if config.prune_keep_max and len(trace) >= config.prune_keep_max: self.logger.info("Max number of snapshot reached!") break elif config.prune_strategy == "keepall": # Do not remove any snapshot trace = list(self.trace_iter) ignored = 0 elif config.prune_strategy == "keep": # Remove all snapshot but one or a few (according to config) for i, snapshot in xrange(self.trace): trace.append(snapshot) if len(trace) >= config.prune_keep: break else: raise ValueError("Unsupported strategy type: %s" % config.prune_strategy) self.trace = trace if ignored is None: ignored = "unknown" self.logger.info("Keeped: %d, Ignored: %s", len(self.trace), ignored) # If the trace is empty, test can not be created if not self.trace: raise RuntimeError( "Test can not be created: function seems not to be called or " \ "the prune politic is too restrictive")
def do_trace(self): '''Run miasm and construct the trace''' self.trace = Trace() # Retrieve miasm tools machine = Machine(self.machine) jitter = machine.jitter("python") # Set the jitter to use our custom emulator jitter.jit.symbexec = CustomEmulatedSymbExec(jitter.cpu, jitter.vm, jitter.jit.ir_arch, {}) jitter.jit.symbexec.enable_emulated_simplifications() jitter.jit.symbexec.reset_regs() elf = vm_load_elf(jitter.vm, open(self.program, "rb").read()) # Init segment jitter.ir_arch.do_stk_segm = True jitter.ir_arch.do_ds_segm = True jitter.ir_arch.do_str_segm = True jitter.ir_arch.do_all_segm = True FS_0_ADDR = 0x7ff70000 jitter.cpu.FS = 0x4 jitter.cpu.set_segm_base(jitter.cpu.FS, FS_0_ADDR) jitter.vm.add_memory_page(FS_0_ADDR + 0x28, PAGE_READ, "\x42\x42\x42\x42\x42\x42\x42\x42") # Init stack and push main args jitter.init_stack() jitter.push_uint64_t(1) jitter.vm.add_memory_page(0x800000, PAGE_READ, self.program) jitter.push_uint64_t(0x800000) jitter.push_uint64_t(0xDEADDEAD) jitter.add_breakpoint(0xDEADDEAD, self.end_do_trace) jitter.add_breakpoint(0x1337beef, self.end_func) jitter.add_breakpoint(self.address, self.begin_func) # Run the execution if self.main_address is None: jitter.init_run(elf.Ehdr.entry) else: jitter.init_run(self.main_address) for addr, info in jitter.vm.get_all_memory().iteritems(): self.segments += [(addr, addr + info['size'])] jitter.continue_run() assert jitter.run == False return self.trace
def prune_snapshots(self): '''Prune available snapshots according to the pruning politics''' self.logger.info("Parsing and prunning snapshots: strategy %s, " \ "with %d elements keeped each time", config.prune_strategy, config.prune_keep) trace = Trace() ignored = None # Prune depending on the strategy if config.prune_strategy == "branch": ignored = 0 already_keeped = {} # path -> seen number for snapshot in self.trace_iter: # TODO use abi if self.avoid_null and snapshot.output_reg["RAX"] == 0: ignored += 1 continue path = frozenset(snapshot.paths.edges()) current = already_keeped.get(path, 0) if current < config.prune_keep: # not enough sample of this current snapshot branch coverage trace.append(snapshot) else: ignored += 1 already_keeped[path] = current + 1 if config.prune_keep_max and len( trace) >= config.prune_keep_max: self.logger.info("Max number of snapshot reached!") break elif config.prune_strategy == "keepall": # Do not remove any snapshot trace = list(self.trace_iter) ignored = 0 elif config.prune_strategy == "keep": # Remove all snapshot but one or a few (according to config) for i, snapshot in xrange(self.trace): trace.append(snapshot) if len(trace) >= config.prune_keep: break else: raise ValueError("Unsupported strategy type: %s" % config.prune_strategy) self.trace = trace if ignored is None: ignored = "unknown" self.logger.info("Keeped: %d, Ignored: %s", len(self.trace), ignored) # If the trace is empty, test can not be created if not self.trace: raise RuntimeError( "Test can not be created: function seems not to be called or " \ "the prune politic is too restrictive")
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' trace = Trace() # Statefull elements started = False current_image_name = None # State machine for parsing for line in traceFile: infos = line.strip().split(' ') entry_type = infos[0] # Image loaded in memory # IMG <img_name> if entry_type == "IMG": img_name = infos[1] current_image_name = img_name continue # Symbol entry # S <symbol_addr> <symbol_name> elif entry_type == 'S': assert current_image_name is not None symbol_name = infos[2] symbol_addr = int(infos[1], 16) trace.add_symbol(current_image_name, symbol_name, symbol_addr) continue values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if entry_type == 'I': if not started: started = True current_snapshot = Snapshot(self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif entry_type == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif entry_type == 'R': if started: current_snapshot.add_memory_read( values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif entry_type == 'W': if started: current_snapshot.add_memory_write( values[0], values[1], values[2]) # End of the learned function # Field are register value elif entry_type == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False yield current_snapshot # Call to a function # CALL <caller_addr> <stack pointer> elif entry_type == "CALL": current_snapshot.add_call(values[0], values[1]) # Return from a function # RET <ret_addr> <stack pointer after> <ret value> elif entry_type == "RET": current_snapshot.add_ret(values[0], values[1], values[2])
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' # Read the begin of file until the first blank line # This correspond to the segment enumeration segments = [] for line in traceFile: if line == "\n": break # Each line begins with the bound of the segment, # separated by a '-' and followed by a white space segments += [ tuple( [int(addr, 16) for addr in line.split(' ')[0].split('-')]) ] trace = Trace() started = False for line in traceFile: infos = line.strip().split(' ') first_char = infos[0] values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if first_char == 'I': if not started: started = True current_snapshot = Snapshot(segments, self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif first_char == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif first_char == 'R': if started: current_snapshot.add_memory_read(values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif first_char == 'W': if started: current_snapshot.add_memory_write(values[0], values[1], values[2]) # End of the learned function # Field are register value elif first_char == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False trace.append(current_snapshot) return trace
def __parse_pin_output_file(self, traceFile): '''Parse the file created by the pintool in order to construct the trace''' trace = Trace() # Statefull elements started = False current_image_name = None # State machine for parsing for line in traceFile: infos = line.strip().split(' ') entry_type = infos[0] # Image loaded in memory # IMG <img_name> if entry_type == "IMG": img_name = infos[1] current_image_name = img_name continue # Symbol entry # S <symbol_addr> <symbol_name> elif entry_type == 'S': assert current_image_name is not None symbol_name = infos[2] symbol_addr = int(infos[1], 16) trace.add_symbol(current_image_name, symbol_name, symbol_addr) continue values = [int(v, 16) for v in infos[1:]] # Start of the learned function # Fields are registers value if entry_type == 'I': if not started: started = True current_snapshot = Snapshot(self.abicls, self.machine) for i, reg_name in enumerate(self.reg_list): current_snapshot.add_input_register(reg_name, values[i]) # Executed instructions address elif entry_type == '@': if started: current_snapshot.add_executed_instruction(values[0]) # Memory read access # Fields are read address, read size and read value elif entry_type == 'R': if started: current_snapshot.add_memory_read(values[0], values[1], values[2]) # Memory write access # Fields are writen address, writen size and writen value elif entry_type == 'W': if started: current_snapshot.add_memory_write(values[0], values[1], values[2]) # End of the learned function # Field are register value elif entry_type == 'O': if started: for i, reg_name in enumerate(self.reg_list): current_snapshot.add_output_register( reg_name, values[i]) # The learned function execution is over # Snapshot can be added to the trace started = False yield current_snapshot # Call to a function # CALL <caller_addr> <stack pointer> elif entry_type == "CALL": current_snapshot.add_call(values[0], values[1]) # Return from a function # RET <ret_addr> <stack pointer after> <ret value> elif entry_type == "RET": current_snapshot.add_ret(values[0], values[1], values[2])