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

时间:2016-08-10 13:04:48

标签: c++ dll hook code-injection detours

我正在尝试使用Detours挂钩SetRect函数,但我的程序在挂钩后直接崩溃。我之前试过挂钩DrawText之类的其他功能,一切正常,现在我不确定我的代码是否有问题,或者有些东西是关于SetRect(和其他类似功能)我不知道造成的碰撞。

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

../admin_module/images/

其中simpleprogram.exe是一个简单的单键C#应用程序。尝试在记事本,计算器,火狐上进行测试,但所有这些都崩溃了。

我的钩子DLL

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

我得到的输出:

  

     

SetRect:138 161 323 161

所以在调用第一个SetRect函数后程序崩溃了,为什么会发生这种情况?

2 个答案:

答案 0 :(得分:2)

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

Visual C ++项目默认为__cdecl,但所有Windows API都使用WINAPI__stdcall)。

由于调用约定的不同,您正在破坏callstack。这个问题在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 ++标准库;)

答案 1 :(得分:1)

我刚尝试挂钩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()的方式,因为这是我的代码和您的代码之间唯一的不同。