绕路 - jmp 00000000

Detours - jmp 00000000

这是我正在使用的代码:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <detours.h>
#include <fstream>

#define real_sendto 0x152942C6
void(__cdecl* originalFunction)();

void tompa_sendto() {
    printf("Hellooo");
    return originalFunction();
}

void hook() {
    originalFunction = (void(__cdecl*)())DetourFunction((PBYTE)real_sendto, (PBYTE)tompa_sendto);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH: hook(); break;
        case DLL_PROCESS_DETACH: return FALSE; break;
    }
    return TRUE;
}

这段代码没有问题,它把钩子放在 0x152942C6 上,我可以看到它跳到了我的 tompa_sendto() 又回来了。

当我使用此代码作为挂钩时,它没有正确设置挂钩,
在内存中,我可以在 0x152942C6 看到:jmp 00000000

void tompa_sendto() {
    char buffer[] = {'x', 'y', 'z'};
    return originalFunction();
}

无论我在 tompa_sendto() 中放置什么代码都会使程序崩溃(因为错误的 jmp),我设法放置在那里的唯一 2 个代码是 printf 和 messageBoxA。

我能够重现这个问题(虽然只有绕行 1.5),所以我做了一些挖掘。看来问题只是你的绕行功能是空的。

当您通过 return 从另一个调用结束调用时,编译器会进行特定的优化:它不会调用该函数,而是通过跳转而不是调用直接延迟控制。这不会推送 return 地址,因此,当下一个函数 return 时,它使用前一个函数 return 地址,并且同时从两个函数中使用 return .长话短说,函数以 jmp func 而不是 call func; ret.

结尾

现在,当你的函数为空时,这个跳转是函数中唯一的指令。另一个事实是您通过变量调用原始函数,这转化为间接跳转。问题是,Detours 1.5 专门检查您的函数是否以间接跳转开始,如果是,它会根据找到的间接跳转使用直接跳转挂钩目标函数。为什么 ?因为很多函数,比如DLL调用,都是通过间接跳转表来调用的,Detours如果找到了就会尝试走捷径。

在你的例子中,目标函数通过跳转到 originalFunction 来挂钩,但是当你安装挂钩时这个变量是 0,因此是 jmp 0。尝试在挂钩前将 originalFunction 设置为 3,你会看到。如果你的函数不为空,这个问题就不会发生,所以不用担心。 returning 之前的一个简单的 __nop(); 将使它即使为空也能正常工作。