def run(self, f): # Get FILE struct io_file_data = io_file_data_for_arch(self.state.arch) # Get the file descriptor from FILE struct result = self.state.mem[f + io_file_data['fd']].int.resolved return result.sign_extend(self.arch.bits - len(result))
def run(self, p_addr, m_addr): strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, p_addr) m_strlen = self.inline_call(strlen, m_addr) p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness='Iend_BE') m_expr = self.state.memory.load(m_addr, m_strlen.max_null_index, endness='Iend_BE') path = self.state.solver.eval(p_expr, cast_to=bytes) mode = self.state.solver.eval(m_expr, cast_to=bytes) # TODO: handle append fd = self.state.posix.open(path, mode_to_flag(mode)) if fd is None: # if open failed return NULL return 0 else: # Allocate a FILE struct in heap malloc = angr.SIM_PROCEDURES['libc']['malloc'] io_file_data = io_file_data_for_arch(self.state.arch) file_struct_ptr = self.inline_call(malloc, io_file_data['size']).ret_expr # Write the fd fd_bvv = self.state.solver.BVV(fd, 4 * 8) # int self.state.memory.store(file_struct_ptr + io_file_data['fd'], fd_bvv, endness=self.state.arch.memory_endness) return file_struct_ptr
def run(self, p_addr, m_addr): strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, p_addr) m_strlen = self.inline_call(strlen, m_addr) p_expr = self.state.memory.load(p_addr, p_strlen.max_null_index, endness='Iend_BE') m_expr = self.state.memory.load(m_addr, m_strlen.max_null_index, endness='Iend_BE') path = self.state.solver.eval(p_expr, cast_to=bytes) mode = self.state.solver.eval(m_expr, cast_to=bytes) # TODO: handle append fd = self.state.posix.open(path, mode_to_flag(mode)) if fd is None: # if open failed return NULL return 0 else: # Allocate a FILE struct in heap malloc = angr.SIM_PROCEDURES['libc']['malloc'] io_file_data = io_file_data_for_arch(self.state.arch) file_struct_ptr = self.inline_call(malloc, io_file_data['size']).ret_expr # Write the fd fd_bvv = self.state.solver.BVV(fd, 4 * 8) # int self.state.memory.store(file_struct_ptr + io_file_data['fd'], fd_bvv, endness=self.state.arch.memory_endness) return file_struct_ptr
def run(self, fd_int, m_addr): #pylint:disable=unused-variable strlen = angr.SIM_PROCEDURES['libc']['strlen'] m_strlen = self.inline_call(strlen, m_addr) m_expr = self.state.memory.load(m_addr, m_strlen.max_null_index, endness='Iend_BE') mode = self.state.solver.eval(m_expr, cast_to=bytes) # TODO: handle append and other mode subtleties fd = self.state.solver.eval(fd_int) if fd not in self.state.posix.fd: # if file descriptor not found return NULL return 0 else: # Allocate a FILE struct in heap malloc = angr.SIM_PROCEDURES['libc']['malloc'] io_file_data = io_file_data_for_arch(self.state.arch) file_struct_ptr = self.inline_call(malloc, io_file_data['size']).ret_expr # Write the fd fd_bvv = self.state.solver.BVV(fd, 4 * 8) # int self.state.memory.store(file_struct_ptr + io_file_data['fd'], fd_bvv, endness=self.state.arch.memory_endness) return file_struct_ptr
def run(self, src, size, nmemb, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 return simfd.write(src, size*nmemb)
def run(self, file_ptr): # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.concrete simfd = self.state.posix.get_fd(fileno) if simfd is None: return None return self.state.solver.If(simfd.eof(), self.state.solver.BVV(1, self.state.arch.bits), 0)
def run(self, file_ptr) -> claripy.BVV: fd_offset = io_file_data_for_arch(self.state.arch)["fd"] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return None # FIXME: no error concept in SimFile return 0
def run(self, dst, size, file_ptr): # let's get the memory back for the file we're interested in and find the newline fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None or dst == 0 or size <= 0: #TODO: errno should be set to EINVAL return 0 # case 0: empty read if self.state.solver.is_true(size == 0): return 0 # case 1: the data is concrete. we should read it a byte at a time since we can't seek for # the newline and we don't have any notion of buffering in-memory elif simfd.read_storage.concrete and not size.symbolic: size = self.state.solver.eval(size) count = 1 # we return immediatly if there are no characters to read, so we start ahead data, real_size = simfd.read_data(1) if real_size == 0: return 0 self.state.memory.store(dst, data) while count < size - 1: data, real_size = simfd.read_data(1) if self.state.solver.is_true(real_size == 0): break self.state.memory.store(dst + count, data) count += 1 if self.state.solver.is_true(data == b'\n'): break self.state.memory.store(dst + count, b'\0') return dst # case 2: the data is symbolic, the newline could be anywhere. Read the maximum number of bytes # (SHORT_READS should take care of the variable length) and add a constraint to assert the # newline nonsense. # caveat: there could also be no newline and the file could EOF. else: data, real_size = simfd.read_data(size - 1) for i, byte in enumerate(data.chop(8)): self.state.solver.add( self.state.solver.If( i + 1 != real_size, byte != b'\n', # if not last byte returned, not newline self.state.solver. Or( # otherwise one of the following must be true: i + 2 == size, # - we ran out of space, or simfd.eof(), # - the file is at EOF, or byte == b'\n' # - it is a newline ))) self.state.memory.store(dst, data, size=real_size) self.state.memory.store(dst + real_size, b'\0') return dst
def run(self, c, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 simfd.write_data(c[7:0]) return c & 0xff
def run(self, c, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 simfd.write_data(c[7:0]) return c & 0xff
def run(self, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 pos = simfd.tell() if pos is None: return -1 return pos
def run(self, f): self.argument_types = {0: self.ty_ptr(SimTypeTop())} self.return_type = SimTypeFd() # Get FILE struct io_file_data = io_file_data_for_arch(self.state.arch) # Get the file descriptor from FILE struct result = self.state.mem[f + io_file_data['fd']].int.resolved return result.sign_extend(self.arch.bits - len(result))
def run(self, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 pos = simfd.tell() if pos is None: return -1 return pos
def run(self, dst, size, nm, file_ptr): # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 ret = simfd.read(dst, size * nm) return self.state.solver.If(self.state.solver.Or(size == 0, nm == 0), 0, ret // size)
def run(self, c, file_ptr): # TODO handle errors # TODO THIS DOESN'T WORK IN ANYTHING BUT THE TYPICAL CASE fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.concrete if hasattr(self.state.posix.fd[fileno], '_read_pos'): self.state.posix.fd[fileno]._read_pos -= 1 else: self.state.posix.fd[fileno]._pos -= 1 return c & 0xff
def run(self, str_addr, file_ptr): # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, str_addr) simfd.write(str_addr, p_strlen.max_null_index) return 1
def run(self, file_ptr, fmt): # pylint:disable=unused-argument # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 fmt_str = self._parse(fmt) items = fmt_str.interpret(self.va_arg, simfd=simfd) return items
def run(self, fd_p): # Resolve file descriptor fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[fd_p + fd_offset:].int.resolved # TODO: use a procedure that's not a linux syscall sys_close = angr.SIM_PROCEDURES['posix']['close'] # Call system close and return retval = self.inline_call(sys_close, fileno).ret_expr return retval
def run(self, str_addr, file_ptr): # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 strlen = angr.SIM_PROCEDURES['libc']['strlen'] p_strlen = self.inline_call(strlen, str_addr) simfd.write(str_addr, p_strlen.max_null_index) return 1
def run(self, file_ptr): # TODO handle errors fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 fmt_str = self._parse(1) items = fmt_str.interpret(2, self.arg, simfd=simfd) return items
def run(self, fd_p): # Resolve file descriptor fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[fd_p + fd_offset:].int.resolved # TODO: use a procedure that's not a linux syscall sys_close = angr.SIM_PROCEDURES['posix']['close'] # Call system close and return retval = self.inline_call(sys_close, fileno).ret_expr return retval
def run(self, file_ptr): fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 # The format str is at index 1 fmt_str = self._parse(1) out_str = fmt_str.replace(2, self.arg) simfd.write_data(out_str, out_str.size() // 8) return out_str.size() // 8
def run(self, file_ptr, fmt): # pylint:disable=unused-argument fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fileno = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fileno) if simfd is None: return -1 # The format str is at index 1 fmt_str = self._parse(1) out_str = fmt_str.replace(2, self.arg) simfd.write_data(out_str, out_str.size() // 8) return out_str.size() // 8
def run(self, dst, size, file_ptr): # let's get the memory back for the file we're interested in and find the newline fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 # case 0: empty read if self.state.solver.is_true(size == 0): return 0 # case 1: the data is concrete. we should read it a byte at a time since we can't seek for # the newline and we don't have any notion of buffering in-memory elif simfd.read_storage.concrete and not size.symbolic: size = self.state.solver.eval(size) count = 0 while count < size - 1: data, real_size = simfd.read_data(1) if self.state.solver.is_true(real_size == 0): break self.state.memory.store(dst + count, data) count += 1 if self.state.solver.is_true(data == b'\n'): break self.state.memory.store(dst + count, b'\0') return count # case 2: the data is symbolic, the newline could be anywhere. Read the maximum number of bytes # (SHORT_READS should take care of the variable length) and add a constraint to assert the # newline nonsense. # caveat: there could also be no newline and the file could EOF. else: data, real_size = simfd.read_data(size-1) for i, byte in enumerate(data.chop(8)): self.state.solver.add(self.state.solver.If( i+1 != real_size, byte != b'\n', # if not last byte returned, not newline self.state.solver.Or( # otherwise one of the following must be true: i+2 == size, # - we ran out of space, or simfd.eof(), # - the file is at EOF, or byte == b'\n' # - it is a newline ))) self.state.memory.store(dst, data, size=real_size) self.state.memory.store(dst+real_size, b'\0') return real_size
def run(self, file_ptr, offset, whence): # TODO: Support symbolic file_ptr, offset, and whence # Make sure whence can only be one of the three values: SEEK_SET(0), SEEK_CUR(1), and SEEK_END(2) try: whence = self.state.solver.eval_one(whence) except SimSolverError: raise angr.SimProcedureError('multi-valued "whence" is not supported in fseek.') try: whence = {0: 'start', 1: 'current', 2: 'end'}[whence] except KeyError: return -1 # EINVAL fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 return self.state.solver.If(simfd.seek(offset, whence), self.state.solver.BVV(0, self.state.arch.bits), -1)
def run(self, file_ptr, offset, whence): # TODO: Support symbolic file_ptr, offset, and whence # Make sure whence can only be one of the three values: SEEK_SET(0), SEEK_CUR(1), and SEEK_END(2) try: whence = self.state.solver.eval_one(whence) except SimSolverError: raise angr.SimProcedureError('multi-valued "whence" is not supported in fseek.') try: whence = {0: 'start', 1: 'current', 2: 'end'}[whence] except KeyError: return -1 # EINVAL fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 return self.state.solver.If(simfd.seek(offset, whence), self.state.solver.BVV(0, self.state.arch.bits), -1)
def run(self, line_ptrptr, len_ptr, delim, file_ptr): # let's get the memory back for the file we're interested in and find the delimiter fd_offset = io_file_data_for_arch(self.state.arch)['fd'] fd = self.state.mem[file_ptr + fd_offset:].int.resolved simfd = self.state.posix.get_fd(fd) if simfd is None: return -1 # symbolic delimiters will make this tricky if delim.symbolic: raise angr.SimProcedureError( "I don't know how to handle a symbolic delimiter") # case 1: the data is concrete. we should read it a byte at a time since we can't seek for # the newline and we don't have any notion of buffering in-memory if simfd.read_storage.concrete: realloc = angr.SIM_PROCEDURES['libc']['realloc'] # #dereference the destination buffer line_ptr = self.state.memory.load(line_ptrptr, 8) size = 120 # im just always going to realloc and restart at size = 120, regardless of if a proper size buffer exists. # this doesn't match the exact behavior of get delim, but is the easiest way to ignore symbolic sizes. dst = self.inline_call(realloc, line_ptr, size).ret_expr count = 0 while True: data, real_size = simfd.read_data(1) if self.state.solver.is_true(real_size == 0): break self.state.memory.store(dst + count, data) count += 1 if count == size: size = count + size + 1 dst = self.inline_call(realloc, dst, size).ret_expr if self.state.solver.is_true(data == delim): break self.state.memory.store(dst + count, b'\0') self.state.memory.store(len_ptr, count) self.state.memory.store(line_ptrptr, dst) return count # case 2: the data is symbolic, the delimiter could be anywhere. Read some maximum number of bytes # and add a constraint to assert the delimiter nonsense. # caveat: there could also be no delimiter and the file could EOF. else: # Just a guess as to a good value for a max size size = 1024 data, real_size = simfd.read_data(size - 1) delim_byte = chr(self.state.solver.eval(delim)) for i, byte in enumerate(data.chop(8)): self.state.add_constraints( self.state.solver.If( i + 1 != real_size, byte != delim_byte, # if not last byte returned, not newline self.state.solver. Or( # otherwise one of the following must be true: i + 2 == size, # - we ran out of space, or simfd.eof(), # - the file is at EOF, or byte == delim_byte # - it is a newline ))) malloc = angr.SIM_PROCEDURES['libc']['malloc'] dst = self.inline_call(malloc, real_size) self.state.memory.store(dst, data, size=real_size) self.state.memory.store(dst + real_size, b'\0') self.state.memory.store(len_ptr, real_size) self.state.memory.store(line_ptrptr, dst).ret_expr return real_size
def run(self, f): # Get FILE struct io_file_data = io_file_data_for_arch(self.state.arch) # Get the file descriptor from FILE struct return self.state.mem[f + io_file_data['fd']].int.resolved