def platformContinue(self): sig = self.getCurrentSignal() if sig == None: sig = 0 print 'PT_THUPDATE',v_posix.ptrace(PT_THUPDATE, self.pid, self.getMeta('StoppedThreadId'), sig) v_posix.ptrace(PT_CONTINUE, self.pid, 1, sig) self.libc.task_resume(self.task)
def platformSetRegCtx(self, tid, ctx): u = self._getAmdRegsStruct(tid) ctx._rctx_Export(u) addr = ctypes.addressof(u) if v_posix.ptrace(PT_SETREGS, tid, addr, 0) != 0: raise Exception("ptrace PT_SETREGS failed!") if v_posix.ptrace(PT_SETDBREGS, tid, addr+amd64_DBG_OFF, 0) != 0: raise Exception("ptrace PT_SETDBREGS failed!")
def platformGetRegs(self): buf = ctypes.create_string_buffer(TOT_REG_CNT*4) #FIXME thread specific if v_posix.ptrace(PT_GETREGS, self.pid, buf, 0) != 0: raise Exception("ptrace PT_GETREGS failed!") if v_posix.ptrace(PT_GETDBREGS, self.pid, ctypes.addressof(buf)+(GEN_REG_CNT*4), 0) != 0: raise Exception("ptrace PT_GETDBREGS failed!") return buf.raw
def platformSetRegCtx(self, tid, ctx): u = bsd_regs_i386() ctx._rctx_Export(u) addr = ctypes.addressof(u) if v_posix.ptrace(PT_SETREGS, self.pid, addr, 0) != 0: raise Exception("ptrace PT_SETREGS failed!") if v_posix.ptrace(PT_SETDBREGS, self.pid, addr+i386_DBG_OFF, 0) != 0: raise Exception("ptrace PT_SETDBREGS failed!")
def platformSetRegCtx(self, tid, ctx): u = user_regs_i386() ctx._rctx_Export(u) if v_posix.ptrace(PT_SETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_SETREGS...) failed!") for i in range(8): val = ctx.getRegister(self.dbgidx + i) if v_posix.ptrace(v_posix.PT_WRITE_U, tid, self.dbgoff+(4*i), val) != 0: raise Exception("PT_WRITE_U for debug%d failed!" % i)
def platformExec(self, cmdline): # Basically just like the one in the Ptrace mixin... self.execing = True cmdlist = e_cli.splitargs(cmdline) os.stat(cmdlist[0]) pid = os.fork() if pid == 0: v_posix.ptrace(PT_TRACE_ME, 0, 0, 0) os.execv(cmdlist[0], cmdlist) sys.exit(-1) return pid
def platformSetRegCtx(self, tid, ctx): u = self.user_reg_struct() # Populate the reg struct with the current values (to allow for # any regs in that struct that we don't track... *fs_base*ahem* if v_posix.ptrace(PT_GETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_GETREGS...) failed!") ctx._rctx_Export(u) if v_posix.ptrace(PT_SETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_SETREGS...) failed!") """
def _getAmdRegsStruct(self, tid): ''' Get (and populate) a register structure (even set regs needs to get it first...) ''' u = bsd_regs_amd64() addr = ctypes.addressof(u) if v_posix.ptrace(PT_GETREGS, tid, addr, 0) != 0: raise Exception("ptrace PT_GETREGS failed!") if v_posix.ptrace(PT_GETDBREGS, tid, addr + amd64_DBG_OFF, 0) != 0: raise Exception("ptrace PT_GETDBREGS failed!") return u
def _getAmdRegsStruct(self, tid): ''' Get (and populate) a register structure (even set regs needs to get it first...) ''' u = bsd_regs_amd64() addr = ctypes.addressof(u) if v_posix.ptrace(PT_GETREGS, tid, addr, 0) != 0: raise Exception("ptrace PT_GETREGS failed!") if v_posix.ptrace(PT_GETDBREGS, tid, addr+amd64_DBG_OFF, 0) != 0: raise Exception("ptrace PT_GETDBREGS failed!") return u
def platformSetRegs(self, buf, tid): """ Reverse of above... """ x = create_string_buffer(buf[32:]) if v_posix.ptrace(PT_SETREGS, tid, 0, addressof(x)) != 0: raise Exception("ERROR ptrace PT_SETREGS failed!") dbgs = struct.unpack("8L", buf[:32]) off = self.usize - 32 for i in range(8): v_posix.ptrace(v_posix.PT_WRITE_U, tid, off+(4*i), dbgs[i])
def platformGetRegCtx(self, tid): ctx = self.archGetRegCtx() u = bsd_regs_amd64() addr = ctypes.addressof(u) if v_posix.ptrace(PT_GETREGS, tid, addr, 0) != 0: raise Exception("ptrace PT_GETREGS failed!") if v_posix.ptrace(PT_GETDBREGS, tid, addr+amd64_DBG_OFF, 0) != 0: raise Exception("ptrace PT_GETDBREGS failed!") ctx._rctx_Import(u) return ctx
def platformGetRegCtx(self, tid): ctx = self.archGetRegCtx() u = bsd_regs_i386() addr = ctypes.addressof(u) if v_posix.ptrace(PT_GETREGS, tid, addr, 0) != 0: raise Exception("ptrace PT_GETREGS failed!") if v_posix.ptrace(PT_GETDBREGS, tid, addr + i386_DBG_OFF, 0) != 0: raise Exception("ptrace PT_GETDBREGS failed!") ctx._rctx_Import(u) return ctx
def platformGetRegCtx(self, tid): ctx = self.archGetRegCtx() u = self.user_reg_struct() if v_posix.ptrace(PT_GETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_GETREGS...) failed!") ctx._rctx_Import(u) for i in dbgregs: offset = self.user_dbg_offset + (self.psize * i) r = v_posix.ptrace(v_posix.PT_READ_U, tid, offset, 0) ctx.setRegister(self.dbgidx+i, r & self.reg_val_mask) return ctx
def platformSetRegs(self, buf): """ Reverse of above... """ tid = self.getMeta("ThreadId", self.getPid()) x = create_string_buffer(buf[32:]) if v_posix.ptrace(PT_SETREGS, tid, 0, addressof(x)) != 0: raise Exception("ERROR ptrace PT_SETREGS failed!") dbgs = struct.unpack("8L", buf[:32]) off = self.usize - 32 for i in range(8): v_posix.ptrace(v_posix.PT_WRITE_U, tid, off + (4 * i), dbgs[i])
def platformGetRegCtx(self, tid): """ """ ctx = self.archGetRegCtx() u = user_regs_i386() if v_posix.ptrace(PT_GETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_GETREGS...) failed!") ctx._rctx_Import(u) for i in range(8): r = v_posix.ptrace(v_posix.PT_READ_U, tid, self.dbgoff+(4*i), 0) ctx.setRegister(self.dbgidx+i, r & 0xffffffff) return ctx
def platformContinue(self): cmd = v_posix.PT_CONTINUE if self.getMode("Syscall", False): cmd = PT_SYSCALL pid = self.getPid() sig = self.getMeta("PendingSignal", 0) # Only deliver signals to the main thread if v_posix.ptrace(cmd, pid, 0, sig) != 0: raise Exception("ERROR ptrace failed for tid %d" % pid) for tid in self.pthreads: if tid == pid: continue if v_posix.ptrace(cmd, tid, 0, 0) != 0: pass
def platformGetRegCtx(self, tid): ctx = LinuxMixin.platformGetRegCtx( self, tid ) for i in intel_dbgregs: offset = self.user_dbg_offset + (self.psize * i) r = v_posix.ptrace(v_posix.PT_READ_U, tid, offset, 0) ctx.setRegister(self.dbgidx+i, r & self.reg_val_mask) return ctx
def platformStepi(self): # This is a total rediculous hack to account # for the fact that the arm platform couldn't # be bothered to implement single stepping in # the stupid hardware... self.stepping = True pc = self.getProgramCounter() op = self.parseOpcode(pc) branches = op.getBranches(self) if not branches: raise Exception(''' The branches for the instruction %r were not decoded correctly. This means that we cant properly predict the possible next instruction executions in a way that allows us to account for the STUPID INSANE FACT THAT THERE IS NO HARDWARE SINGLE STEP CAPABILITY ON ARM (non-realtime or JTAG anyway). We *would* have written invalid instructions to each of those locations and cleaned them up before you ever knew anything was amiss... which is how we pretend arm can single step... even though IT CANT. (please tell visi...) ''' % op) # Save the memory at the branches for later # restoration in the _fireStep callback. self._step_cleanup = [] for bva, bflags in op.getBranches(self): self._step_cleanup.append((bva, self.readMemory(bva, 4))) self.writeMemory(bva, arm_break_le) tid = self.getMeta('ThreadId') if v_posix.ptrace(v_posix.PT_CONTINUE, tid, 0, 0) != 0: raise Exception("ERROR ptrace failed for tid %d" % tid)
def platformSetRegCtx(self, tid, ctx): LinuxMixin.platformSetRegCtx( self, tid, ctx ) for i in intel_dbgregs: val = ctx.getRegister(self.dbgidx + i) offset = self.user_dbg_offset + (self.psize * i) if v_posix.ptrace(v_posix.PT_WRITE_U, tid, offset, val) != 0: libc.perror('PT_WRITE_U failed for debug%d' % i)
def platformAttach(self, pid): self.pthreads = [pid,] self.setMeta("ThreadId", pid) if v_posix.ptrace(PT_ATTACH, pid, 0, 0) != 0: raise Exception("PT_ATTACH failed!") self.setupPtraceOptions(pid) self.setMeta("ExeName", self._findExe(pid))
def platformSetRegCtx(self, tid, ctx): u = self.user_reg_struct() # Populate the reg struct with the current values (to allow for # any regs in that struct that we don't track... *fs_base*ahem* if v_posix.ptrace(PT_GETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_GETREGS...) failed!") ctx._rctx_Export(u) if v_posix.ptrace(PT_SETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_SETREGS...) failed!") for i in dbgregs: val = ctx.getRegister(self.dbgidx + i) offset = self.user_dbg_offset + (self.psize * i) if v_posix.ptrace(v_posix.PT_WRITE_U, tid, offset, val) != 0: libc.perror('PT_WRITE_U failed for debug%d' % i)
def platformSetRegCtx(self, tid, ctx): LinuxMixin.platformSetRegCtx(self, tid, ctx) for i in intel_dbgregs: val = ctx.getRegister(self.dbgidx + i) offset = self.user_dbg_offset + (self.psize * i) if v_posix.ptrace(v_posix.PT_WRITE_U, tid, offset, val) != 0: libc.perror('PT_WRITE_U failed for debug%d' % i)
def platformGetRegCtx(self, tid): ctx = LinuxMixin.platformGetRegCtx(self, tid) for i in intel_dbgregs: offset = self.user_dbg_offset + (self.psize * i) r = v_posix.ptrace(v_posix.PT_READ_U, tid, offset, 0) ctx.setRegister(self.dbgidx + i, r & self.reg_val_mask) return ctx
def platformAttach(self, pid): print 'CLASSIC',machhelper.is_pid_classic(pid) self.task = self.taskForPid(pid) self.setExceptionPort() if v_posix.ptrace(PT_ATTACHEXC, pid, 0, 0) != 0: #self.libc.perror('ptrace( PT_ATTACHEXC, %d, 0, 0) Failed' % (pid)) raise Exception("PT_ATTACH failed!")
def platformStepi(self): # This is a total rediculous hack to account # for the fact that the arm platform couldn't # be bothered to implement single stepping in # the stupid hardware... self.stepping = True pc = self.getProgramCounter() op = self.parseOpcode( pc ) branches = op.getBranches( self ) if not branches: raise Exception(''' The branches for the instruction %r were not decoded correctly. This means that we cant properly predict the possible next instruction executions in a way that allows us to account for the STUPID INSANE FACT THAT THERE IS NO HARDWARE SINGLE STEP CAPABILITY ON ARM (non-realtime or JTAG anyway). We *would* have written invalid instructions to each of those locations and cleaned them up before you ever knew anything was amiss... which is how we pretend arm can single step... even though IT CANT. (please tell visi...) ''' % op) # Save the memory at the branches for later # restoration in the _fireStep callback. self._step_cleanup = [] for bva,bflags in op.getBranches( self ): self._step_cleanup.append( (bva, self.readMemory( bva, 4 )) ) self.writeMemory( bva, arm_break_le ) tid = self.getMeta('ThreadId') if v_posix.ptrace(v_posix.PT_CONTINUE, tid, 0, 0) != 0: raise Exception("ERROR ptrace failed for tid %d" % tid)
def platformExec(self, cmdline): # Very similar to posix, but not # quite close enough... self.execing = True cmdlist = e_cli.splitargs(cmdline) os.stat(cmdlist[0]) pid = os.fork() if pid == 0: try: # Don't use PT_TRACEME -- on some linux (tested on ubuntu) # it will cause immediate asignment of ptrace slot to parent # without parent having PT_ATTACH'D.... MAKES SYNCHRONIZATION HARD # SIGSTOP ourself until parent continues us os.kill(os.getpid(), signal.SIGSTOP) os.execv(cmdlist[0], cmdlist) except Exception as e: print(e) sys.exit(-1) # Attach to child. should cause SIGSTOP if 0 != v_posix.ptrace(PT_ATTACH, pid, 0, 0): raise Exception("PT_ATTACH failed! linux platformExec") # Eat all SIGSTOP (or other signal) and break from loop on SIGTRAP. # SIGTRAP triggered by execv while PTRACE_ATTACH'd while True: wpid, status = os.waitpid(pid, os.WUNTRACED) if wpid != pid: # should never happen continue if os.WIFSTOPPED(status): cause = os.WSTOPSIG(status) if cause == signal.SIGTRAP: break if v_posix.ptrace(v_posix.PT_CONTINUE, pid, 0, 0) != 0: raise Exception("PT_CONTINUE failed! linux platformExec") # Do a single step, which will allow a new stop event for the # rest of vtrace to eat up. if v_posix.ptrace(v_posix.PT_STEP, pid, 0, 0) != 0: raise Exception("PT_CONTINUE failed! linux platformExec") self.pthreads = [ pid, ] self.setMeta("ExeName", self._findExe(pid)) return pid
def platformGetRegCtx(self, tid): ctx = self.archGetRegCtx() u = self.user_reg_struct() if v_posix.ptrace(PT_GETREGS, tid, 0, addressof(u)) == -1: raise Exception("Error: ptrace(PT_GETREGS...) failed!") ctx._rctx_Import(u) return ctx
def platformExec(self, cmdline): # Very similar to posix, but not # quite close enough... self.execing = True cmdlist = e_cli.splitargs(cmdline) os.stat(cmdlist[0]) pid = os.fork() if pid == 0: try: # Don't use PT_TRACEME -- on some linux (tested on ubuntu) # it will cause immediate asignment of ptrace slot to parent # without parent having PT_ATTACH'D.... MAKES SYNCHRONIZATION HARD # SIGSTOP ourself until parent continues us os.kill(os.getpid(),signal.SIGSTOP) os.execv(cmdlist[0], cmdlist) except Exception as e: print e sys.exit(-1) # Attach to child. should cause SIGSTOP if 0 != v_posix.ptrace(PT_ATTACH, pid, 0, 0): raise Exception("PT_ATTACH failed! linux platformExec") # Eat all SIGSTOP (or other signal) and break from loop on SIGTRAP. # SIGTRAP triggered by execv while PTRACE_ATTACH'd while True: wpid,status = os.waitpid(pid,os.WUNTRACED) if wpid != pid: #should never happen continue if os.WIFSTOPPED(status): cause = os.WSTOPSIG(status) if cause == signal.SIGTRAP: break if v_posix.ptrace(v_posix.PT_CONTINUE, pid, 0, 0) != 0: raise Exception("PT_CONTINUE failed! linux platformExec") # Do a single step, which will allow a new stop event for the # rest of vtrace to eat up. if v_posix.ptrace(v_posix.PT_STEP, pid, 0, 0) != 0: raise Exception("PT_CONTINUE failed! linux platformExec") self.pthreads = [pid,] self.setMeta("ExeName", self._findExe(pid)) return pid
def platformContinue(self): cmd = v_posix.PT_CONTINUE if self.getMode("Syscall", False): cmd = PT_SYSCALL pid = self.getPid() sig = self.getCurrentSignal() if sig == None: sig = 0 # Only deliver signals to the main thread if v_posix.ptrace(cmd, pid, 0, sig) != 0: libc.perror('ptrace PT_CONTINUE failed for pid %d' % pid) raise Exception("ERROR ptrace failed for pid %d" % pid) for tid in self.pthreads: if tid == pid: continue if v_posix.ptrace(cmd, tid, 0, 0) != 0: pass
def detachThread(self, tid, ecode): self.setMeta('ThreadId', tid) self._fireExitThread(tid, ecode) if v_posix.ptrace(PT_DETACH, tid, 0, 0) != 0: raise Exception("ERROR ptrace detach failed for thread %d" % tid) self.pthreads.remove(tid)
def platformGetThreads(self): ret = {} cnt = self._getThreadCount() buf = (ctypes.c_int * cnt)() if v_posix.ptrace(PT_GETLWPLIST, self.pid, ctypes.addressof(buf), cnt) != cnt: raise Exception("ptrace PW_GETLWPLIST failed") for x in buf: ret[x] = x return ret
def platformGetThreads(self): ret = {} cnt = self._getThreadCount() buf = (ctypes.c_int * cnt)() if v_posix.ptrace(PT_GETLWPLIST, self.pid, buf, cnt) != cnt: raise Exception("ptrace PW_GETLWPLIST failed") for x in buf: ret[x] = x return ret
def getPtraceEvent(self): """ This *thread wrapped* function will get any pending GETEVENTMSG msgs. """ p = c_ulong(0) tid = self.getMeta("ThreadId", -1) if v_posix.ptrace(PT_GETEVENTMSG, tid, 0, addressof(p)) != 0: raise Exception('ptrace PT_GETEVENTMSG failed!') return p.value
def setupPtraceOptions(self, tid): """ Called by doAttachThread to setup ptrace related options. """ opts = PT_O_TRACESYSGOOD if platform.release().startswith("2.6"): opts |= PT_O_TRACECLONE x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: print "WARNING ptrace SETOPTIONS failed for thread %d (%d)" % (tid,x)
def setupPtraceOptions(self, tid): """ Called by doAttachThread to setup ptrace related options. """ opts = PT_O_TRACESYSGOOD if platform.release().startswith("2.6"): opts |= PT_O_TRACECLONE x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: libc.perror('ptrace PT_SETOPTION failed for thread %d' % tid)
def platformContinue(self): cmd = PT_CONTINUE if self.getMode("Syscall"): cmd = PT_SYSCALL sig = self.getMeta("PendingSignal", 0) # In freebsd address is the place to continue from # but 1 means use existing EIP if v_posix.ptrace(cmd, self.pid, 1, sig) != 0: raise Exception("ptrace PT_CONTINUE/PT_SYSCALL failed")
def setupPtraceOptions(self, tid): """ Called by doAttachThread to setup ptrace related options. """ opts = PT_O_TRACESYSGOOD if platform.release().startswith("2.6"): opts |= PT_O_TRACECLONE x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: print "WARNING ptrace SETOPTIONS failed for thread %d (%d)" % (tid, x)
def platformWait(self): pid,status = v_posix.PosixMixin.platformWait(self) # Get the thread id from the ptrace interface info = PTRACE_LWPINFO() size = ctypes.sizeof(info) if v_posix.ptrace(PT_LWPINFO, self.pid, ctypes.addressof(info), size) == 0: self.setMeta('ThreadId', info.pl_lwpid) return pid,status
def setupPtraceOptions(self, tid): """ Called per pid/tid to setup proper options for ptrace. """ opts = PT_O_TRACESYSGOOD if platform.release()[:3] in ('2.6', '3.0', '3.1', '3.2'): opts |= PT_O_TRACECLONE | PT_O_TRACEEXIT x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: libc.perror('ptrace PT_SETOPTION failed for thread %d' % tid)
def setupPtraceOptions(self, tid): """ Called per pid/tid to setup proper options for ptrace. """ opts = PT_O_TRACESYSGOOD if platform.release()[:3] in ('2.6','3.0','3.1','3.2'): opts |= PT_O_TRACECLONE | PT_O_TRACEEXIT x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: libc.perror('ptrace PT_SETOPTION failed for thread %d' % tid)
def setupPtraceOptions(self, tid): """ Called per pid/tid to setup proper options for ptrace. """ opts = PT_O_TRACESYSGOOD ver = tuple(platform.release()[:3].split('.')) if (int(ver[0]), int(ver[1])) >= (2, 6): opts |= PT_O_TRACECLONE | PT_O_TRACEEXIT x = v_posix.ptrace(PT_SETOPTIONS, tid, 0, opts) if x != 0: libc.perror('ptrace PT_SETOPTION failed for thread %d' % tid)
def platformGetExtendedRegs(self, tid, ctx): ''' for now, the only real way to get access to things like YMM and ZMM registers ''' buflen = 2048 # Guess. Actual length will be set by kernel buffer = (c_uint8 * buflen)() vec = iovec(cast(buffer, c_void_p), buflen) if v_posix.ptrace(PT_GETREGSET, tid, NT_X86_XSTATE, addressof(vec)) != 0: raise v_exc.PtraceException("PT_GETREGSET(NT_X86_XSTATE)") self.parseXSave(ctx, buffer)
def platformExec(self, cmdline): # Very similar to posix, but not # quite close enough... self.execing = True cmdlist = e_cli.splitargs(cmdline) os.stat(cmdlist[0]) pid = os.fork() if pid == 0: v_posix.ptrace(v_posix.PT_TRACE_ME, 0, 0, 0) # Make sure our parent gets some cycles time.sleep(0.1) os.execv(cmdlist[0], cmdlist) sys.exit(-1) if v_posix.ptrace(PT_ATTACH, pid, 0, 0) != 0: raise Exception("PT_ATTACH failed! linux platformExec") self.pthreads = [pid,] self.setMeta("ExeName", self._findExe(pid)) return pid
def doAttachThread(self, tid, attached=False): """ Do the work for attaching a thread. This must be *under* attachThread() so callers in notifiers may call it (because it's also gotta be thread wrapped). """ if not attached: if v_posix.ptrace(PT_ATTACH, tid, 0, 0) != 0: raise Exception("ERROR ptrace attach failed for thread %d" % tid) os.waitpid(tid, 0x40000002) self.setupPtraceOptions(tid) self.pthreads.append(tid)
def platformWriteMemory(self, address, buf): #FIXME optimize for speed! iod = PTRACE_IO_DESC() cbuf = ctypes.create_string_buffer(buf) iod.piod_op = PIOD_WRITE_D iod.piod_addr = ctypes.addressof(cbuf) iod.piod_offs = address iod.piod_len = len(buf) if v_posix.ptrace(PT_IO, self.pid, ctypes.addressof(iod), 0) != 0: raise Exception("ptrace PT_IO failed to read 0x%.8x" % address)
def platformWait(self): status = v_posix.PosixMixin.platformWait(self) # Get the thread id from the ptrace interface info = PTRACE_LWPINFO() size = ctypes.sizeof(info) if v_posix.ptrace(PT_LWPINFO, self.pid, ctypes.byref(info), size) == 0: self.setMeta("ThreadId", info.pl_lwpid) else: #FIXME this is because posix wait is linux specific and broke self.setMeta("ThreadId", self.pid) return status