【问题标题】:Can't find how to use ptrace() properly找不到如何正确使用 ptrace()
【发布时间】:2018-05-08 16:19:02
【问题描述】:

目前,对于一个项目,我需要使用 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;
}

这是“bin”二进制文件的代码:

#include <unistd.h>

void toto()
{
        write(1, "hello\n", 6);
}

int main()
{
        toto();
        toto();
        return (1);
}

当我查看我的迷你调试器的输出时,它似乎只找到一个系统调用和一个调用...我尝试弄乱寄存器和偏移量,但我在互联网上找到的每个教程似乎都是针对32位机器,在我的情况下不起作用:/

有人可以给我一个小提示来帮助我继续吗?

谢谢,祝你有美好的一天!

【问题讨论】:

  • 直接使用ptraceblack art(该术语应用于计算的最后剩下的真实示例之一)。如果有任何方法可以重用已经完成这项工作的现有程序,例如 stracegdb,那么您绝对应该这样做。
  • @zwol 我不能很遗憾:/
  • @tijko 是的,我可能(而且我确信我是)错了,但我看到有人这样做。如果它不起作用,可能是为什么^^...你有什么想法吗?
  • @LeVentilo 编辑了我的回复,如果您仍然需要它

标签: c ptrace


【解决方案1】:

你快到了,但你的掩蔽(正如最初所怀疑的那样)没有捕捉到callq 操作码。使用PTRACE_SINGLESTEP 还会捕获大量额外的callq 代码,我不确定你是否意识到这一点。

我静态编译了您的bin 程序,因此您可以获得maintoto 的一致地址

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

你只需要屏蔽检查第一个字节,看它是否匹配call操作码。我添加了一些带有指令指针地址的额外打印语句,因此您可以检查静态源代码,以确保您正在捕获正确的调用。

你可以从主程序重定向你的输出(我称之为stepper):

./stepper > calls.txt

如果您随后执行objdump -S bin &gt; dump.txt,您可以看到来自totomain 的地址,其中执行callq 指令的地址也将在calls.txt 文件中

您最终会得到来自 crt 函数、链接器和库调用的所有额外调用。

【讨论】:

  • 我本来打算这样做,但是这样,我也无法跟踪用户功能:/(例如我的示例中的 toto())
  • @LeVentilo 您需要用户定义的函数而不仅仅是系统调用?
  • 是的,这就是问题所在:/否则我会使用 SYSCALL,那会更容易^^
  • 谢谢,我正在尝试!
  • 那么,我必须寻找的地址是什么?插入?
猜你喜欢
  • 2020-02-09
  • 1970-01-01
  • 2015-06-08
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多