/* * long ptrace(enum request, int pid, void* addr, void* data) */ void SysCalls::sys_ptrace(CONTEXT& ctx) { int request = ctx.Ebx; int pid = ctx.Ecx; void* addr = (void*)ctx.Edx; void* data = (void*)ctx.Esi; Process * pTraced = g_pKernelTable->FindProcess(pid); //TODO: what does ptrace on a process with threads actually do? ThreadInfo * pTracedThread = pTraced->m_ThreadList[0]; switch(request) { case linux::PTRACE_TRACEME: ktrace("ptrace PTRACE_TRACEME\n"); P->m_ptrace.OwnerPid = P->m_ParentPid; P->m_ptrace.Request = linux::PTRACE_TRACEME; ctx.Eax = 0; break; case linux::PTRACE_SYSCALL: { ktrace("ptrace PTRACE_SYSCALL pid %d\n", pid); pTraced->m_ptrace.Request = linux::PTRACE_SYSCALL; if((int)data!=0 && (int)data!=linux::SIGSTOP) pTraced->m_ptrace.new_signal = (int)data; ktrace("ptrace_syscall resuming pid %d\n",pid); ResumeThread(pTraced->m_KernelThreadHandle); //kernel handler thread is paused when using ptrace ctx.Eax = 0; } break; case linux::PTRACE_CONT: { ktrace("ptrace PTRACE_CONT pid %d\n", pid); pTraced->m_ptrace.Request = 0; if((int)data!=0 && (int)data!=linux::SIGSTOP) pTraced->m_ptrace.new_signal = (int)data; ktrace("ptrace_cont resuming pid %d\n",pid); ResumeThread(pTraced->m_KernelThreadHandle); //kernel handler thread is paused when using ptrace ctx.Eax = 0; } break; case linux::PTRACE_PEEKUSR: { ktrace("ptrace PTRACE_PEEKUSR pid %d addr 0x%lx (reg %ld) data 0x%08lx\n", pid, addr, (DWORD)addr>>2, data); if((unsigned long)addr > sizeof(linux::user)-3) { ctx.Eax = -linux::EFAULT; break; } //read data at offset 'addr' in the kernel 'user' struct (struct user in asm/user.h) //we don't keep one of those so make one here CONTEXT *pTracedCtx; CONTEXT TempCtx; if(pTraced->m_ptrace.ctx_valid) pTracedCtx = &pTraced->m_ptrace.ctx; else { ktrace("peekusr get Traced context\n"); //it's possible that the traced process has caught a signal and then //signalled us, however it's kernel thread has yet to sleep //so we do an extra suspend here to get the correct context SuspendThread(pTracedThread->hThread); TempCtx.ContextFlags = CONTEXT_FULL; GetThreadContext(pTracedThread->hThread, &TempCtx); ResumeThread(pTracedThread->hThread); pTracedCtx = &TempCtx; } linux::user usr; memset(&usr,0,sizeof(usr)); usr.regs.eax = pTracedCtx->Eax; usr.regs.ebx = pTracedCtx->Ebx; usr.regs.ecx = pTracedCtx->Ecx; usr.regs.edx = pTracedCtx->Edx; usr.regs.esi = pTracedCtx->Esi; usr.regs.edi = pTracedCtx->Edi; usr.regs.ebp = pTracedCtx->Ebp; usr.regs.ds = (unsigned short)pTracedCtx->SegDs; usr.regs.__ds = 0; usr.regs.es = (unsigned short)pTracedCtx->SegEs; usr.regs.__es = 0; usr.regs.fs = (unsigned short)pTracedCtx->SegFs; usr.regs.__fs = 0; usr.regs.gs = (unsigned short)pTracedCtx->SegGs; usr.regs.__gs = 0; usr.regs.cs = (unsigned short)pTracedCtx->SegCs; usr.regs.__cs = 0; usr.regs.ss = (unsigned short)pTracedCtx->SegSs; usr.regs.__ss = 0; usr.regs.orig_eax = pTraced->m_ptrace.Saved_Eax; usr.regs.eip = pTracedCtx->Eip; usr.regs.eflags = pTracedCtx->EFlags; usr.regs.esp = pTracedCtx->Esp; //usr.signal = SIGTRAP; //man ptrace says parent thinks Traced is in this state char * pWanted = ((char*)&usr) + (DWORD)addr; DWORD retdata = *((DWORD*)pWanted); P->WriteMemory((ADDR)data, sizeof(retdata), &retdata); ktrace("ptrace [0x%x]=0x%x eax=0x%x orig_eax=0x%x\n", addr, retdata, usr.regs.eax, usr.regs.orig_eax); ctx.Eax = 0; } break; case linux::PTRACE_PEEKTEXT: case linux::PTRACE_PEEKDATA: { ktrace("ptrace PTRACE_PEEKDATA pid %d addr 0x%lx data 0x%08lx\n", pid, addr, data); DWORD tmp; if(!pTraced->ReadMemory(&tmp, (ADDR)addr, sizeof(tmp))) { ctx.Eax = -linux::EFAULT; } else { P->WriteMemory((ADDR)data, sizeof(tmp), &tmp); ctx.Eax = tmp; ktrace("ptrace [0x%x]=0x%x\n", addr, tmp); } } break; case linux::PTRACE_KILL: ktrace("ptrace PTRACE_KILL pid %d \n", pid); pTraced->SendSignal(linux::SIGKILL); ResumeThread(pTraced->m_KernelThreadHandle); //need to wake kernel handler thread so it can die ctx.Eax = 0; break; default: ktrace("IMPLEMENT ptrace request %lx\n", ctx.Ebx); ctx.Eax = -linux::ENOSYS; break; } }
/* * int kill(pid, sig) */ void SysCalls::sys_kill(CONTEXT& ctx) { PID pid = ctx.Ebx; unsigned int sig = ctx.Ecx; if(sig>=linux::_NSIG) { ctx.Eax = -linux::EINVAL; return; } //helper: sig 0 allows for error checking on pids. no signal actually sent // positive - send to 1 process if(pid>0) { ctx.Eax = -linux::ESRCH; Process * pDest = g_pKernelTable->FindProcess(pid); if(pDest!=NULL) { if(sig!=0) pDest->SendSignal(sig); ctx.Eax = 0; } return; } // -1 all processes except init if(pid == -1) { KernelTable::ProcessList::iterator it; for(it=g_pKernelTable->m_Processes.begin(); it!=g_pKernelTable->m_Processes.end(); ++it) { if((*it)->m_Pid != 1) { if(sig!=0) (*it)->SendSignal(sig); } } ctx.Eax = 0; return; } //else send to a process group PID pgrp = 0; if(pid==0) pgrp = P->m_Pid; //our group else pgrp = -pid; //dest group KernelTable::ProcessList::iterator it; for(it=g_pKernelTable->m_Processes.begin(); it!=g_pKernelTable->m_Processes.end(); ++it) { if((*it)->m_Pid != 1 && (*it)->m_ProcessGroupPID == pgrp) { if(sig!=0) (*it)->SendSignal(sig); } } ctx.Eax = 0; #undef DO_SIGNAL }