def main(): p = angr.Project('normalread') # adjusted version of normalread state = p.factory.blank_state(remove_options={simuvex.s_options.LAZY_SOLVES}) image_name = "test.png" content = simuvex.SimSymbolicMemory(memory_id="file_%s" % image_name) content.set_state(state) #storing content in the simulated file can decrease number of paths and constraint solving time #f = open('test.png', 'r') #content.store(0, f.read()) image_file = simuvex.SimFile(image_name, 'rw', size=255, content=content) state.posix.fs = {image_name: image_file} # set state filesystem path = p.factory.path(state=state) ex = p.surveyors.Explorer(start=path) deCount = 0 while len(ex.active) > 0: ex.run(10) print ex if len(ex.deadended) > deCount: for x in range(deCount,len(ex.deadended)): try: print ex.deadended[x].state.posix.dumps(1) # dump the std output except: pass try: print ex.deadended[x].state.posix.dumps(2) # dump the std err except: pass deCount = len(ex.deadended)
=--------------------------------= """ password_len = 0xf # Create our symbolic input for our symbolic memory region s_password = state.se.BVS('password_bytes', password_len * 8) # Create our symbolic memory region for our symbolic file content = simuvex.SimSymbolicMemory( memory_id='file_{}'.format(password_filename)) content.set_state(state) content.store(0, s_password) # Associate our symbolic file with the correct file name password_file = simuvex.SimFile(password_filename, 'rw', size=15, content=content) fs = {password_filename: password_file} state.posix.fs = fs # Explore until the "Congrats" message and avoid all other messages pg = p.factory.path_group(state) pg.explore(find=0x400743, avoid=(0x400683, 0x4006b6, 0x400732)) state = pg.found[0].state # Grab current files from our files dict files = state.posix.files # The largest file ID is the content of the file we care about """
def execute_one_file(self, input_file): """ :param input_file: """ starttime = time.clock() l.debug("input: %s nopfunc %s skiplibs:%s" % (input_file, repr(self.nop_funcs), repr(self.skip_libs))) # init self.path_unqueued.clear() global_cache.clear() load_options = {} load_options['skip_libs'] = self.skip_libs p = angr.Project(self.exec_file, load_options=load_options) for nopf in self.nop_funcs: l.debug("hook %x with nop" % int(nopf, 16)) p.hook(int(nopf, 16), simuvex.SimProcedures['stubs']['Nop']) for k in p.loader.shared_objects.keys(): if k not in self.check_libs and k != os.path.basename( self.exec_file): self.exclude_addrs.append( (p.loader.shared_objects[k].get_min_addr(), p.loader.shared_objects[k].get_max_addr())) global_cache.set_exclude_addrs(self.exclude_addrs) # import IPython # IPython.embed() args = [input_file if x == "@@" else x for x in self.args] if self.opexpr: add_options_c = { simuvex.s_options.CACHE_OP_EXPR, simuvex.s_options.CONCRETE_RUN } add_options_s = { simuvex.s_options.CACHE_OP_EXPR, simuvex.s_options.SYMBOLIC_RUN } else: add_options_c = {simuvex.s_options.CONCRETE_RUN} add_options_s = {simuvex.s_options.SYMBOLIC_RUN} if self.size_restrict == 0 or self.size_restrict == 1: add_options_c.update({ simuvex.s_options.CACHE_WRITE_ADDRESS, simuvex.s_options.CACHE_READ_ADDRESS }) add_options_s.update({ simuvex.s_options.CACHE_WRITE_ADDRESS, simuvex.s_options.CACHE_READ_ADDRESS }) add_options_c.add(simuvex.s_options.CACHE_SIMPROCEDURE_PARMS) add_options_s.add(simuvex.s_options.CACHE_SIMPROCEDURE_PARMS) # if not self.size_restrict is None: # add_options_c.add(simuvex.s_options.CACHE_SIMPROCEDURE_PARMS) # add_options_s.add(simuvex.s_options.CACHE_SIMPROCEDURE_PARMS) # init concrete running init_state = p.factory.entry_state( concrete_fs=True, args=args, add_options=add_options_c, remove_options={simuvex.s_options.LAZY_SOLVES}) pg = p.factory.path_group(init_state) # init symbolic running init_state_s = p.factory.entry_state(args=args, add_options=add_options_s) # constraint file content try: with open(input_file, "rb") as fp: inputbytes = fp.read() except IOError: # if the file doesn't exist return error l.error("open queue %s failed" % input_file) return # symbyte = [] # for i in xrange(len(inputbytes)): # symbyte.append(init_state_s.se.BVS("queue_%d" % i,8)) # import ipdb # ipdb.set_trace() # init_state_s.add_constraints(symbyte[-1] == inputbytes[i]) # symbytes = init_state_s.se.Concat(*symbyte) # backing = simuvex.SimSymbolicMemory(memory_id = "file_%s" % input_file) # backing.set_state(init_state_s) # backing.store(0, symbytes) # constraint file length if self.size_restrict == 0: inputsize = os.path.getsize(input_file) sym_inputfile = simuvex.SimFile(input_file, 'rw', size=inputsize) else: sym_inputfile = simuvex.SimFile(input_file, 'rw') sym_inputfile.set_state(init_state_s) fs = {input_file: sym_inputfile} init_state_s.posix.fs = fs path0 = p.factory.path(init_state_s) # set breakpoint for debug if self.bp: import ipdb init_state.inspect.b('instruction', when=simuvex.BP_BEFORE, instruction=self.bp, action='ipdb') init_state_s.inspect.b('instruction', when=simuvex.BP_BEFORE, instruction=self.bp, action='ipdb') # init bitmap try: with open(self.bitmap_file, "r") as fp: bitmap = fp.read() except IOError: # if the file doesn't exist return error l.error("open bitmap file failed") sys.exit(1) l.debug( "bitmap length: %d" % len(filter(lambda x: True if ord(x) != 0xff else False, bitmap))) try: with open(self.static_file, "r") as fp: staticmap = fp.read() except IOError: # if the file doesn't exist return error l.info("static_map doesn't exsit, use general mode") staticmap = array.array('c', [chr(0xff) for x in range(65536)]) l.debug("staticmap length: %d" % len( filter(lambda x: True if ord(x) == 0xff else False, staticmap))) # start explore index = 0 while True: index += 1 global_cache.switch_enable(True) # concrete run pg.step(n=1, step_func=self.conc_step_func) if len(pg.active) == 0: if len(pg.errored) > 0: l.warning("path ended with an error " + repr(pg.errored[0].error)) break target = pg.active[0].addr nextpaths = path0.step() l.debug("index: %d size: %d path0: %x" % (index, len(nextpaths), path0.addr)) if (len(nextpaths) < 1): l.error("symbolic execution has none path!") return # symbolic run found = None for np in nextpaths: l.debug("nextpath: %x target: %x" % (np.addr, target)) matched = self.checkpath_withtrace(np.addr, target) matchstatic = self.checkpath_withbitmap( path0.addr, np.addr, staticmap) # no match count checkall = False if matched: found = np l.debug("path %x has matched" % np.addr) nmc = 0 if matchstatic is None and not global_cache.is_addr_in_exclude( np.addr): nmc += 1 else: nmc = 0 if nmc > 5: l.info('Trace out of staticmap, abort!') return if self.mult_conspath == True and self.size_restrict is None: checkall = True if (not matched or checkall) and matchstatic is not None: pathkey = self.checkpath_withbitmap( path0.addr, np.addr, bitmap) if not pathkey is None: if global_cache.is_addr_in_exclude(np.addr): l.debug("path %x out of check range" % np.addr) else: l.info("new path %x has found" % np.addr) # retrieve the input symbolic file infiles = [ v for k, v in np.state.posix.files.items() if v.name == input_file ] #and v.closed == False] if len(infiles) > 1: openinfiles = filter( lambda x: x.closed == False, infiles) if len(openinfiles) == 1: infiles = openinfiles else: l.warning( "There are %d inputfiles found, It must be one!" % len(infiles)) infiles = infiles[-1:] if len(infiles) != 1: l.error( "There are %d inputfiles found, It must be one!" % len(infiles)) # solve constrants and generate input elif not self.is_path_queued(pathkey): if self.loop_mode == 'FULL' or ( self.loop_mode == 'LOG' and self.should_check_unqueued(pathkey)): def try_generate(): try: # np.state.se.remove_constraints(len(inputbytes)) # import ipdb # ipdb.set_trace() input = np.state.se.any_str( infiles[0].all_bytes()) l.info("new input has generated") l.debug("input is: " + input) except Exception as e: l.debug( "path is unsat. reason is: " + repr(e)) if self.path_unqueued.has_key( pathkey): self.path_unqueued[ pathkey] += 1 else: self.path_unqueued[pathkey] = 1 return try: queue_index = 0 for _, _, files in os.walk( self.output_queuedir): for file in files: if file[0:3] == 'id:': queue_index += 1 queue_name = self.generate_queuename( path0.addr, np.addr, index, queue_index) with open( os.path.join( self.output_queuedir, queue_name), "wb") as fp: fp.write(input) self.path_queued[ pathkey] = None except IOError: l.error("create queue %s failed!" % queue_name) return try_generate() pass else: self.path_unqueued[pathkey] += 1 else: l.debug("path %x has generated queue" % np.addr) else: l.debug("path %x has tested by afl" % np.addr) if found is None: l.error( "symbolic execution can't find same path as concretely run!" ) for x in nextpaths: if x.errored: l.error("path ended with an error " + repr(x.error)) return else: path0 = found l.info("The path length: %d with input %s" % (index, input_file)) l.info("execution time: %f" % (time.clock() - starttime))
def main(): p = angr.Project("license", load_options={'auto_load_libs': False}) # Create a blank state state = p.factory.blank_state() # Build the file whose name is weird license_name = "_a\nb\tc_" # This is the license file # From analyzing the binary, we know that the license file should have five # lines in total, and each line has 6 characters. Not setting file content # may also work, but in that case, angr will produce many more paths, and we # will spent much more time in path trimming. bytes = None constraints = [] for i in xrange(5): line = [] for j in xrange(6): line.append(state.se.BVS('license_file_byte_%d_%d' % (i, j), 8)) state.add_constraints(line[-1] != 0x0a) if bytes is None: bytes = state.se.Concat(*line) else: bytes = state.se.Concat(bytes, state.se.BVV(0x0a, 8), *line) content = simuvex.SimSymbolicMemory(memory_id="file_%s" % license_name) content.set_state(state) content.store(0, bytes) license_file = simuvex.SimFile(license_name, 'rw', content=content, size=len(bytes) / 8) # Build the file system dict # This interface might change in the near future fs = {license_name: license_file} state.posix.fs = fs path = p.factory.path(state=state) ex = p.surveyors.Explorer(start=path, find=(0x400e93, ), avoid=(0x400bb1, 0x400b8f, 0x400b6d, 0x400a85, 0x400ebf, 0x400a59)) ex.run() # One path will be found found = ex.found[0] rsp = found.state.regs.rsp flag_addr = rsp + 0x278 - 0xd8 # Ripped from IDA # Perform an inline call to strlen() in order to determine the length of the # flag FAKE_ADDR = 0x100000 strlen = lambda state, arguments: \ simuvex.SimProcedures['libc.so.6']['strlen'](FAKE_ADDR, p.arch).execute( state, arguments=arguments ) flag_length = strlen(found.state, arguments=[flag_addr]).ret_expr # In case it's not null-terminated, we get the least number as the length flag_length_int = min(found.state.se.any_n_int(flag_length, 3)) # Read out the flag! flag_int = found.state.se.any_int( found.state.memory.load(flag_addr, flag_length_int)) flag = hex(flag_int)[2:-1].decode("hex") return flag