Linux进程图形界面在附加时冻结

huangapple go评论62阅读模式
英文:

Linux Process GUI freezes when attached

问题

我试图附加(Linux)/ .dll注入(Windows)到给定进程。 代码成功,但图像冻结。 附加的进程本身继续工作(我添加了一个恢复)。

我以前做过这个,但这是我第一次尝试一个具有GUI的进程(游戏)。

在Linux上是否可行,或者我没有正确的方法?

英文:

Im trying to attach(linux)/.dll inject(windows) to a given process. The code succeeds but the image freezes. The attached process itself continues to work (I added a resume).

Ive done this previously but this is the first time I try with a process(game) that has a GUI.

Is it doable in Linux or I dont have the correct approach?

#include <wx/wx.h>
#include <wx/thread.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <string>
#include <dirent.h>
#include <libgen.h>
#include <fcntl.h>
#include <signal.h> // Add this include at the top of your file

// Define new event types
wxDEFINE_EVENT(EVT_ATTACH_SUCCESS, wxThreadEvent);
wxDEFINE_EVENT(EVT_DETACH_SUCCESS, wxThreadEvent);

class WorkerThread : public wxThread {
public:
    WorkerThread(wxEvtHandler *parent) : wxThread(wxTHREAD_JOINABLE), m_parent(parent), targetPid(-1) {}

    ~WorkerThread() override {
        if (targetPid != -1) {
            if (ptrace(PTRACE_DETACH, targetPid, nullptr, nullptr) == -1) {
                wxLogError("Failed to detach from process: %s", strerror(errno));
            } else {
                wxLogMessage("Successfully detached from process %ld", targetPid);
            }
            wxQueueEvent(m_parent, new wxThreadEvent(wxEVT_THREAD, EVT_DETACH_SUCCESS));
        }
    }

    wxThread::ExitCode Entry() override {
        std::string processName = "dura";
        int pipefd[2];
        if (pipe(pipefd) == -1) {
            wxLogError("pipe failed: %s", strerror(errno));
            return (wxThread::ExitCode)0;
        }

        pid_t childPid = fork();
        if (childPid == -1) {
            wxLogError("fork failed: %s", strerror(errno));
            return (wxThread::ExitCode)0;
        }

        if (childPid == 0) {  // Child process
            close(pipefd[0]);  // Close read end
            dup2(pipefd[1], STDOUT_FILENO);  // Redirect stdout to pipe
            execlp("pgrep", "pgrep", processName.c_str(), nullptr);
            wxLogError("execlp failed: %s", strerror(errno));
            exit(EXIT_FAILURE);
        } else {  // Parent process
            close(pipefd[1]);  // Close write end

            int status;
            waitpid(childPid, &status, 0);

            if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {  // Process found
                char buf[32];
                read(pipefd[0], buf, sizeof(buf) - 1);
                pid_t targetPid = strtoul(buf, nullptr, 10);

                if (ptrace(PTRACE_ATTACH, targetPid, nullptr, nullptr) == -1) {
                    wxLogError("Failed to attach to process: %s", strerror(errno));
                    return (wxThread::ExitCode)0;
                } else {
                    this->targetPid = targetPid;
                    kill(targetPid, SIGCONT); // Add this line to send the SIGCONT signal
                    wxLogMessage("Successfully attached to process %ld", targetPid);
                    wxThreadEvent* event = new wxThreadEvent(wxEVT_THREAD, EVT_ATTACH_SUCCESS);
                    event->SetString("Successfully attached to process " + std::to_string(targetPid));
                    wxQueueEvent(m_parent, event);
                }

                // Wait for the process to stop
                waitpid(targetPid, nullptr, 0);

                while(!TestDestroy()) {
                    wxThread::This()->Sleep(1000);  // 1 second sleep
                }
            } else if (WIFEXITED(status)) {  // Process not found or error executing pgrep
                wxLogError("Process %s not found or error executing pgrep.", processName.c_str());
            }
        }

        return (wxThread::ExitCode)0;
    }

private:
    wxEvtHandler *m_parent;
    pid_t targetPid;
};

class MyFrame : public wxFrame {
public:
    MyFrame() : wxFrame(NULL, wxID_ANY, "Hello wxWidgets") {
        m_panel = new wxPanel(this);
        m_attachBtn = new wxButton(m_panel, wxID_ANY, "Attach");
        m_detachBtn = new wxButton(m_panel, wxID_ANY, "Detach");
        m_textCtrl = new wxTextCtrl(m_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
                                    wxTE_MULTILINE | wxTE_READONLY);

        wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
        sizer->Add(m_attachBtn, 0, wxEXPAND | wxALL, 5);
        sizer->Add(m_detachBtn, 0, wxEXPAND | wxALL, 5);
        sizer->Add(m_textCtrl, 1, wxEXPAND | wxALL, 5);
        m_panel->SetSizer(sizer);

        Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnAttach, this, m_attachBtn->GetId());
        Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnDetach, this, m_detachBtn->GetId());
        Bind(EVT_ATTACH_SUCCESS, &MyFrame::OnAttachSuccess, this);
        Bind(EVT_DETACH_SUCCESS, &MyFrame::OnDetachSuccess, this);

        m_workerThread = nullptr;
    }

    void OnAttach(wxCommandEvent &event) {
        m_workerThread = new WorkerThread(this);
        if (m_workerThread->Run() != wxTHREAD_NO_ERROR) {
            wxLogError("Could not create the worker thread!");
            delete m_workerThread;
            m_workerThread = nullptr;
        }
        m_textCtrl->AppendText("Attaching to process...\n");
    }

    void OnDetach(wxCommandEvent &event) {
        if (m_workerThread) {
            m_workerThread->Delete();  // Signals the thread to exit its main loop
            m_workerThread->Wait();    // Waits for the thread to exit
            delete m_workerThread;
            m_workerThread = nullptr;
        }
    }

    void OnAttachSuccess(wxThreadEvent &event) {
        m_textCtrl->AppendText(event.GetString() + "\n");
    }

    void OnDetachSuccess(wxThreadEvent &event) {
        m_textCtrl->AppendText("Successfully detached from process.\n");
    }

private:
    wxPanel *m_panel;
    wxButton *m_attachBtn;
    wxButton *m_detachBtn;
    wxTextCtrl *m_textCtrl;
    WorkerThread *m_workerThread;
};

class MyApp : public wxApp {
public:
    bool OnInit() override {
        MyFrame *frame = new MyFrame();
        frame->Show();
        return true;
    }
};

wxIMPLEMENT_APP(MyApp);

答案1

得分: 2

你正在尝试通过发送SIGCONT信号来恢复附加的进程。

ptrace手册描述了Signal-delivery-stop

当一个(可能是多线程的)进程接收到除了SIGKILL之外的任何信号时,内核会选择一个处理该信号的任意线程... 如果选择的线程被跟踪,它会进入信号传递停止状态。 在这一点上,信号尚未传递给进程,可以被跟踪器抑制。如果跟踪器不抑制信号,它会在下一个ptrace重启请求中将信号传递给被跟踪者。本手册页中称此信号传递的第二步为信号注入。请注意,如果信号被阻塞,直到信号解除阻塞,信号传递停止才会发生,唯一的例外是SIGSTOP不能被阻塞。

跟踪器将信号传递停止视为waitpid(2)返回WIFSTOPPED(status)为true,并返回由WSTOPSIG(status)返回的信号。如果信号是SIGTRAP,这可能是一种不同类型的ptrace停止;有关详细信息,请参阅下面的“Syscall-stops”和“execve”部分。

所以你所做的只是将信号排队发送给仍然由原始的PTRACE_ATTACH停止的进程。你可以按照手册中描述的方式,在发送信号后调用waitpid来确认这一点。

如果你只想让附加的进程继续运行而无需监督,你应该使用PTRACE_CONT

英文:

You're trying to resume the attached process by sending SIGCONT.

The ptrace manpage describes Signal-delivery-stop:

> When a (possibly multithreaded) process receives any signal except SIGKILL, the kernel selects an arbitrary thread which handles
the signal ... If the selected thread is traced, it enters signal-delivery-stop. At this point, the signal is not yet delivered to the process, and can be
suppressed by the tracer. If the tracer doesn't suppress the signal, it passes the signal to the tracee in the next ptrace restart
request. This second step of signal delivery is called signal injection in this manual page. Note that if the signal is blocked,
signal-delivery-stop doesn't happen until the signal is unblocked, with the usual exception that SIGSTOP can't be blocked.

> Signal-delivery-stop is observed by the tracer as waitpid(2) returning with WIFSTOPPED(status) true, with the signal returned by
WSTOPSIG(status). If the signal is SIGTRAP, this may be a different kind of ptrace-stop; see the "Syscall-stops" and "execve" sections below for details.

So all you've done is queued up a signal to a process which is still stopped by the original PTRACE_ATTACH. You should be able to confirm this by calling waitpid after sending the signal, as described in the manpage.

If you just want the attached process to keep running without supervision, you should use PTRACE_CONT instead.

huangapple
  • 本文由 发表于 2023年5月25日 23:02:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76333718.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定