cursey / safetyhook

C++23 procedure hooking library.
https://cursey.dev/safetyhook
Boost Software License 1.0
363 stars 46 forks source link

create_inline: game launched via Rockstar Games Launcher crashes #79

Open ThirteenAG opened 3 months ago

ThirteenAG commented 3 months ago
shLoadLibraryExA = safetyhook::create_inline(LoadLibraryExA, shCustomLoadLibraryExA);
shLoadLibraryExW = safetyhook::create_inline(LoadLibraryExW, shCustomLoadLibraryExW);

This is not something I can personally reproduce, since launching from steam that launches RGL that launches the game (GTA5 in this case) works fine. However I was sent a crash dump that has this:

    KERNELBASE.dll!RaiseException() Unknown Non-user code. Symbols loaded without source information.
    VCRUNTIME140D.dll!_CxxThrowException(void * pExceptionObject=0x000000a2b9b1cab8, const _s__ThrowInfo * pThrowInfo=0x00007ffb6e4f1520) Line 81   C++ Non-user code. Symbols loaded.
    MSVCP140D.dll!std::_Throw_Cpp_error(int code=0x00000005) Line 33    C++ Symbols loaded.
    dinput8.dll!std::_Mutex_base::lock() Line 54    C++ Symbols loaded.
    dinput8.dll!std::scoped_lock<std::mutex>::scoped_lock<std::mutex>(std::mutex & _Mtx={...}) Line 503 C++ Symbols loaded.
>   dinput8.dll!safetyhook::TrapManager::trap_handler(_EXCEPTION_POINTERS * exp=0x000000a2b9b1cf50) Line 230    C++ Symbols loaded.
    ntdll.dll!RtlpCallVectoredHandlers()    Unknown Non-user code. Symbols loaded without source information.
    ntdll.dll!RtlDispatchException()    Unknown Non-user code. Symbols loaded without source information.
    ntdll.dll!KiUserExceptionDispatch() Unknown Non-user code. Symbols loaded without source information.
    kernel32.dll!VirtualProtectStub()   Unknown Non-user code. Symbols loaded without source information.
    dinput8.dll!safetyhook::trap_threads(unsigned char * from=0x00007ffba724b0d0, unsigned char * to=0x00007ffba6e1001a, unsigned __int64 len=0x0000000000000007, const std::function<void __cdecl(void)> & run_fn={...}) Line 285  C++ Symbols loaded.
    dinput8.dll!safetyhook::InlineHook::enable() Line 383   C++ Symbols loaded.
    dinput8.dll!safetyhook::InlineHook::create(const std::shared_ptr<safetyhook::Allocator> & allocator={...}, void * target=0x00007ffba724b0d0, void * destination=0x00007ffb5fa6ab25, safetyhook::InlineHook::Flags flags=Default) Line 132   C++ Symbols loaded.
    dinput8.dll!safetyhook::InlineHook::create(void * target=0x00007ffba724b0d0, void * destination=0x00007ffb5fa6ab25, safetyhook::InlineHook::Flags flags=Default) Line 118   C++ Symbols loaded.
    dinput8.dll!safetyhook::create_inline(void * target=0x00007ffba724b0d0, void * destination=0x00007ffb5fa6ab25, safetyhook::InlineHook::Flags flags=Default) Line 5  C++ Symbols loaded.
    dinput8.dll!safetyhook::create_inline<HINSTANCE__ * (__cdecl*)(wchar_t const *,void *,unsigned long),HINSTANCE__ * (__cdecl*)(wchar_t const *,void *,unsigned long)>(HINSTANCE__ *(*)(const wchar_t *, void *, unsigned long) target=0x00007ffba724b0d0, HINSTANCE__ *(*)(const wchar_t *, void *, unsigned long) destination=0x00007ffb5fa6ab25, safetyhook::InlineHook::Flags flags=Default) Line 26  C++ Symbols loaded.
//safetyhook::create_inline calls here

image

The reason of exception is this

    void lock() {
        if (_Mtx_lock(_Mymtx()) != _Thrd_result::_Success) {
            // undefined behavior, only occurs for plain mutexes (N4950 [thread.mutex.requirements.mutex.general]/6)
            _STD _Throw_Cpp_error(_RESOURCE_DEADLOCK_WOULD_OCCUR);
        }

I'm not sure if anything can be done to fix/avoid this, since it's not easy to reproduce, maybe it's anticheat kicks in, maybe something else.

ThirteenAG commented 3 months ago

Upon closer inspection, on my end this code works fine:

    VirtualProtect(from, len, new_protect, &from_protect);
    VirtualProtect(to, len, new_protect, &to_protect);

    if (run_fn) {
        run_fn();
    }

    VirtualProtect(to, len, to_protect, &to_protect);
    VirtualProtect(from, len, from_protect, &from_protect);

However, with RGL version stepping through this:

image

image

image

Shows that Kernel32.VirtualProtect protection changes, despite ["from"; "from+len"] not pointing to it, which leads to crash. Is this magic?