diff --git a/OptiScaler.ini b/OptiScaler.ini index bd62f752..d76dd8ec 100644 --- a/OptiScaler.ini +++ b/OptiScaler.ini @@ -844,6 +844,9 @@ Registry=auto ; string value - Default (auto) is 32.0.15.7302 (For Nvidia) RegistryDriver=auto +; Spoofs Vendor ID, Device ID at User32 level +; true or false - Default (auto) is false +User32=auto ; ------------------------------------------------------- diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp index 7ea6b554..e3a84e50 100644 --- a/OptiScaler/Config.cpp +++ b/OptiScaler/Config.cpp @@ -589,6 +589,7 @@ bool Config::Reload(std::filesystem::path iniPath) UESpoofIntelAtomics64.set_from_config(readBool("Spoofing", "UEIntelAtomics")); SpoofRegistry.set_from_config(readBool("Spoofing", "Registry")); SpoofedDriver.set_from_config(readWString("Spoofing", "RegistryDriver")); + SpoofUser32.set_from_config(readBool("Spoofing", "User32")); } // Inputs @@ -1248,6 +1249,7 @@ bool Config::SaveIni() ini.SetValue("Spoofing", "Registry", GetBoolValue(Instance()->SpoofRegistry.value_for_config()).c_str()); ini.SetValue("Spoofing", "RegistryDriver", wstring_to_string(Instance()->SpoofedDriver.value_for_config_or(L"auto")).c_str()); + ini.SetValue("Spoofing", "User32", GetBoolValue(Instance()->SpoofUser32.value_for_config()).c_str()); // Enable HAGS when DLSS-G will be used if (!Instance()->SpoofHAGS.has_value()) diff --git a/OptiScaler/Config.h b/OptiScaler/Config.h index 77fb6fd4..c94495ca 100644 --- a/OptiScaler/Config.h +++ b/OptiScaler/Config.h @@ -406,6 +406,7 @@ class Config CustomOptional SpoofedGPUName { L"NVIDIA GeForce RTX 4090" }; CustomOptional UESpoofIntelAtomics64 { false }; CustomOptional SpoofRegistry { false }; + CustomOptional SpoofUser32 { false }; CustomOptional SpoofedDriver { L"32.0.15.7302" }; // Plugins diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index f5804567..107a6a56 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -318,6 +318,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + @@ -566,6 +567,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + diff --git a/OptiScaler/OptiScaler.vcxproj.filters b/OptiScaler/OptiScaler.vcxproj.filters index 1e23a4c3..a8c373c0 100644 --- a/OptiScaler/OptiScaler.vcxproj.filters +++ b/OptiScaler/OptiScaler.vcxproj.filters @@ -764,6 +764,9 @@ Header Files + + Header Files + @@ -1169,6 +1172,9 @@ Source Files + + Source Files + diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index 286fdf5f..2dabe43d 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -10,11 +10,6 @@ #include "proxies/Dxgi_Proxy.h" #include #include -#include -#include -#include -#include -#include #include "proxies/Kernel32_Proxy.h" #include "proxies/KernelBase_Proxy.h" #include "proxies/Ntdll_Proxy.h" @@ -36,8 +31,16 @@ #include #include #include +#include +#include +#include +#include +#include + #include +#include "spoofing/User32_Spoofing.h" + #include #include @@ -878,7 +881,15 @@ static void CheckWorkingMode() // Advapi32 if (Config::Instance()->DxgiSpoofing.value_or_default() || Config::Instance()->StreamlineSpoofing.value_or_default()) + { hookAdvapi32(); + } + + // User32 + if (Config::Instance()->SpoofUser32.value_or_default()) + { + User32Spoofing::Hook(); + } // hook streamline right away if it's already loaded HMODULE slModule = nullptr; diff --git a/OptiScaler/spoofing/User32_Spoofing.cpp b/OptiScaler/spoofing/User32_Spoofing.cpp new file mode 100644 index 00000000..e885e271 --- /dev/null +++ b/OptiScaler/spoofing/User32_Spoofing.cpp @@ -0,0 +1,153 @@ +#include +#include "User32_Spoofing.h" + +#include + +#include + +typedef BOOL(WINAPI* PFN_EnumDisplayDevicesA)(PSTR lpDevice, uint32_t iDevNum, DISPLAY_DEVICEA* lpDisplayDevice, + uint32_t dwFlags); +typedef BOOL(WINAPI* PFN_EnumDisplayDevicesW)(PWSTR lpDevice, uint32_t iDevNum, DISPLAY_DEVICEW* lpDisplayDevice, + uint32_t dwFlags); + +static PFN_EnumDisplayDevicesA o_EnumDisplayDevicesA = nullptr; +static PFN_EnumDisplayDevicesW o_EnumDisplayDevicesW = nullptr; + +inline static BOOL WINAPI hkEnumDisplayDevicesA(PSTR lpDevice, uint32_t iDevNum, DISPLAY_DEVICEA* lpDisplayDevice, + uint32_t dwFlags) +{ + auto result = o_EnumDisplayDevicesA(lpDevice, iDevNum, lpDisplayDevice, dwFlags); + + if (!result || lpDisplayDevice == nullptr) + return result; + + static std::string vendorId = std::format("VEN_{:04X}", Config::Instance()->SpoofedVendorId.value_or_default()); + static std::string deviceId = std::format("DEV_{:04X}", Config::Instance()->SpoofedDeviceId.value_or_default()); + + // Spoof DeviceString (GPU name) + auto gpuName = wstring_to_string(Config::Instance()->SpoofedGPUName.value_or_default()); + strncpy_s(lpDisplayDevice->DeviceString, gpuName.c_str(), sizeof(lpDisplayDevice->DeviceString) - 1); + + // Spoof VEN_/DEV_ tokens in DeviceID (e.g. "PCI\VEN_1002&DEV_687F&...") + std::string deviceIdStr(lpDisplayDevice->DeviceID); + bool found = false; + + static const char* srcVendors[] = { "VEN_1002", "VEN_8086" }; + for (auto srcVendor : srcVendors) + { + size_t pos = 0; + while ((pos = deviceIdStr.find(srcVendor, pos)) != std::string::npos) + { + deviceIdStr.replace(pos, 8, vendorId); + pos += vendorId.size(); + found = true; + } + if (found) + break; + } + + if (found) + { + size_t pos = 0; + while ((pos = deviceIdStr.find("DEV_", pos)) != std::string::npos) + { + deviceIdStr.replace(pos, 8, deviceId); + pos += deviceId.size(); + } + strncpy_s(lpDisplayDevice->DeviceID, deviceIdStr.c_str(), sizeof(lpDisplayDevice->DeviceID) - 1); + LOG_INFO("Spoofed DeviceID: {}", deviceIdStr); + } + + return result; +} + +inline static BOOL WINAPI hkEnumDisplayDevicesW(PWSTR lpDevice, uint32_t iDevNum, DISPLAY_DEVICEW* lpDisplayDevice, + uint32_t dwFlags) +{ + auto result = o_EnumDisplayDevicesW(lpDevice, iDevNum, lpDisplayDevice, dwFlags); + + if (!result || lpDisplayDevice == nullptr) + return result; + + static std::wstring vendorId = std::format(L"VEN_{:04X}", Config::Instance()->SpoofedVendorId.value_or_default()); + static std::wstring deviceId = std::format(L"DEV_{:04X}", Config::Instance()->SpoofedDeviceId.value_or_default()); + + // Spoof DeviceString (GPU name) + auto gpuName = Config::Instance()->SpoofedGPUName.value_or_default(); + wcsncpy_s(lpDisplayDevice->DeviceString, gpuName.c_str(), + sizeof(lpDisplayDevice->DeviceString) / sizeof(wchar_t) - 1); + + // Spoof VEN_/DEV_ tokens in DeviceID (e.g. L"PCI\VEN_1002&DEV_687F&...") + std::wstring deviceIdStr(lpDisplayDevice->DeviceID); + bool found = false; + + static const wchar_t* srcVendors[] = { L"VEN_1002", L"VEN_8086" }; + for (auto srcVendor : srcVendors) + { + size_t pos = 0; + while ((pos = deviceIdStr.find(srcVendor, pos)) != std::wstring::npos) + { + deviceIdStr.replace(pos, 8, vendorId); + pos += vendorId.size(); + found = true; + } + if (found) + break; + } + + if (found) + { + size_t pos = 0; + while ((pos = deviceIdStr.find(L"DEV_", pos)) != std::wstring::npos) + { + deviceIdStr.replace(pos, 8, deviceId); + pos += deviceId.size(); + } + wcsncpy_s(lpDisplayDevice->DeviceID, deviceIdStr.c_str(), + sizeof(lpDisplayDevice->DeviceID) / sizeof(wchar_t) - 1); + LOG_INFO("Spoofed DeviceID: {}", wstring_to_string(deviceIdStr)); + } + + return result; +} + +void User32Spoofing::Hook() +{ + LOG_FUNC(); + + o_EnumDisplayDevicesA = + reinterpret_cast(DetourFindFunction("User32.dll", "EnumDisplayDevicesA")); + o_EnumDisplayDevicesW = + reinterpret_cast(DetourFindFunction("User32.dll", "EnumDisplayDevicesW")); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_EnumDisplayDevicesA) + DetourAttach(&(PVOID&) o_EnumDisplayDevicesA, hkEnumDisplayDevicesA); + + if (o_EnumDisplayDevicesW) + DetourAttach(&(PVOID&) o_EnumDisplayDevicesW, hkEnumDisplayDevicesW); + + DetourTransactionCommit(); +} + +void User32Spoofing::Unhook() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + if (o_EnumDisplayDevicesA) + { + DetourDetach(&(PVOID&) o_EnumDisplayDevicesA, hkEnumDisplayDevicesA); + o_EnumDisplayDevicesA = nullptr; + } + + if (o_EnumDisplayDevicesW) + { + DetourDetach(&(PVOID&) o_EnumDisplayDevicesW, hkEnumDisplayDevicesW); + o_EnumDisplayDevicesW = nullptr; + } + + DetourTransactionCommit(); +} diff --git a/OptiScaler/spoofing/User32_Spoofing.h b/OptiScaler/spoofing/User32_Spoofing.h new file mode 100644 index 00000000..b71df417 --- /dev/null +++ b/OptiScaler/spoofing/User32_Spoofing.h @@ -0,0 +1,14 @@ +#pragma once + +#include "SysUtils.h" + + +class User32Spoofing +{ + public: + static void Hook(); + static void Unhook(); + + private: + +};