绕过3.0应用程序在钩子SetRect时崩溃

Detours 3.0 application crashing when hooking SetRect

本文关键字:SetRect 崩溃 应用程序 绕过      更新时间:2023-10-16

我试图使用弯路挂钩SetRect函数,但我的程序在挂钩后直接崩溃。我尝试挂钩其他功能,如DrawText之前,一切工作正常,现在我不确定是否有问题与我的代码或有一些关于SetRect(和其他类似的功能),我不知道导致崩溃。

对于测试,我使用提供的Detours运行与dll程序:

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

simpleprogram.exe是一个简单的一键c#应用程序。我也试过在记事本,calc,火狐上测试,但是它们都崩溃了。

我的钩子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;
}

我得到的输出:

SetRect: 138 161 323 161

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

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

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++标准库;)

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