From e7d869bd857bd8ed15ade97119a4df260a3d6b86 Mon Sep 17 00:00:00 2001 From: Richard Fortier Date: Sat, 30 Nov 2024 20:04:58 -0500 Subject: [PATCH] Windows 11 24H2 changed some low-level call hierarchies. This is a compatibility change, works on 23H2 and 24H2. Since in 24H2 GetModuleHandle no longer down-calls to LdrGetDllHandleEx, have to hook the GetModuleHandle() routines also. --- Code/immersive_launcher/stubs/FileMapping.cpp | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Code/immersive_launcher/stubs/FileMapping.cpp b/Code/immersive_launcher/stubs/FileMapping.cpp index 67b4f5d5a..b15ddc8a0 100644 --- a/Code/immersive_launcher/stubs/FileMapping.cpp +++ b/Code/immersive_launcher/stubs/FileMapping.cpp @@ -26,7 +26,7 @@ std::wstring s_OverridePath; DWORD(WINAPI* RealGetModuleFileNameW)(HMODULE, LPWSTR, DWORD) = nullptr; DWORD(WINAPI* RealGetModuleFileNameA)(HMODULE, LPSTR, DWORD) = nullptr; HMODULE(WINAPI* RealGetModuleHandleW)(LPCWSTR) = nullptr; -HMODULE(WINAPI* RealGetModuleHandleA)(LPSTR) = nullptr; +HMODULE(WINAPI* RealGetModuleHandleA)(LPCSTR) = nullptr; NTSTATUS(WINAPI* RealLdrLoadDll)(const wchar_t*, uint32_t*, UNICODE_STRING*, HANDLE*) = nullptr; NTSTATUS(WINAPI* RealLdrGetDllHandle)(PWSTR, PULONG, PUNICODE_STRING, PVOID*) = nullptr; NTSTATUS(WINAPI* RealLdrGetDllFullName)(HMODULE, PUNICODE_STRING) = nullptr; @@ -87,6 +87,28 @@ bool IsLocalModulePath(HMODULE aHmod) return buf.find(s_OverridePath) != std::wstring::npos; } +// some mods do GetModuleHandle("SkyrimSE.exe") for some reason instead of GetModuleHandle(nullptr) +HMODULE WINAPI TP_GetModuleHandleW(LPCWSTR lpModuleName) +{ + constexpr auto pTarget = TARGET_NAME L".exe"; + auto targetSize = std::wcslen(pTarget); + + if (lpModuleName && std::wcsncmp(pTarget, lpModuleName, targetSize) == 0) + lpModuleName = nullptr; + return RealGetModuleHandleW(lpModuleName); +} + +// some mods do GetModuleHandle("SkyrimSE.exe") for some reason instead of GetModuleHandle(nullptr) +HMODULE WINAPI TP_GetModuleHandleA(LPCSTR lpModuleName) +{ + constexpr LPCSTR pTarget = "SkyrimSE.exe"; + constexpr auto targetSize = sizeof("SkyrimSE.exe"); + + if (lpModuleName && std::strncmp(pTarget, lpModuleName, targetSize) == 0) + lpModuleName = nullptr; + return RealGetModuleHandleA(lpModuleName); +} + // some mods do GetModuleHandle("SkyrimSE.exe") for some reason instead of GetModuleHandle(nullptr) NTSTATUS WINAPI TP_LdrGetDllHandle(PWSTR DllPath, PULONG DllCharacteristics, PUNICODE_STRING DllName, PVOID* DllHandle) { @@ -300,6 +322,12 @@ void CoreStubsInit() // TODO(Vince): we need some check if usvfs already fucked with this? // MH_CreateHookApi(L"ntdll.dll", "LdrGetDllFullName", &TP_LdrGetDllFullName, (void**)&RealLdrGetDllFullName); VALIDATE(MH_CreateHookApi(L"ntdll.dll", "LdrLoadDll", &TP_LdrLoadDll, (void**)&RealLdrLoadDll)); + + // Starting with Windows 11 24H2 the call stack has changed and GetModuleHandle() no longer + // downcalls to LdrGetDllHandleEx, so we have to hook this too. + VALIDATE(MH_CreateHookApi(L"kernel32.dll", "GetModuleHandleW", &TP_GetModuleHandleW, (void**)&RealGetModuleHandleW)); + VALIDATE(MH_CreateHookApi(L"kernel32.dll", "GetModuleHandleA", &TP_GetModuleHandleA, (void**)&RealGetModuleHandleA)); + VALIDATE(MH_EnableHook(nullptr)); }