Linux:有没有一种方法可以在不停止/暂停进程的情况下使用ptrace(SIGSTOP)



我正在尝试将一个程序从Windows移植到Linux
当我发现Linux上没有"真正的"ReadProcessMemory对应程序时,我遇到了一个问题;我搜索了一个替代方案,发现了一个强大的进程调试器ptrace
在程序中使用ptrace之前,我用C++快速编写了两个小型控制台应用程序来测试它。

TestApp

这就是痕迹;它保持每50毫秒打印两个整数,同时每次将其值增加1。

#include <QCoreApplication>
#include <QThread>
#include <iostream>
using namespace std;
class Sleeper : public QThread
{
public:
    static void usleep(unsigned long usecs){QThread::usleep(usecs);}
    static void msleep(unsigned long msecs){QThread::msleep(msecs);}
    static void sleep(unsigned long secs){QThread::sleep(secs);}
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    int value = 145;
    int i = 0;
    do {
    cout << "i: " << i << " " << "Value: " << value << endl;
    value++;
    i++;
    Sleeper::msleep(50);
    } while (true);
    return a.exec();
}

内存测试

这是示踪剂;它询问进程名称并使用命令pidof -s检索PID,然后ptrace附加到进程并每隔500毫秒检索内存地址值,共10次。

#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <string>
#include <sys/ptrace.h>
#include <errno.h>
using namespace std;
class Sleeper : public QThread
{
public:
    static void usleep(unsigned long usecs){QThread::usleep(usecs);}
    static void msleep(unsigned long msecs){QThread::msleep(msecs);}
    static void sleep(unsigned long secs){QThread::sleep(secs);}
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    char process_name[50];
    cout << "Process name: ";
    cin >> process_name;
    char command[sizeof(process_name) + sizeof("pidof -s ")];
    snprintf(command, sizeof(command), "pidof -s %s", process_name);
    FILE* shell = popen(command, "r");
    char pidI[sizeof(shell)];
    fgets(pidI, sizeof(pidI), shell);
    pclose(shell);
    pid_t pid = atoi(pidI);
    cout << "The PID is " << pid << endl;
    long status = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
    cout << "Status: " << status << endl;
    cout << "Error: " << errno << endl;
    unsigned long addr = 0x012345; // Example address, not the true one
    int i = 0;
    do {
    status = ptrace(PTRACE_PEEKDATA, pid, addr, NULL);
    cout << "Status: " << status << endl;
    cout << "Error: " << errno << endl;
    i++;
    Sleeper::msleep(500);
    } while (i < 10);
    status = ptrace(PTRACE_DETACH, pid, NULL, NULL);
    cout << "Status: " << status << endl;
    cout << "Error: " << errno << endl;
    return a.exec();
}

一切正常,但TestApp会暂停(SIGSTOP),直到ptrace从中分离。
此外,当它连接到进程时,状态为0,错误为2;它第一次尝试检索内存地址值时失败,状态为-1,错误为3。这正常吗
有没有办法防止ptrace向进程发送SIGSTOP信号?我已经尝试使用PTRACE_SEIZE而不是PTRACE_ATTACH,但它不起作用:状态-1和错误3。

更新:在"do while"循环之前在MemoryTest中使用Sleeper可以修复第一个内存地址值检索的问题,即使秒、毫秒或微秒的值为0。为什么?

经过大量研究,我确信没有一种方法可以在不停止进程的情况下使用ptrace
我发现了一个真正的ReadProcessMemory对应物,叫做process_vm_readv,它要简单得多

我发布这个代码是希望能帮助一个和我(以前)处境相同的人。

非常感谢mkrautz用这个漂亮的函数帮助编写MemoryTest。

#include <QCoreApplication>
#include <QThread>
#include <sys/uio.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <iostream>
using namespace std;
class Sleeper : public QThread
{
public:
    static void usleep(unsigned long usecs){QThread::usleep(usecs);}
    static void msleep(unsigned long msecs){QThread::msleep(msecs);}
    static void sleep(unsigned long secs){QThread::sleep(secs);}
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    char process_name[50];
    cout << "Process name: ";
    cin >> process_name;
    char command[sizeof(process_name) + sizeof("pidof -s ")];
    snprintf(command, sizeof(command), "pidof -s %s", process_name);
    FILE* shell = popen(command, "r");
    char pidI[sizeof(shell)];
    fgets(pidI, sizeof(pidI), shell);
    pclose(shell);
    pid_t pid = atoi(pidI);
    cout << "The PID is " << pid << endl;
    if (pid == 0)
        return false;
    struct iovec in;
    in.iov_base = (void *) 0x012345; // Example address, not the true one
    in.iov_len = 4;
    uint32_t foo;
    struct iovec out;
    out.iov_base = &foo;
    out.iov_len = sizeof(foo);
    do {
        ssize_t nread = process_vm_readv(pid, &out, 1, &in, 1, 0);
        if (nread == -1) {
            fprintf(stderr, "error: %s", strerror(errno));
        } else if (nread != in.iov_len) {
            fprintf(stderr, "error: short read of %li bytes", (ssize_t)nread);
        }
        cout << foo << endl;
        Sleeper::msleep(500);
    } while (true);
    return a.exec();
}

Davide,

您看过/proc文件系统吗?它包含可用于查看整个进程空间的内存映射文件。您也可以在空间中写入以设置断点。/proc中还有大量其他信息。

PTRACE_CONT命令可用于继续处理。通常,当调试器连接时,目标将使用PTRACE_ATTACH暂停。

手册页上说PTRACE_SIEZE不应该暂停这个过程。您使用的Linux是什么风格和版本?PTRACE_SIEZE已经存在很长一段时间了,所以我不知道你为什么在那里遇到麻烦。

我注意到addr值设置为0x12345。这是目标空间中的有效地址吗?或者这只是一个例子?两个进程之间如何传递感兴趣的堆栈地址(&value)?

我不太确定返回代码。通常,0表示一切正常,errno可能只是上一个错误的遗留值。

--Matt

相关内容

最新更新