所以我试图为游戏添加一个函数,但是有一个小问题。如果诸如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?有没有办法保留这些寄存器的内容并在返回之前将它们恢复为原始值?

最佳答案

挂钩已编译的程序时,寄存器肯定是不可互换的,因为各个寄存器的含义由挂钩程序的代码和挂钩在该代码中的位置定义。因此,您必须检查挂钩的代码和挂钩的位置,以确定挂钩的代码是否依赖于保留的某些寄存器的内容。

开头是push eax指令,结尾是pop eax指令,您已经在保留EAX寄存器的内容并在其后恢复它。您可以对EBX和EDX寄存器执行相同的操作,也可以仅使用PUSHAD / POPAD指令保存所有通用寄存器。根据游戏中钩子(Hook)的位置,您可能还必须保留EFLAGS寄存器,这需要PUSHFD / POPFD指令。

保存和恢复ECX寄存器并不是那么容易,因为挂钩正在使用该寄存器来计算完成后跳转到的地址。

但是,由于您说第二个代码示例在第一个代码示例导致钩子(Hook)程序崩溃的同时起作用,因此问题很可能仅在于修改了EBX寄存器。这是因为第一个代码样本修改了EBX寄存器,而第二个代码样本没有修改。

因此,解决您的问题的可能方法是,以与保留EAX寄存器相同的方式保留EBX寄存器。为此,您只需要在push ebx指令的相同位置添加push eax指令,并在与pop ebx指令相同的位置添加pop eax指令即可。但是,请注意,由于堆栈的工作方式,推入和弹出指令必须采用相反的顺序,如下所示:

挂钩开始:

push eax
push ebx

钩端:
pop ebx
pop eax

07-24 09:45
查看更多