I have the following basic DLL code that detours the Windows API WindowsEnumDisplaySettingsA function:
static BOOL(WINAPI* WindowsEnumDisplaySettingsA)(LPCSTR lpszDeviceName, DWORD iModeNum,
DEVMODEA* lpDevMode) = EnumDisplaySettingsA;
BOOL WINAPI DetouredEnumDisplaySettingsA(LPCSTR lpszDeviceName, DWORD iModeNum,
DEVMODEA* lpDevMode)
{
// Call the real GetDeviceCaps function
return WindowsEnumDisplaySettingsA(lpszDeviceName, iModeNum, lpDevMode);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
// Restore the in memory import table after we are loaded by withdll.exe
DetourRestoreAfterWith();
// Switch based on the reason for this function call
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Attach the function detours
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)WindowsEnumDisplaySettingsA, DetouredEnumDisplaySettingsA);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
// Detach the function detours
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)WindowsEnumDisplaySettingsA, DetouredEnumDisplaySettingsA);
DetourTransactionCommit();
break;
}
return TRUE;
}
which works great when starting the program with the following command:
withdll.exe /d:test.dll program.exe
However, if I change the function being detoured to GetDeviceCaps and end up with the following code (the only changes are the function name and signature):
static int (WINAPI* WindowsGetDeviceCaps)(HDC hdc, int index) = GetDeviceCaps;
int DetouredGetDeviceCaps(HDC hdc, int index)
{
// Call the real GetDeviceCaps function
return WindowsGetDeviceCaps(hdc, index);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
// Restore the in memory import table after we are loaded by withdll.exe
DetourRestoreAfterWith();
// Switch based on the reason for this function call
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Attach the function detours
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)WindowsGetDeviceCaps, DetouredGetDeviceCaps);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
// Detach the function detours
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)WindowsGetDeviceCaps, DetouredGetDeviceCaps);
DetourTransactionCommit();
break;
}
return TRUE;
}
and start the application with the exact same command, it simply fails silently without any errors displayed. In the Event Viewer I find the following error:
I've tried this with several different applications and they all fail silently when detouring the GetDeviceCaps function but work just fine if I detour a different function. Is there any other way to go about detouring the GetDeviceCaps function in an application without it preventing the application from starting?
I have the following basic DLL code that detours the Windows API
WindowsEnumDisplaySettingsA
function:which works great when starting the program with the following command:
However, if I change the function being detoured to
GetDeviceCaps
and end up with the following code (the only changes are the function name and signature):and start the application with the exact same command, it simply fails silently without any errors displayed. In the Event Viewer I find the following error:
The exception code seems to stand for
STATUS_ACCESS_VIOLATION
according to https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55 which must be happening somewhere in the Detours code because nothing in the DLL code should be throwing this exception.I've tried this with several different applications and they all fail silently when detouring the GetDeviceCaps function but work just fine if I detour a different function. Is there any other way to go about detouring the GetDeviceCaps function in an application without it preventing the application from starting?