mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-08-28 17:16:46 +00:00
Added registry spoofing option & quirk. Thanks to @artur-graniszewski
Added Black Myth quirk
This commit is contained in:
@@ -583,6 +583,7 @@ bool Config::Reload(std::filesystem::path iniPath)
|
||||
TargetVendorId.set_from_config(readUInt("Spoofing", "TargetVendorId"));
|
||||
TargetDeviceId.set_from_config(readUInt("Spoofing", "TargetDeviceId"));
|
||||
UESpoofIntelAtomics64.set_from_config(readBool("Spoofing", "UEIntelAtomics"));
|
||||
SpoofRegistry.set_from_config(readBool("Spoofing", "Registry"));
|
||||
}
|
||||
|
||||
// Inputs
|
||||
@@ -1239,6 +1240,7 @@ bool Config::SaveIni()
|
||||
GetIntValue(Instance()->TargetVendorId.value_for_config(), true).c_str());
|
||||
ini.SetValue("Spoofing", "TargetDeviceId",
|
||||
GetIntValue(Instance()->TargetDeviceId.value_for_config(), true).c_str());
|
||||
ini.SetValue("Spoofing", "Registry", GetBoolValue(Instance()->SpoofRegistry.value_for_config()).c_str());
|
||||
}
|
||||
|
||||
// Plugins
|
||||
|
||||
@@ -405,6 +405,7 @@ class Config
|
||||
CustomOptional<uint32_t, NoDefault> TargetDeviceId;
|
||||
CustomOptional<std::wstring> SpoofedGPUName { L"NVIDIA GeForce RTX 4090" };
|
||||
CustomOptional<bool> UESpoofIntelAtomics64 { false };
|
||||
CustomOptional<bool> SpoofRegistry { false };
|
||||
|
||||
// Plugins
|
||||
CustomOptional<std::wstring> PluginPath { L"plugins" };
|
||||
|
||||
@@ -1306,6 +1306,12 @@ static void printQuirks(flag_set<GameQuirk>& quirks)
|
||||
state->detectedQuirks.push_back("Disable Resize Skip");
|
||||
}
|
||||
|
||||
if (quirks & GameQuirk::SpoofRegistry)
|
||||
{
|
||||
spdlog::info("Quirk: Spoof Registry");
|
||||
state->detectedQuirks.push_back("Spoof Registry");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1459,6 +1465,11 @@ static void CheckQuirks()
|
||||
Config::Instance()->FGXeFGSkipResizeBuffers.set_volatile_value(false);
|
||||
}
|
||||
|
||||
if (quirks & GameQuirk::SpoofRegistry && !Config::Instance()->SpoofRegistry.has_value())
|
||||
{
|
||||
Config::Instance()->SpoofRegistry.set_volatile_value(true);
|
||||
}
|
||||
|
||||
// For Luma, we assume if Luma addon in game folder it's used
|
||||
const auto dir = Util::ExePath().parent_path();
|
||||
bool lumaDetected = false;
|
||||
|
||||
@@ -8,10 +8,14 @@ const HKEY signatureMark = (HKEY) 0xFFFFFFFF13372137;
|
||||
typedef decltype(&RegOpenKeyExW) PFN_RegOpenKeyExW;
|
||||
typedef decltype(&RegEnumValueW) PFN_RegEnumValueW;
|
||||
typedef decltype(&RegCloseKey) PFN_RegCloseKey;
|
||||
typedef decltype(&RegQueryValueExW) PFN_RegQueryValueExW;
|
||||
typedef decltype(&RegQueryValueExA) PFN_RegQueryValueExA;
|
||||
|
||||
static PFN_RegOpenKeyExW o_RegOpenKeyExW = nullptr;
|
||||
static PFN_RegEnumValueW o_RegEnumValueW = nullptr;
|
||||
static PFN_RegCloseKey o_RegCloseKey = nullptr;
|
||||
static PFN_RegQueryValueExW o_RegQueryValueExW = nullptr;
|
||||
static PFN_RegQueryValueExA o_RegQueryValueExA = nullptr;
|
||||
|
||||
static LSTATUS hkRegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
|
||||
{
|
||||
@@ -81,7 +85,241 @@ static LSTATUS hkRegCloseKey(HKEY hKey)
|
||||
return o_RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
// Replaces all values returned for SOFTWARE\\NVIDIA Corporation\\Global so could potentially cause issues on Nvidia
|
||||
// Original implementation:
|
||||
// https://github.com/artur-graniszewski/dlss-enabler-main/blob/1f8b24722f1b526ffb896ae62b6aa3ca766b0728/Utils/RegistryProxy.cpp#L137
|
||||
static LONG hkRegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
|
||||
LPDWORD lpcbData)
|
||||
{
|
||||
std::wstring valueName = L"";
|
||||
|
||||
if (lpValueName != NULL)
|
||||
{
|
||||
valueName = std::wstring(lpValueName);
|
||||
}
|
||||
|
||||
if (valueName == L"HwSchMode")
|
||||
{
|
||||
// Check if lpcbData is not NULL
|
||||
if (lpcbData != nullptr)
|
||||
{
|
||||
// If lpData is NULL, we're being asked for the required size
|
||||
if (lpData == nullptr)
|
||||
{
|
||||
*lpcbData = sizeof(DWORD); // Indicate the required size
|
||||
|
||||
// Set the type to REG_DWORD
|
||||
if (lpType)
|
||||
{
|
||||
*lpType = REG_DWORD;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Check if the buffer is large enough
|
||||
if (*lpcbData >= sizeof(DWORD))
|
||||
{
|
||||
*(DWORD*) lpData = 2;
|
||||
|
||||
// Set the type to REG_DWORD
|
||||
if (lpType)
|
||||
{
|
||||
*lpType = REG_DWORD;
|
||||
}
|
||||
|
||||
// Set the size of the data returned
|
||||
*lpcbData = sizeof(DWORD);
|
||||
|
||||
// Return success
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is too small, return required size
|
||||
*lpcbData = sizeof(DWORD);
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
// If lpcbData is NULL, return an error
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Call the original function
|
||||
auto result = o_RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||
|
||||
// Check the result of the query and if the valueName matches
|
||||
if (result == ERROR_SUCCESS && !State::Instance().isRunningOnNvidia)
|
||||
{
|
||||
if (valueName == L"DriverVersion")
|
||||
{
|
||||
const std::wstring spoofedValue = L"31.0.15.5244";
|
||||
size_t spoofedValueSize =
|
||||
(spoofedValue.size() + 1) * sizeof(wchar_t); // Size in bytes including null terminator
|
||||
|
||||
if (lpData != nullptr && lpcbData != nullptr)
|
||||
{
|
||||
// Check if buffer size is sufficient
|
||||
if (*lpcbData >= spoofedValueSize)
|
||||
{
|
||||
// Copy the spoofed value into lpData
|
||||
std::memcpy(lpData, spoofedValue.c_str(), spoofedValueSize);
|
||||
// Update lpcbData with the size of the spoofed value
|
||||
*lpcbData = static_cast<DWORD>(spoofedValueSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If buffer is too small, set lpcbData to the required size
|
||||
*lpcbData = static_cast<DWORD>(spoofedValueSize);
|
||||
result = ERROR_MORE_DATA; // Indicate that buffer was too small
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valueName == L"HardwareID")
|
||||
{
|
||||
// Handle REG_SZ type
|
||||
std::wstring data(reinterpret_cast<wchar_t*>(lpData), *lpcbData / sizeof(wchar_t));
|
||||
std::wstring newData = data;
|
||||
size_t pos = 0;
|
||||
|
||||
// Replace VEN_1002 and VEN_8086 with VEN_10DE in REG_SZ
|
||||
while ((pos = newData.find(L"VEN_1002", pos)) != std::wstring::npos)
|
||||
{
|
||||
newData.replace(pos, 8, L"VEN_10DE");
|
||||
pos += 8; // Move past the replacement
|
||||
}
|
||||
pos = 0;
|
||||
while ((pos = newData.find(L"VEN_8086", pos)) != std::wstring::npos)
|
||||
{
|
||||
newData.replace(pos, 8, L"VEN_10DE");
|
||||
pos += 8; // Move past the replacement
|
||||
}
|
||||
|
||||
LOG_ERROR(L"NEW PAYLOAD: " + newData);
|
||||
// Copy the new data back
|
||||
wcscpy_s(reinterpret_cast<wchar_t*>(lpData), *lpcbData / sizeof(wchar_t), newData.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LONG WINAPI hkRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData,
|
||||
LPDWORD lpcbData)
|
||||
{
|
||||
std::string valueName = "";
|
||||
|
||||
if (lpValueName != NULL)
|
||||
{
|
||||
valueName = std::string(lpValueName);
|
||||
}
|
||||
|
||||
if (valueName == "HwSchMode")
|
||||
{
|
||||
// Check if lpcbData is not NULL
|
||||
if (lpcbData != nullptr)
|
||||
{
|
||||
// If lpData is NULL, we're being asked for the required size
|
||||
if (lpData == nullptr)
|
||||
{
|
||||
*lpcbData = sizeof(DWORD); // Indicate the required size
|
||||
|
||||
// Set the type to REG_DWORD
|
||||
if (lpType)
|
||||
{
|
||||
*lpType = REG_DWORD;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Check if the buffer is large enough
|
||||
if (*lpcbData >= sizeof(DWORD))
|
||||
{
|
||||
*(DWORD*) lpData = 2;
|
||||
|
||||
// Set the type to REG_DWORD
|
||||
if (lpType)
|
||||
{
|
||||
*lpType = REG_DWORD;
|
||||
}
|
||||
|
||||
// Set the size of the data returned
|
||||
*lpcbData = sizeof(DWORD);
|
||||
|
||||
// Return success
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is too small, return required size
|
||||
*lpcbData = sizeof(DWORD);
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
// If lpcbData is NULL, return an error
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Call the original function
|
||||
auto result = o_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, lpcbData);
|
||||
|
||||
// Check the result of the query and if the valueName matches
|
||||
if (result == ERROR_SUCCESS && !State::Instance().isRunningOnNvidia)
|
||||
{
|
||||
if (valueName == "DriverVersion")
|
||||
{
|
||||
const std::wstring spoofedValue = L"31.0.15.5244";
|
||||
size_t spoofedValueSize =
|
||||
(spoofedValue.size() + 1) * sizeof(wchar_t); // Size in bytes including null terminator
|
||||
|
||||
if (lpData != nullptr && lpcbData != nullptr)
|
||||
{
|
||||
// Check if buffer size is sufficient
|
||||
if (*lpcbData >= spoofedValueSize)
|
||||
{
|
||||
// Copy the spoofed value into lpData
|
||||
std::memcpy(lpData, spoofedValue.c_str(), spoofedValueSize);
|
||||
// Update lpcbData with the size of the spoofed value
|
||||
*lpcbData = static_cast<DWORD>(spoofedValueSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If buffer is too small, set lpcbData to the required size
|
||||
*lpcbData = static_cast<DWORD>(spoofedValueSize);
|
||||
result = ERROR_MORE_DATA; // Indicate that buffer was too small
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valueName == "HardwareID")
|
||||
{
|
||||
// Handle REG_SZ type
|
||||
std::string data(reinterpret_cast<char*>(lpData), *lpcbData / sizeof(char));
|
||||
std::string newData = data;
|
||||
size_t pos = 0;
|
||||
|
||||
// Replace VEN_1002 and VEN_8086 with VEN_10DE in REG_SZ
|
||||
while ((pos = newData.find("VEN_1002", pos)) != std::wstring::npos)
|
||||
{
|
||||
newData.replace(pos, 8, "VEN_10DE");
|
||||
pos += 8; // Move past the replacement
|
||||
}
|
||||
pos = 0;
|
||||
while ((pos = newData.find("VEN_8086", pos)) != std::wstring::npos)
|
||||
{
|
||||
newData.replace(pos, 8, "VEN_10DE");
|
||||
pos += 8; // Move past the replacement
|
||||
}
|
||||
|
||||
// Copy the new data back
|
||||
std::memcpy(lpData, newData.c_str(), *lpcbData);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void hookAdvapi32()
|
||||
{
|
||||
LOG_FUNC();
|
||||
@@ -90,6 +328,14 @@ static void hookAdvapi32()
|
||||
o_RegEnumValueW = reinterpret_cast<PFN_RegEnumValueW>(DetourFindFunction("Advapi32.dll", "RegEnumValueW"));
|
||||
o_RegCloseKey = reinterpret_cast<PFN_RegCloseKey>(DetourFindFunction("Advapi32.dll", "RegCloseKey"));
|
||||
|
||||
if (Config::Instance()->SpoofRegistry.value_or_default())
|
||||
{
|
||||
o_RegQueryValueExW =
|
||||
reinterpret_cast<PFN_RegQueryValueExW>(DetourFindFunction("Advapi32.dll", "RegQueryValueExW"));
|
||||
o_RegQueryValueExA =
|
||||
reinterpret_cast<PFN_RegQueryValueExA>(DetourFindFunction("Advapi32.dll", "RegQueryValueExA"));
|
||||
}
|
||||
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
@@ -102,6 +348,12 @@ static void hookAdvapi32()
|
||||
if (o_RegCloseKey)
|
||||
DetourAttach(&(PVOID&) o_RegCloseKey, hkRegCloseKey);
|
||||
|
||||
if (o_RegQueryValueExW)
|
||||
DetourAttach(&(PVOID&) o_RegQueryValueExW, hkRegQueryValueExW);
|
||||
|
||||
if (o_RegQueryValueExA)
|
||||
DetourAttach(&(PVOID&) o_RegQueryValueExA, hkRegQueryValueExA);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ enum class GameQuirk : uint64_t
|
||||
SetVelocityValidNow,
|
||||
SetHudlessValidNow,
|
||||
DisableResizeSkip,
|
||||
SpoofRegistry,
|
||||
|
||||
// Quirks that are applied deeper in code
|
||||
CyberpunkHudlessFixes,
|
||||
@@ -197,6 +198,10 @@ static const QuirkEntry quirkTable[] = {
|
||||
QUIRK_ENTRY("prey.exe", GameQuirk::DontUseNTShared, GameQuirk::DisableOptiXessPipelineCreation,
|
||||
GameQuirk::DisableDxgiSpoofing),
|
||||
|
||||
// Black Myth: Wukong
|
||||
// To enable DLSS-FG option
|
||||
QUIRK_ENTRY_UE(b1, GameQuirk::SpoofRegistry),
|
||||
|
||||
// Avowed
|
||||
// NoBarriers needed to avoid post-loading crash with DLSS
|
||||
QUIRK_ENTRY_UE(avowed, GameQuirk::ForceAutoExposure, GameQuirk::DontUseUnrealBarriers, GameQuirk::DisableFSR2Inputs,
|
||||
|
||||
Reference in New Issue
Block a user