首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法使PTRACE_SEIZED(PTRACE_SEIZED)工作

无法使PTRACE_SEIZED(PTRACE_SEIZED)工作
EN

Stack Overflow用户
提问于 2017-07-06 22:24:37
回答 1查看 1.7K关注 0票数 2

我正在处理ptrace并试图获得我的进程的注册系统调用值(Orig_rax),我对PTRACE_TRACEME请求(tracer/tracee)没有问题,然后我尝试使用PTRACE_ATTACH(在运行时附加进程),但现在我尝试使用PTRACE_SEIZED,我遇到了一些问题来获得那些系统调用,我只是不能正确解析我的进程。

我知道,PTRACE_ATTACHPTRACE_SEIZED之间的区别在于,对于process,我需要停止这个过程(我使用PTRACE_INTERRUPT for that)。

下面是我的代码:while(1)之后的所有printf和while(1)都是用于调试的。

因此,我所要做的只是解析我的程序,方法是使用PTRACE_SEIZED请求(从ptrace函数)附加我的进程,并提取完成的所有系统调用(orig_rax寄存器)(特别是隔离使用orig_rax函数(调用/bin/ls,在main中调用/bin/ls)完成的调用)。

当我运行我的代码时,所有的ptrace_function返回0,进程很好地收到停止信号(WIFSTOPPED(status) == true),但是rip寄存器似乎没有改变(有时它改变了,我只得到一次正确的orig_rax值,在没有任何情况下,我总是得到相同的值)。

我还尝试了使用PTRACE_SINGLESTEP而不是PTRACE_SYSCALL,它在我的while(1)中只工作了一次,因为RIP总是相同的值。

(我在谷歌上做了一些研究,但没有发现用PTRACE_SEIZED进行进程解析的例子,我是个穷追不舍的人,喜欢使用ptrace、内核、信号之类的东西,所以也许我的误解是从这里开始的)。

任何帮助,例子,有帮助的链接都是非常感谢的。希望我说得够清楚。

谢谢。

代码语言:javascript
复制
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int             seized_process(pid_t pid)
{
        int                                             status;
        struct user_regs_struct regs;
        int                                             pt_ret;
        siginfo_t                               siginfo;
        int                                     i = 0;

        pt_ret = ptrace(PTRACE_SEIZE, pid, NULL, NULL);
        printf("PTRACE_SEIZE ret: %d\n", pt_ret);
        printf("parent :%d \n", pid);

        while (1) {
                if (i == 3)
                        break;
                pt_ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
                printf("PTRACE_INTERRUPT ret: %d\n", pt_ret);
                waitpid(pid, &status, 0);
                printf("waitpid status: %d\n", status);
                if (WIFSTOPPED(status))
                        printf("process received stopping signal(Group-stop)\n");

                pt_ret = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
                printf("PTRACE_SIGINFO ret: %d, sig num: %d, si_code: %d \n",
                                pt_ret, siginfo.si_signo, siginfo.si_code);
                pt_ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
                printf("PTRACE_GETREGS ret: %d rip %#llx, orig_rax: %#llx,"
                           " rax : %#llx\n", pt_ret, regs.rip, regs.orig_rax,
                           regs.rax);

                pt_ret = ptrace(PTRACE_SYSCALL, pid, NULL,
                                WSTOPSIG(status));
                printf("PTRACE_SYSCALL ret : %d\n", pt_ret);

                if (WIFEXITED(status)) {
                        printf("WIFEXITED(status)\n");
                        break ;
                }
                else if (WSTOPSIG(status)) {
                        printf("WSTOPSIG(status)\n");
                }
                printf("\n---------------------\n");
                i++;
        }
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
}

int main(int argc, char *argv[])
{
        pid_t   child;

        child = fork();
        printf("fork value: %d \n", child);
        if (child == 0) {
                printf("child\n");
                execl("/bin/ls", "ls", NULL);
        }
        else {
                seized_process(child);
        }
    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-06 23:04:56

ptrace手册页面..。

PTRACE_SEIZE一节中,我们有:

与PTRACE_ATTACH不同的是,PTRACE_SEIZE不停止而不是停止进程。

PTRACE_TRACEME下,我们有:

对于PTRACE_ATTACH、PTRACE_SEIZE、PTRACE_INTERRUPT和PTRACE_KILL以外的请求,必须停止tracee。

因此,为了使跟踪器能够检查tracee的寄存器等,必须停止跟踪。但是,PTRACE_SEIZE本身并不能做到这一点。

因此,在尝试检查进程寄存器或内存之前,您需要使用PTRACE_ATTACH或在PTRACE_SEIZE之外执行其他操作来停止进程。

考虑一下,获得正在运行的进程的快照没有多大价值,因为您不会得到它的原子视图。您将“竞争”它,就像两个线程在全局值上运行一样。也就是说,(例如)您可以获取eax,然后是内存,但是它们可能已经在ptrace调用之间更改了值。

更新:

我知道我必须停止我的进程(Tracee),这就是为什么我使用:pt_ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);

在您的循环中,您可以执行PTRACE_INTERRUPT来停止该进程。然后,你抓取数据,打印出来,然后循环。

但是,在您的循环中,您从不做任何事情来恢复tracee (例如,PTRACE_CONT),因此,一旦您的循环的第一次迭代完成,跟踪的进程就会停止。只有在退出循环并执行PTRACE_DETACH之后,它才会恢复。

更新2:

是。PTRACE_SYSCALL将恢复跟踪过程。但是,跟踪器的ptrace调用将立即返回。然后,在循环顶部执行另一个PTRACE_INTERRUPT

这意味着跟踪的进程将被排定为运行,但可能会在获得运行机会之前再次停止。(即追踪器和曲棍球是“赛车”的)。这可能和你看到的情况很接近。

另外,我还会增加跟踪器中的迭代次数,因为3有点小,看不出多少。

尝试在循环之前执行PTRACE_INTERRUPT。这使得PTRACE_SEIZEPTRACE_INTERRUPT成为PTRACE_ATTACH的道德等价物。

然后,循环:waitpid,print,PTRACE_SYSCALL应该不需要赛车。让PTRACE_INTERRUPT在与PTRACE_SYSCALL相同的循环中执行某种程度上违背了PTRACE_SYSCALL的目的。

在最初的PTRACE_INTERRUPT之后使用PTRACE_CONT才有意义。

但是,在执行PTRACE_SYSCALL时,使用WNOHANGwaitpid上循环可能是有意义的。如果您没有在合理的时间内停止,这意味着目标没有做任何系统。此时,您可能会发出PTRACE_INTERRUPT,强制停止,以便检查状态。

在循环上面的PTRACE_INTERRUPT中,尝试使用PTRACE_SINGLESTEP来减少粒度。

就单步执行而言,ls有点不透明(例如,您可能需要安装调试器包才能获得符号表)。

尝试编写一个简单的目标/跟踪程序,在那里您可以精确地控制行为。您可以生成它的完全反汇编。然后,将地址与从单步跟踪中得到的rip值匹配。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44959801

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档