阅读另一个进程的堆栈?


16

我正在尝试读取子进程的堆栈,但是没有运气。我知道可以使用ptrace,但是ptrace的界面仅允许您一次只读取一个单词,而我正在尝试扫描堆栈的较大部分。

我也试着阅读/proc/$pid/mem从堆栈的boundries从提取/proc/$pid/maps使用ptrace的附加到它(如建议的文件后先在这里),但(以root运行时,即使)读不停地进行故障虽然尝试时相同的代码成功从过程的不同部分(例如堆)读取。

我究竟做错了什么?还有其他选择吗?


您是否waitpidptrace(PTRACE_ATTACH,…)和之间打过电话read(否则可能存在比赛情况)?read返回什么错误?该子对象是否在执行其内存映射所特有的操作-您可以像这样的简单子对象尝试代码sleep吗?
吉尔(Gilles)“所以,别再邪恶了”,

我在ptrace之后确实使用了wait,并且在孩子中放了一个scanf来强迫它等待。
user4537 2011年

这仅在Linux上吗?Solaris也具有/ proc文件系统,但从哲学上讲,它与Linux完全不同。很多“二进制文件”。
Bruce Ediger

只是做一个system(“ pstack pid ”)并解析输出..
vrdhn 2011年

Answers:


5

ptrace的界面允许您一次只读取一个字,而我正尝试扫描堆栈的较大部分

好吧,那么就使用循环。老实说ptrace,我看不出这是什么问题,我一直都在使用它来远程访问流程。

我用这样的东西:

static int memcpy_from_target(pid_t pid, char *dest, long src, size_t n)
{
    static int const align = sizeof(long) - 1;

    while (n)
    {
        size_t todo = MIN(n, sizeof(long) - (src & align));
        long data = ptrace(PTRACE_PEEKTEXT, pid, src - (src & align), 0);
        if (errno)
        {
            perror("ptrace_peektext (memcpy_from_target)");
            return -1;
        }
        memcpy(dest, (char *)&data + (src & align), todo);

        dest += todo; src += todo; n -= todo;
    }

    return 0;
}

嗨,山姆,虽然您的代码可以执行(实际上这是我当前正在执行的操作),但它具有很大的性能开销。
2011年

@ user4536:我知道了。我有另一种策略,我会在有时间写下来时发布。典型的堆栈大小是多少?
sam hocevar

很难说是真的,因为我的研究没有假设特定的堆栈大小,但是为了这个论点,让我们至少说几页,您能不能就策略提出一些建议?无论如何,谢谢您的帮助!
2011年

1

这是另一种可能需要调整的策略,但对大数据量应该更有效。这个想法是在远程进程中执行系统调用,以检索堆栈内容。它将需要特定的体系结构代码,但是如果您仅针对x86 / x86_64,则应该不会太麻烦。

  1. "/tmp/fifo"在调用过程中创建一个命名管道。
  2. 进入被跟踪的进程,直到它从系统调用返回为止,使用PTRACE_SYSCALL来执行步骤,waitpid()以等待和PTRACE_GETREGS/ PTRACE_PEEKTEXT检查当前执行的操作码。
  3. 备份远程进程的寄存器和堆栈的一小部分。
  4. 通过使用您自己的数据覆盖堆栈open("/tmp/fifo")write()堆栈内容close()和描述符,在远程进程上执行系统调用。
  5. 恢复远程进程的状态。
  6. 从调用过程中读取fifo数据。

命名管道可能会有更优雅的替代方法,但是我现在想不起来。我仅使用syscall的原因是由于各种安全保护,在现代系统上远程代码注入非常不可靠。缺点是它将挂起,直到远程进程执行系统调用为止(这对于某些主要执行计算的程序可能是个问题)。

您可以在此源文件中看到一些免费的代码来实现大部分工作。欢迎提供有关代码的反馈!



1

您可以使用proc文件系统轻松读取另一个进程的堆栈(为此您将需要root访问权限)。在从/ proc / pid / mem任意读取之前,您需要查阅/ proc / pid / maps。对该文件进行简单的读取即可显示很多条目。我们对标记为堆栈的条目感兴趣。一旦掌握了这一点,就需要阅读堆栈的上下边界。现在,只需打开/ proc / pid / mem文件,找到堆栈的下限并读取正确的数据大小即可。


1
你确定你的意思mems,而不是maps?(我mems/proc文件系统下看不到任何条目。)OP已经提到从中读取堆栈边界/proc/$pid/maps-您建议它们做些什么不同?
JigglyNaga

编辑错字。我做了我在回答中提到的内容,它转储了132 KB的堆栈数据。我们需要有关OP错误的更多信息。也许OP可以共享他用于读取堆栈边界的代码。如果他不回答,我将与我分享。
Ajay Brahmakshatriya

0

您可以尝试lsstack。就像其他所有成功的“读取另一个进程的堆栈”程序一样,它使用ptrace。我无法使用/ proc / $ pid / mem读取来运行程序。我相信您不能那样做,尽管从逻辑上讲您应该这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.