C++ C++;midfunction钩子覆盖原始局部变量
我编写了一个中间函数钩子,我注意到函数的原始局部变量被我在函数中声明的变量覆盖 这是我的密码:C++ C++;midfunction钩子覆盖原始局部变量,c++,x86,inline-assembly,C++,X86,Inline Assembly,我编写了一个中间函数钩子,我注意到函数的原始局部变量被我在函数中声明的变量覆盖 这是我的密码: DWORD jbPlantTrap = 0x48ED53 + 7; DWORD jbPlantTrapSkip = 0x48EDD6; __declspec(naked) void hkPlantTrap() { __asm { PUSHAD PUSHFD } // this variable is overwriting the or
DWORD jbPlantTrap = 0x48ED53 + 7;
DWORD jbPlantTrapSkip = 0x48EDD6;
__declspec(naked) void hkPlantTrap()
{
__asm
{
PUSHAD
PUSHFD
}
// this variable is overwriting the original [EBP-4]
unsigned char* player;
unsigned char* packet;
__asm
{
MOV ECX, DWORD PTR SS : [EBP + 0x8]
MOV player, ECX
MOV EDX, DWORD PTR SS : [EBP + 0x0C]
MOV packet, EDX
}
if (*(WORD*)(packet + 2) == 114 && sub_46261E(player, 104))
{
__asm
{
POPFD
POPAD
JMP[jbPlantTrapSkip]
}
}
else
{
// go back to original jump
__asm
{
POPFD
POPAD
MOV DWORD PTR SS : [EBP - 0x34] , 0x0
JMP[jbPlantTrap]
}
}
}
我怎样才能防止它这样做,这样我在迂回中声明的任何变量都不会影响原始函数
就像player
是如何覆盖[EBP-4]
并弄乱原始函数上的变量,从而导致奇怪的行为
我的挂钩功能供参考:
void __cdecl PlaceJMP(BYTE *pAddress, DWORD dwJumpTo, DWORD dwLen)
{
DWORD dwOldProtect, dwBkup, dwRelAddr;
VirtualProtect(pAddress, dwLen, PAGE_EXECUTE_READWRITE, &dwOldProtect);
dwRelAddr = (DWORD)(dwJumpTo - (DWORD)pAddress) - 5;
*pAddress = 0xE9;
*((DWORD *)(pAddress + 0x1)) = dwRelAddr;
for (DWORD x = 0x5; x < dwLen; x++)
*(pAddress + x) = 0x90;
VirtualProtect(pAddress, dwLen, dwOldProtect, &dwBkup);
}
更新 将变量声明移到函数外部可以使其按预期工作,但我希望避免这种情况。我还有其他选择吗
DWORD jbPlantTrap = 0x48ED53 + 7;
DWORD jbPlantTrapSkip = 0x48EDD6;
unsigned char* player1; // moved outside function
unsigned char* packet1; // moved outside function
__declspec(naked) void hkPlantTrap() {
...
当使用mid函数钩子和declspec裸函数时,必须在汇编中编写所有函数。您应该声明裸函数之外的任何变量,然后在程序集中引用这些变量,这样就不会损坏堆栈
或者,您可以增加堆栈大小,完成自己的工作,然后在返回之前展开堆栈,但老实说,这会更烦人。当使用mid函数挂钩和declspec裸函数时,您必须在汇编中编写所有内容。您应该声明裸函数之外的任何变量,然后在程序集中引用这些变量,这样就不会损坏堆栈
或者,您可以增加堆栈大小,完成自己的工作,然后在返回之前展开堆栈,但老实说,这会更烦人。IIRC,裸函数的整个主体都必须用asm编写。使用C变量和语句将导致编译器生成代码,而没有进行任何正确的设置。此外,您自己的asm使用
[EBP+0x8]
表示某些内容,但您从未将EBP设置为指向任何内容。@PeterCordes打印出player
和packet
实际上表明它指向正确的变量,因此我相信[EBP]
设置正确。我还有其他类似的函数,可以用,但它仍然替换了原来的函数变量。幸运的是,这些被覆盖的变量并不重要,因此不会影响行为。不幸的是,这个函数覆盖了一个重要的变量。IIRC,一个裸函数的整个函数体必须用asm编写。使用C变量和语句将导致编译器生成代码,而没有进行任何正确的设置。此外,您自己的asm使用[EBP+0x8]
表示某些内容,但您从未将EBP设置为指向任何内容。@PeterCordes打印出player
和packet
实际上表明它指向正确的变量,因此我相信[EBP]
设置正确。我还有其他类似的函数,可以用,但它仍然替换了原来的函数变量。幸运的是,这些被覆盖的变量并不重要,因此不会影响行为。不幸的是,这个函数覆盖了一个重要的变量。我确实尝试过通过保存esp和sub'ng它来执行prolog
和epilog
,希望能为变量获得额外的空间。在我的2个int指针中有8个字节,但它似乎根本不起作用。只在函数外使用变量是可行的,但我有点担心多线程访问全局变量。@majidarif我这么做已经很长时间了,而且在多线程处理方面从来没有遇到过任何问题,但将来可能会出现问题。当你到达那里时,我会穿过那座桥,我确实试着做了一个prolog
和epilog
,通过保存esp和sub'ng它,希望能为变量获得额外的空间。在我的2个int指针中有8个字节,但它似乎根本不起作用。只在函数外使用变量是可行的,但我有点担心多线程访问全局变量。@majidarif我这么做已经很长时间了,而且在多线程处理方面从来没有遇到过任何问题,但将来可能会出现问题。我想,你到了那里我会过桥的
DWORD jbPlantTrap = 0x48ED53 + 7;
DWORD jbPlantTrapSkip = 0x48EDD6;
unsigned char* player1; // moved outside function
unsigned char* packet1; // moved outside function
__declspec(naked) void hkPlantTrap() {
...