【发布时间】:2020-04-21 16:51:06
【问题描述】:
所以我正在尝试为游戏挂钩一个功能,但有一个小问题。如果 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 中?有没有办法保留这些寄存器的内容,并在返回之前将它们恢复到原来的值?
【问题讨论】:
-
在标准调用约定中,只有 EAX、ECX 和 EDX 被调用破坏。您必须不触摸或保存/恢复调用者值的其他寄存器。在
naked函数中,编译器不会像通常那样为您执行此操作。 -
@PeterCordes:我不确定标准调用约定是否适用于此,因为 OP 正在讨论将钩子插入游戏,可能是通过在任意位置向其中注入代码。跨度>
标签: c++ visual-c++ x86 inline-assembly calling-convention