所以我试图为游戏 Hook 一个函数,但有一个小问题。如果 eax、ebx、ecx 和 edx 等寄存器可以互换,为什么下面的第一个代码示例会导致游戏进程崩溃,但第二个代码不会崩溃并按预期工作?
// Crashes game process
void __declspec(naked) HOOK_UnfreezePlayer()
{
__asm push eax
if ( !state->player.frozen || !state->ready )
__asm jmp hk_Disabled
__asm
{
mov eax, g_dwBase_Addr
mov ebx, [eax + LOCAL_PLAYER_INFO_OFFSET]
add ebx, 0x4
mov ecx, [ebx]
add ecx, 0x40
lea edx, [esi + 0x0C]
cmp edx, ecx
je hk_Return
hk_Disabled:
movss [esi + 0x0C], xmm0
hk_Return:
pop eax
mov ecx, g_dwBase_Addr
add ecx, RETURN_UnfreezePlayer
jmp ecx
}
}
// Works
void __declspec(naked) HOOK_UnfreezePlayer()
{
__asm push eax
if ( !state->player.frozen || !state->ready )
__asm jmp hk_Disabled
__asm
{
mov ecx, g_dwBase_Addr
mov edx, [ecx + LOCAL_PLAYER_INFO_OFFSET]
add edx, 0x4
mov ebp, [edx]
add ebp, 0x40
lea ecx, [esi + 0x0C]
cmp ecx, ebp
je hk_Return
hk_Disabled:
movss [esi + 0x0C], xmm0
hk_Return:
pop eax
mov ecx, g_dwBase_Addr
add ecx, RETURN_UnfreezePlayer
jmp ecx
}
}
我认为崩溃可能是由于我的汇编代码覆盖了寄存器 eax、ebx、ecx 等中的重要数据引起的。例如,如果游戏在 eax 中存储了一个重要值,然后由于我的操作而导致该数据丢失,该怎么办? if 语句将结构体指针移动到 eax 中?有没有办法保留这些寄存器的内容并在返回之前将它们恢复为原始值?
最佳答案
当 Hook 一个已经编译的程序时,寄存器当然是不可互换的,因为各个寄存器的含义是由 Hook 程序的代码和该代码中 Hook 的位置定义的。因此,您必须检查被 Hook 的代码和 Hook 的位置,以确定被 Hook 的代码是否依赖于所保留的某些寄存器的内容。
通过开头的 push eax
指令和结尾的 pop eax
指令,您已经保存了 EAX 寄存器的内容并在之后恢复它。您可以对 EBX 和 EDX 寄存器执行相同的操作,或者简单地使用 PUSHAD/POPAD 指令来保存所有通用寄存器。根据游戏中 Hook 的位置,您可能还必须保留 EFLAGS 寄存器,这需要 PUSHFD/POPFD 指令。
保存和恢复 ECX 寄存器并不那么容易,因为钩子(Hook)正在使用该寄存器来计算完成后要跳转到的地址。
但是,由于您说第二个代码示例有效,而第一个代码示例导致 Hook 程序崩溃,因此问题很可能仅在于 EBX 寄存器被修改。这是因为第一个代码示例修改了 EBX 寄存器,而第二个代码示例则没有。
因此,解决您的问题的可能方法是以与保存 EAX 寄存器相同的方式保存 EBX 寄存器。为此,您只需在 push eax
指令的同一位置添加一条 push ebx
指令,并添加一条 pop ebx
> 指令与 pop eax 指令位于同一位置。但是,请注意,由于堆栈的工作方式,入栈和出栈指令必须是相反的顺序,如下所示:
Hook 开始:
push eax
push ebx
钩端:
pop ebx
pop eax
关于c++ - 除非使用某些寄存器,否则函数 Hook 会崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59573227/