From 5b0303357f84ae445a4c6409d0828e0827eebb6a Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Tue, 7 May 2024 14:44:12 +0200 Subject: [PATCH] Engine: fix stack smash in client side UserMessage processor Unclamped CBitRead::ReadBits() call on stack buffer of MAX_USER_MSG_DATA bytes. Function has been rebuilt with additional clamping to mitigate the problem. --- src/engine/client/cdll_engine_int.h | 6 ++++++ src/engine/client/clientstate.cpp | 32 +++++++++++++++++++++++++++++ src/engine/client/clientstate.h | 4 ++++ 3 files changed, 42 insertions(+) diff --git a/src/engine/client/cdll_engine_int.h b/src/engine/client/cdll_engine_int.h index 7952fb9c..ce2972e0 100644 --- a/src/engine/client/cdll_engine_int.h +++ b/src/engine/client/cdll_engine_int.h @@ -47,6 +47,12 @@ public: const static int index = 28; return CallVFunc(index, this, sequenceNumber); /*48 83 EC 28 48 8B 05 ? ? ? ? 48 8D 0D ? ? ? ? 44 8B C2*/ } + + bool DispatchUserMessage(int msgType, bf_read* msgData) + { + const static int index = 59; + return CallVFunc(index, this, msgType, msgData); + } }; /* ==== CHLCLIENT ======================================================================================================================================================= */ diff --git a/src/engine/client/clientstate.cpp b/src/engine/client/clientstate.cpp index f7c42b5a..2a2a57c0 100644 --- a/src/engine/client/clientstate.cpp +++ b/src/engine/client/clientstate.cpp @@ -9,6 +9,7 @@ // ///////////////////////////////////////////////////////////////////////////////// #include "core/stdafx.h" +#include "mathlib/bitvec.h" #include "tier0/frametask.h" #include "engine/common.h" #include "engine/host.h" @@ -307,6 +308,36 @@ bool CClientState::_ProcessCreateStringTable(CClientState* thisptr, SVC_CreateSt return (endbit - startbit) == msg->m_nLength; } +//------------------------------------------------------------------------------ +// Purpose: processes user message data +// Input : *thisptr - +// *msg - +// Output : true on success, false otherwise +//------------------------------------------------------------------------------ +bool CClientState::_ProcessUserMessage(CClientState* thisptr, SVC_UserMessage* msg) +{ + CClientState* const cl = thisptr->GetShiftedBasePointer(); + + if (!cl->IsConnected()) + return false; + + // buffer for incoming user message + ALIGN4 byte userdata[MAX_USER_MSG_DATA] ALIGN4_POST = { 0 }; + bf_read userMsg("UserMessage(read)", userdata, sizeof(userdata)); + + int bitsRead = msg->m_DataIn.ReadBitsClamped(userdata, msg->m_nLength); + userMsg.StartReading(userdata, Bits2Bytes(bitsRead)); + + // dispatch message to client.dll + if (!g_pHLClient->DispatchUserMessage(msg->m_nMsgType, &userMsg)) + { + Warning(eDLL_T::CLIENT, "Couldn't dispatch user message (%i)\n", msg->m_nMsgType); + return false; + } + + return true; +} + static ConVar cl_onlineAuthEnable("cl_onlineAuthEnable", "1", FCVAR_RELEASE, "Enables the client-side online authentication system"); static ConVar cl_onlineAuthToken("cl_onlineAuthToken", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "The client's online authentication token"); @@ -402,6 +433,7 @@ void VClientState::Detour(const bool bAttach) const DetourSetup(&CClientState__ProcessStringCmd, &CClientState::_ProcessStringCmd, bAttach); DetourSetup(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick, bAttach); DetourSetup(&CClientState__ProcessCreateStringTable, &CClientState::_ProcessCreateStringTable, bAttach); + DetourSetup(&CClientState__ProcessUserMessage, &CClientState::_ProcessUserMessage, bAttach); DetourSetup(&CClientState__Connect, &CClientState::VConnect, bAttach); } diff --git a/src/engine/client/clientstate.h b/src/engine/client/clientstate.h index 41f879ee..8c663507 100644 --- a/src/engine/client/clientstate.h +++ b/src/engine/client/clientstate.h @@ -40,6 +40,7 @@ public: // Hook statics. static bool _ProcessStringCmd(CClientState* thisptr, NET_StringCmd* msg); static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg); static bool _ProcessCreateStringTable(CClientState* thisptr, SVC_CreateStringTable* msg); + static bool _ProcessUserMessage(CClientState* thisptr, SVC_UserMessage* msg); static void VConnect(CClientState* thisptr, connectparams_t* connectParams); @@ -228,6 +229,7 @@ inline bool(*CClientState__HookClientStringTable)(CClientState* thisptr, const c inline bool(*CClientState__ProcessStringCmd)(CClientState* thisptr, NET_StringCmd* msg); inline bool(*CClientState__ProcessServerTick)(CClientState* thisptr, SVC_ServerTick* msg); inline bool(*CClientState__ProcessCreateStringTable)(CClientState* thisptr, SVC_CreateStringTable* msg); +inline bool(*CClientState__ProcessUserMessage)(CClientState* thisptr, SVC_UserMessage* msg); /////////////////////////////////////////////////////////////////////////////// class VClientState : public IDetour @@ -242,6 +244,7 @@ class VClientState : public IDetour LogFunAdr("CClientState::ProcessStringCmd", CClientState__ProcessStringCmd); LogFunAdr("CClientState::ProcessServerTick", CClientState__ProcessServerTick); LogFunAdr("CClientState::ProcessCreateStringTable", CClientState__ProcessCreateStringTable); + LogFunAdr("CClientState::ProcessUserMessage", CClientState__ProcessUserMessage); LogVarAdr("g_ClientState", g_pClientState); LogVarAdr("g_ClientState_Shifted", g_pClientState_Shifted); } @@ -255,6 +258,7 @@ class VClientState : public IDetour g_GameDll.FindPatternSIMD("40 53 48 81 EC ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 48 8B DA").GetPtr(CClientState__ProcessStringCmd); g_GameDll.FindPatternSIMD("40 57 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B F9 7C 66").GetPtr(CClientState__ProcessServerTick); g_GameDll.FindPatternSIMD("48 89 4C 24 ?? 53 56 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ??").GetPtr(CClientState__ProcessCreateStringTable); + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ??").GetPtr(CClientState__ProcessUserMessage); } virtual void GetVar(void) const {