读取另一个进程的堆栈?

读取另一个进程的堆栈?

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

我还尝试在第一次使用 ptrace 附加到它之后从文件/proc/$pid/mem中提取的堆栈边界中读取(如建议的那样)/proc/$pid/maps这里)但读取不断失败(即使以 root 身份运行),尽管在尝试从进程的不同部分(例如堆)读取时相同的代码会成功。

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

答案1

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

答案2

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

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

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

您可以在以下位置看到一些实现大部分工作的免费代码这个源文件。欢迎对代码提供反馈!

答案3

另一个建议。

当/如果它被主 Linux 内核树接受时,您将能够使用 Christopher Yeoh 的交叉内存连接修补。请参阅文档进程_vm_readv例如。

答案4

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

相关内容