为什么使用函数指针调用函数可以绕过钩子?
Why does using a function pointer to call a function bypass the hook?
使用 Microsoft Detours 库,我编写了以下简单代码:
#include <Windows.h>
#include <detours.h>
#include <stdio.h>
void RealFunc(int num) {
printf("RealFunc %d\n", num);
}
void(*RealFuncPtr)(int) = &RealFunc;
void HookedFunc(int num) {
printf("HookedFunc %d\n", num + 100);
// RealFunc(num); // This starts an infinite loop because it calls HookedFunc which calls RealFunc which calls HookedFunc etc...
(*RealFuncPtr)(num); // This doesn't start an infinite loop and only calls RealFunc without calling HookedFunc. Why is this?
}
int main() {
RealFunc(100);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*) &RealFuncPtr, &HookedFunc); //redirect RealFunc to HookedFunc
if (DetourTransactionCommit() != NO_ERROR) {
return 0;
}
printf("Hook successful!\n");
RealFunc(100);
getchar(); // Pause console
return 0;
}
这是输出:
RealFunc 100
Hook successful!
HookedFunc 200
RealFunc 100
如您所见,由于 (*RealFuncPtr)(num);
行,真正的函数在挂钩函数调用的末尾被调用。但是,如果我注释掉 (*RealFuncPtr)(num);
并取消注释 RealFunc(num);
,它似乎开始了一个无限循环。为什么只在我使用 RealFunc(num);
时出现循环?
另外,出于某种原因,当我将项目设置为发布模式时,输出如下:
RealFunc 100
Hook successful!
RealFunc 100
这个钩子似乎在发布模式下不起作用。是我的 Visual Studio 配置还是我的代码有问题?
函数挂钩并不是编译器或任何标准所期望的。
明显是有绕过hook的优化。关闭各种编译器优化,直到找到导致问题的那个。
否则,根本不使用函数挂钩可能是个好习惯。
Detours 就是这样运作的。 DetourAttach
修改 RealFuncPtr
以指向一些直接调用原始函数的蹦床代码,绕过钩子。如果需要,挂钩能够调用原始函数是必需的。
至于发布模式,编译器会内联您对 RealFunc 的调用,从而使挂钩失效。您可以添加一个间接级别来绕过它,或者将编译器的 no-inline 属性应用于该函数。
使用 Microsoft Detours 库,我编写了以下简单代码:
#include <Windows.h>
#include <detours.h>
#include <stdio.h>
void RealFunc(int num) {
printf("RealFunc %d\n", num);
}
void(*RealFuncPtr)(int) = &RealFunc;
void HookedFunc(int num) {
printf("HookedFunc %d\n", num + 100);
// RealFunc(num); // This starts an infinite loop because it calls HookedFunc which calls RealFunc which calls HookedFunc etc...
(*RealFuncPtr)(num); // This doesn't start an infinite loop and only calls RealFunc without calling HookedFunc. Why is this?
}
int main() {
RealFunc(100);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach((PVOID*) &RealFuncPtr, &HookedFunc); //redirect RealFunc to HookedFunc
if (DetourTransactionCommit() != NO_ERROR) {
return 0;
}
printf("Hook successful!\n");
RealFunc(100);
getchar(); // Pause console
return 0;
}
这是输出:
RealFunc 100
Hook successful!
HookedFunc 200
RealFunc 100
如您所见,由于 (*RealFuncPtr)(num);
行,真正的函数在挂钩函数调用的末尾被调用。但是,如果我注释掉 (*RealFuncPtr)(num);
并取消注释 RealFunc(num);
,它似乎开始了一个无限循环。为什么只在我使用 RealFunc(num);
时出现循环?
另外,出于某种原因,当我将项目设置为发布模式时,输出如下:
RealFunc 100
Hook successful!
RealFunc 100
这个钩子似乎在发布模式下不起作用。是我的 Visual Studio 配置还是我的代码有问题?
函数挂钩并不是编译器或任何标准所期望的。
明显是有绕过hook的优化。关闭各种编译器优化,直到找到导致问题的那个。
否则,根本不使用函数挂钩可能是个好习惯。
Detours 就是这样运作的。 DetourAttach
修改 RealFuncPtr
以指向一些直接调用原始函数的蹦床代码,绕过钩子。如果需要,挂钩能够调用原始函数是必需的。
至于发布模式,编译器会内联您对 RealFunc 的调用,从而使挂钩失效。您可以添加一个间接级别来绕过它,或者将编译器的 no-inline 属性应用于该函数。