【问题标题】:Winapi hook via mhook causes program crash or hang通过 mhook 的 Winapi 钩子导致程序崩溃或挂起
【发布时间】:2016-08-16 20:57:24
【问题描述】:

我正在尝试挂钩 StartDocW 以通过 mhook 拦截打印。我使用 AppInit_DLLs 加载我的库。

DLL 代码很简单:

#include <windows.h>
#include "mhook/mhook-lib/mhook.h"
using StartDocPtr = int(*)(HDC, const DOCINFO*);
StartDocPtr orig;

int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
    return orig(hdc, lpdi);
}

BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
    orig = (StartDocPtr)GetProcAddress(GetModuleHandle("gdi32"), "StartDocW");
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
        break;
    case DLL_PROCESS_DETACH:
        Mhook_Unhook((PVOID*)&orig);
        break;
    }
}

挂钩正常工作,打印完成。但是如果我将 HookStartDocW 更改为以下:

int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
    char buf[40];
    GetModuleFileName(NULL, buf, 40);
    return orig(hdc, lpdi);
}

打印程序会立即崩溃。即使我只是离开char buf[40] 并评论GetModuleHandle - 程序也会挂起。为什么会这样?

此外,如果程序崩溃\打印时挂起(如果我添加了除 return orig(hdc, lpdi) 之外的任何内容)- PC 开始表现得很奇怪,拒绝运行程序等。如果我重新启动它 - Windows 只是在启动屏幕上无休止地旋转,让它恢复运行的唯一方法是通过 liveCD 启动并重命名\删除我的钩子 DLL。

打印程序:Excel 2016、记事本。

编译器 - MSVC 2015,x64 版本的 DLL 编译,使用 MBCS 而不是 unicode。

【问题讨论】:

  • 你已经从 StartDocW 签名中遗漏了 WINAPI 调用约定(在它的替换和指向旧函数的 typedef 中),所以堆栈正在被修改。

标签: c++ winapi hook


【解决方案1】:

你的钩子被宣布错误。

StartDocW()Wingdi.h中的实际声明:

__gdi_entry WINGDIAPI int WINAPI StartDocW(__in HDC hdc, __in CONST DOCINFOW *lpdi);

你可以忽略__gdi_entryWINGDIAPI 简单地解析为 __declspec(dllimport)。此声明中重要的是WINAPI

几乎所有 Win32 API 函数一样,StartDocW() 使用__stdcall 调用约定。 WINAPI 宏解析为 __stdcall

您的代码根本没有指定任何调用约定,因此它使用编译器的默认值,通常是__cdecl。所以你对调用堆栈管理不善。这就是您的代码崩溃的原因。

当您应该使用 DOCINFOW 时,您也在使用 DOCINFO。在您的代码中很清楚您正在为 MBCS 而不是为 UNICODE 进行编译,因此 DOCINFO 映射到 DOCINFOA。您不能将DOCINFOA 传递给StartDocW(),它需要一个DOCINFOW

你需要修正你的声明,例如:

#include <windows.h>
#include "mhook/mhook-lib/mhook.h"

using StartDocPtr = int (WINAPI *)(HDC, const DOCINFOW*);
StartDocPtr orig = nullptr;

int WINAPI HookedStartDocW(HDC hdc, const DOCINFOW* lpdi) {
    //...
    return orig(hdc, lpdi);
}

BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
    orig = (StartDocPtr) GetProcAddress(GetModuleHandle(TEXT("gdi32")), "StartDocW");
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
        break;
    case DLL_PROCESS_DETACH:
        Mhook_Unhook((PVOID*)&orig);
        break;
    }
}

【讨论】:

  • 我最初也假设调用约定不匹配。但是 OP 正在编译 x64 代码。我错过了什么?
  • @IInspectable 仍然存在 DOCINFO 不匹配
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多