Hi
Migration to Detours from your own custom hooking implementation in 27.1.0 is a step in right direction. However, if you use Detours as is and without additional tweaks, it will result in third party hooks compatibility regress. There are two main reasons behind it:
Then simply use it to modify target hook pointer before calling DetourAttach:
The second possible reason of Detours related incompatibilities is lack of built-in rehooking mechanisms in Detours. If multiple hooks are installed by different apps and one hook owner application closes, whole hook chain can be lost and won’t be restored. It can become troublesome, considering that some hooks can be dynamically uninstalled even when hook owner application is still running (as an example, RTSS injects ID3D12CommandQueue::ExecuteCommandLists for a short period of time, the hook is only necessary to get initial D3D12 command queue / swapchain mapping during the first few rendered frames, then the hook is kicked so chained hooks can follow it too). So there should be some logic handling such cases.
Migration to Detours from your own custom hooking implementation in 27.1.0 is a step in right direction. However, if you use Detours as is and without additional tweaks, it will result in third party hooks compatibility regress. There are two main reasons behind it:
- Detours builds hook chains in rather specific way, which will be detected as unsafe by most of other third party hook engines. Detours is always overwriting top level JMP to the hook handler, which was previously installed by other hook. Yes, Detours performs such overwrite correctly and correctly relocates other hook’s JMP to own trampoline (with adjusting relative jump address properly), however other many other hooks are protected against such kind of hook relocation in general and do not tolerate modification of JMP they previously installed. Depending on third party hook implementation and architecture, they can do the following in case of installing Detour on top of their previously installed hook:
- Deadlock
- Crash
- Restore their own jump
Code:
PBYTE detour_skip_jmp_chain(PBYTE pbCode)
{
if (pbCode[0] == 0xe9)
{ // jmp +imm32
PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32*) & pbCode[1];
pbCode = pbNew;
return detour_skip_jmp_chain(pbCode);
}
#ifdef _WIN64
if (pbCode[0] == 0xff && pbCode[1] == 0x25)
{ // jmp [+imm32]
PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32*) & pbCode[2];
PBYTE pbNew = *(UNALIGNED PBYTE*)pbTarget;
pbCode = pbNew;
return detour_skip_jmp_chain(pbCode);
}
#else
if (pbCode[0] == 0xff && pbCode[1] == 0x25)
{ // jmp [imm32]
PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2];
PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget;
pbCode = pbNew;
return detour_skip_jmp_chain(pbCode);
}
#endif
return pbCode;
}
//////////////////////////////////////////////////////////////////////
PVOID DetourCodeFromPointerEx(PVOID pPointer, PVOID *ppGlobals)
{
return detour_skip_jmp_chain((PBYTE)DetourCodeFromPointer(pPointer, ppGlobals));
}
//////////////////////////////////////////////////////////////////////
Then simply use it to modify target hook pointer before calling DetourAttach:
Code:
lpTargetFn = DetourCodeFromPointerEx(lpTargetFn, NULL);
DetourAttach(&(PVOID&)lpTargetFn,DetourFn);
The second possible reason of Detours related incompatibilities is lack of built-in rehooking mechanisms in Detours. If multiple hooks are installed by different apps and one hook owner application closes, whole hook chain can be lost and won’t be restored. It can become troublesome, considering that some hooks can be dynamically uninstalled even when hook owner application is still running (as an example, RTSS injects ID3D12CommandQueue::ExecuteCommandLists for a short period of time, the hook is only necessary to get initial D3D12 command queue / swapchain mapping during the first few rendered frames, then the hook is kicked so chained hooks can follow it too). So there should be some logic handling such cases.