Ejemplo n.º 1
0
 def _alter_arg(number, arg, saved_arg, pid=pid):
     if not saved_arg:
         saved_arg = ptrace.peekuser(pid, 4 * number)
     if arg != saved_arg:
         if debug():
             print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * number, arg)
         ptrace.pokeuser(pid, 4 * number, arg)
         return (number, saved_arg)
Ejemplo n.º 2
0
 def _alter_arg(number, arg, saved_arg, pid=pid):
     if not saved_arg:
         saved_arg = ptrace.peekuser(pid, 4 * number)
     if arg != saved_arg:
         if debug():
             print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * number, arg)
         ptrace.pokeuser(pid, 4 * number, arg)
         return (number, saved_arg)
Ejemplo n.º 3
0
def force_syscall(pid, scno, p1=0, p2=0, p3=0, p4=0, p5=0, p6=0):
    registers = peek_args(pid, 6)
    eip = ptrace.peekuser(pid, EIP)
    eax = ptrace.peekuser(pid, EAX)
    ptrace.pokeuser(pid, EIP, eip - 2)
    ptrace.pokeuser(pid, EAX, scno)  # Select new scno and point eip to syscall
    poke_args(pid, 6, [p1, p2, p3, p4, p5, p6])
    ptrace.syscall(pid, 0)  # We make it return to userland and do syscal
    wpid, status = os.waitpid(pid, wait_flags)
    assert pid == wpid
    ptrace.syscall(pid, 0)  # Kernel stops us before syscall is done
    wpid, status = os.waitpid(pid, wait_flags)
    if wpid != pid:
        print "problem: other syscall stopped woke up /2: ", pid, " != ", wpid
    assert pid == wpid  # Kernel stops us when syscall is done
    res = ptrace.peekuser(pid, EAX)  # We get the syscall result
    ptrace.pokeuser(pid, EAX, eax)  # and then mimic like nothing happened
    poke_args(pid, 6, registers)
    return res
Ejemplo n.º 4
0
def force_syscall(pid, scno, p1=0, p2=0, p3=0, p4=0, p5=0, p6=0):
    registers = peek_args(pid, 6)
    eip = ptrace.peekuser(pid, EIP)
    eax = ptrace.peekuser(pid, EAX)
    ptrace.pokeuser(pid, EIP, eip - 2)
    ptrace.pokeuser(pid, EAX, scno)  # Select new scno and point eip to syscall
    poke_args(pid, 6, [p1, p2, p3, p4, p5, p6])
    ptrace.syscall(pid, 0)  # We make it return to userland and do syscal
    wpid, status = os.waitpid(pid, wait_flags)
    assert pid == wpid
    ptrace.syscall(pid, 0)  # Kernel stops us before syscall is done
    wpid, status = os.waitpid(pid, wait_flags)
    if wpid != pid:
        print "problem: other syscall stopped woke up /2: ", pid, " != ", wpid
    assert pid == wpid  # Kernel stops us when syscall is done
    res = ptrace.peekuser(pid, EAX)  # We get the syscall result
    ptrace.pokeuser(pid, EAX, eax)  # and then mimic like nothing happened
    poke_args(pid, 6, registers)
    return res
Ejemplo n.º 5
0
def trace_syscall_after(pid, flags, tricklist, call, eax):
    result = eax
    state = flags["state"]
    call_changes = flags["call_changes"]
    # del flags['call_changes']		 # ?

    # FIX: copy/reverse slow?
    tricklist = tricklist[:]

    # do callafters for tricks we did callbefores on, in reverse order,
    # minus the annulled trick (if any)
    if flags.has_key("annul"):
        result, annultrick = flags["annul"]
        assert isinstance(result, types.IntType), "oops: waitsuspend not cleared?"
        del flags["annul"]
        call = call_changes[annultrick]
        while tricklist and tricklist.pop()[0] != annultrick:
            pass
    elif flags.has_key("sigreturn"):
        # we have to do this because ORIG_EAX somehow gets stomped by the
        # sigreturn calls.  maybe this is a kernel bug?
        call = flags["sigreturn"]
        del flags["sigreturn"]
    tricklist.reverse()

    memory = getMemory(pid)

    for trick, callmask, signalmask in tricklist:
        call = call_changes.get(trick, call)
        if (not callmask or callmask.has_key(call)) and trick.is_enabled(pid):
            r = trick.callafter(pid, call, result, state.get(trick))
            if r != None:
                result = r
            memory.pop(trick)

    assert memory.empty()  # all momentary changes got popped

    if result != eax:
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, EAX, result)
        ptrace.pokeuser(pid, EAX, result)

        # undo any changes to child's args made on entry
        # XXX: does this go here?
    for n, arg in flags.get("args_delta", []):
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * n, arg)
        ptrace.pokeuser(pid, 4 * n, arg)
    call_save = flags.get("call_delta", -1)
    if call_save >= 0:
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, call_save)
        ptrace.pokeuser(pid, ORIG_EAX, call_save)

        # could continue child hereabouts
    ptrace.syscall(pid, 0)

    if flags.has_key("call_delta"):
        del flags["call_delta"]
    if flags.has_key("args_delta"):
        del flags["args_delta"]
    del flags["insyscall"]
Ejemplo n.º 6
0
def trace_syscall_before(pid, flags, tricklist, call, scno, sysent):
    nargs = sysent[syscallmap.NARGS]
    args = peek_args(pid, nargs)

    call_save = call
    args_save = args[:]
    call_changes = {}

    state = {}
    for trick, callmask, signalmask in tricklist:
        if (not callmask or callmask.has_key(call)) and trick.is_enabled(pid):
            r = trick.callbefore(pid, call, args)
            # r is None or (state, result, call, args)
            if r:
                assert len(r) == 4, "callbefore must return None or a 4-tuple"
                if r[1] != None:
                    # annul the call
                    call_changes[trick] = call
                    call = _badcall
                    args = []
                    flags["annul"] = (r[1], trick)
                    break
                if r[0] != None:
                    state[trick] = r[0]
                if r[2] != None:
                    call_changes[trick] = call
                    call = r[2]
                    assert isinstance(call, types.StringType)
                if r[3] != None:
                    args = r[3]
                    assert len(args) <= 6, "kernel doesn't support 7+ args?"

                # STATE at this point ?
                # call_changes, args, args_save, scno, call, call_save, state, ???

    flags["call_changes"] = call_changes

    # XXX: maybe faster to just brute force args rather than this careful
    # delta stuff?

    # make any necessary changes to child's args, saving undo info
    # (XXX: hmm, is this actually better than the iterative version?)
    def _alter_arg(number, arg, saved_arg, pid=pid):
        if not saved_arg:
            saved_arg = ptrace.peekuser(pid, 4 * number)
        if arg != saved_arg:
            if debug():
                print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * number, arg)
            ptrace.pokeuser(pid, 4 * number, arg)
            return (number, saved_arg)

    n = len(args)
    args_delta = filter(None, map(_alter_arg, range(n), args, args_save[:n]))
    if args_delta:
        flags["args_delta"] = args_delta

    if call == "sigreturn" or call == "rt_sigreturn":
        flags["sigreturn"] = call

    if call != call_save:
        if isinstance(call, types.StringType):
            callno = syscallmap.lookup_number(call)
        else:
            callno = call

        try:
            if debug():
                print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, callno)
            ptrace.pokeuser(pid, ORIG_EAX, callno)
            flags["call_delta"] = scno
        except OSError, e:
            # FIX: do something better here
            sys.exit("panic: call alter failed in trick %s (%s)" % (trick, e))
Ejemplo n.º 7
0
def poke_args(pid, nargs, args):
    assert nargs <= 6, "kernel doesn't support 7+ args?"
    for i in range(nargs):
        ptrace.pokeuser(pid, 4 * i, args[i])
Ejemplo n.º 8
0
_skipcallafter = {}


def set_skipcallafter(pid):
    global _skipcallafter
    _skipcallafter[pid] = 1


def hard_kill(pid):
    # FIX: isn't this a race?  don't we need to wait on the child?
    try:
        poke_args(pid, 6, [0, 0, 0, 0, 0, 0])
    except OSError, e:
        print "warning: attempt to annul last syscall by zapping args failed" " (pid=%s, error=%s)" % (pid, e)
    try:
        ptrace.pokeuser(pid, ORIG_EAX, _badcall)
    except OSError, e:
        print "warning: attempt to annul last syscall" " (pid=%s, error=%s)" % (pid, e)
    try:
        ptrace.kill(pid)
    except OSError, e:
        print "warning: attempt to ptrace.kill process failed" " (pid=%s, error=%s)" % (pid, e)
    except:
        # XXX: should we really catch this?  we shouldn't be absorbing
        # arbitrary exceptions; this will cause trouble
        print "warning: attempt to ptrace.kill process failed strangely" " (pid=%s, error=%s)" % (pid, e)
        raise

    try:
        # SIGKILL isn't delivered until completion of the current syscall; this
        # function tries to abort the current syscall before killing the child.
Ejemplo n.º 9
0
 def callafter(self, pid, call, result, state):
     v = ptrace.peekuser(pid, self.options['offset'])
     print '[%s] found %s at offset %s' % (pid, v, self.options['offset'])
     print '[%s] restoring %s at offset %s' % (pid, state,
                                               self.options['offset'])
     ptrace.pokeuser(pid, self.options['offset'], state)
Ejemplo n.º 10
0
 def callbefore(self, pid, call, args):
     v = ptrace.peekuser(pid, self.options['offset'])
     print '[%s] poking %s at offset %s' % (pid, self.options['data'],
                                            self.options['offset'])
     ptrace.pokeuser(pid, self.options['offset'], self.options['data'])
     return (v, None, None, None)
Ejemplo n.º 11
0
 def callafter(self, pid, call, result, state):
     v = ptrace.peekuser(pid, self.options['offset'])
     print '[%s] found %s at offset %s' % (pid, v, self.options['offset'])
     print '[%s] restoring %s at offset %s' % (pid, state, self.options['offset'])
     ptrace.pokeuser(pid, self.options['offset'], state)
Ejemplo n.º 12
0
 def callbefore(self, pid, call, args):
     v = ptrace.peekuser(pid, self.options['offset'])
     print '[%s] poking %s at offset %s' % (pid, self.options['data'], self.options['offset'])
     ptrace.pokeuser(pid, self.options['offset'], self.options['data'])
     return (v, None, None, None)
Ejemplo n.º 13
0
def trace_syscall_after(pid, flags, tricklist, call, eax):
    result = eax
    state = flags['state']
    call_changes = flags['call_changes']
    #del flags['call_changes']		 # ?

    # FIX: copy/reverse slow?
    tricklist = tricklist[:]

    # do callafters for tricks we did callbefores on, in reverse order,
    # minus the annulled trick (if any)
    if flags.has_key('annul'):
        result, annultrick = flags['annul']
        assert isinstance(result,
                          types.IntType), "oops: waitsuspend not cleared?"
        del flags['annul']
        call = call_changes[annultrick]
        while tricklist and tricklist.pop()[0] != annultrick:
            pass
    elif flags.has_key('sigreturn'):
        # we have to do this because ORIG_EAX somehow gets stomped by the
        # sigreturn calls.  maybe this is a kernel bug?
        call = flags['sigreturn']
        del flags['sigreturn']
    tricklist.reverse()

    memory = getMemory(pid)

    for trick, callmask, signalmask in tricklist:
        call = call_changes.get(trick, call)
        if (not callmask or callmask.has_key(call)) \
                                         and trick.is_enabled(pid):
            r = trick.callafter(pid, call, result, state.get(trick))
            if r != None:
                result = r
            memory.pop(trick)

    assert memory.empty()  # all momentary changes got popped

    if result != eax:
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, EAX, result)
        ptrace.pokeuser(pid, EAX, result)

    # undo any changes to child's args made on entry
    # XXX: does this go here?
    for n, arg in flags.get('args_delta', []):
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * n, arg)
        ptrace.pokeuser(pid, 4 * n, arg)
    call_save = flags.get('call_delta', -1)
    if call_save >= 0:
        if debug():
            print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, call_save)
        ptrace.pokeuser(pid, ORIG_EAX, call_save)

    # could continue child hereabouts
    ptrace.syscall(pid, 0)

    if flags.has_key('call_delta'):
        del flags['call_delta']
    if flags.has_key('args_delta'):
        del flags['args_delta']
    del flags['insyscall']
Ejemplo n.º 14
0
def trace_syscall_before(pid, flags, tricklist, call, scno, sysent):
    nargs = sysent[syscallmap.NARGS]
    args = peek_args(pid, nargs)

    call_save = call
    args_save = args[:]
    call_changes = {}

    state = {}
    for trick, callmask, signalmask in tricklist:
        if (not callmask or callmask.has_key(call)) \
                                         and trick.is_enabled(pid):
            r = trick.callbefore(pid, call, args)
            # r is None or (state, result, call, args)
            if r:
                assert len(r) == 4, "callbefore must return None or a 4-tuple"
                if r[1] != None:
                    # annul the call
                    call_changes[trick] = call
                    call = _badcall
                    args = []
                    flags['annul'] = (r[1], trick)
                    break
                if r[0] != None:
                    state[trick] = r[0]
                if r[2] != None:
                    call_changes[trick] = call
                    call = r[2]
                    assert isinstance(call, types.StringType)
                if r[3] != None:
                    args = r[3]
                    assert len(args) <= 6, "kernel doesn't support 7+ args?"

    # STATE at this point ?
    # call_changes, args, args_save, scno, call, call_save, state, ???

    flags['call_changes'] = call_changes

    # XXX: maybe faster to just brute force args rather than this careful
    # delta stuff?

    # make any necessary changes to child's args, saving undo info
    # (XXX: hmm, is this actually better than the iterative version?)
    def _alter_arg(number, arg, saved_arg, pid=pid):
        if not saved_arg:
            saved_arg = ptrace.peekuser(pid, 4 * number)
        if arg != saved_arg:
            if debug():
                print "ptrace.pokeuser(%s, %s, %s)" % (pid, 4 * number, arg)
            ptrace.pokeuser(pid, 4 * number, arg)
            return (number, saved_arg)

    n = len(args)
    args_delta = filter(None, map(_alter_arg, range(n), args, args_save[:n]))
    if args_delta:
        flags['args_delta'] = args_delta

    if call == 'sigreturn' or call == 'rt_sigreturn':
        flags['sigreturn'] = call

    if call != call_save:
        if isinstance(call, types.StringType):
            callno = syscallmap.lookup_number(call)
        else:
            callno = call

        try:
            if debug():
                print "ptrace.pokeuser(%s, %s, %s)" % (pid, ORIG_EAX, callno)
            ptrace.pokeuser(pid, ORIG_EAX, callno)
            flags['call_delta'] = scno
        except OSError, e:
            # FIX: do something better here
            sys.exit('panic: call alter failed in trick %s (%s)' % (trick, e))
Ejemplo n.º 15
0
def poke_args(pid, nargs, args):
    assert nargs <= 6, "kernel doesn't support 7+ args?"
    for i in range(nargs):
        ptrace.pokeuser(pid, 4 * i, args[i])
Ejemplo n.º 16
0

def set_skipcallafter(pid):
    global _skipcallafter
    _skipcallafter[pid] = 1


def hard_kill(pid):
    # FIX: isn't this a race?  don't we need to wait on the child?
    try:
        poke_args(pid, 6, [0, 0, 0, 0, 0, 0])
    except OSError, e:
        print "warning: attempt to annul last syscall by zapping args failed" \
                     " (pid=%s, error=%s)" % (pid, e)
    try:
        ptrace.pokeuser(pid, ORIG_EAX, _badcall)
    except OSError, e:
        print "warning: attempt to annul last syscall" \
                     " (pid=%s, error=%s)" % (pid, e)
    try:
        ptrace.kill(pid)
    except OSError, e:
        print "warning: attempt to ptrace.kill process failed" \
                     " (pid=%s, error=%s)" % (pid, e)
    except:
        # XXX: should we really catch this?  we shouldn't be absorbing
        # arbitrary exceptions; this will cause trouble
        print "warning: attempt to ptrace.kill process failed strangely" \
                     " (pid=%s, error=%s)" % (pid, e)
        raise