def run(self, sim_nmemb, sim_size): self.argument_types = { 0: SimTypeLength(self.state.arch), 1: SimTypeLength(self.state.arch) } plugin = self.state.get_plugin('libc') self.return_type = self.ty_ptr( SimTypeArray(SimTypeTop(sim_size), sim_nmemb)) if self.state.se.symbolic(sim_nmemb): # TODO: find a better way nmemb = self.state.se.max_int(sim_nmemb) else: nmemb = self.state.se.any_int(sim_nmemb) if self.state.se.symbolic(sim_size): # TODO: find a better way size = self.state.se.max_int(sim_size) else: size = self.state.se.any_int(sim_size) final_size = size * nmemb * 8 if final_size > plugin.max_variable_size: final_size = plugin.max_variable_size addr = plugin.heap_location plugin.heap_location += final_size v = self.state.se.BVV(0, final_size) self.state.memory.store(addr, v) return addr
def run(self, fd, dst, length): self.argument_types = { 0: SimTypeFd(), 1: self.ty_ptr(SimTypeArray(SimTypeChar(), length)), 2: SimTypeLength(self.state.arch) } self.return_type = SimTypeLength(self.state.arch) # TODO handle errors self.state.posix.read(fd, length, dst_addr=dst) return length
def run(self, dst_addr, char, num): char = char[7:0] self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: SimTypeInt(32, True), # ? 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) if self.state.se.symbolic(num): l.debug("symbolic length") max_size = self.state.se.min_int( num) + self.state.libc.max_buffer_size write_bytes = self.state.se.Concat(*([char] * max_size)) self.state.memory.store(dst_addr, write_bytes, size=num) else: max_size = self.state.se.any_int(num) if max_size == 0: self.ret(dst_addr) return # Concatenating many bytes is slow, so some sort of optimization is required if char._model_concrete.value == 0: write_bytes = self.state.se.BVV(0, max_size * 8) else: rb = memset._repeat_bytes(char._model_concrete.value, max_size * 8) write_bytes = self.state.se.BVV(rb, max_size * 8) self.state.memory.store(dst_addr, write_bytes) l.debug("memset writing %d bytes", max_size) return dst_addr
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 = simuvex.SimProcedures['libc.so.6']['strlen'] memcpy = simuvex.SimProcedures['libc.so.6']['memcpy'] src_len = src_len if src_len is not None else self.inline_call( strlen, src_addr) cpy_size = self.state.se.If( self.state.se.ULE(limit, src_len.ret_expr + 1), limit, src_len.ret_expr + 1) #print "===================" #print sorted(self.state.expr_value(src_len.ret_expr).se.any_n(20)) #print self.state.expr_value(limit.expr).se.any_n(20) #print sorted(self.state.expr_value(cpy_size).se.any_n(20)) #print "-------------------" self.inline_call(memcpy, dst_addr, src_addr, cpy_size) return dst_addr
def run(self, dst_addr, src_addr, limit): #additional code trace_data = ("memmove", { "dst_addr": (dst_addr, dst_addr.symbolic), "src_addr": (src_addr, src_addr.symbolic), "limit": (limit, limit.symbolic) }) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) memcpy = simuvex.SimProcedures['libc.so.6']['memcpy'] self.inline_call(memcpy, dst_addr, src_addr, limit) return dst_addr
def run(self, fd): #pylint:disable=attribute-defined-outside-init self.argument_types = {0: SimTypeFd()} self.return_type = SimTypeLength(self.state.arch) return self.state.se.BVV(0, self.state.arch.bits)
def run(self, ptr, size): #additional code trace_data = ("realloc", { "ptr": (ptr, ptr.symbolic), "size": (size, size.symbolic) }) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code self.state.add_constraints(size <= self.state.libc.max_variable_size) size_int = self.state.se.max_int(size) l.debug("Size: %d", size_int) self.state.add_constraints(size_int == size) self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop(size)) addr = self.state.libc.heap_location v = self.state.memory.load(ptr, size_int) self.state.memory.store(addr, v) self.state.libc.heap_location += size_int return addr
def run(self, dst_addr, char, num): char = char[7:0] self.argument_types = {0: self.ty_ptr(SimTypeTop()), 1: SimTypeInt(32, True), # ? 2: SimTypeLength(self.state.arch)} self.return_type = self.ty_ptr(SimTypeTop()) if self.state.se.symbolic(num): l.debug("symbolic length") max_size = self.state.se.min_int(num) + self.state.libc.max_buffer_size write_bytes = self.state.se.Concat(*([ char ] * max_size)) self.state.memory.store(dst_addr, write_bytes, size=num) else: max_size = self.state.se.any_int(num) if max_size == 0: self.ret(dst_addr) return write_bytes = self.state.se.Concat(*([ char ] * max_size)) self.state.memory.store(dst_addr, write_bytes) l.debug("memset writing %d bytes", max_size) return dst_addr
def run(self, sim_nmemb, sim_size): #additional code trace_data = ("calloc", { "sim_nmemb": (sim_nmemb, sim_nmemb.symbolic), "sim_size": (sim_size, sim_size.symbolic) }) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code self.argument_types = { 0: SimTypeLength(self.state.arch), 1: SimTypeLength(self.state.arch) } plugin = self.state.get_plugin('libc') self.return_type = self.ty_ptr( SimTypeArray(SimTypeTop(sim_size), sim_nmemb)) if self.state.se.symbolic(sim_nmemb): # TODO: find a better way nmemb = self.state.se.max_int(sim_nmemb) else: nmemb = self.state.se.any_int(sim_nmemb) if self.state.se.symbolic(sim_size): # TODO: find a better way size = self.state.se.max_int(sim_size) else: size = self.state.se.any_int(sim_size) final_size = size * nmemb if final_size > plugin.max_variable_size: final_size = plugin.max_variable_size addr = plugin.heap_location plugin.heap_location += final_size v = self.state.se.BVV(0, final_size * 8) self.state.memory.store(addr, v) return addr
def run(self, dst_addr, src_addr, limit): #additional code trace_data = ("self", { "dst_addr": (dst_addr, dst_addr.symbolic), "src_addr": (src_addr, src_addr.symbolic), "limit": (limit, limit.symbolic) }) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) if not self.state.se.symbolic(limit): # not symbolic so we just take the value conditional_size = self.state.se.any_int(limit) else: # constraints on the limit are added during the store max_memcpy_size = self.state.libc.max_memcpy_size max_limit = self.state.se.max_int(limit) conditional_size = max(self.state.se.min_int(limit), min(max_limit, max_memcpy_size)) if max_limit > max_memcpy_size and conditional_size < max_limit: l.warning( "memcpy upper bound of %#x outside limit, limiting to %#x instead", max_limit, conditional_size) l.debug("Memcpy running with conditional_size %#x", conditional_size) if conditional_size > 0: src_mem = self.state.memory.load(src_addr, conditional_size, endness='Iend_BE') if ABSTRACT_MEMORY in self.state.options: self.state.memory.store(dst_addr, src_mem, size=conditional_size, endness='Iend_BE') else: self.state.memory.store(dst_addr, src_mem, size=limit, endness='Iend_BE') return dst_addr
def run(self, dst_addr, src_addr, limit): # TODO: some way to say that type(0) == type(1) ? self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } return self.inline_call(simuvex.SimProcedures['libc.so.6']['memcpy'], dst_addr, src_addr, limit).ret_expr
def run(self, fd, dst, length): #additional code trace_data = ("read", {"fd": (fd, fd.symbolic), "dst": (dst, dst.symbolic), "length": (length, length.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append(trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append(trace_data) #end of additional code self.argument_types = {0: SimTypeFd(), 1: self.ty_ptr(SimTypeArray(SimTypeChar(), length)), 2: SimTypeLength(self.state.arch)} self.return_type = SimTypeLength(self.state.arch) # TODO handle errors length = self.state.posix.read(fd, dst, length) return length
def run(self, dst_addr, src_addr, limit): # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) memcpy = simuvex.SimProcedures['libc.so.6']['memcpy'] self.inline_call(memcpy, dst_addr, src_addr, limit) return dst_addr
def run(self, dst, size, fd): self.argument_types = {2: SimTypeFd(), 0: self.ty_ptr(SimTypeArray(SimTypeChar(), size)), 1: SimTypeLength(self.state.arch)} self.return_type = self.argument_types[0] f = self.state.posix.get_file(fd) old_pos = self.state.posix.pos(fd) self.state.memory.copy_contents(dst, old_pos, size, src_memory=f.content) f.seek(old_pos + size) return dst
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: 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(i) self.state.add_constraints(*c) return r - s
def run(self, sim_size): self.argument_types = {0: SimTypeLength(self.state.arch)} self.return_type = self.ty_ptr(SimTypeTop(sim_size)) if self.state.se.symbolic(sim_size): size = self.state.se.max_int(sim_size) if size > self.state.libc.max_variable_size: size = self.state.libc.max_variable_size else: size = self.state.se.any_int(sim_size) * 8 addr = self.state.libc.heap_location self.state.libc.heap_location += size return addr
def run(self, dst_addr, src_addr, limit): # TODO: some way to say that type(0) == type(1) ? self.argument_types = {0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch)} #additional code trace_data = ("bcopy", {"dst_addr": (dst_addr, dst_addr.symbolic), "src_addr": (src_addr, src_addr.symbolic), "limit": (limit, limit.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append(trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append(trace_data) #end of additional code return self.inline_call(simuvex.SimProcedures['libc.so.6']['memcpy'], dst_addr, src_addr, limit).ret_expr
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 r, c, i = self.state.memory.find(s, self.state.BVV(0, 8), max_str_len, max_symbolic_bytes=max_symbolic_bytes) self.max_null_index = max(i) self.state.add_constraints(*c) return r - s
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 r, c, i = self.state.memory.find(s, self.state.se.BVV(0, 8), search_len, max_symbolic_bytes=max_symbolic_bytes) # stop searching after some reasonable limit if search_len > 0x10000: raise simuvex.SimMemoryLimitError("strlen hit limit of 0x10000") self.max_null_index = max(i) self.state.add_constraints(*c) return r - s
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 = simuvex.SimProcedures['libc.so.6']['strlen'] memcpy = simuvex.SimProcedures['libc.so.6']['memcpy'] src_len = src_len if src_len is not None else self.inline_call( strlen, src_addr).ret_expr cpy_size = self.state.se.If(self.state.se.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, fd): #pylint:disable=attribute-defined-outside-init #additional code trace_data = ("fflush", {"fd": (fd, fd.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append( trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append( trace_data) #end of additional code self.argument_types = {0: SimTypeFd()} self.return_type = SimTypeLength(self.state.arch) return self.state.se.BVV(0, self.state.arch.bits)
def run(self, dst_addr, char, num): #additional code trace_data = ("memset", {"dst_addr": (dst_addr, dst_addr.symbolic), "char": (char, char.symbolic), "num": (num, num.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append(trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append(trace_data) #end of additional code char = char[7:0] self.argument_types = {0: self.ty_ptr(SimTypeTop()), 1: SimTypeInt(32, True), # ? 2: SimTypeLength(self.state.arch)} self.return_type = self.ty_ptr(SimTypeTop()) if self.state.se.symbolic(num): l.debug("symbolic length") max_size = self.state.se.min_int(num) + self.state.libc.max_buffer_size write_bytes = self.state.se.Concat(*([ char ] * max_size)) self.state.memory.store(dst_addr, write_bytes, size=num) else: max_size = self.state.se.any_int(num) if max_size == 0: return dst_addr if self.state.se.symbolic(char): l.debug("symbolic char") write_bytes = self.state.se.Concat(*([char] * max_size)) else: # Concatenating many bytes is slow, so some sort of optimization is required if char._model_concrete.value == 0: write_bytes = self.state.se.BVV(0, max_size * 8) else: rb = memset._repeat_bytes(char._model_concrete.value, max_size) write_bytes = self.state.se.BVV(rb, max_size * 8) self.state.memory.store(dst_addr, write_bytes) l.debug("memset writing %d bytes", max_size) return dst_addr
def run(self, ptr, size): self.state.add_constraints(size <= self.state.libc.max_variable_size) size_int = self.state.se.max_int(size) l.debug("Size: %d", size_int) self.state.add_constraints(size_int == size) self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop(size)) addr = self.state.libc.heap_location v = self.state.memory.load(ptr, size_int) self.state.memory.store(addr, v) self.state.libc.heap_location += size_int return addr
def run(self, dst_addr, src_addr, limit): # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) if not self.state.se.symbolic(limit): # not symbolic so we just take the value conditional_size = self.state.se.any_int(limit) else: # constraints on the limit are added during the store max_memcpy_size = self.state.libc.max_memcpy_size max_limit = self.state.se.max_int(limit) conditional_size = max(self.state.se.min_int(limit), min(max_limit, max_memcpy_size)) if max_limit > max_memcpy_size and conditional_size < max_limit: l.warning( "memcpy upper bound of %#x outside limit, limiting to %#x instead", max_limit, conditional_size) l.debug("Memcpy running with conditional_size %#x", conditional_size) if conditional_size > 0: src_mem = self.state.memory.load(src_addr, conditional_size, endness='Iend_BE') if ABSTRACT_MEMORY in self.state.options: self.state.memory.store(dst_addr, src_mem, size=conditional_size, endness='Iend_BE') else: self.state.memory.store(dst_addr, src_mem, size=limit, endness='Iend_BE') return dst_addr
def run(self, dst_addr, src_addr, limit): # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = self.ty_ptr(SimTypeTop()) if not self.state.se.symbolic(limit): if BEST_EFFORT_MEMORY_STORING in self.state.options: conditional_size = self.state.se.max_int(limit) else: conditional_size = self.state.se.any_int(limit) else: max_memcpy_size = self.state.libc.max_buffer_size conditional_size = max( self.state.se.min_int(limit), min(self.state.se.max_int(limit), max_memcpy_size)) l.debug("Memcpy running with conditional_size %d", conditional_size) if conditional_size > 0: src_mem = self.state.memory.load(src_addr, conditional_size, endness='Iend_BE') if ABSTRACT_MEMORY in self.state.options: self.state.memory.store(dst_addr, src_mem, size=conditional_size, endness='Iend_BE') else: self.state.memory.store(dst_addr, src_mem, size=limit, endness='Iend_BE') return dst_addr
def run(self, dst_addr, src_addr, limit, src_len=None): #additional code trace_data = ("strncpy", {"dist_addr": (dist_addr, dst_addr.symbolic), "src_addr": (src_addr, src_addr.symbolic), "limit": (limit, limit.symbolic), "src_len": (src_len, src_len.symbolic)}) try: self.state.procedure_data.global_variables["trace"].append(trace_data) except KeyError: self.state.procedure_data.global_variables["trace"] = [] self.state.procedure_data.global_variables["trace"].append(trace_data) #end of additional code 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 = simuvex.SimProcedures['libc.so.6']['strlen'] memcpy = simuvex.SimProcedures['libc.so.6']['memcpy'] src_len = src_len if src_len is not None else self.inline_call(strlen, src_addr).ret_expr cpy_size = self.state.se.If(self.state.se.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, a_addr, b_addr, limit, a_len=None, b_len=None): #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 = simuvex.SimProcedures['libc.so.6']['strlen'] a_strlen = a_len if a_len is not None else self.inline_call(strlen, a_addr) b_strlen = b_len if b_len is not None else self.inline_call(strlen, b_addr) 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) # 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.any_int(a_len) c_b_len = self.state.se.any_int(b_len) c_limit = self.state.se.any_int(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.any_int(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.any_int(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.any_int(a_len) == self.state.se.any_int(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.any_int(a_byte) b_conc = self.state.se.any_int(b_byte) variables |= a_byte.variables variables |= b_byte.variables 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': 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, a_addr, b_addr, limit, a_len=None, b_len=None): #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 = simuvex.SimProcedures['libc.so.6']['strlen'] a_strlen = a_len if a_len is not None else self.inline_call(strlen, a_addr) b_strlen = b_len if b_len is not None else self.inline_call(strlen, b_addr) 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) # 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): c_a_len = self.state.se.any_int(a_len) c_b_len = self.state.se.any_int(b_len) c_limit = self.state.se.any_int(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") return self.state.se.BVV(1, self.state.arch.bits, variables=variables) concrete_run = True maxlen = min(c_a_len, c_b_len, c_limit) else: if not self.state.se.symbolic(limit): c_limit = self.state.se.any_int(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: l.debug("returning equal for 0-length maximum strings") return self.state.se.BVV(0, 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 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 not self.state.se.symbolic(a_byte) and not self.state.se.symbolic(b_byte): a_conc = self.state.se.any_int(a_byte) b_conc = self.state.se.any_int(b_byte) variables |= a_byte.variables variables |= b_byte.variables if a_conc != b_conc: l.debug("... found mis-matching concrete bytes 0x%x and 0x%x", a_conc, b_conc) return self.state.se.BVV(1, self.state.arch.bits, variables=variables) else: concrete_run = False 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) # 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, dst, size, file_ptr): self.argument_types = { 2: SimTypeFd(), 0: self.ty_ptr(SimTypeArray(SimTypeChar(), size)), 1: SimTypeLength(self.state.arch) } self.return_type = self.argument_types[0] # some sensible limits for the new line search max_symbolic_bytes = self.state.libc.buf_symbolic_bytes max_str_len = self.state.libc.max_str_len # let's get the memory back for the file we're interested in and find the newline fd_offset = _IO_FILE[self.state.arch.name]['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved fp = self.state.posix.get_file(fd) pos = fp.pos mem = fp.content # if there exists a limit on the file size, let's respect that, the limit cannot be symbolic limit = max_str_len if fp.size is None else self.state.se.max_int( fp.size - pos) # limit will always be concrete, if it's zero we EOF'd if limit != 0: # XXX max_str_len is small, might not be suitable for tracing! # measure up to the newline of size - 1 r, c, i = mem.find(pos, self.state.se.BVV('\n'), limit, max_symbolic_bytes=max_symbolic_bytes) else: r = 0 c = [] # XXX: this is a HACK to determine if r is 0 because there is a newline at the first index or # if r is 0 because there cannot be any newline errored = False if not self.state.se.satisfiable(extra_constraints=(r > 0, )): errored = True if self.state.se.solution(mem.load(0, 1), self.state.se.BVV('\n')): errored = False # make sure we only read up to size - 1 read_size = self.state.se.If(size == 0, 0, size - 1) # if file can EOF (ie not completely symbolic) if fp.size is not None: read_size = self.state.se.If(limit < read_size, limit, read_size) # now if find errored then there cannot exist a newline in the file, otherwise this logic checks out if not errored: newline_d = self.state.se.If(r == 0, r, r - pos + 1) distance = self.state.se.If(read_size < newline_d, read_size, newline_d) else: distance = read_size # read in up to the newline ret = self.inline_call(simuvex.SimProcedures['libc.so.6']['read'], fd, dst, distance).ret_expr # in case there's no newline c = self.state.se.Or(ret == read_size, *c) self.state.add_constraints(c) # otherwise we take care of the newline case # now write the terminating null byte, should be placed after the newline which is also stored self.state.memory.store(dst + distance, self.state.se.BVV(0, 8)) inner_case = self.state.se.If(self.state.se.And(fp.pos == 0, ret == 0), 0, dst) return self.state.se.If(size == 0, 0, inner_case)
def run(self, s1_addr, s2_addr, n): # TODO: look into smarter types here self.argument_types = { 0: self.ty_ptr(SimTypeTop()), 1: self.ty_ptr(SimTypeTop()), 2: SimTypeLength(self.state.arch) } self.return_type = SimTypeInt(32, True) max_memcmp_size = self.state.libc.max_buffer_size definite_size = self.state.se.min_int(n) conditional_s1_start = s1_addr + definite_size conditional_s2_start = s2_addr + definite_size if self.state.se.symbolic(n): conditional_size = int(max(max_memcmp_size - definite_size, 0)) else: conditional_size = 0 l.debug("Definite size %s and conditional size: %s", definite_size, conditional_size) if definite_size > 0: s1_part = self.state.memory.load(s1_addr, definite_size, endness='Iend_BE') s2_part = self.state.memory.load(s2_addr, definite_size, endness='Iend_BE') cases = [[ s1_part == s2_part, self.state.se.BVV(0, self.state.arch.bits) ], [ self.state.se.ULT(s1_part, s2_part), self.state.se.BVV(-1, self.state.arch.bits) ], [ self.state.se.UGT(s1_part, s2_part), self.state.se.BVV(1, self.state.arch.bits) ]] definite_answer = self.state.se.ite_cases(cases, 2) constraint = self.state.se.Or(*[c for c, _ in cases]) self.state.add_constraints(constraint) l.debug("Created definite answer: %s", definite_answer) l.debug("Created constraint: %s", constraint) l.debug("... crom cases: %s", cases) else: definite_answer = self.state.se.BVV(0, self.state.arch.bits) if not self.state.se.symbolic( definite_answer) and self.state.se.any_int( definite_answer) != 0: return definite_answer if conditional_size > 0: s1_all = self.state.memory.load(conditional_s1_start, conditional_size, endness='Iend_BE') s2_all = self.state.memory.load(conditional_s2_start, conditional_size, endness='Iend_BE') conditional_rets = {0: definite_answer} for byte, bit in zip(range(conditional_size), range(conditional_size * 8, 0, -8)): s1_part = s1_all[conditional_size * 8 - 1:bit - 8] s2_part = s2_all[conditional_size * 8 - 1:bit - 8] cases = [[ s1_part == s2_part, self.state.se.BVV(0, self.state.arch.bits) ], [ self.state.se.ULT(s1_part, s2_part), self.state.se.BVV(-1, self.state.arch.bits) ], [ self.state.se.UGT(s1_part, s2_part), self.state.se.BVV(1, self.state.arch.bits) ]] conditional_rets[byte + 1] = self.state.se.ite_cases(cases, 0) self.state.add_constraints( self.state.se.Or(*[c for c, _ in cases])) ret_expr = self.state.se.ite_dict(n - definite_size, conditional_rets, 2) self.state.add_constraints( self.state.se.Or( *[n - definite_size == c for c in conditional_rets.keys()])) return ret_expr else: return definite_answer