如何ptrace多线程应用程序?

发布于 2024-10-28 06:07:20 字数 1627 浏览 6 评论 0原文

编辑(已取得进展):

我正在尝试 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

EDIT (MADE PROGRESS):

I am trying to ptrace a vsftpd daemon. I have the following code which is attaching to the daemon. Then it successfully displays the PID of the first spawned process. However, for the children of this spawned process it returns the PIDs as 2,3,.. The program does catch the exiting of the spawned processes though, which makes me think I am close.

Any ideas?

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);
    }  
}

Sample output:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

别念他 2024-11-04 06:07:20

在阅读 使用 ptrace 文章时,我发现 此评论来自一位也遇到此问题的用户:

/* 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;
}

While reading the Playing with ptrace article, I found this comment from a user who also struggled with this:

/* 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;
}
ぇ气 2024-11-04 06:07:20

进一步研究我的代码后,我意识到它确实可以捕获来自父级及其子级的所有系统调用。唯一的问题是 PID 以相对数字的形式返回,而不是实际的 PID。这导致无法确定等待 PID 是否实际上是从父进程生成的。无论哪种方式,代码都会为您提供所有系统调用。据我所知,我仍然想知道为什么 PID 是相对的,但代码工作正常。

After going further with my code, I realize that it does actually work to capture all the system calls that are coming from the parent and its children. The only issue is that the PIDs are returned as relative numbers, rather than actual PIds. This results in not being certain that a wait PID was actually generated from the parent. Either way, the code will get you all the system calls. I would still like to know why the PID is relative, for my own knowledge, but the code works fine.

坚持沉默 2024-11-04 06:07:20

让线程在下一个 wait() 之前运行。

尝试:

ptrace(PTRACE_SYSCALL,child, NULL, NULL);

之前:

while(TURE)

Let the thread run before the next wait().

Try:

ptrace(PTRACE_SYSCALL,child, NULL, NULL);

Before:

while(TURE)
等风来 2024-11-04 06:07:20

在多线程进程中,每个
线程可以单独连接到(可能不同)
跟踪器,或未附加,因此未调试。所以,
“tracee”始终表示“(一个)线程”,而不是“一个(可能
多线程)进程”。ptrace 命令总是发送到
使用以下形式的调用的特定被跟踪者

http:// man7.org/linux/man-pages/man2/ptrace.2.html

in a multithreaded process, every
thread can be individually attached to a (potentially different)
tracer, or left not attached and thus not debugged. Therefore,
"tracee" always means "(one) thread", never "a (possibly
multithreaded) process". Ptrace commands are always sent to a
specific tracee using a call of the form

from the man page http://man7.org/linux/man-pages/man2/ptrace.2.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文