C ++中间函数钩子覆盖原始局部变量

问题描述 投票:0回答:1

我写了一个中间函数钩子,我注意到函数的原始局部变量被我在函数中声明的变量所覆盖。

这是我的代码:

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);
}

相关来源:

CPU Disasm
Address   Hex dump          Command                                  Comments
0048ED53  |> \C745 CC 00000 MOV DWORD PTR SS:[LOCAL.13],0
0048ED5A  |.  EB 09         JMP SHORT 0048ED65
0048ED5C  |>  8B4D CC       /MOV ECX,DWORD PTR SS:[EBP-34]
0048ED5F  |.  83C1 01       |ADD ECX,1
0048ED62  |.  894D CC       |MOV DWORD PTR SS:[EBP-34],ECX
0048ED65  |>  837D CC 02    |CMP DWORD PTR SS:[EBP-34],2
0048ED69  |.  73 6B         |JNB SHORT 0048EDD6
0048ED6B  |.  8B55 CC       |MOV EDX,DWORD PTR SS:[EBP-34]
0048ED6E  |.  8B45 08       |MOV EAX,DWORD PTR SS:[EBP+8]
0048ED71  |.  66:8B8C50 E43 |MOV CX,WORD PTR DS:[EDX*2+EAX+37E4]
0048ED79  |.  51            |PUSH ECX                                ; /Arg1
0048ED7A  |.  E8 11E8FFFF   |CALL 0048D590                           ; \file.0048D590
0048ED7F  |.  83C4 04       |ADD ESP,4
0048ED82  |.  8945 D4       |MOV DWORD PTR SS:[EBP-2C],EAX
0048ED85  |.  837D D4 00    |CMP DWORD PTR SS:[EBP-2C],0
0048ED89  |.^ 74 49         |JE SHORT 0048EDD4
0048ED8B  |.  8B55 D4       |MOV EDX,DWORD PTR SS:[EBP-2C]
0048ED8E  |.  33C0          |XOR EAX,EAX
0048ED90  |.  66:8B82 3A270 |MOV AX,WORD PTR DS:[EDX+273A]
0048ED97  |.  8B4D E4       |MOV ECX,DWORD PTR SS:[EBP-1C]
0048ED9A  |.  81E1 FFFF0000 |AND ECX,0000FFFF
0048EDA0  |.  3BC1          |CMP EAX,ECX
0048EDA2  |.^ 75 30         |JNE SHORT 0048EDD4
0048EDA4  |.  8B55 D4       |MOV EDX,DWORD PTR SS:[EBP-2C]
0048EDA7  |.  33C0          |XOR EAX,EAX
0048EDA9  |.  66:8B82 4B270 |MOV AX,WORD PTR DS:[EDX+274B]
0048EDB0  |.  8B4D 08       |MOV ECX,DWORD PTR SS:[EBP+8]
0048EDB3  |.  33D2          |XOR EDX,EDX
0048EDB5  |.  66:8B51 0C    |MOV DX,WORD PTR DS:[ECX+0C]
0048EDB9  |.  3BC2          |CMP EAX,EDX
0048EDBB  |.^ 75 17         |JNE SHORT 0048EDD4
0048EDBD  |.  6A 05         |PUSH 5                                  ; /Arg2 = 5
0048EDBF  |.  8B45 08       |MOV EAX,DWORD PTR SS:[EBP+8]            ; |
0048EDC2  |.  66:8B48 0C    |MOV CX,WORD PTR DS:[EAX+0C]             ; |
0048EDC6  |.  51            |PUSH ECX                                ; |Arg1
0048EDC7  |.  E8 A3FEFFFF   |CALL 0048EC6F                           ; \file.0048EC6F
0048EDCC  |.  83C4 08       |ADD ESP,8
0048EDCF  |.  E9 22030000   |JMP 0048F0F6
0048EDD4  |>^ EB 86         \JMP SHORT 0048ED5C
0048EDD6  |>  C745 B8 00000 MOV DWORD PTR SS:[EBP-48],0

UPDATE

将变量声明移到函数外部可以使其按预期工作,但我想避免这种情况。我还有什么其他选择?

DWORD jbPlantTrap = 0x48ED53 + 7;
DWORD jbPlantTrapSkip = 0x48EDD6;
unsigned char* player1; // moved outside function
unsigned char* packet1; // moved outside function
__declspec(naked) void hkPlantTrap() {
...
c++ x86 inline-assembly
1个回答
2
投票

使用中间函数挂钩和declspec裸函数时,必须全部用汇编语言编写。您应该在裸函数之外声明任何变量,然后在程序集中引用这些变量,以免破坏堆栈。

或者,您可以增加堆栈大小,做一些事情,然后在返回之前放松堆栈,但是说实话,这会很烦人。

© www.soinside.com 2019 - 2024. All rights reserved.