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.
This commit is contained in:
Kawe Mazidjatari 2023-06-05 01:24:23 +02:00
parent 9f2b1b1bb5
commit 11fd49efde
3 changed files with 61 additions and 13 deletions

View File

@ -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"

View File

@ -0,0 +1,43 @@
//====== Copyright <20> 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);
}

View File

@ -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<void(*)(CUserCmd* pUserC
inline CMemory p_CUserCmd__Copy;
inline auto v_CUserCmd__Copy = p_CUserCmd__Copy.RCast<CUserCmd*(*)(CUserCmd* pDest, CUserCmd* pSource)>();
inline CMemory p_ReadUserCmd;
inline auto v_ReadUserCmd = p_ReadUserCmd.RCast<int (*)(bf_read* buf, CUserCmd* move, CUserCmd* from)>();
//-------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------
@ -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<CUserCmd* (*)(CUserCmd*, CUserCmd*)>();
p_ReadUserCmd = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 4C 8B C6 48 81 C6 ?? ?? ?? ??").FollowNearCallSelf();
v_ReadUserCmd = p_ReadUserCmd.RCast<int (*)(bf_read*, CUserCmd*, CUserCmd*)>();
}
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;
};
///////////////////////////////////////////////////////////////////////////////