Added optional User32 EnumDisplayDevicesA & EnumDisplayDevicesW spoofing

This commit is contained in:
cdozdil
2026-03-05 15:46:36 +03:00
parent c87d4a9689
commit 041a9c8de7
8 changed files with 197 additions and 5 deletions
+3
View File
@@ -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
; -------------------------------------------------------
+2
View File
@@ -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())
+1
View File
@@ -406,6 +406,7 @@ class Config
CustomOptional<std::wstring> SpoofedGPUName { L"NVIDIA GeForce RTX 4090" };
CustomOptional<bool> UESpoofIntelAtomics64 { false };
CustomOptional<bool> SpoofRegistry { false };
CustomOptional<bool> SpoofUser32 { false };
CustomOptional<std::wstring> SpoofedDriver { L"32.0.15.7302" };
// Plugins
+2
View File
@@ -318,6 +318,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClInclude Include="hooks\FG_Hooks.h" />
<ClInclude Include="hooks\LibraryLoad_Hooks.h" />
<ClInclude Include="hooks\CommandBuffer_StateTracker.h" />
<ClInclude Include="spoofing\User32_Spoofing.h" />
<ClInclude Include="hooks\VulkanwDx12_Hooks.h" />
<ClInclude Include="inputs\FSR2_Dx11.h" />
<ClInclude Include="inputs\FSR2_Vk.h" />
@@ -566,6 +567,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
<ClCompile Include="shaders\Shader_Dx12.cpp" />
<ClCompile Include="shaders\Shader_Vk.cpp" />
<ClCompile Include="spoofing\Dxgi_Spoofing.cpp" />
<ClCompile Include="spoofing\User32_Spoofing.cpp" />
<ClCompile Include="spoofing\Vulkan_Spoofing.cpp" />
<ClCompile Include="upscalers\fsr2_212\FSR2Feature_VkOnDx12_212.cpp" />
<ClCompile Include="upscalers\fsr31\FSR31Feature_VkOn12.cpp" />
+6
View File
@@ -764,6 +764,9 @@
<ClInclude Include="shaders\output_scaling\precompile\bcds_lanczos3_Shader_Vk.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="spoofing\User32_Spoofing.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Config.cpp">
@@ -1169,6 +1172,9 @@
<ClCompile Include="shaders\render_ui\RUI_Dx12.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="spoofing\User32_Spoofing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="OptiScaler.rc" />
+16 -5
View File
@@ -10,11 +10,6 @@
#include "proxies/Dxgi_Proxy.h"
#include <proxies/XeSS_Proxy.h>
#include <proxies/NVNGX_Proxy.h>
#include <hooks/Gdi32_Hooks.h>
#include <hooks/Wintrust_Hooks.h>
#include <hooks/Crypt32_Hooks.h>
#include <hooks/Advapi32_Hooks.h>
#include <hooks/Streamline_Hooks.h>
#include "proxies/Kernel32_Proxy.h"
#include "proxies/KernelBase_Proxy.h"
#include "proxies/Ntdll_Proxy.h"
@@ -36,8 +31,16 @@
#include <hooks/Vulkan_Hooks.h>
#include <hooks/Ntdll_Hooks.h>
#include <hooks/Kernel_Hooks.h>
#include <hooks/Gdi32_Hooks.h>
#include <hooks/Wintrust_Hooks.h>
#include <hooks/Crypt32_Hooks.h>
#include <hooks/Advapi32_Hooks.h>
#include <hooks/Streamline_Hooks.h>
#include <nvapi/NvApiHooks.h>
#include "spoofing/User32_Spoofing.h"
#include <cwctype>
#include <version_check.h>
@@ -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;
+153
View File
@@ -0,0 +1,153 @@
#include <pch.h>
#include "User32_Spoofing.h"
#include <Config.h>
#include <detours/detours.h>
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<PFN_EnumDisplayDevicesA>(DetourFindFunction("User32.dll", "EnumDisplayDevicesA"));
o_EnumDisplayDevicesW =
reinterpret_cast<PFN_EnumDisplayDevicesW>(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();
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "SysUtils.h"
class User32Spoofing
{
public:
static void Hook();
static void Unhook();
private:
};