我正在尝试ptrace一个vsftpd守护进程。我有以下代码附加到守护程序。然后它成功显示第一个衍生进程的PID。但是,对于这个衍生进程的子进程,它将PID返回为2,3,..程序确实捕获了生成进程的退出,这让我觉得我很接近。
有什么想法吗?
void * trace_process(void * pid){
pid_t child = atoi((char *) pid);
long orig_eax, eax;
int status;
int callmade = FALSE;
long opt = PTRACE_O_TRACEFORK;
long newpid;
long trace = ptrace(PTRACE_ATTACH,child,NULL,NULL);
ptrace(PTRACE_SETOPTIONS,child,NULL,opt);
if(trace == FALSE)
printf("Attached to %d\n",child);
while(TRUE) {
child = waitpid(-1, &status, __WALL);
if (status >> 16 == PTRACE_EVENT_FORK) {
ptrace(PTRACE_GETEVENTMSG, child, NULL, (long) &newpid);
ptrace(PTRACE_SYSCALL, newpid, NULL, NULL);
printf("Attached to offspring %ld\n", newpid);
}
else{
if(WIFEXITED(status))
printf("Child %d exited\n", child);
}
ptrace(PTRACE_SYSCALL,child, NULL, NULL);
}
}
示例输出:
Attached to 2015 // daemon
Attached to offspring 5302 // new connection handler
Attached to offspring 2 // should be authenticator
Child 5303 exited // authenticator exiting on successful login
Attached to offspring 3 // should be process serving files
Child 5304 exited // logout: process serving files
Child 5302 exited // connection closed
Attached to offspring 5305 // new connection handler
Attached to offspring 2 // ... repeat
Child 5306 exited
Attached to offspring 3
Child 5307 exited
Child 5305 exited
答案 0 :(得分:1)
在阅读Playing with ptrace文章时,我发现来自同时也在努力解决此问题的用户this comment:
/* After struggled a long time, I got a true way to make my ptrace worked
* correct with multi-thread application. Here're my sample codes, hope it
* can help others whom have the same confusion. */
char trapCode[] = {0, 0, 0, 0};
int status;
ptrace(PTRACE_ATTACH, childProcess, NULL, NULL); //childProcess is the main thread
wait(NULL);
printf("\nchild %d created\n", childProcess);
fflush(stdout);
long ptraceOption = PTRACE_O_TRACECLONE;
ptrace(PTRACE_SETOPTIONS, childProcess, NULL, ptraceOption);
struct user_regs_struct regs;
for(unsigned int i = 0; i < m_breakPoints.size(); i++)
{
BreakPoint_Info breakPointInfo = m_breakPoints[i];
if(!breakPointInfo.m_enabled)
continue;
unsigned int index = breakPointInfo.m_checkPointIndex;
if(m_bytesBackup.find(m_checkPoints[index].m_offset) != m_bytesBackup.end())
continue;
unsigned long readAddr = m_checkPoints[index].m_offset;
One_Byte_With_Result *oneByte = new One_Byte_With_Result;
getData(childProcess, readAddr, trapCode, 4);
oneByte->m_char = trapCode[0];
trapCode[0] = 0xcc;
putData(childProcess, readAddr, trapCode, 4);
m_bytesBackup.insert(std::make_pair(m_checkPoints[index].m_offset, oneByte));
}
std::set allThreads;
std::set::iterator allThreadsIter;
allThreads.insert(childProcess);
int rec = ptrace(PTRACE_CONT, childProcess, NULL, NULL);
while(true)
{
pid_t child_waited = waitpid(-1, &status, __WALL);
if(child_waited == -1)
break;
if(allThreads.find(child_waited) == allThreads.end())
{
printf("\nreceived unknown child %d\t", child_waited);
break;
}
if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
{
pid_t new_child;
if(((status >> 16) & 0xffff) == PTRACE_EVENT_CLONE)
{
if(ptrace(PTRACE_GETEVENTMSG, child_waited, 0, &new_child) != -1)
{
allThreads.insert(new_child);
ptrace(PTRACE_CONT, new_child, 0, 0);
printf("\nchild %d created\t", new_child);
}
ptrace(PTRACE_CONT, child_waited, 0, 0);
continue;
}
}
if(WIFEXITED(status))
{
allThreads.erase(child_waited);
printf("\nchild %d exited with status %d\t", child_waited, WEXITSTATUS(status));
if(allThreads.size() == 0)
break;
}
else if(WIFSIGNALED(status))
{
allThreads.erase(child_waited);
printf("\nchild %d killed by signal %d\t", child_waited, WTERMSIG(status));
if(allThreads.size() == 0)
break;
}
else if(WIFSTOPPED(status))
{
int stopCode = WSTOPSIG(status);
if(stopCode == SIGTRAP)
{
ptrace(PTRACE_GETREGS, child_waited, NULL, ®s);
unsigned long currentEip = regs.eip;
//printf("%d\t%08x\n", child_waited, currentEip);
Address_Bytes_Map::iterator iter = m_bytesBackup.find(currentEip - 1);
if(iter != m_bytesBackup.end())
{
iter->second->m_result = true;
regs.eip = regs.eip - 1;
getData(child_waited, regs.eip, trapCode, 4);
trapCode[0] = iter->second->m_char;
putData(child_waited, regs.eip, trapCode, 4);
rec = ptrace(PTRACE_SETREGS, child_waited, NULL, ®s);
}
}
}
rec = ptrace(PTRACE_CONT, child_waited, 1, NULL);
continue;
}
答案 1 :(得分:1)
在进一步使用我的代码之后,我意识到它确实可以捕获来自父代及其子代的所有系统调用。唯一的问题是PID是作为相对数字返回的,而不是实际的PIds。这导致无法确定实际从父节点生成等待PID。无论哪种方式,代码都将为您提供所有系统调用。我仍然想知道为什么PID是相对的,据我所知,但代码工作正常。
答案 2 :(得分:1)
让线程在下一个wait()
之前运行。
尝试:
ptrace(PTRACE_SYSCALL,child, NULL, NULL);
在:
while(TURE)
答案 3 :(得分:0)
在多线程进程中,每个 线程可以单独连接到(可能不同) 示踪剂,或者未连接,因此未调试。因此, “ tracee”始终表示“(一个)线程”,从不表示“一个(可能 多线程)进程”。Ptrace命令始终发送到 使用表格形式的调用来创建特定的痕迹