通过mhook的Winapi钩子导致程序崩溃或挂起

时间:2016-08-16 20:57:25

标签: c++ winapi hook

我正试图通过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;
    }
}

Hook工作正常,打印完成。但如果我将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。

1 个答案:

答案 0 :(得分:2)

您的挂钩声明错误。

查看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。所以你对调用堆栈管理不善。这就是你的代码崩溃的原因。

当您应该使用DOCINFO时,您也在使用DOCINFOW。在您的代码中很明显,您正在为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;
    }
}