Linux: 有没有办法在没有 stopping/pausing 进程 (SIGSTOP) 的情况下使用 ptrace?
Linux: is there a way to use ptrace without stopping/pausing the process (SIGSTOP)?
我正在尝试将程序从 Windows 移植到 Linux。
当我发现 Linux 上没有 "real" ReadProcessMemory
对应项时,我遇到了一个问题;我搜索了一个替代方案,然后找到了 ptrace
,一个功能强大的进程调试器。
在程序中使用它之前,我用 C++ 快速编写了两个小型控制台应用程序来测试 ptrace
。
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
修复了第一个内存地址值检索的问题,即使是seconds的值, 毫秒或微秒为 0。为什么?
大卫,
您看过 /proc 文件系统了吗?它包含内存映射文件,可用于查看完整过程 space。也可以在space中写入来设置断点。 /proc 中还有大量其他信息。
PTRACE_CONT 命令可用于继续进程。通常,当调试器附加时,目标将以 PTRACE_ATTACH 暂停。
手册页说 PTRACE_SIEZE 不应暂停进程。您使用的 Linux 是什么风格和版本? PTRACE_SIEZE 已经存在了很长一段时间,所以我不确定你为什么会遇到问题。
我注意到地址值设置为 0x12345。这是目标 space 中的有效地址吗?或者这只是一个例子?两个进程之间如何传递感兴趣的堆栈地址(&value)?
我不太确定 return 代码。通常 0 表示一切正常,errno 可能只是上次错误的遗留值。
--马特
经过大量研究,我很确定没有办法在不停止进程的情况下使用 ptrace
。
我找到了一个真正的ReadProcessMemory
对应物,叫做<a href="http://linux.die.net/man/2/process_vm_readv" rel="nofollow">process_vm_readv</a>
,就简单多了
我发布代码是希望能帮助处于我(以前)情况的人。
非常感谢 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();
}
我正在尝试将程序从 Windows 移植到 Linux。
当我发现 Linux 上没有 "real" ReadProcessMemory
对应项时,我遇到了一个问题;我搜索了一个替代方案,然后找到了 ptrace
,一个功能强大的进程调试器。
在程序中使用它之前,我用 C++ 快速编写了两个小型控制台应用程序来测试 ptrace
。
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
修复了第一个内存地址值检索的问题,即使是seconds的值, 毫秒或微秒为 0。为什么?
大卫,
您看过 /proc 文件系统了吗?它包含内存映射文件,可用于查看完整过程 space。也可以在space中写入来设置断点。 /proc 中还有大量其他信息。
PTRACE_CONT 命令可用于继续进程。通常,当调试器附加时,目标将以 PTRACE_ATTACH 暂停。
手册页说 PTRACE_SIEZE 不应暂停进程。您使用的 Linux 是什么风格和版本? PTRACE_SIEZE 已经存在了很长一段时间,所以我不确定你为什么会遇到问题。
我注意到地址值设置为 0x12345。这是目标 space 中的有效地址吗?或者这只是一个例子?两个进程之间如何传递感兴趣的堆栈地址(&value)?
我不太确定 return 代码。通常 0 表示一切正常,errno 可能只是上次错误的遗留值。
--马特
经过大量研究,我很确定没有办法在不停止进程的情况下使用 ptrace
。
我找到了一个真正的ReadProcessMemory
对应物,叫做<a href="http://linux.die.net/man/2/process_vm_readv" rel="nofollow">process_vm_readv</a>
,就简单多了
我发布代码是希望能帮助处于我(以前)情况的人。
非常感谢 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();
}