def callafter(self, pid, call, result, state): if call == 'rt_sigaction' or call == 'sigaction' or call == 'signal': if state != None and not (-1024 < result < 0): sig = state[0] f = self.allflags[pid] handler = state[1] if sig == signal.SIGCHLD: sa_flags = ptrace.peekdata(pid, handler + 4) f['SA_NOCLDSTOP'] = sa_flags & 0x1 # SA_NOCLDSTOP else: if call != 'signal': handler = ptrace.peekdata(pid, handler) f[signalmap.lookup_name(sig)] = handler elif call == 'wait4' or call == 'waitpid': f = self.allflags[pid] if f.has_key('waitresult'): wpid, statusptr, status = f['waitresult'] del f['waitresult'] del f['waiting'] if statusptr != 0: try: ptrace.pokedata(pid, statusptr, status) except OSError, e: if e.errno != errno.ESRCH: # FIX assert 0, "wait status pointer bad? (%s)" % e else: print 'waiter dead or not stopped' # XXX return wpid # XXX: is this actually correct and useful? if result == -errno_internal.ERESTARTNOHAND: # like pause return -errno_internal.ERESTARTSYS # like wait
def poke(self, address, data, fortrick=None): if fortrick: self.save.insert(0, (fortrick, address, self.peek(address, len(data)))) # XXX: could check whether poke is a noop here # This fails since write access to mem has been disabled in 2.4 kernels # _memseek(self.m, address) # r = os.write(self.m, data) # assert r == len(data) # FIX # a better implementation may be possible here if len(data) > 0: address1 = address + len(data) pa0 = address / 4 * 4 pa1 = (address1 - 1) / 4 * 4 + 4 for pa in xrange(pa0, pa1, 4): a = pa - address if address <= pa and pa + 4 <= address1: s = data[a : a + 4] else: s = list(self.peek(pa, 4)) for i in xrange(4): if address <= pa + i < address1: s[i] = data[a + i] s = string.join(s, "") ptrace.pokedata(self.pid, pa, struct.unpack("=l", s)[0])
def poke(self, address, data, fortrick=None): if fortrick: self.save.insert(0, (fortrick, address, self.peek(address, len(data)))) # XXX: could check whether poke is a noop here # This fails since write access to mem has been disabled in 2.4 kernels # _memseek(self.m, address) #r = os.write(self.m, data) #assert r == len(data) # FIX # a better implementation may be possible here if len(data) > 0: address1 = address + len(data) pa0 = address / 4 * 4 pa1 = (address1 - 1) / 4 * 4 + 4 for pa in xrange(pa0, pa1, 4): a = pa - address if address <= pa and pa + 4 <= address1: s = data[a:a+4] else: s = list(self.peek(pa, 4)) for i in xrange(4): if address <= pa + i < address1: s[i] = data[a+i] s = string.join(s, '') ptrace.pokedata(self.pid, pa, struct.unpack('=l', s)[0])
def _callbefore_wait(self, pid, args, flags): r = self.do_wait(pid, args, flags) wpid = r[1] if wpid and wpid > 0: statuspair = r[0] statusptr, status = statuspair if statusptr: try: ptrace.pokedata(pid, statusptr, status) except OSError, e: if e.errno != errno.ESRCH: # FIX assert 0, "wait status pointer bad? (%s)" % e else: print 'waiter dead or not stopped' # XXX
def callafter(self, pid, call, result, state): now = time.time() delta_t = now - self.start_t now_w = self.start_t + delta_t * self.w + self.delta if call == 'time': now_wi = int(now_w) if state: # FIX: might throw exception ptrace.pokedata(pid, state, now_wi) return now_wi elif call == 'gettimeofday' and result != -1: _put_timeval(pid, state, now_w) elif call == 'select' and result != -1 and state: _warp_timeval(pid, 1.0 / self.w, state) elif call == 'nanosleep': oldtimeval, args = state if args[1]: _warp_timeval(pid, 1.0 / self.w, args[1], 1000) # save and restore it so it doesn't get stepped on remaining = _get_timeval_2(pid, args[1]) _put_timeval_2(pid, args[0], oldtimeval) # here if args[1]: _put_timeval_2(pid, args[1], remaining)
def poke(self, addr, data): self.attach() ptrace.pokedata(self.pid, addr, data) self.detach()
def callbefore(self, pid, call, args): # print pid, call, args def doreadwrite(callt, args): # print 'doreadwrite',call,callt,args, fd = args[0] pfd = pid, fd fdinfo = self.__do_fail.get(pfd, None) # if fdinfo: # print fdinfo if fdinfo and callt in fdinfo.modes: if callt == 'r': #after = self.afterr if not fdinfo.rerrs: return after = min([err.after for err in fdinfo.rerrs]) failinfo = fdinfo.r else: #after = self.afterw if not fdinfo.werrs: return after = min([err.after for err in fdinfo.werrs]) failinfo = fdinfo.w failcount, bytes = failinfo.failed, failinfo.bytes if failcount > 5: print 'exiting on %ith failed %s of %i' % (failcount, callt, pfd) import sys sys.exit(1) if bytes < after: size = args[2] if bytes + size > after: size = after - bytes print pfd, callt, (fd, args[1], size), 'was', args return (pfd, None, None, (fd, args[1], size)) failinfo.failed += 1 print pid, 'failing', call, callt, '#%i' % failcount, 'for fd', fd return (pfd, -errno.EIO, None, None) # else: # print 'allowing',call,'for',args[0] if call == 'read': return doreadwrite('r', args) elif call == 'write': return doreadwrite('w', args) elif call == 'close': fd = args[0] pfd = pid, fd fdinfo = self.__do_fail.get(pfd, None) # print pfd, call, args, fdinfo if fdinfo and fdinfo.cerrs: return (pfd, -errno.EIO, None, None) return (pfd, None, None, None) elif call == 'dup' or call == 'dup2': return (args[0], None, None, None) elif call == 'open': getarg = Memory.getMemory(pid).get_string fn = getarg(args[0]) # print pid,call,[fn]+args[1:],args[1]&O_ACCMODE fes = [] m = '' flags = args[1] & O_ACCMODE for fe in self.ferrs: if (flags == os.O_RDWR or (flags == os.O_WRONLY and 'w' in fe.modes) or (flags == os.O_RDONLY and 'r' in fe.modes)): if fe.match.search(fn): fes.append(fe) if fes: fdinfo = FDInfo(fes) #if flags == FCNTL.O_WRONLY: # after = min([err.after for err in fdinfo.werrs]) #elif flags == FCNTL.O_RDONLY: # after = min([err.after for err in fdinfo.rerrs]) #else: #elif flags == FCNTL.O_RDWR: after = min([err.after for err in fdinfo.errs]) if after < 0: print pid, 'failing', call, [fn] + args[1:] return (None, -errno.EIO, None, None) return (fdinfo, None, None, None) elif call == 'socketcall': # print pid, call, args subcall = args[0] do = 0 if subcall == 1: # socket # FIX: might fail if ptrace.peekdata(pid, args[1]) in (socket.AF_INET, socket.AF_INET6): do = -2 elif subcall == 3: # connect do = -1 elif subcall == 4: # listen do = -1 elif subcall == 5: # accept do = -1 elif subcall in (9, 10): # send/recv if subcall == 9: # send r = doreadwrite('w', (ptrace.peekdata( pid, args[1]), ptrace.peekdata(pid, args[1] + 4), ptrace.peekdata(pid, args[1] + 8))) subcalln = 'write' elif subcall == 10: # recv r = doreadwrite('r', (ptrace.peekdata( pid, args[1]), ptrace.peekdata(pid, args[1] + 4), ptrace.peekdata(pid, args[1] + 8))) subcalln = 'read' if not r or r[ 1]: # if default return or error, we can return it with no probs. return r #otherwise we have to convert from doreadwrite return which is in read()/write() format to socketcall format ptrace.pokedata(args[1] + 8, r[3][2]) # set new recv/write size return ((subcalln, r[0]), r[1], r[2], args) if do: #ses = [] #for se in self.serrs: after = min([err.after for err in self.serrs]) if after == do: print pid, 'failing', call, args return (None, -errno.EIO, None, None) errs = [err for err in self.serrs if err.after >= 0] if errs: fdinfo = FDInfo(errs) return (('open', fdinfo), None, None, None) elif call == 'rename': getarg = Memory.getMemory(pid).get_string sfn = getarg(args[0]) dfn = getarg(args[1]) # print pid,call,sfn,dfn for rene in self.renameerrs: if rene.srcmatch.search(sfn) and rene.dstmatch.search(dfn): print pid, 'failing', call, sfn, dfn return (None, -errno.EIO, None, None)
def _put_timeval_2(pid, addr, pair): ptrace.pokedata(pid, addr, pair[0]) ptrace.pokedata(pid, addr + 4, pair[1])