def run(self, data, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch.bits, True) try: fmt_str = self._parse(1) items = fmt_str.interpret(2, self.arg, addr=data) return items except angr.SimUnsatError: return self.state.se.Unconstrained('sscanf', 32, uninitialized=False)
def run(self, a_addr, b_addr): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(32, True) strlen = angr.SIM_PROCEDURES['libc']['strlen'] a_strlen = self.inline_call(strlen, a_addr) b_strlen = self.inline_call(strlen, b_addr) maxlen = self.state.se.BVV(max(a_strlen.max_null_index, b_strlen.max_null_index), self.state.arch.bits) strncmp = self.inline_call(angr.SIM_PROCEDURES['libc']['strncmp'], a_addr, b_addr, maxlen, a_len=a_strlen, b_len=b_strlen) return strncmp.ret_expr
def run(self, category, locale): self.argument_types = { 0: SimTypeInt(32, True), 1: self.ty_ptr(SimTypeString()) } self.return_type = self.ty_ptr(SimTypeString()) # FIXME: just symbolic maxlen string max_str_len = self.state.libc.max_str_len malloc = SIM_PROCEDURES['libc']['malloc'] str_addr = self.inline_call(malloc, max_str_len).ret_expr return self.state.se.If(self.state.se.BoolS("setlocale_flag"), str_addr, self.state.se.BVV(0, self.state.arch.bits))
def run(self, data, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = SimTypeInt(self.state.arch.bits, True) fmt_str = self._parse(1) items = fmt_str.interpret(2, self.arg, addr=data) return items
def run(self, lpString1, lpString2): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = SimTypeInt(signed=True) strcmp = angr.SIM_PROCEDURES['libc']['strcmp'] return self.inline_call(strcmp, lpString1, lpString2, wchar=True, ignore_case=True).ret_expr
def run(self, dst_addr, src_addr, limit, src_len=None): self.argument_types = {0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()), 2: SimTypeLength(self.state.arch)} self.return_type = self.ty_ptr(SimTypeString()) strlen = angr.SIM_PROCEDURES['libc']['strlen'] memcpy = angr.SIM_PROCEDURES['libc']['memcpy'] src_len = src_len if src_len is not None else self.inline_call(strlen, src_addr).ret_expr cpy_size = self.state.solver.If(self.state.solver.ULE(limit, src_len + 1), limit, src_len + 1) self.inline_call(memcpy, dst_addr, src_addr, cpy_size) return dst_addr
def run(self, s): self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = self.ty_ptr(SimTypeString()) strlen = angr.SIM_PROCEDURES['libc']['strlen'] strncpy = angr.SIM_PROCEDURES['libc']['strncpy'] malloc = angr.SIM_PROCEDURES['libc']['malloc'] src_len = self.inline_call(strlen, s).ret_expr new_s = self.inline_call(malloc, src_len + 1).ret_expr self.inline_call(strncpy, new_s, s, src_len + 1, src_len=src_len) return new_s
def run(self, str_ptr, delim_ptr, str_strlen=None, delim_strlen=None): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = self.ty_ptr(SimTypeString()) malloc = angr.SIM_PROCEDURES['libc']['malloc'] token_ptr = self.inline_call( malloc, self.state.libc.strtok_token_size).ret_expr r = self.state.se.If( self.state.se.Unconstrained('strtok_case', self.state.arch.bits) == 0, token_ptr, self.state.se.BVV(0, self.state.arch.bits)) self.state.libc.strtok_heap.append(token_ptr) return r
def run(self, s_addr, c_int, s_strlen=None): c = c_int[7:0] self.argument_types = {0: self.ty_ptr(SimTypeString()), 1: SimTypeInt(32, True)} # ? self.return_type = self.ty_ptr(SimTypeChar()) # ? s_strlen = self.inline_call(angr.SIM_PROCEDURES['libc']['strlen'], s_addr) chunk_size = None if MEMORY_CHUNK_INDIVIDUAL_READS in self.state.options: chunk_size = 1 if self.state.solver.symbolic(s_strlen.ret_expr): l.debug("symbolic strlen") # TODO: more constraints here to make sure we don't search too little max_sym = min(self.state.solver.max_int(s_strlen.ret_expr)+1, self.state.libc.max_symbolic_strchr) a, c, i = self.state.memory.find(s_addr, c, s_strlen.max_null_index, max_symbolic_bytes=max_sym, default=0) else: l.debug("concrete strlen") max_search = self.state.solver.eval(s_strlen.ret_expr)+1 a, c, i = self.state.memory.find(s_addr, c, max_search, default=0, chunk_size=chunk_size) if len(i) > 1: a = a.annotate(MultiwriteAnnotation()) self.state.add_constraints(*c) return a
def run(self, addr_in): #pylint:disable=unused-argument # arg types: struct....... :( self.return_type = self.ty_ptr(SimTypeString()) #TODO: return an IP address string ret_expr = self.state.solver.Unconstrained("inet_ntoa_ret", self.state.arch.bits) return ret_expr
def run(self, s, wchar=False): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeLength(self.state.arch) if wchar: null_seq = self.state.se.BVV(0, 16) step = 2 else: null_seq = self.state.se.BVV(0, 8) step = 1 max_symbolic_bytes = self.state.libc.buf_symbolic_bytes max_str_len = self.state.libc.max_str_len if self.state.mode == 'static': self.max_null_index = 0 # Make sure to convert s to ValueSet s_list = self.state.memory.normalize_address(s, convert_to_valueset=True) length = self.state.se.ESI(self.state.arch.bits) for s_ptr in s_list: r, c, i = self.state.memory.find(s, null_seq, max_str_len, max_symbolic_bytes=max_symbolic_bytes, step=step) self.max_null_index = max([self.max_null_index] + i) # Convert r to the same region as s r_list = self.state.memory.normalize_address(r, convert_to_valueset=True, target_region=s_ptr._model_vsa.regions.keys()[0]) for r_ptr in r_list: length = length.union(r_ptr - s_ptr) return length else: search_len = max_str_len r, c, i = self.state.memory.find(s, null_seq, search_len, max_symbolic_bytes=max_symbolic_bytes, step=step) # try doubling the search len and searching again s_new = s while all(con.is_false() for con in c): s_new += search_len search_len *= 2 r, c, i = self.state.memory.find(s_new, null_seq, search_len, max_symbolic_bytes=max_symbolic_bytes, step=step) # stop searching after some reasonable limit if search_len > 0x10000: raise angr.SimMemoryLimitError("strlen hit limit of 0x10000") self.max_null_index = max(i) self.state.add_constraints(*c) result = r - s if result.depth > 3: rresult = claripy.BVS('strlen', len(result)) self.state.solver.add(result == rresult) result = rresult return result
def run(self, scan, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = SimTypeInt(self.state.arch.bits, True) fmt_str = self._parse(1) _, items = fmt_str.interpret(self.arg(0), 2, self.arg, region=self.state.memory) return items
def run(self, s): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch, True) strtol = angr.SIM_PROCEDURES['libc']['strtol'] return strtol.strtol_inner(s, self.state, self.state.memory, 10, True)[1]
def run(self, dst, src): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = self.ty_ptr(SimTypeString()) strlen = angr.SIM_PROCEDURES['libc']['strlen'] strncpy = angr.SIM_PROCEDURES['libc']['strncpy'] src_len = self.inline_call(strlen, src).ret_expr dst_len = self.inline_call(strlen, dst).ret_expr self.inline_call(strncpy, dst + dst_len, src, src_len + 1, src_len=src_len) return dst
def run(self, string): self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(32, True) stdout = self.state.posix.get_fd(1) if stdout is None: return -1 strlen = angr.SIM_PROCEDURES['libc']['strlen'] length = self.inline_call(strlen, string).ret_expr out = stdout.write(string, length) stdout.write_data(self.state.solver.BVV(b'\n')) return out + 1
def run(self, string): self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(32, True) # TODO: use a write that's not a linux syscall write = angr.SIM_PROCEDURES['linux_kernel']['write'] strlen = angr.SIM_PROCEDURES['libc']['strlen'] length = self.inline_call(strlen, string).ret_expr self.inline_call(write, self.state.se.BVV(1, self.state.arch.bits), string, length) self.state.posix.write(1, self.state.se.BVV(0x0a, 8), 1) # TODO: return values return self.state.se.Unconstrained('puts', self.state.arch.bits)
def run(self, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch.bits, True) fmt_str = self._parse(0) # we're reading from stdin so the region is the file's content simfd = self.state.posix.get_fd(0) if simfd is None: return -1 items = fmt_str.interpret(1, self.arg, simfd=simfd) return items
def check_fsb(state): if not state.project.is_hooked(state.addr): return False sim_func = state.project.hooked_by(state.addr) # check whether it is a format string function # is yes, which argument is the format for i in range(len(FORMAT_FUNCS)): FORMAT_FUNC = FORMAT_FUNCS[i] if sim_func.display_name in FORMAT_FUNC: pos = i break else: return False # perfrom calling convention analysis and extract the format argument # TODO: currently, the CFGFast will fail when auto_load_libs is True, # to circumvent that, we create a new project each time, which is # extremely slow proj = angr.Project(state.project.filename, auto_load_libs=False) proj.analyses.CFG() # fill in knowledge base proj.analyses.CompleteCallingConventions(recover_variables=True) func = proj.kb.functions[sim_func.display_name] # extract arguments across projects. I think it should be fine args = func.calling_convention.get_args(state) # now check if is a symbolic string fmt = args[pos] sim_str = SimTypeString() try: sim_str.extract(state, fmt) except ValueError: return True return False
def run(self, s): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeLength(self.state.arch) max_symbolic_bytes = self.state.libc.buf_symbolic_bytes max_str_len = self.state.libc.max_str_len if self.state.mode == 'static': self.max_null_index = [ ] # Make sure to convert s to ValueSet s_list = self.state.memory.normalize_address(s, convert_to_valueset=True) length = self.state.se.ESI(self.state.arch.bits) for s_ptr in s_list: r, c, i = self.state.memory.find(s, self.state.se.BVV(0, 8), max_str_len, max_symbolic_bytes=max_symbolic_bytes) self.max_null_index = max(self.max_null_index + i) # Convert r to the same region as s r_list = self.state.memory.normalize_address(r, convert_to_valueset=True, target_region=s_ptr._model_vsa.regions.keys()[0]) for r_ptr in r_list: length = length.union(r_ptr - s_ptr) return length else: search_len = max_str_len r, c, i = self.state.memory.find(s, self.state.se.BVV(0, 8), search_len, max_symbolic_bytes=max_symbolic_bytes) # try doubling the search len and searching again while all(con.is_false() for con in c): search_len *= 2 # stop searching after some reasonable limit if search_len > 0x10000: raise angr.SimMemoryLimitError("strlen hit limit of 0x10000") r, c, i = self.state.memory.find(s, self.state.se.BVV(0, 8), search_len, max_symbolic_bytes=max_symbolic_bytes) self.max_null_index = max(i) self.state.add_constraints(*c) return r - s
def run(self, p_addr, flags): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: SimTypeInt(32, True) } self.return_type = SimTypeFd() strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, p_addr) p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness='Iend_BE') path = self.state.se.eval(p_expr, cast_to=str) fd = self.state.posix.open(path, flags) return fd
def run(self, p_addr, flags, mode=0644): # pylint:disable=unused-argument self.argument_types = {0: self.ty_ptr(SimTypeString()), 1: SimTypeInt(32, True)} self.return_type = SimTypeFd() strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, p_addr) p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness='Iend_BE') try: path = self.state.se.eval(p_expr, cast_to=str) fd = self.state.posix.open(path, flags) if fd is None: return -1 return fd except angr.SimUnsatError: return self.state.se.Unconstrained("open", 32, uninitialized=False)
def run(self, p_addr, flags, mode): # pylint:disable=unused-argument self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: SimTypeInt(32, True) } self.return_type = SimTypeFd() strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, p_addr) p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness='Iend_BE') path = self.state.solver.eval(p_expr, cast_to=bytes) fd = self.state.posix.open(path, flags) if fd is None: return -1 return fd
def run(self, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch.bits, True) try: fmt_str = self._parse(0) # we're reading from stdin so the region is the file's content simfd = self.state.posix.get_fd(0) if simfd is None: return -1 items = fmt_str.interpret(1, self.arg, simfd=simfd) return items except angr.SimUnsatError: return self.state.se.Unconstrained('scanf', 32, uninitialized=False)
def run(self, fmt): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: self.ty_ptr(SimTypeString())} self.return_type = SimTypeInt(self.state.arch.bits, True) fmt_str = self._parse(0) # we're reading from stdin so the region is the file's content f = self.state.posix.get_file(0) region = f.content start = f.pos (end, items) = fmt_str.interpret(start, 1, self.arg, region=region) # do the read, correcting the internal file position and logging the action self.state.posix.read_from(0, end - start) return items
def run(self, s_addr, c_int, s_strlen=None): c = c_int[7:0] self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: SimTypeInt(32, True) } # ? self.return_type = self.ty_ptr(SimTypeChar()) # ? s_strlen = self.inline_call(angr.SIM_PROCEDURES['libc']['strlen'], s_addr) if self.state.se.symbolic(s_strlen.ret_expr): l.debug("symbolic strlen") # TODO: more constraints here to make sure we don't search too little try: max_sym = min(self.state.se.max_int(s_strlen.ret_expr), self.state.libc.max_symbolic_strchr) a, c, i = self.state.memory.find(s_addr, c, s_strlen.max_null_index, max_symbolic_bytes=max_sym, default=0) except angr.SimUnsatError: # XXX: reduce constraint max_sym = self.state.libc.max_symbolic_strchr a, c, i = self.state.memory.find(s_addr, c, self.state.libc.max_str_len, max_symbolic_bytes=max_sym, default=0) else: l.debug("concrete strlen") max_search = self.state.se.eval(s_strlen.ret_expr) a, c, i = self.state.memory.find(s_addr, c, max_search, default=0) if len(i) > 1: a = a.annotate(MultiwriteAnnotation()) self.state.add_constraints(*c) return a
def run(self, nptr, endptr, base): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(self.ty_ptr(SimTypeString())), 2: SimTypeInt(self.state.arch, True) } self.return_type = SimTypeInt(self.state.arch, True) if self.state.solver.symbolic(base): l.warning("Concretizing symbolic base in strtol") base_concrete = self.state.solver.eval(base) self.state.add_constraints(base == base_concrete) base = self.state.solver.eval(base) if base == 0: # in this case the base is 16 if it starts with 0x, 8 if it starts with 0, 10 otherwise # here's the possibilities base_16_pred = self.state.solver.Or( self.state.memory.load(nptr, 2) == self.state.solver.BVV(b"0x"), self.state.memory.load(nptr, 3) == self.state.solver.BVV(b"+0x"), self.state.memory.load(nptr, 3) == self.state.solver.BVV(b"-0x")) base_8_pred = self.state.solver.And( self.state.solver.Or( self.state.memory.load(nptr, 1) == self.state.solver.BVV(b"0"), self.state.memory.load(nptr, 2) == self.state.solver.BVV(b"+0"), self.state.memory.load(nptr, 2) == self.state.solver.BVV(b"-0")), self.state.solver.Not(base_16_pred)) base_10_pred = self.state.solver.And( self.state.solver.Not(base_16_pred), self.state.solver.Not(base_8_pred)) expressions = [] values = [] num_bytes_arr = [] # read a string to long for each possibility pred_base = zip([base_16_pred, base_10_pred, base_8_pred], [16, 10, 8]) for pred, base in pred_base: expression, value, num_bytes = self.strtol_inner( nptr, self.state, self.state.memory, base, True) expressions.append(self.state.solver.And(expression, pred)) values.append(value) num_bytes_arr.append(num_bytes) # we would return the Or(expressions) as the indicator whether or not it succeeded, but it's not needed # for strtol # expression = self.state.solver.Or(expressions) value = self.state.solver.ite_cases(zip(expressions, values), 0) num_bytes = self.state.solver.ite_cases( zip(expressions, num_bytes_arr), 0) self.state.memory.store(endptr, nptr + num_bytes, condition=(endptr != 0), endness=self.state.arch.memory_endness) return value expression, value, num_bytes = self.strtol_inner( nptr, self.state, self.state.memory, base, True) self.state.memory.store(endptr, nptr + num_bytes, condition=(endptr != 0), endness=self.state.arch.memory_endness) return self.state.solver.If(expression, value, 0)
def run(self, a_addr, b_addr, limit, a_len=None, b_len=None, wchar=False, ignore_case=False): #pylint:disable=arguments-differ # TODO: smarter types here? self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()), 2: SimTypeLength(self.state.arch) } self.return_type = SimTypeInt(32, True) strlen = angr.SIM_PROCEDURES['libc']['strlen'] a_strlen = a_len if a_len is not None else self.inline_call( strlen, a_addr, wchar=wchar) b_strlen = b_len if b_len is not None else self.inline_call( strlen, b_addr, wchar=wchar) a_len = a_strlen.ret_expr b_len = b_strlen.ret_expr match_constraints = [] variables = a_len.variables | b_len.variables | limit.variables ret_expr = self.state.se.Unconstrained("strncmp_ret", self.state.arch.bits, key=('api', 'strncmp')) # determine the maximum number of bytes to compare concrete_run = False #if not self.state.se.symbolic(a_len) and not self.state.se.symbolic(b_len) and not self.state.se.symbolic(limit): if self.state.se.single_valued(a_len) and self.state.se.single_valued( b_len) and self.state.se.single_valued(limit): c_a_len = self.state.se.eval(a_len) c_b_len = self.state.se.eval(b_len) c_limit = self.state.se.eval(limit) l.debug("everything is concrete: a_len %d, b_len %d, limit %d", c_a_len, c_b_len, c_limit) if (c_a_len < c_limit or c_b_len < c_limit) and c_a_len != c_b_len: l.debug("lengths < limit and unmatched") concrete_run = True maxlen = min(c_a_len, c_b_len, c_limit) else: if self.state.se.single_valued(limit): c_limit = self.state.se.eval(limit) maxlen = min(a_strlen.max_null_index, b_strlen.max_null_index, c_limit) else: maxlen = max(a_strlen.max_null_index, b_strlen.max_null_index) match_constraints.append( self.state.se.Or( a_len == b_len, self.state.se.And(self.state.se.UGE(a_len, limit), self.state.se.UGE(b_len, limit)))) if maxlen == 0: # there is a corner case: if a or b are not both empty string, and limit is greater than 0, we should return # non-equal. Basically we only return equal when limit is 0, or a_len == b_len == 0 if self.state.se.single_valued(limit) and self.state.se.eval( limit) == 0: # limit is 0 l.debug("returning equal for 0-limit") return self.state.se.BVV(0, self.state.arch.bits, variables=variables) elif self.state.se.single_valued(a_len) and self.state.se.single_valued(b_len) and \ self.state.se.eval(a_len) == self.state.se.eval(b_len) == 0: # two empty strings l.debug("returning equal for two empty strings") return self.state.se.BVV(0, self.state.arch.bits, variables=variables) else: # all other cases fall into this branch l.debug( "returning non-equal for comparison of an empty string and a non-empty string" ) if a_strlen.max_null_index == 0: return self.state.se.BVV(-1, self.state.arch.bits, variables=variables) else: return self.state.se.BVV(1, self.state.arch.bits, variables=variables) # the bytes a_bytes = self.state.memory.load(a_addr, maxlen, endness='Iend_BE') b_bytes = self.state.memory.load(b_addr, maxlen, endness='Iend_BE') # TODO: deps # all possible return values in static mode return_values = [] for i in range(maxlen): l.debug("Processing byte %d", i) maxbit = (maxlen - i) * 8 a_byte = a_bytes[maxbit - 1:maxbit - 8] b_byte = b_bytes[maxbit - 1:maxbit - 8] if concrete_run and self.state.se.single_valued( a_byte) and self.state.se.single_valued(b_byte): a_conc = self.state.se.eval(a_byte) b_conc = self.state.se.eval(b_byte) variables |= a_byte.variables variables |= b_byte.variables if ignore_case: # convert both to lowercase if ord('a') <= a_conc <= ord('z'): a_conc -= ord(' ') if ord('a') <= b_conc <= ord('z'): b_conc -= ord(' ') if a_conc != b_conc: l.debug( "... found mis-matching concrete bytes 0x%x and 0x%x", a_conc, b_conc) if a_conc < b_conc: return self.state.se.BVV(-1, self.state.arch.bits, variables=variables) else: return self.state.se.BVV(1, self.state.arch.bits, variables=variables) else: if self.state.mode == 'static': return_values.append(a_byte - b_byte) concrete_run = False if self.state.mode != 'static': if ignore_case: byte_constraint = self.state.se.Or( self.state.se.Or( a_byte == b_byte, self.state.se.And( ord('A') <= a_byte, a_byte <= ord('Z'), ord('a') <= b_byte, b_byte <= ord('z'), b_byte - ord(' ') == a_byte, ), self.state.se.And( ord('A') <= b_byte, b_byte <= ord('Z'), ord('a') <= a_byte, a_byte <= ord('z'), a_byte - ord(' ') == b_byte, ), ), self.state.se.ULT(a_len, i), self.state.se.ULT(limit, i)) else: byte_constraint = self.state.se.Or( a_byte == b_byte, self.state.se.ULT(a_len, i), self.state.se.ULT(limit, i)) match_constraints.append(byte_constraint) if concrete_run: l.debug("concrete run made it to the end!") return self.state.se.BVV(0, self.state.arch.bits, variables=variables) if self.state.mode == 'static': ret_expr = self.state.se.ESI(8) for expr in return_values: ret_expr = ret_expr.union(expr) ret_expr = ret_expr.sign_extend(self.state.arch.bits - 8) else: # make the constraints l.debug("returning symbolic") match_constraint = self.state.se.And(*match_constraints) nomatch_constraint = self.state.se.Not(match_constraint) #l.debug("match constraints: %s", match_constraint) #l.debug("nomatch constraints: %s", nomatch_constraint) match_case = self.state.se.And(limit != 0, match_constraint, ret_expr == 0) nomatch_case = self.state.se.And(limit != 0, nomatch_constraint, ret_expr == 1) l0_case = self.state.se.And(limit == 0, ret_expr == 0) empty_case = self.state.se.And(a_strlen.ret_expr == 0, b_strlen.ret_expr == 0, ret_expr == 0) self.state.add_constraints( self.state.se.Or(match_case, nomatch_case, l0_case, empty_case)) return ret_expr
def run(self, haystack_addr, needle_addr, haystack_strlen=None, needle_strlen=None): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()) } self.return_type = self.ty_ptr(SimTypeString()) strlen = angr.SIM_PROCEDURES['libc']['strlen'] strncmp = angr.SIM_PROCEDURES['libc']['strncmp'] haystack_strlen = self.inline_call( strlen, haystack_addr) if haystack_strlen is None else haystack_strlen needle_strlen = self.inline_call( strlen, needle_addr) if needle_strlen is None else needle_strlen # naive approach haystack_maxlen = haystack_strlen.max_null_index needle_maxlen = needle_strlen.max_null_index l.debug("strstr with size %d haystack and size %d needle...", haystack_maxlen, needle_maxlen) if needle_maxlen == 0: l.debug("... zero-length needle.") return haystack_addr elif haystack_maxlen == 0: l.debug("... zero-length haystack.") return self.state.se.BVV(0, self.state.arch.bits) if self.state.se.symbolic(needle_strlen.ret_expr): cases = [[needle_strlen.ret_expr == 0, haystack_addr]] exclusions = [needle_strlen.ret_expr != 0] remaining_symbolic = self.state.libc.max_symbolic_strstr for i in range(haystack_maxlen): l.debug("... case %d (%d symbolic checks remaining)", i, remaining_symbolic) # big hack! cmp_res = self.inline_call(strncmp, haystack_addr + i, needle_addr, needle_strlen.ret_expr, a_len=haystack_strlen, b_len=needle_strlen) c = self.state.se.And(*([ self.state.se.UGE(haystack_strlen.ret_expr, needle_strlen. ret_expr), cmp_res.ret_expr == 0 ] + exclusions)) exclusions.append(cmp_res.ret_expr != 0) if self.state.se.symbolic(c): remaining_symbolic -= 1 #print "CASE:", c cases.append([c, haystack_addr + i]) haystack_strlen.ret_expr = haystack_strlen.ret_expr - 1 if remaining_symbolic == 0: l.debug("... exhausted remaining symbolic checks.") break cases.append([ self.state.se.And(*exclusions), self.state.se.BVV(0, self.state.arch.bits) ]) l.debug("... created %d cases", len(cases)) r = self.state.se.ite_cases(cases, 0) c = [self.state.se.Or(*[c for c, _ in cases])] else: needle_length = self.state.se.eval(needle_strlen.ret_expr) needle_str = self.state.memory.load(needle_addr, needle_length) r, c, i = self.state.memory.find( haystack_addr, needle_str, haystack_strlen.max_null_index, max_symbolic_bytes=self.state.libc.max_symbolic_strstr, default=0) self.state.add_constraints(*c) return r
def run(self, str_ptr, delim_ptr, save_ptr, str_strlen=None, delim_strlen=None): self.argument_types = { 0: self.ty_ptr(SimTypeString()), 1: self.ty_ptr(SimTypeString()), 2: self.ty_ptr(self.ty_ptr(SimTypeString())) } self.return_type = self.ty_ptr(SimTypeString()) if self.state.libc.simple_strtok: malloc = angr.SIM_PROCEDURES['libc']['malloc'] token_ptr = self.inline_call( malloc, self.state.libc.strtok_token_size).ret_expr r = self.state.solver.If( self.state.solver.Unconstrained('strtok_case', self.state.arch.bits) == 0, token_ptr, self.state.solver.BVV(0, self.state.arch.bits)) self.state.libc.strtok_heap.append(token_ptr) return r else: strstr = angr.SIM_PROCEDURES['libc']['strstr'] strlen = angr.SIM_PROCEDURES['libc']['strlen'] l.debug("Doin' a strtok_r!") l.debug("... geting the saved state") saved_str_ptr = self.state.memory.load( save_ptr, self.state.arch.bytes, endness=self.state.arch.memory_endness) start_ptr = self.state.solver.If(str_ptr == 0, saved_str_ptr, str_ptr) l.debug("... getting the lengths") str_strlen = self.inline_call( strlen, start_ptr) if str_strlen is None else str_strlen delim_strlen = self.inline_call( strlen, delim_ptr) if delim_strlen is None else delim_strlen l.debug( "... STRTOK SLOW PATH (symbolic-length delimiteter and/or string)" ) l.debug("... calling strstr") where = self.inline_call(strstr, start_ptr, delim_ptr, haystack_strlen=str_strlen, needle_strlen=delim_strlen) write_length = self.state.solver.If(where.ret_expr != 0, delim_strlen.ret_expr, 0) write_content = self.state.solver.BVV( 0, delim_strlen.max_null_index * 8) # do a symbolic write (we increment the limit because of the possibility that the write target is 0, in which case the length will be 0, anyways) l.debug("... doing the symbolic write") self.state.memory.store(where.ret_expr, write_content, size=write_length, strategy=["symbolic_nonzero", "any"], limit=str_strlen.max_null_index + 1) l.debug("... creating the return address") new_start = write_length + where.ret_expr new_state = self.state.solver.If(new_start != 0, new_start, start_ptr) l.debug("... saving the state") self.state.memory.store(save_ptr, new_state, endness=self.state.arch.memory_endness) l.debug("... done") return new_start