From 1324f8d97118b855e6bfd2db4eb0950324359bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Lewandowski?= <49685661+FakeMichau@users.noreply.github.com> Date: Mon, 23 Jun 2025 12:17:14 +0200 Subject: [PATCH] Workaround the ntdll-Hide_Wine_Exports patch (#538) --- OptiScaler/dllmain.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index c23dcaa7..07f1b862 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -42,6 +42,46 @@ static std::vector _asiHandles; typedef const char*(CDECL* PFN_wine_get_version)(void); typedef void (*PFN_InitializeASI)(void); +static inline void* ManualGetProcAddress(HMODULE hModule, const char* functionName) +{ + if (!hModule) + return nullptr; + + // Verify the alignment + auto dosHeader = (IMAGE_DOS_HEADER*) hModule; + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + return nullptr; + + auto ntHeaders = (IMAGE_NT_HEADERS*) ((BYTE*) hModule + dosHeader->e_lfanew); + if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) + return nullptr; + + // Look at the export directory + IMAGE_DATA_DIRECTORY exportData = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (!exportData.VirtualAddress) + return nullptr; + + auto exportDir = (IMAGE_EXPORT_DIRECTORY*) ((BYTE*) hModule + exportData.VirtualAddress); + + DWORD* nameRvas = (DWORD*) ((BYTE*) hModule + exportDir->AddressOfNames); + WORD* ordinalTable = (WORD*) ((BYTE*) hModule + exportDir->AddressOfNameOrdinals); + DWORD* functionTable = (DWORD*) ((BYTE*) hModule + exportDir->AddressOfFunctions); + + // Iterate over exported names + for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) + { + const char* name = (const char*) hModule + nameRvas[i]; + if (_stricmp(name, functionName) == 0) + { + WORD ordinal = ordinalTable[i]; + DWORD funcRva = functionTable[ordinal]; + return (BYTE*) hModule + funcRva; + } + } + + return nullptr; // Not found +} + static bool IsRunningOnWine() { LOG_FUNC(); @@ -56,6 +96,10 @@ static bool IsRunningOnWine() auto pWineGetVersion = (PFN_wine_get_version) KernelBaseProxy::GetProcAddress_()(ntdll, "wine_get_version"); + // Workaround for the ntdll-Hide_Wine_Exports patch + if (!pWineGetVersion && KernelBaseProxy::GetProcAddress_()(ntdll, "wine_server_call") != nullptr) + pWineGetVersion = (PFN_wine_get_version) ManualGetProcAddress(ntdll, "wine_get_version"); + if (pWineGetVersion) { LOG_INFO("Running on Wine {0}!", pWineGetVersion());