Esempio n. 1
0
    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))
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
 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)
Esempio n. 6
0
 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)
Esempio n. 7
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
Esempio n. 8
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
Esempio n. 9
0
    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
Esempio n. 10
0
    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
Esempio n. 11
0
 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
Esempio n. 12
0
    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))
Esempio n. 13
0
 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
Esempio n. 14
0
    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)
Esempio n. 15
0
    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
Esempio n. 16
0
    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
Esempio n. 17
0
    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
Esempio n. 18
0
    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
Esempio n. 19
0
    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
Esempio n. 20
0
    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
Esempio n. 21
0
    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
Esempio n. 22
0
    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
Esempio n. 23
0
    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
Esempio n. 24
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:
            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
Esempio n. 25
0
    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)
Esempio n. 26
0
    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)
Esempio n. 27
0
    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
Esempio n. 28
0
    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