【问题标题】:How to exit a window procedure inside of a dll injected into a process?如何退出注入进程的dll中的窗口过程?
【发布时间】:2021-11-13 16:01:39
【问题描述】:

我在我的 dll 中创建了一个虚拟窗口作为 IPC 方法:

窗口程序:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_COPYDATA:
        {
          //....
        }
        case WM_DESTROY:
        case WM_QUIT:
            OutputDebugString(L"WM_QUIT");
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


int Main(LPCWSTR dummy_class_name)
{
    WNDCLASSEX wc{};
    //HWND dummy_hwnd;
    MSG Msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = 0;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = dummy_class_name;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);


    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    dummy_hwnd = CreateWindowEx(WS_EX_LEFT, // this is the default
                        dummy_class_name, // the name of the class, as passed to the RegisterClass function
                        NULL, //  Title
                        0,    //  dwFlags, in our case this really doesn't matter
                        0,    //  X 
                        0,    //  Y 
                        0,    //  W 
                        0,    //  H 
                        HWND_MESSAGE , //the most important flag! Creates a message-only window
                        0,    //  hMenu 
                        0 ,   //  hInstance this function gets the instance handle of the current app
                        0     //  lpParam 
    );

    if(dummy_hwnd == NULL)
    {
        MessageBox(NULL, L"Window Creation Failed!", L"Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(dummy_hwnd, SW_SHOW);
    UpdateWindow(dummy_hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return 0; // Msg.wParam;
}

我在辅助线程上初始化窗口过程:

class std::future<void> thread;

void Foo() {
    // ...
    thread = std::async(std::launch::async, [dummy_class_name]
    { Main(dummy_class_name); });
}

但是,当我与 dll 挂钩的进程“退出”时,它仍处于“休眠”状态。 当我不调用Foo 函数时,它会完全退出。

我尝试挂接目标进程函数ExitCode 并使用WM_QUITWM_DESTROY 调用WndProc 函数,它确实收到了消息,但进程仍然保持打开状态。

void ExitProcess_Hook(UINT uExitCode)
{
    OutputDebugString(L"\nExitProcess_Hook!");

    //PostMessageW(dummy_hwnd, WM_DESTROY, 0, 0);
    WndProc(dummy_hwnd, WM_DESTROY, 0, 0);

    return ExitProcess(uExitCode);
}

我错过了什么?

【问题讨论】:

  • 尝试调用TerminateProcess - "..因此,如果您不知道进程中所有线程的状态,最好调用TerminateProcess而不是ExitProcess。..." docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/…
  • @RichardCritten 谢谢,TerminateProcess 确实有效。你能把它作为答案吗?
  • @RichardCritten 如果您不知道进程中所有线程的状态 - 但这几乎总是如此。但并不意味着需要致电TerminateProcess。如果进程挂在 ExitProcess 中 - 这意味着编码错误。并使用TerminateProcess - 快速解决方案,而不是研究、理解和修复错误
  • 你应该在某处发布一个最小的复制项目。 stackoverflow.com/help/minimal-reproducible-example

标签: c++ winapi hook


【解决方案1】:

您缺少的一件事是窗口过程实际上不应该看到 WM_QUIT 消息。如果检索到的消息是 WM_QUIT 并且应该在调用 DispatchMessage 之前退出消息循环,则 GetMessage 返回 0。

您缺少的另一件事是窗口消息队列是基于线程的,因此即使您从仅消息窗口的 WindowProc 中的其他消息中执行PostQuitMessage(0);,退出消息也不会进入进程'主消息循环。您可以执行 PostThreadMessage(dwMainThreadID, WM_QUIT, 0, 0);(其中 dwMainThreadID 是您调用 std::async 时 GetCurrentThreadId() 的结果,这将进入进程的 UI 线程消息队列。

【讨论】:

  • " 在你调用 std::async 时" 你的意思是从Main 内部调用GetCurrentThreadId() 吗?然后将其与PostThreadMessage(dwMainThreadID, WM_QUIT, 0, 0); 一起使用
  • 我做到了,这个过程仍然是开放的。在调用PostThreadMessage(dwMainThreadID, WM_QUIT, 0, 0); 之后,我尝试了:HWND hwnd = FindWindowExW(HWND_MESSAGE, NULL, L"MyClass", NULL);,它找到了她hwnd,所以它没有收到WM_QUIT 消息?
  • @Razec - 你的问题根本不在这里。当调用ExitProcess 时,所有线程都被杀死,除了调用ExitProcess 的线程。没有意义向窗口发布一些东西 - 它的线程已经被杀死并且 nodody 接收消息(并且窗口也被破坏了)。更快地挂在全局对象的析构函数中。您首先需要查看调用堆栈
  • @RbMm 我的意思是当关闭注入dll的应用程序时,为什么它会杀死窗口过程所在的线程?窗口没有被破坏,正如我在之前的评论中所说,我仍然可以找到带有FindWindow 的窗口。
  • @Razec 如果 ExitProcess 被调用,进程中的所有线程都会被杀死。(调用者除外)。后调用堆栈
猜你喜欢
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 1970-01-01
相关资源
最近更新 更多