Can';无法找到如何正确使用ptrace()

Can';无法找到如何正确使用ptrace(),c,ptrace,C,Ptrace,目前,对于一个项目,我需要使用ptrace()编写某种调试器。最后,它应该显示要跟踪的程序中输入/退出的每个函数/系统调用 现在,我被卡住了。我制作了一个小程序,它应该尝试跟踪给定的程序,并根据操作码(用寄存器检索)打印是否找到调用或系统调用。这是: #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include &l

目前,对于一个项目,我需要使用ptrace()编写某种调试器。最后,它应该显示要跟踪的程序中输入/退出的每个函数/系统调用

现在,我被卡住了。我制作了一个小程序,它应该尝试跟踪给定的程序,并根据操作码(用寄存器检索)打印是否找到调用或系统调用。这是:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t child;
        const int long_size = sizeof(long);

        child = fork();

        if(child == 0) {
                ptrace(PTRACE_TRACEME, 0, NULL, NULL);
                execl("./bin", "bin", NULL);
        } else {
                int status;
                unsigned ins;
                struct user_regs_struct regs;
                unsigned char prim, sec;

                while (1) {
                        wait(&status);
                        if (WIFEXITED(status))
                                break;
                        ptrace(PTRACE_GETREGS, child, NULL, &regs);
                        ins = ptrace(PTRACE_PEEKTEXT, child, regs.rip, NULL);
                        prim = (unsigned)0xFF & ins;
                        sec = ((unsigned)0xFF00 & ins) >> 8;
                        if (prim == 0xE8 && sec == 0xCD)
                                printf("call found!\n");
                        if (prim == 0x80 && sec == 0xCD)
                                printf("syscall found!\n");
                        ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
                }
        }
        return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main()
{
pid_t儿童;
const int long_size=sizeof(long);
child=fork();
如果(子项==0){
ptrace(ptrace_TRACEME,0,NULL,NULL);
execl(“./bin”,“bin”,空);
}否则{
智力状态;
未签名ins;
结构用户\u注册表\u结构注册表;
无符号字符prim,秒;
而(1){
等待(&状态);
如果(妻子退出(状态))
打破
ptrace(ptrace_GETREGS、child、NULL和regs);
ins=ptrace(ptrace_PEEKTEXT,child,regs.rip,NULL);
prim=(无符号)0xFF&ins;
秒=((无符号)0xFF00&ins)>>8;
if(prim==0xE8&&sec==0xCD)
printf(“找到调用!\n”);
if(prim==0x80&&sec==0xCD)
printf(“找到系统调用!\n”);
ptrace(ptrace_SINGLESTEP,child,NULL,NULL);
}
}
返回0;
}
下面是“bin”二进制文件的代码:

#包括
无效toto()
{
写(1,“hello\n”,6);
}
int main()
{
toto();
toto();
申报表(1);
}
当我查看迷你调试器的输出时,似乎只找到一个系统调用和一个调用。。。我试着弄乱寄存器和偏移量,但我在互联网上找到的每个教程似乎都是针对32位机器的,在我的情况下,这是行不通的:/

有人能给我一个小提示帮我继续吗


谢谢,祝你今天愉快

你就快到了,但是你的掩蔽(第一次怀疑)没有捕捉到
callq
操作码。使用
PTRACE\u SINGLESTEP
也会捕获大量额外的
callq
代码,我不确定您是否意识到这一点

我静态编译了您的
bin
程序,这样您就可以获得
main
toto
的一致地址

gcc-bin.c-o-bin-g-Wall-static
在64位机器上

然后在主脚本中,我更改了
ins
变量上的掩蔽操作:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t child;

        child = fork();

        if(child == 0) {
                ptrace(PTRACE_TRACEME, 0, NULL, NULL);
                execl("./bin", "bin", NULL);
        } else {
                int status;
                unsigned ins;
                struct user_regs_struct regs;
                unsigned char prim;

                while (1) {
                        ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
                        wait(&status);
                        if (WIFEXITED(status))
                                break;
                        ptrace(PTRACE_GETREGS, child, NULL, &regs);
                        ins = ptrace(PTRACE_PEEKTEXT, child, regs.rip, NULL);
                        prim = (unsigned)0xFF & ins;
                        // Here in prim just mask for the first byte
                        if (prim == 0xe8) {
                        // Print the addresses to check out too
                                printf("RIP: %#x --> %#x\n", regs.rip, ins);
                                printf("call found!\n");
                        }
                }
        }
        return 0;
}
如果随后执行
objdump-S bin>dump.txt
操作,您可以看到
toto
main
中发出
callq
指令的地址也将位于
calls.txt
文件中


最后,所有额外的调用都来自crt函数、链接器和库调用。

直接使用
ptrace
是一个(应用于计算的该术语的最后一个真实示例之一)。如果有任何方法可以重用已经执行此任务的现有程序,例如
strace
gdb
,那么您绝对应该这样做。@zwol我不能遗憾地说:/@tijko是的,我可能(我肯定我是)错了,但我见过一些人这样做。如果它不起作用,可能是因为^^。。。你有什么想法吗?@LeVentilo编辑了我的回复,如果你还需要它的话,我会这样做,但是这样,我也无法跟踪用户函数:/(就像我的例子中的toto())@LeVentilo你需要的是用户定义的函数,而不仅仅是系统调用?是的,这是问题:/否则我会使用系统调用,这会更容易些^^谢谢,我正在尝试!那么,我要找的地址是什么?移民局?
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t child;

        child = fork();

        if(child == 0) {
                ptrace(PTRACE_TRACEME, 0, NULL, NULL);
                execl("./bin", "bin", NULL);
        } else {
                int status;
                unsigned ins;
                struct user_regs_struct regs;
                unsigned char prim;

                while (1) {
                        ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
                        wait(&status);
                        if (WIFEXITED(status))
                                break;
                        ptrace(PTRACE_GETREGS, child, NULL, &regs);
                        ins = ptrace(PTRACE_PEEKTEXT, child, regs.rip, NULL);
                        prim = (unsigned)0xFF & ins;
                        // Here in prim just mask for the first byte
                        if (prim == 0xe8) {
                        // Print the addresses to check out too
                                printf("RIP: %#x --> %#x\n", regs.rip, ins);
                                printf("call found!\n");
                        }
                }
        }
        return 0;
}
./stepper > calls.txt