I am trying to hook SetRect function using Detours but my program is crashing directly after hooking. I tried hooking other functions such as DrawText before and everything worked fine and now I am not sure if there is a problem with my code or there is something about SetRect (and other similar functions) that I am not aware of causing the crash.
For testing I am using the provided Detours run with dll program:
withdll.exe -d:mydll.exe simpleprogram.exe
Where simpleprogram.exe is a simple one button C# application. Tried testing also on notepad, calc, firefox but all of them crashed too.
My hook 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;
}
The output I am getting:
Attached
SetRect: 138 161 323 161
So the program is crashing after the first SetRect function is called, any ideas why this is happening ?
Your detoured function's calling convention is wrong.
Visual C++ projects default to __cdecl
, but ALL of the Windows API uses WINAPI
(__stdcall
).
You are trashing the callstack due to differences in calling convention. This issue does not exist in 64-bit software since there is only one calling convention, but for x86 it is critically important that you match any calling convention defined in the original function's prototype.
__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);
}
On another, possibly even more serious and difficult to debug note. I would refrain from doing C++ stream I/O in DllMain (...)
. Unless you statically linked your DLL to the MSVCRT this brings in dependencies on other DLLs while you are holding the loader lock.
You can wind up deadlocking if you call any function from DllMain that is not statically linked or part of kernel32.dll
or user32.dll
. The good news is kernel32 and user32 have a plethora of string functions -- enough that you should not even need the C++ standard library ;)