stevemk14ebr / PolyHook_2_0

C++20, x86/x64 Hooking Libary v2.0
MIT License
1.58k stars 222 forks source link

Crashes when hooking e.g. QueryPerformanceCounter in x64 but works with x86 #180

Closed BullyWiiPlaza closed 1 year ago

BullyWiiPlaza commented 1 year ago

Hello,

I'm using the latest vcpkg port of PolyHook2 (polyhook2[core,detours,exception,inlinentd,pe,virtuals]:x64-windows -> 2023-05-16#1). My dependencies asmjit, asmtk and zydis are also up-to-date. I noticed when I'm hooking the QueryPerformanceCounter function, the process crashes. My reproduction code is as follows:

#include <iostream>
#include <polyhook2/Detour/NatDetour.hpp>
#include <Windows.h>

using namespace std::chrono_literals;

using tQueryPerformanceCounter = BOOL(WINAPI*)(LARGE_INTEGER* lp_performance_count);
tQueryPerformanceCounter oQueryPerformanceCounter;

auto called_count = 0;

BOOL WINAPI hQueryPerformanceCounter(LARGE_INTEGER* performance_count)
{
    called_count++;

    return oQueryPerformanceCounter(performance_count);
}

int main()
{
    oQueryPerformanceCounter = QueryPerformanceCounter;

    PLH::NatDetour hook(reinterpret_cast<uint64_t>(oQueryPerformanceCounter),
        reinterpret_cast<uint64_t>(hQueryPerformanceCounter),
        reinterpret_cast<uint64_t*>(&oQueryPerformanceCounter));

    const auto successfully_hooked = hook.hook();
    std::cout << "Successfully hooked: " << successfully_hooked << std::endl;

    for (auto index = 0; index < 5; index++)
    {
        std::cout << "Called count: " << called_count << std::endl;
        std::this_thread::sleep_for(1000ms);
    } // Exception thrown at 0x00007FFCC43A6E10 (kernel32.dll) in PolyHookQueryPerformanceCounterHookingTest.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

    hook.unHook();

    return EXIT_SUCCESS;
}

ErrorLog output:

[+] Info: Original function:
7ffcc4411f28 [9]: a0 29 01 c5 fc 7f 00 00 00              mov al, byte ptr ds:[0x0000007FFCC50129]
7ffcc4411f31 [2]: 00 00                                   add byte ptr ds:[rax], al
7ffcc4411f33 [2]: 00 00                                   add byte ptr ds:[rax], al
7ffcc4411f35 [2]: 00 00                                   add byte ptr ds:[rax], al
7ffcc4411f37 [6]: 00 90 67 bd c2 fc                       add byte ptr ds:[rax-0x33D4299], dl
7ffcc4411f3d [2]: 7f 00                                   jnle 0x00007FFCC4411F3F -> 7ffcc4411f3f
7ffcc4411f3f [6]: 00 90 69 bd c2 fc                       add byte ptr ds:[rax-0x33D4297], dl
7ffcc4411f45 [2]: 7f 00                                   jnle 0x00007FFCC4411F47 -> 7ffcc4411f47
7ffcc4411f47 [2]: 00 30                                   add byte ptr ds:[rax], dh
7ffcc4411f49 [1]: 99                                      cdq cdq
7ffcc4411f4a [2]: b1 c2                                   mov cl, 0xC2
7ffcc4411f4c [1]: fc                                      cld cld
7ffcc4411f4d [2]: 7f 00                                   jnle 0x00007FFCC4411F4F -> 7ffcc4411f4f
7ffcc4411f4f [6]: 00 b0 4a bb c2 fc                       add byte ptr ds:[rax-0x33D44B6], dh
7ffcc4411f55 [2]: 7f 00                                   jnle 0x00007FFCC4411F57 -> 7ffcc4411f57
7ffcc4411f57 [3]: 00 40 6b                                add byte ptr ds:[rax+0x6B], al
7ffcc4411f5a [5]: bd c2 fc 7f 00                          mov ebp, 0x7FFCC2
7ffcc4411f5f [2]: 00 d0                                   add al, dl
7ffcc4411f61 [2]: e0 b2                                   loopne 0x00007FFCC4411F15 -> 7ffcc4411f15
7ffcc4411f63 [3]: c2 fc 7f                                ret 0x7FFC

[+] Info: Prologue to overwrite:
7ffcc4411f28 [9]: a0 29 01 c5 fc 7f 00 00 00              mov al, byte ptr ds:[0x0000007FFCC50129]

[+] Info: Trampoline address: 0x000001d7663e1530
[+] Info: Jmp To Prol:
1d7663e1539 [6]: ff 25 49 00 00 00                       jmp [1d7663e1588] ->7ffcc4411f31
1d7663e1588 [8]: 31 1f 41 c4 fc 7f 00 00                 dest holder

[+] Info: m_trampoline: 0x000001d7663e1530

[+] Info: m_trampolineSz: 0x0064

[+] Info: Trampoline:
1d7663e1530 [9]: a0 29 01 c5 fc 7f 00 00 00              mov al, byte ptr ds:[0x0000007FFCC50129]
1d7663e1539 [6]: ff 25 49 00 00 00                       jmp qword ptr ds:[0x000001D7663E1588] -> 7ffcc4411f31

[+] Info: Hook instructions:
7ffcc4411f28 [6]: ff 25 d2 e0 08 80                       jmp [7ffc444a0000] ->7ff621f83299
7ffc444a0000 [8]: 99 32 f8 21 f6 7f 00 00                 dest holder

I expect this code to run successfully and return with EXIT_SUCCESS but it doesn't. image

Other types of hooks generally seem to work fine.

When I compile and run this example in x86, it also works and produces a reasonable output of:

Successfully hooked: 1
Called count: 0
Called count: 3
Called count: 6
Called count: 9
Called count: 12

Any idea how this issue is caused in x64? Can I maybe use a different detours scheme? When using the Microsoft Detours library, the QueryPerformanceCounter hook works fine in x64 so it's not generally problematic to hook e.g. QueryPerformanceCounter. It would be great to be able to fully switch over to PolyHook2.

BritishPiper commented 1 year ago

Fixed in #183