挂钩 SetRect 时 Detours 3.0 应用程序崩溃

Detours 3.0 application crashing when hooking SetRect

我之前尝试挂钩 SetRect function using Detours but my program is crashing directly after hooking. I tried hooking other functions such as DrawText,一切正常,现在我不确定我的代码是否有问题,或者我不知道 SetRect(和其他类似函数)是否有问题意识到导致崩溃。

为了测试,我使用提供的 Detours 运行 和 dll 程序:

withdll.exe -d:mydll.exe simpleprogram.exe

其中 simpleprogram.exe 是一个简单的一键式 C# 应用程序。也尝试在记事本、calc、firefox 上进行测试,但它们都崩溃了。

我的挂钩DLL

#include <Windows.h>
#include <detours.h>
#include<string>
#include<fstream>
#include<iostream>
using namespace std;

wofstream out;

BOOL(__stdcall * T14)
(
_Out_ LPRECT lprc,
_In_  int    xLeft,
_In_  int    yTop,
_In_  int    xRight,
_In_  int    yBottom

) = SetRect;


__declspec(dllexport) BOOL  M14
(
_Out_ LPRECT lprc,
_In_  int    L,
_In_  int    T,
_In_  int    R,
_In_  int    B
){

    out << "SetRect: " << L << " " << T << " " << R << " " << B << endl;
    return T14(lprc, L, T, R, B);
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        out.open("out.txt");
        out << "Attached" << endl;
        DetourRestoreAfterWith();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)T14, M14);
        DetourTransactionCommit();
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        out << "detached" << endl;
        out.close();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID&)T14, M14);
        DetourTransactionCommit();
    }

    return TRUE;
}

我得到的输出:

Attached

SetRect: 138 161 323 161

所以在调用第一个 SetRect 函数后程序崩溃了,知道为什么会这样吗?

我刚刚尝试挂钩 SetRect(),我让它在 Calc 上正确挂钩。我将在下面放置我用于 DLL 的代码。

    static BOOL (WINAPI *TrueSetRect)(LPRECT, int, int, int, int) = SetRect;
    ...
    ...
    BOOL WINAPI __stdcall MySetRect(LPRECT lprc, int L, int T, int R, int B)
    {
        printf("MySetRect: L = %i; T = %i; R = %i; B = %i", L, T, R, B);
        return TrueSetRect(lprc, L, T, R, B);
    }

    __declspec(dllexport)
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
        if(fdwReason == DLL_PROCESS_ATTACH)
        {
             DetourTransactionBegin();
             DetourUpdateThread(GetCurrentThread());
             DetourAttach( &reinterpret_cast<PVOID&>(TrueSetRect), MySetRect);
             if(DetourTransactionCommit() == NO_ERROR)
             {
                 //Detour successful
             }
        }
        if(fdwReason == DLL_PROCESS_DETACH)
        {
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourDetach( &reinterpret_cast<PVOID&>(TrueSetRect), MySetRect);
            if(DetourTransactionCommit() != NO_ERROR)
            {
                //Detach unsuccessful
            } else {
                //Detach successful
            }
         }
     }

我怀疑这可能是您实例化 SetRect()YourSetRect() 的方式,因为这是我的代码与您的代码之间唯一不同的地方。

你绕行函数的调用约定是错误的。

Visual C++ 项目默认为 __cdecl,但所有 Windows API 使用 WINAPI (__stdcall).

由于调用约定的差异,您正在破坏调用堆栈。这个问题在 64 位软件中不存在,因为只有一个调用约定,但对于 x86,匹配原始函数原型中定义的任何调用约定至关重要。


__declspec(dllexport) BOOL WINAPI M14
(
_Out_ LPRECT lprc,
_In_  int    L,
_In_  int    T,
_In_  int    R,
_In_  int    B
){

    out << "SetRect: " << L << " " << T << " " << R << " " << B << endl;
    return T14(lprc, L, T, R, B);
}

另一个可能更严重且更难调试的注释。我会避免在 DllMain (...) 中执行 C++ 流 I/O。除非您将 DLL 静态链接到 MSVCRT,否则这会在您持有加载程序锁时引入对其他 DLL 的依赖。

如果从 DllMain 调用任何非静态链接的函数或 kernel32.dlluser32.dll 的一部分,则可能会导致死锁。好消息是 kernel32 和 user32 有大量的字符串函数——足以让你甚至不需要 C++ 标准库 ;)