Linux: есть ли способ использовать ptrace без остановки / приостановки процесса (SIGSTOP)?

Я пытаюсь портировать программу с Windows на Linux.
Я столкнулся с проблемой, когда узнал, что нет «настоящего» ReadProcessMemory аналог на Linux; Я искал альтернативу, и я нашел 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();
}

Тест памяти

Это трассировщик; он запрашивает имя процесса и получает PID с помощью команды pidof -s, затем 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.

Обновить: С помощью Sleeper в MemoryTest перед циклом «do-while» устраняется проблема получения первого значения адреса памяти, даже если значение секунд, миллисекунд или микросекунд равно 0. Почему?

2

Решение

Davide,

Вы смотрели на файловую систему / proc? Он содержит файлы карты памяти, которые можно использовать для просмотра всего пространства процесса. Вы также можете написать в пространстве, чтобы установить точку останова. Также в / proc есть много другой информации.

Команда PTRACE_CONT может использоваться для продолжения процесса. Как правило, цель будет приостановлена ​​с помощью PTRACE_ATTACH, когда подключится отладчик.

Страница man говорит, что PTRACE_SIEZE не должен приостанавливать процесс. Какой вариант и версию Linux вы используете? PTRACE_SIEZE существует уже довольно давно, поэтому я не уверен, почему у вас там проблемы.

Я отмечаю, что значение addr установлено в 0x12345. Это действительный адрес в целевом пространстве? Или это просто пример? Как интересует адрес стека (&значение) между двумя процессами?

Я не слишком уверен насчет кодов возврата. Обычно 0 означает, что все хорошо, errno может быть просто значением зависания из последней ошибки.

—Matt

2

Другие решения

После долгих исследований я уверен, что нет никакого способа использовать 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();
}
1

По вопросам рекламы [email protected]