From 11fd49efdef8024407fd070e6597a296f5511324 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 5 Jun 2023 01:24:23 +0200 Subject: [PATCH] Fix speed hack exploit The frame time send from CL_Move is not sanitized on the server; clamp it to the same cvars the client is clamping them to so players busting out the clamps cannot speed hack. The values are replicated between the server and client, so if someone wants to tweak the values, it won't mess up on either the server or client. --- r5dev/game/CMakeLists.txt | 1 + r5dev/game/shared/usercmd.cpp | 43 +++++++++++++++++++++++++++++++++++ r5dev/game/shared/usercmd.h | 30 +++++++++++++----------- 3 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 r5dev/game/shared/usercmd.cpp diff --git a/r5dev/game/CMakeLists.txt b/r5dev/game/CMakeLists.txt index 43efc0f3..4138ea05 100644 --- a/r5dev/game/CMakeLists.txt +++ b/r5dev/game/CMakeLists.txt @@ -19,6 +19,7 @@ add_sources( SOURCE_GROUP "Shared" "shared/shared_classnames.h" "shared/shareddefs.h" "shared/takedamageinfo.h" + "shared/usercmd.cpp" "shared/usercmd.h" "shared/util_shared.cpp" "shared/util_shared.h" diff --git a/r5dev/game/shared/usercmd.cpp b/r5dev/game/shared/usercmd.cpp new file mode 100644 index 00000000..c55d0e16 --- /dev/null +++ b/r5dev/game/shared/usercmd.cpp @@ -0,0 +1,43 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "usercmd.h" + +//----------------------------------------------------------------------------- +// Purpose: Read in a delta compressed usercommand. +// Input : *buf - +// *move - +// *from - +// Output : random seed +//----------------------------------------------------------------------------- +int ReadUserCmd(bf_read* buf, CUserCmd* move, CUserCmd* from) +{ + int seed = v_ReadUserCmd(buf, move, from); + + // On the client, the frame time must be within 'usercmd_frametime_min' + // and 'usercmd_frametime_max'. Testing revealed that speed hacking could + // be achieved by sending bogus frametimes. Clamp the networked frame time + // to the exact values that the client should be using to make sure it + // couldn't be circumvented by busting out the client side clamps. + if (host_timescale->GetFloat() == 1.0f) + move->frametime = clamp(move->frametime, + usercmd_frametime_min->GetFloat(), + usercmd_frametime_max->GetFloat()); + + return seed; +} + +//----------------------------------------------------------------------------- +void VUserCmd::Attach() const +{ + DetourAttach(&v_ReadUserCmd, &ReadUserCmd); +} + +void VUserCmd::Detach() const +{ + DetourDetach(&v_ReadUserCmd, &ReadUserCmd); +} diff --git a/r5dev/game/shared/usercmd.h b/r5dev/game/shared/usercmd.h index d403aa58..c947eff5 100644 --- a/r5dev/game/shared/usercmd.h +++ b/r5dev/game/shared/usercmd.h @@ -10,6 +10,7 @@ #ifdef _WIN32 #pragma once #endif +#include "tier1/bitbuf.h" #include "mathlib/vector.h" //------------------------------------------------------------------------------------- @@ -23,6 +24,9 @@ inline auto v_CUserCmd__Reset = p_CUserCmd__Reset.RCast(); +inline CMemory p_ReadUserCmd; +inline auto v_ReadUserCmd = p_ReadUserCmd.RCast(); + //------------------------------------------------------------------------------------- // //------------------------------------------------------------------------------------- @@ -34,21 +38,15 @@ public: Reset(); } - CUserCmd* Copy(CUserCmd* pSource) - { - return v_CUserCmd__Copy(this, pSource); - } - - void Reset() - { - v_CUserCmd__Reset(this); - } + inline CUserCmd* Copy(CUserCmd* pSource) { return v_CUserCmd__Copy(this, pSource); } + inline void Reset() { v_CUserCmd__Reset(this); } int32_t command_number; int32_t tick_count; float curtime; QAngle viewangles; - char pad_0x0018[12]; + float maybe; + char pad_0x0018[8]; float forwardmove; float sidemove; float upmove; @@ -58,9 +56,11 @@ public: char pad_0x0188[8]; Vector3D headposition; float maxpitch; - char pad_0x01A0[60]; + char pad_0x01A0[56]; + float frametime; }; +static_assert(sizeof(CUserCmd) == 0x1DC); /////////////////////////////////////////////////////////////////////////////// class VUserCmd : public IDetour @@ -69,6 +69,7 @@ class VUserCmd : public IDetour { LogFunAdr("CUserCmd::Reset", p_CUserCmd__Reset.GetPtr()); LogFunAdr("CUserCmd::Copy", p_CUserCmd__Copy.GetPtr()); + LogFunAdr("ReadUserCmd", p_ReadUserCmd.GetPtr()); } virtual void GetFun(void) const { @@ -77,11 +78,14 @@ class VUserCmd : public IDetour p_CUserCmd__Copy = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 4C 8B 9B ?? ?? ?? ??").FollowNearCallSelf(); v_CUserCmd__Copy = p_CUserCmd__Copy.RCast(); + + p_ReadUserCmd = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 4C 8B C6 48 81 C6 ?? ?? ?? ??").FollowNearCallSelf(); + v_ReadUserCmd = p_ReadUserCmd.RCast(); } virtual void GetVar(void) const { } virtual void GetCon(void) const { } - virtual void Attach(void) const { } - virtual void Detach(void) const { } + virtual void Attach(void) const; + virtual void Detach(void) const; }; ///////////////////////////////////////////////////////////////////////////////