为什么使用函数指针调用函数绕过钩子?

时间:2015-05-26 15:19:30

标签: c++ hook detours

使用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配置还是我的代码有问题?

2 个答案:

答案 0 :(得分:1)

Detours的工作方式。 DetourAttach修改RealFuncPtr以指向一些直接调用原始函数的trampoline代码,绕过钩子。如果需要,钩子必须能够调用原始函数。

对于发布模式,编译器会内联对RealFunc的调用,使钩子无效。您可以添加一个间接级别来绕过它,或者将编译器的no-inline属性应用于该函数。

答案 1 :(得分:0)

编译器或任何标准都不能完全期望函数挂钩。

显然有一种优化绕过了钩子。关闭各种编译器优化,直到找到导致问题的那个。

否则,最好不要使用函数钩子。