我正在尝试将程序从 Windows 移植到 Linux。
当我发现 Linux 上没有“真正的”ReadProcessMemory 对应物时,我遇到了一个问题;我寻找了替代方案,并找到了 ptrace ,这是一个强大的进程调试器。
我很快用 C++ 编写了两个小的控制台应用程序来测试 ptrace ,然后在程序中使用它。

测试应用程序

这是被跟踪者;它保持每 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();
}

MemoryTest

这是示踪剂;它询问进程名称并使用命令 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();
}

关于c++ - Linux:有没有办法在不停止/暂停进程(SIGSTOP)的情况下使用 ptrace?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38676995/

10-11 18:57