挂钩Windows API函数会使应用程序崩溃

时间:2019-02-24 13:06:47

标签: c++ windows winapi hook detours

我正在制作一个与Microsoft Detours挂钩的特定Windows API函数的DLL,以便进行一些分析。 DLL被添加到第三方游戏的导入表中,以便运行DllMain函数并应用挂钩。

当我尝试挂钩GetFileSize函数时遇到问题。当我绕道而行时,即使是简单的绕行,由于访问冲突异常,游戏几乎立即崩溃。在我看来,弯路以某种方式破坏了应用程序。这是导致我的问题的最简单的代码:

static DWORD(WINAPI * TrueGetFileSize) (

    HANDLE  hFile,
    LPDWORD lpFileSizeHigh

    ) = GetFileSize;


DWORD GetFileSizeDetour(HANDLE hFile, LPDWORD lpFileSizeHigh) {
    return TrueGetFileSize(hFile, lpFileSizeHigh);
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
{
    if (DetourIsHelperProcess()) {
        return TRUE;
    }

    if (dwReason == DLL_PROCESS_ATTACH) {

        DetourRestoreAfterWith();

        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)TrueGetFileSize, GetFileSizeDetour);
        DetourTransactionCommit();
    }
    else if (dwReason == DLL_PROCESS_DETACH) {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID&)TrueGetFileSize, GetFileSizeDetour);
        DetourTransactionCommit();
    }
    return TRUE;
}

当我使用添加的DLL调试游戏时,绕道实际上被击中一次,但是当我继续执行时,绕道失败。这是进程崩溃时Visual Studio中的调用堆栈窗口的屏幕截图:

Crash call stack

问题似乎是在dsound.dll初始化CRT的过程中发生的,我猜这是Windows游戏如何处理声音的问题。

该过程因访问冲突异常而崩溃,原因是它无法执行调用堆栈屏幕快照中的位置。

这似乎使绕道看起来以某种方式破坏了应用程序,使某些依赖于该函数的代码失败了。但是,我可能误会了某些东西,或者试图以错误的方式来做某事。 :)

任何帮助或指导将不胜感激!

1 个答案:

答案 0 :(得分:1)

问题

绕行功能的calling convention

DWORD GetFileSizeDetour(HANDLE hFile, LPDWORD lpFileSizeHigh)

与原始GetFileSize()函数的调用约定不匹配:

DWORD WINAPI GetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh );

我已经通过右键单击>“转到声明”从“ fileapi.h”中获取了后者,并删除了不相关的内容。

WINAPI__stdcall的定义。您的绕行功能没有明确的调用约定修饰符,因此MSVC默认使用__cdecl

为什么这是个问题? __cdecl要求调用方清除堆栈,而__stdcall要求被调用函数清除堆栈。如果使用了错误的调用约定,显然会损坏堆栈。

奖励阅读Calling Conventions Demystified

解决方案

通过添加WINAPI来解决呼叫约定:

 DWORD WINAPI GetFileSizeDetour(HANDLE hFile, LPDWORD lpFileSizeHigh)