2016-08-16 80 views
1

我试图挂钩StartDocW通过mhook截获打印。我使用AppInit_DLLs来加载我的库。通过mook的Winapi挂钩导致程序崩溃或挂起

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。

+0

你忽略了从'StartDocW'签名'WINAPI'调用约定(无论是在其更换,并指向旧功能的typedef) ,所以堆栈正在被消除。 –

回答

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

如果您应该使用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; 
    } 
} 
+0

我最初也假定调用约定不匹配。但OP正在编译x64代码。我错过了什么? – IInspectable

+0

@IInspectable仍然存在'DOCINFO'不匹配 –