【发布时间】:2014-07-22 19:41:30
【问题描述】:
我要做的是在 x86 asm 中的给定地址处截取寄存器值并将其放入变量中。为此,我将一个 dll 注入到我的程序中,这里是:
#include <Windows.h>
#include <stdio.h>
void test()
{
int randomNum;
DWORD address = 0x088AD6D; // return address (used only with JMP)
__asm
{
//rewriting what I erased with my detour
movsx eax, byte ptr ds:[esi+4]
push ebp
push eax
// moving ecx to my variable
mov randomNum, ecx
}
printf("number: %d\n", randomNum); // This correctly print the value I detoured
// this part is only used if I use JMP instead of call
__asm
{
JMP address // return to where the program should have been
}
}
void DetourAddress(void* funcPtr, void* hook)
{
// write jmp
BYTE cmd[5] =
{
0xE9, //jmp
0x00, 0x00, 0x00, 0x00 //address
};
/*
// write call
BYTE cmd[5] =
{
0xE8, // call
0x00, 0x00, 0x00, 0x00 // our function address
};
*/
DWORD dwProtect;
VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect); // make memory writable
DWORD offset = ((DWORD)hook - (DWORD)funcPtr - 5); //((to)-(from)-5)
memcpy(&cmd[1], &offset, 4); // write address into jmp
WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, cmd, 5, 0); // write jmp / call
VirtualProtect(funcPtr, 5, dwProtect, NULL); // reprotect
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourAddress((void*)0x088AD68, (void*)&test);
break;
case DLL_PROCESS_DETACH:
FreeConsole();
break;
}
return TRUE;
}
DetourAddress 函数是所有魔法应该发生的地方,我在我想绕道到我的 test() 函数的地址处编写了一个 jmp 命令。测试函数复制了被擦除的代码,我将 ecx 值移动到我的变量 randomNum 中。然后,如果我不绕道,我会跳回到代码应该在的位置。从理论上讲,它可以正常工作,但问题是在我的 test() 函数期间,寄存器值发生了变化,当我跳转回原始代码时,我的程序不仅停止按预期工作,而且很快就崩溃了因为访问冲突...
对于那些视觉化的人,以下是 ollydbg 中发生的事情:
第1步(原代码):
第二步,我绕行代码后的样子:
第三步,ollydbg中的test()函数:
第四步,jmp回到原代码:
如您所见,当我们返回到原始代码时,寄存器的值会完全改变,这会导致各种问题......我正在寻找一种方法来防止这种情况发生。
我发现这个问题 (C++ mid-function hook: get register values and jump back [x86 assembly on windows]) 与我的相似(甚至相同...),但给出的答案对我没有帮助。我尝试使用 call 命令而不是 jmp 不仅寄存器值不断变化,而且还导致另一个问题:当我从 test() 函数返回时,它返回到非可读内存而不是原始函数...
请帮忙?
【问题讨论】:
-
所以问题似乎源于您在绕道途中调用 printf 的事实。调用函数时,有些寄存器必须被调用函数保留,有些可以被覆盖。这些规则因使用的调用约定而异。也许您可以对值执行其他操作(将其写入缓冲区?)或推送/弹出在 printf 之前/之后更改的寄存器。
标签: c++ x86 hook inline-assembly