Fix engine bug regarding forcing application borders

In Respawn's engine, the '-forceborder' command line parameter does the same thing as '-noborder'. '-forceborder' should remove the flags (nand) while '-noborder' should append the borderless flag. This code is an attempt to mitigate the problem. There was not enough bytes to assemble the nand operation for this code path without involving code caves or shifting.
This commit is contained in:
Kawe Mazidjatari 2022-12-06 00:48:11 +01:00
parent 37318f915b
commit ebf7bb5e0b
11 changed files with 169 additions and 47 deletions

View File

@ -11,6 +11,7 @@
#include "engine/host_cmd.h"
#include "engine/gl_screen.h"
#include "engine/gl_matsysiface.h"
#include "engine/matsys_interface.h"
#include "engine/modelloader.h"
#include "engine/server/sv_main.h"
#include "engine/client/cl_main.h"
@ -312,11 +313,11 @@ void Dedicated_Init()
//-------------------------------------------------------------------------
// RUNTIME: GAME_CFG
//-------------------------------------------------------------------------
UpdateMaterialSystemConfig.Offset(0x0).Patch({ 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 }); // FUN --> RET | Return early to prevent the server from updating material system configurations.
UpdateCurrentVideoConfig.Offset(0x0).Patch({ 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 }); // FUN --> RET | Return early to prevent the server from writing a videoconfig.txt file to the disk (overwriting the existing one).
HandleConfigFile.Offset(0x0).Patch({ 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 }); // FUN --> RET | Return early to prevent the server from writing various input and ConVar config files to the disk (overwriting the existing one).
ResetPreviousGameState.Offset(0x0).Patch({ 0xC3 }); // FUN --> RET | Return early to prevent the server from writing a previousgamestate.txt file to the disk (overwriting the existing one).
LoadPlayerConfig.Offset(0x0).Patch({ 0xC3 }); // FUN --> RET | Return early to prevent the server from executing 'config_default_pc.cfg' (execPlayerConfig) and (only for >S3) running 'chat_wheel' code.
p_UpdateMaterialSystemConfig.Offset(0x0).Patch({ 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 });// FUN --> RET | Return early to prevent the server from updating material system configurations.
p_UpdateCurrentVideoConfig.Offset(0x0).Patch({ 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 }); // FUN --> RET | Return early to prevent the server from writing a videoconfig.txt file to the disk (overwriting the existing one).
p_HandleConfigFile.Offset(0x0).Patch({ 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3 }); // FUN --> RET | Return early to prevent the server from writing various input and ConVar config files to the disk (overwriting the existing one).
p_ResetPreviousGameState.Offset(0x0).Patch({ 0xC3 }); // FUN --> RET | Return early to prevent the server from writing a previousgamestate.txt file to the disk (overwriting the existing one).
p_LoadPlayerConfig.Offset(0x0).Patch({ 0xC3 }); // FUN --> RET | Return early to prevent the server from executing 'config_default_pc.cfg' (execPlayerConfig) and (only for >S3) running 'chat_wheel' code.
//-------------------------------------------------------------------------
// RUNTIME: COMMUNITIES

View File

@ -66,13 +66,8 @@ inline CMemory Server_S2C_CONNECT_1;
#endif // !CLIENT_DLL
//-------------------------------------------------------------------------
// RUNTIME: GAME_CFG
// RUNTIME:
//-------------------------------------------------------------------------
inline CMemory UpdateCurrentVideoConfig;
inline CMemory UpdateMaterialSystemConfig;
inline CMemory HandleConfigFile;
inline CMemory ResetPreviousGameState;
inline CMemory LoadPlayerConfig;
inline CMemory MatchMaking_Frame;
inline CMemory GetEngineClientThread;
inline CMemory CWin32Surface_initStaticData;
@ -104,11 +99,6 @@ class VOpcodes : public IDetour
spdlog::debug("| FUN: Server_S2C_CONNECT_1 : {:#18x} |\n", Server_S2C_CONNECT_1.GetPtr());
#endif // !CLIENT_DLL
spdlog::debug("+----------------------------------------------------------------+\n");
spdlog::debug("| FUN: UpdateMaterialSystemConfig : {:#18x} |\n", UpdateMaterialSystemConfig.GetPtr());
spdlog::debug("| FUN: UpdateCurrentVideoConfig : {:#18x} |\n", UpdateCurrentVideoConfig.GetPtr());
spdlog::debug("| FUN: HandleConfigFile : {:#18x} |\n", HandleConfigFile.GetPtr());
spdlog::debug("| FUN: ResetPreviousGameState : {:#18x} |\n", ResetPreviousGameState.GetPtr());
spdlog::debug("| FUN: LoadPlayerConfig : {:#18x} |\n", LoadPlayerConfig.GetPtr());
spdlog::debug("| FUN: GetEngineClientThread : {:#18x} |\n", GetEngineClientThread.GetPtr());
spdlog::debug("| FUN: MatchMaking_Frame : {:#18x} |\n", MatchMaking_Frame.GetPtr());
spdlog::debug("+----------------------------------------------------------------+\n");
@ -184,15 +174,6 @@ class VOpcodes : public IDetour
#endif // !CLIENT_DLL
//-------------------------------------------------------------------------
UpdateMaterialSystemConfig = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 80 3D ?? ?? ?? ?? ?? 0F 84 ?? ?? ?? ??");
UpdateCurrentVideoConfig = g_GameDll.FindPatternSIMD("40 55 ?? 41 56 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 8B F1");
HandleConfigFile = g_GameDll.FindPatternSIMD("40 56 48 81 EC ?? ?? ?? ?? 8B F1");
ResetPreviousGameState = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 44 89 3D ?? ?? ?? ?? ?? 8B ?? 24 ??").ResolveRelativeAddressSelf(0x1, 0x5);
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2)
LoadPlayerConfig = g_GameDll.FindPatternSIMD("48 81 EC ?? ?? ?? ?? 48 83 3D ?? ?? ?? ?? ?? 75 0C");
#elif defined (GAMEDLL_S3)
LoadPlayerConfig = g_GameDll.FindPatternSIMD("89 4C 24 08 48 81 EC ?? ?? ?? ?? 48 83 3D ?? ?? ?? ?? ??");
#endif
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
GetEngineClientThread = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 65 48 8B 04 25 ?? ?? ?? ?? 48 8B D9 B9 ?? ?? ?? ?? 48 8B 10 8B 04 11 39 05 ?? ?? ?? ?? 7F 15");
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)

View File

@ -92,6 +92,7 @@
#ifndef DEDICATED
#include "engine/sys_mainwind.h"
#endif // !DEDICATED
#include "engine/matsys_interface.h"
#include "engine/gl_matsysiface.h"
#include "engine/gl_screen.h"
#ifndef DEDICATED
@ -233,6 +234,8 @@ void Systems_Init()
#ifndef DEDICATED
HCVideoMode_Common_Attach();
DebugOverlays_Attach();
MatSys_Iface_Attach();
RSurf_Attach();
#endif // !DEDICATED
@ -365,6 +368,8 @@ void Systems_Shutdown()
#ifndef DEDICATED
HCVideoMode_Common_Detach();
DebugOverlays_Detach();
MatSys_Iface_Detach();
RSurf_Detach();
#endif // !DEDICATED

View File

@ -0,0 +1,37 @@
#include "core/stdafx.h"
#include "tier0/commandline.h"
#include "public/imaterialsystem.h"
#include "engine/matsys_interface.h"
//-----------------------------------------------------------------------------
// Updates the material system config
//-----------------------------------------------------------------------------
bool UpdateCurrentVideoConfig(MaterialSystem_Config_t* pConfig)
{
// This is a bug in Respawn's engine.
// In 'OverrideMaterialSystemConfigFromCommandLine',
// They added a cmdline check for '-noborder' and '-forceborder'.
// However, '-noborder' and 'forceborder' perform the exact same operation.
// Both feature the or instruction, there was unfortunately not
// enough bytes left to assemble a 'not and' operation to mitigate
// this bug without code caves, which is why we create this hook to remove the
// flag after it has been ran in 'OverrideMaterialSystemConfigFromCommandLine',
// but before 'UpdateCurrentVideoConfig' so that the file gets created properly.
if (CommandLine()->FindParm("-forceborder"))
{
pConfig->m_Flags &= ~3U;
}
return v_UpdateCurrentVideoConfig(pConfig);
}
///////////////////////////////////////////////////////////////////////////////
void MatSys_Iface_Attach()
{
DetourAttach(&v_UpdateCurrentVideoConfig, &UpdateCurrentVideoConfig);
}
void MatSys_Iface_Detach()
{
DetourDetach(&v_UpdateCurrentVideoConfig, &UpdateCurrentVideoConfig);
}

View File

@ -0,0 +1,55 @@
#ifndef MATSYS_INTERFACE_H
#define MATSYS_INTERFACE_H
#include "public/imaterialsystem.h"
//-------------------------------------------------------------------------
// RUNTIME: GAME_CFG
//-------------------------------------------------------------------------
inline CMemory p_UpdateCurrentVideoConfig;
inline CMemory p_UpdateMaterialSystemConfig;
inline CMemory p_HandleConfigFile;
inline CMemory p_ResetPreviousGameState;
inline CMemory p_LoadPlayerConfig;
inline auto v_UpdateCurrentVideoConfig = p_UpdateCurrentVideoConfig.RCast<bool (*)(MaterialSystem_Config_t* pConfig)>();
void MatSys_Iface_Attach();
void MatSys_Iface_Detach();
///////////////////////////////////////////////////////////////////////////////
class VMatSys_Interface : public IDetour
{
virtual void GetAdr(void) const
{
spdlog::debug("+----------------------------------------------------------------+\n");
spdlog::debug("| FUN: UpdateMaterialSystemConfig : {:#18x} |\n", p_UpdateMaterialSystemConfig.GetPtr());
spdlog::debug("| FUN: UpdateCurrentVideoConfig : {:#18x} |\n", p_UpdateCurrentVideoConfig.GetPtr());
spdlog::debug("| FUN: HandleConfigFile : {:#18x} |\n", p_HandleConfigFile.GetPtr());
spdlog::debug("| FUN: ResetPreviousGameState : {:#18x} |\n", p_ResetPreviousGameState.GetPtr());
spdlog::debug("| FUN: LoadPlayerConfig : {:#18x} |\n", p_LoadPlayerConfig.GetPtr());
}
virtual void GetFun(void) const
{
p_UpdateMaterialSystemConfig = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 80 3D ?? ?? ?? ?? ?? 0F 84 ?? ?? ?? ??");
p_UpdateCurrentVideoConfig = g_GameDll.FindPatternSIMD("40 55 ?? 41 56 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 4C 8B F1");
p_HandleConfigFile = g_GameDll.FindPatternSIMD("40 56 48 81 EC ?? ?? ?? ?? 8B F1");
p_ResetPreviousGameState = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 44 89 3D ?? ?? ?? ?? ?? 8B ?? 24 ??").ResolveRelativeAddressSelf(0x1, 0x5);
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2)
LoadPlayerConfig = g_GameDll.FindPatternSIMD("48 81 EC ?? ?? ?? ?? 48 83 3D ?? ?? ?? ?? ?? 75 0C");
#elif defined (GAMEDLL_S3)
p_LoadPlayerConfig = g_GameDll.FindPatternSIMD("89 4C 24 08 48 81 EC ?? ?? ?? ?? 48 83 3D ?? ?? ?? ?? ??");
#endif
v_UpdateCurrentVideoConfig = p_UpdateCurrentVideoConfig.RCast<bool (*)(MaterialSystem_Config_t*)>();
}
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }
virtual void Attach(void) const { }
virtual void Detach(void) const { }
};
///////////////////////////////////////////////////////////////////////////////
REGISTER(VMatSys_Interface);
#endif // MATSYS_INTERFACE_H

View File

@ -0,0 +1,27 @@
#ifndef IMATERIALSYSTEM_H
#define IMATERIALSYSTEM_H
//-----------------------------------------------------------------------------
// Video mode info..
//-----------------------------------------------------------------------------
struct MaterialVideoMode_t
{
int m_Width;
int m_Height;
int m_Format;
int m_RefreshRate;
};
//-----------------------------------------------------------------------------
// Material system config..
//-----------------------------------------------------------------------------
struct MaterialSystem_Config_t
{
MaterialVideoMode_t m_VideoMode;
int m_nPad;
int m_Flags;
// TODO: The rest..
};
#endif // IMATERIALSYSTEM_H

View File

@ -7,7 +7,7 @@
#define SIGDB_DICT_SIZE 20
#define SIGDB_MAJOR_VERSION 0x1 // Increment when library changes are made.
#define SIGDB_MINOR_VERSION 0x1 // Increment when SDK updates are released.
#define SIGDB_MINOR_VERSION 0x2 // Increment when SDK updates are released.
#ifdef DEDICATED
#define SIGDB_FILE "cfg\\server\\startup.bin"

View File

@ -719,6 +719,26 @@ void CUIBaseSurface::ForwardCommandToGame(Forms::Control* pSender)
}
}
//-----------------------------------------------------------------------------
// Purpose: appends the reversed core count value to the command line buffer
// Input : &svParameters -
//-----------------------------------------------------------------------------
void CUIBaseSurface::AppendReservedCoreCount(string& svParameters)
{
const char* pszReservedCores = this->m_ReservedCoresTextBox->Text().ToCString();
if (StringIsDigit(pszReservedCores))
{
int nReservedCores = atoi(pszReservedCores);
if (nReservedCores) // A reserved core count of 0 seems to crash the game on some systems.
{
svParameters.append("-numreservedcores \"" + this->m_ReservedCoresTextBox->Text() + "\"\n");
}
}
if (StringIsDigit(this->m_WorkerThreadsTextBox->Text().ToCString()))
svParameters.append("-numworkerthreads \"" + this->m_WorkerThreadsTextBox->Text() + "\"\n");
}
//-----------------------------------------------------------------------------
// Purpose: clears the form and reloads the playlist
// Input : &svParameters -
@ -766,13 +786,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters)
svParameters.append("-playlistfile \"" + this->m_PlaylistFileTextBox->Text() + "\"\n");
// ENGINE ###############################################################
if (StringIsDigit(this->m_ReservedCoresTextBox->Text().ToCString()))
svParameters.append("-numreservedcores \"" + this->m_ReservedCoresTextBox->Text() + "\"\n");
//else error;
if (StringIsDigit(this->m_WorkerThreadsTextBox->Text().ToCString()))
svParameters.append("-numworkerthreads \"" + this->m_WorkerThreadsTextBox->Text() + "\"\n");
//else error;
this->AppendReservedCoreCount(svParameters);
if (this->m_SingleCoreDediToggle->Checked())
svParameters.append("+sv_single_core_dedi \"1\"\n");
@ -889,13 +903,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters)
svParameters.append("-playlistfile \"" + this->m_PlaylistFileTextBox->Text() + "\"\n");
// ENGINE ###############################################################
if (StringIsDigit(this->m_ReservedCoresTextBox->Text().ToCString()))
svParameters.append("-numreservedcores \"" + this->m_ReservedCoresTextBox->Text() + "\"\n");
//else error;
if (StringIsDigit(this->m_WorkerThreadsTextBox->Text().ToCString()))
svParameters.append("-numworkerthreads \"" + this->m_WorkerThreadsTextBox->Text() + "\"\n");
//else error;
this->AppendReservedCoreCount(svParameters);
if (this->m_SingleCoreDediToggle->Checked())
svParameters.append("+sv_single_core_dedi \"1\"\n");
@ -982,13 +990,7 @@ eLaunchMode CUIBaseSurface::BuildParameter(string& svParameters)
svParameters.append("-playlistfile \"" + this->m_PlaylistFileTextBox->Text() + "\"\n");
// ENGINE ###############################################################
if (StringIsDigit(this->m_ReservedCoresTextBox->Text().ToCString()))
svParameters.append("-numreservedcores \"" + this->m_ReservedCoresTextBox->Text() + "\"\n");
//else error;
if (StringIsDigit(this->m_WorkerThreadsTextBox->Text().ToCString()))
svParameters.append("-numworkerthreads \"" + this->m_WorkerThreadsTextBox->Text() + "\"\n");
//else error;
this->AppendReservedCoreCount(svParameters);
if (this->m_SingleCoreDediToggle->Checked())
svParameters.append("+sv_single_core_dedi \"1\"\n");

View File

@ -34,7 +34,9 @@ private:
static void VirtualItemToClipboard(const std::unique_ptr<MouseEventArgs>& pEventArgs, Forms::Control* pSender);
static void GetVirtualItem(const std::unique_ptr<Forms::RetrieveVirtualItemEventArgs>& pEventArgs, Forms::Control* pSender);
static void ForwardCommandToGame(Forms::Control* pSender);
eLaunchMode BuildParameter(string& svParameter);
void AppendReservedCoreCount(string& svParameter);
enum class eMode
{

View File

@ -44,6 +44,7 @@
<ClCompile Include="..\engine\host.cpp" />
<ClCompile Include="..\engine\host_cmd.cpp" />
<ClCompile Include="..\engine\host_state.cpp" />
<ClCompile Include="..\engine\matsys_interface.cpp" />
<ClCompile Include="..\engine\modelloader.cpp" />
<ClCompile Include="..\engine\net.cpp" />
<ClCompile Include="..\engine\networkstringtable.cpp" />
@ -217,6 +218,7 @@
<ClInclude Include="..\engine\host.h" />
<ClInclude Include="..\engine\host_cmd.h" />
<ClInclude Include="..\engine\host_state.h" />
<ClInclude Include="..\engine\matsys_interface.h" />
<ClInclude Include="..\engine\modelloader.h" />
<ClInclude Include="..\engine\net.h" />
<ClInclude Include="..\engine\networkstringtable.h" />
@ -320,6 +322,7 @@
<ClInclude Include="..\public\ihandleentity.h" />
<ClInclude Include="..\public\imaterial.h" />
<ClInclude Include="..\public\imaterialinternal.h" />
<ClInclude Include="..\public\imaterialsystem.h" />
<ClInclude Include="..\public\inetchannel.h" />
<ClInclude Include="..\public\inetmessage.h" />
<ClInclude Include="..\public\inetmsghandler.h" />

View File

@ -684,6 +684,9 @@
<ClCompile Include="..\public\utility\sigcache.cpp">
<Filter>sdk\public\utility</Filter>
</ClCompile>
<ClCompile Include="..\engine\matsys_interface.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1964,6 +1967,12 @@
<ClInclude Include="..\public\utility\sigcache.h">
<Filter>sdk\public\utility</Filter>
</ClInclude>
<ClInclude Include="..\public\imaterialsystem.h">
<Filter>sdk\public</Filter>
</ClInclude>
<ClInclude Include="..\engine\matsys_interface.h">
<Filter>sdk\engine</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">