예제 #1
0
def validate_address_argument(pid,
                              syscall_object,
                              trace_arg,
                              exec_arg,
                              params=None,
                              except_on_mismatch=True):
    logging.debug(
        'Validating address argument (trace position: %d '
        'execution position: %d)', trace_arg, exec_arg)
    if not params:
        arg = cint.peek_register(pid, _pos_to_reg(exec_arg))
    else:
        arg = params[exec_arg]
    # Convert signed interpretation from peek register to unsigned
    arg = arg & 0xffffffff
    if syscall_object.args[trace_arg].value == 'NULL':
        arg_from_trace = 0
    else:
        arg_from_trace = int(syscall_object.args[trace_arg].value, 16)
    if arg_from_trace != arg:
        message = 'Argument value at trace position: {}, ' \
                  'execution position: {} from execution  ({}) ' \
                  'differs argument value from trace ({})' \
                  .format(trace_arg, exec_arg, arg, arg_from_trace)
        _except_or_warn(message, except_on_mismatch)
예제 #2
0
def validate_integer_argument(pid,
                              syscall_object,
                              trace_arg,
                              exec_arg,
                              params=None,
                              except_on_mismatch=True):
    logging.debug(
        'Validating integer argument (trace position: %d '
        'execution position: %d)', trace_arg, exec_arg)
    # EAX is the system call number
    POS_TO_REG = {
        0: cint.EBX,
        1: cint.ECX,
        2: cint.EDX,
        3: cint.ESI,
        4: cint.EDI
    }
    if not params:
        arg = cint.peek_register(pid, POS_TO_REG[exec_arg])
    else:
        arg = params[exec_arg]
    arg_from_trace = int(syscall_object.args[trace_arg].value)
    logging.debug('Argument from execution: %d', arg)
    logging.debug('Argument from trace: %d', arg_from_trace)
    # Check to make sure everything is the same
    # Decide if this is a system call we want to replay
    if arg_from_trace != arg:
        message = 'Argument value at trace position: {}, ' \
                  'execution position: {} from execution  ({}) ' \
                  'differs argument value from trace ({})' \
                  .format(trace_arg, exec_arg, arg, arg_from_trace)
        _except_or_warn(message, except_on_mismatch)
예제 #3
0
def subcall_return_success_handler(syscall_id, syscall_object, pid):
    '''This probably should be here.  This badly named handler simply takes a
    socket subcall situation, validates the file descriptor involved, no-ops
    the call, and applies the return conditions from the system call object.
    For several socket calls, this is all that's required so we don't need to
    write individual handlers that all do the same thing.

    TODO: Move this to generic_handlers module
    TODO: Replace parameter extraction with call to
    extract_socketcall_parameters

    '''
    logging.debug('Entering subcall return success handler')
    if syscall_object.ret[0] == -1:
        logging.debug('Handling unsuccessful call')
    else:
        logging.debug('Handling successful call')
        ecx = cint.peek_register(pid, cint.ECX)
        logging.debug('Extracting parameters from address %s', ecx)
        params = extract_socketcall_parameters(pid, ecx, 1)
        fd = params[0]
        fd_from_trace = syscall_object.args[0].value
        logging.debug('File descriptor from execution: %s', fd)
        logging.debug('File descriptor from trace: %s', fd_from_trace)
        if fd != int(fd_from_trace):
            raise ReplayDeltaError(
                'File descriptor from execution ({}) '
                'differs from file descriptor from trace'.format(
                    fd, fd_from_trace))
    noop_current_syscall(pid)
    apply_return_conditions(pid, syscall_object)
예제 #4
0
def noop_current_syscall(pid):
    """
  <Purpose>
    No-op' out the current system call the child process is trying to
    execute by replacing it with a call to getpid() (a system call that takes
    no parameters and has no side effects).  Then, configure ptrace to allow
    the child process to run until it exits this call to getpid() and tell our
    own process to wait for this notification.  Set the entering flip-flip flag
    to to show that we are exiting a system call (because the child application
    now believes the system call it tried to make completed successfully).

    When this function is called from a handler, the handler needs to deal with
    setting up the output buffers and return value that the system call would
    have done itself had we allowed it to run normally.

    Note: This function leaves the child process in a state of waiting at the
    point just before execution returns to userspace code.

  <Returns>
    Nothing

  """

    logging.debug('Nooping the current system call in pid: %s', pid)
    # Transform the current system call in the child process into a call to
    # getpid() by poking 20 into ORIG_EAX
    cint.poke_register(pid, cint.ORIG_EAX, 20)
    # Tell ptrace we want the child process to stop at the next system call
    # event and restart its execution.
    cint.syscall(pid, 0)
    # Have our process monitor the execution of the child process until it
    # receives a system call event notification.  The notification we receive
    # at this point (if all goes according to plan) is the EXIT notification
    # for the getpid() call we forced the application to make.
    next_syscall()
    # Take a look at the current system call (i.e. the one that triggered the
    # notification we just received from ptrace).  It should be getpid().  If
    # it isnt, something has gone horribly wrong and we must bail out.
    skipping = cint.peek_register(pid, cint.ORIG_EAX)
    if skipping != 20:
        raise Exception(
            'Nooping did not result in getpid exit. Got {}'.format(skipping))
    # Because we are exiting the getpid() call so we need to set the entering
    # flip-flop flag to reflect this.  This allows later code (in main.py) to
    # set it BACK to entering before we begin processing the entry for the next
    # system call.
    cint.entering_syscall = False
예제 #5
0
def validate_return_value(pid, syscall_object, except_on_mismatch=True):
    ret_from_execution = cint.peek_register(pid, cint.EAX)
    ret_from_trace = cleanup_return_value(syscall_object.ret[0])
    if syscall_object.ret[1] is not None:
        logging.debug('We have an errno code')
        logging.debug('Errno code: %s', syscall_object.ret[1])
        errno_retval = -1 * ERRNO_CODES[syscall_object.ret[1]]
        logging.debug('Errno ret_val: %d', errno_retval)
        if errno_retval == ret_from_execution:
            return
    if ret_from_execution < 0:
        ret_from_execution &= 0xffffffff
    if ret_from_execution != ret_from_trace:
        message = 'Return value from execution ({}, {:02x}) differs ' \
                  'from return value from trace ({}, {:02x})' \
                  .format(ret_from_execution,
                          ret_from_execution,
                          ret_from_trace,
                          ret_from_trace)
    _except_or_warn(message, except_on_mismatch)
예제 #6
0
def check_return_value_exit_handler(syscall_id, syscall_object, pid):
    """
  <Purpose>
    Generic handler that works with
    check_return_value_entry_handler to check whether the return value from
    allowing a system call to pass through matches the system call recorded
    for the same system call in syscall_object.  This is where the actual
    checking happens
    Checks:
    The return value from syscall execution

    Sets:
    Nothing
  <Returns>
    None

  """
    logging.debug('check_return_value exit handler')
    ret_from_execution = syscallreplay.peek_register(pid, syscallreplay.EAX)
    ret_from_trace = util.cleanup_return_value(syscall_object.ret[0])
    logging.debug('Return value from execution %x', ret_from_execution)
    logging.debug('Return value from trace %x', ret_from_trace)
    # HACK HACK HACK
    if syscall_object.ret[1] is not None:
        logging.debug('We have an errno code')
        logging.debug('Errno code: %s', syscall_object.ret[1])
        errno_retval = -1 * errno_dict.ERRNO_CODES[syscall_object.ret[1]]
        logging.debug('Errno ret_val: %d', errno_retval)
        if errno_retval == ret_from_execution:
            return
    if ret_from_execution < 0:
        ret_from_execution &= 0xffffffff
    if ret_from_execution != ret_from_trace:
        raise util.ReplayDeltaError('Return value from execution ({}, {:02x}) '
                                    'differs from return value from trace '
                                    '({}, {:02x})'.format(
                                        ret_from_execution, ret_from_execution,
                                        ret_from_trace, ret_from_trace))