绕路 - 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();
将使它即使为空也能正常工作。
这是我正在使用的代码:
#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();
将使它即使为空也能正常工作。