mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
This commit fixes an engine bug where netmessages are getting copied into the replay buffer, while these messages should never be replayed. The engine performs an internal check on 'CNetMessage::m_nGroup', and if its NOT 2, the message is getting copied into the replay buffer. All messages returning false in 'ShouldReplayMessage' are not getting copied into the replay buffer anymore. This exploit has been used in the past to route clients that were watching a replay to an arbitrary server, which essentially forms an info leak as the client attempts to connect to the arbitrary server on its own. The exploit also allows for some form of remote code execution, depending on if the client was launched in developer mode or not.
248 lines
11 KiB
C++
248 lines
11 KiB
C++
#pragma once
|
|
#include "vpc/keyvalues.h"
|
|
#include "common/protocol.h"
|
|
#include "engine/net_chan.h"
|
|
#include "public/edict.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Enumerations
|
|
//-----------------------------------------------------------------------------
|
|
enum Reputation_t
|
|
{
|
|
REP_NONE = 0,
|
|
REP_REMOVE_ONLY,
|
|
REP_MARK_BAD
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Forward declarations
|
|
//-----------------------------------------------------------------------------
|
|
class CServer;
|
|
class CClient;
|
|
|
|
struct Spike_t
|
|
{
|
|
public:
|
|
Spike_t() :
|
|
m_nBits(0)
|
|
{
|
|
m_szDesc[0] = 0;
|
|
}
|
|
|
|
// !TODO: !unconfirmed!
|
|
char m_szDesc[64];
|
|
int m_nBits;
|
|
};
|
|
|
|
class CNetworkStatTrace
|
|
{
|
|
public:
|
|
CNetworkStatTrace() :
|
|
m_nStartBit(0), m_nCurBit(0), m_nMinWarningBytes(0)
|
|
{
|
|
}
|
|
int m_nStartBit;
|
|
int m_nCurBit;
|
|
int m_nMinWarningBytes;
|
|
CUtlVector< Spike_t > m_Records;
|
|
};
|
|
|
|
class CClientFrame
|
|
{
|
|
// !TODO: !unconfirmed!
|
|
int last_entity;
|
|
int tick_count;
|
|
CClientFrame* m_pNext;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
extern CClient* g_pClient;
|
|
|
|
class CClient : IClientMessageHandler, INetChannelHandler
|
|
{
|
|
public:
|
|
CClient* GetClient(int nIndex) const;
|
|
int64_t GetTeamNum() const;
|
|
edict_t GetHandle(void) const;
|
|
int GetUserID(void) const;
|
|
uint64_t GetNucleusID(void) const;
|
|
SIGNONSTATE GetSignonState(void) const;
|
|
PERSISTENCE GetPersistenceState(void) const;
|
|
CNetChan* GetNetChan(void) const;
|
|
CServer* GetServer(void) const;
|
|
int GetCommandTick(void) const;
|
|
const char* GetServerName(void) const;
|
|
const char* GetClientName(void) const;
|
|
void SetHandle(edict_t nHandle);
|
|
void SetUserID(uint32_t nUserID);
|
|
void SetNucleusID(uint64_t nNucleusID);
|
|
void SetSignonState(SIGNONSTATE nSignonState);
|
|
void SetPersistenceState(PERSISTENCE nPersistenceState);
|
|
void SetNetChan(CNetChan* pNetChan);
|
|
bool IsConnected(void) const;
|
|
bool IsSpawned(void) const;
|
|
bool IsActive(void) const;
|
|
bool IsPersistenceAvailable(void) const;
|
|
bool IsPersistenceReady(void) const;
|
|
bool IsFakeClient(void) const;
|
|
bool IsHumanPlayer(void) const;
|
|
|
|
bool SendNetMsgEx(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
|
|
bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
|
|
void Disconnect(const Reputation_t nRepLvl, const char* szReason, ...);
|
|
static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
|
|
void Clear(void);
|
|
|
|
public: // Hook statics:
|
|
static void VClear(CClient* pClient);
|
|
static void VActivatePlayer(CClient* pClient);
|
|
static bool VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg);
|
|
static void* VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck);
|
|
static bool VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
|
|
|
|
private:
|
|
int m_nUserID; //0x0010
|
|
edict_t m_nHandle; //0x0014
|
|
char m_szServerName[256]; //0x0160
|
|
char m_szClientName[256]; //0x0116
|
|
char pad_0015[258]; //0x0216
|
|
int m_nCommandTick; //0x0318
|
|
char pad_031C[60]; //0x031C
|
|
int64_t m_iTeamNum; //0x0258
|
|
KeyValues* m_ConVars; //0x0360
|
|
char pad_0368[8]; //0x0368
|
|
CServer* m_pServer; //0x0370
|
|
char pad_0378[40]; //0x0378
|
|
CNetChan* m_NetChannel; //0x03A0
|
|
char pad_03A8[8]; //0x03A8
|
|
SIGNONSTATE m_nSignonState; //0x03B0
|
|
int32_t m_nDeltaTick; //0x03B4
|
|
uint64_t m_nNucleusID; //0x03B8
|
|
int32_t m_nStringTableAckTick; //0x03BC
|
|
int32_t m_nSignonTick; //0x03C0
|
|
char pad_03C0[464]; //0x03C4
|
|
#if defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
|
|
char pad_0598[8]; //0x0598
|
|
#endif
|
|
bool m_bFakePlayer; //0x05A0
|
|
bool m_bReceivedPacket; //0x05A1
|
|
bool m_bLowViolence; //0x05A2
|
|
bool m_bFullyAuthenticated; //0x05A3
|
|
char pad_05A4[24]; //0x05A4
|
|
PERSISTENCE m_nPersistenceState; //0x05BC
|
|
char pad_05C0[295312]; //0x05C0
|
|
int m_iTracing; //0x48750
|
|
CNetworkStatTrace m_Trace; //0x48754
|
|
char pad_4878C[7304]; //0x4878C
|
|
int32_t m_LastMovementTick; //0x4A414
|
|
#if defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
|
|
char pad_4A418[120]; //0x4A418
|
|
#endif
|
|
char pad_4A440[48]; //0x4A440
|
|
};
|
|
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
|
|
static_assert(sizeof(CClient) == 0x4A440);
|
|
#else
|
|
static_assert(sizeof(CClient) == 0x4A4C0);
|
|
#endif
|
|
|
|
|
|
/* ==== CBASECLIENT ===================================================================================================================================================== */
|
|
inline CMemory p_CClient_Connect;
|
|
inline auto v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize)>();
|
|
|
|
inline CMemory p_CClient_Disconnect;
|
|
inline auto v_CClient_Disconnect = p_CClient_Disconnect.RCast<bool (*)(CClient* pClient, const Reputation_t nRepLvl, const char* szReason, ...)>();
|
|
|
|
inline CMemory p_CClient_Clear;
|
|
inline auto v_CClient_Clear = p_CClient_Clear.RCast<void (*)(CClient* pClient)>();
|
|
|
|
inline CMemory p_CClient_ActivatePlayer;
|
|
inline auto v_CClient_ActivatePlayer = p_CClient_ActivatePlayer.RCast<void (*)(CClient* pClient)>();
|
|
|
|
inline CMemory p_CClient_ProcessStringCmd;
|
|
inline auto v_CClient_ProcessStringCmd = p_CClient_ProcessStringCmd.RCast<bool (*)(CClient* pClient, NET_StringCmd* pMsg)>();
|
|
|
|
inline CMemory p_CClient_SetSignonState;
|
|
inline auto v_CClient_SetSignonState = p_CClient_SetSignonState.RCast<bool (*)(CClient* pClient, SIGNONSTATE signon)>();
|
|
|
|
inline CMemory p_CClient_SendNetMsgEx;
|
|
inline auto v_CClient_SendNetMsgEx = p_CClient_SendNetMsgEx.RCast<bool (*)(CClient* pClient, CNetMessage* pMsg, bool bLocal, bool bForceReliable, bool bVoice)>();
|
|
|
|
inline CMemory p_CClient_SendSnapshot;
|
|
inline auto v_CClient_SendSnapshot = p_CClient_SendSnapshot.RCast<void* (*)(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck)>();
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
class VClient : public IDetour
|
|
{
|
|
virtual void GetAdr(void) const
|
|
{
|
|
LogFunAdr("CClient::Connect", p_CClient_Connect.GetPtr());
|
|
LogFunAdr("CClient::Disconnect", p_CClient_Disconnect.GetPtr());
|
|
LogFunAdr("CClient::Clear", p_CClient_Clear.GetPtr());
|
|
LogFunAdr("CClient::ActivatePlayer", p_CClient_ActivatePlayer.GetPtr());
|
|
LogFunAdr("CClient::ProcessStringCmd", p_CClient_ProcessStringCmd.GetPtr());
|
|
LogFunAdr("CClient::SetSignonState", p_CClient_SetSignonState.GetPtr());
|
|
LogFunAdr("CClient::SendNetMsgEx", p_CClient_SendNetMsgEx.GetPtr());
|
|
LogFunAdr("CClient::SendSnapshot", p_CClient_SendSnapshot.GetPtr());
|
|
LogVarAdr("g_Client[128]", reinterpret_cast<uintptr_t>(g_pClient));
|
|
}
|
|
virtual void GetFun(void) const
|
|
{
|
|
p_CClient_Connect = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 20 41 0F B6 E9");
|
|
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) || defined (GAMEDLL_S2)
|
|
p_CClient_Disconnect = g_GameDll.FindPatternSIMD("48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 0F B6 F2");
|
|
#else // !GAMEDLL_S0 || !GAMEDLL_S1 || !GAMEDLL_S2
|
|
p_CClient_Disconnect = g_GameDll.FindPatternSIMD("48 8B C4 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC ?? ?? ?? ?? 83 B9 ?? ?? ?? ?? ?? 49 8B F8 8B F2");
|
|
#endif
|
|
p_CClient_Clear = g_GameDll.FindPatternSIMD("40 53 41 56 41 57 48 83 EC 20 48 8B D9 48 89 74");
|
|
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
|
|
p_CClient_ActivatePlayer = g_GameDll.FindPatternSIMD("40 53 57 41 57 48 83 EC 30 8B 81 ?? ?? ?? ??");
|
|
p_CClient_ProcessStringCmd = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 48 81 EC ?? ?? ?? ?? 49 8B D8");
|
|
p_CClient_SendNetMsg = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 30 48 8B 05 ?? ?? ?? ?? 45 0F B6 F1");
|
|
p_CClient_SendSnapshot = g_GameDll.FindPatternSIMD("44 89 44 24 ?? 48 89 4C 24 ?? 55 53 56 57 41 55");
|
|
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
|
|
p_CClient_ActivatePlayer = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 8B 81 B0 03 ?? ?? 48 8B D9 C6");
|
|
p_CClient_ProcessStringCmd = g_GameDll.FindPatternSIMD("48 89 6C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 7A 20");
|
|
p_CClient_SendNetMsgEx = g_GameDll.FindPatternSIMD("40 53 55 56 57 41 56 48 83 EC 40 48 8B 05 ?? ?? ?? ??");
|
|
p_CClient_SendSnapshot = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 56 41 55 41 56 41 57 48 8D 6C 24 ??");
|
|
#endif // !GAMEDLL_S0 || !GAMEDLL_S1
|
|
p_CClient_SetSignonState = g_GameDll.FindPatternSIMD("48 8B C4 48 89 58 10 48 89 70 18 57 48 81 EC ?? ?? ?? ?? 0F 29 70 E8 8B F2");
|
|
|
|
v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient*, const char*, void*, bool, void*, char*, int)>();
|
|
v_CClient_Disconnect = p_CClient_Disconnect.RCast<bool (*)(CClient*, const Reputation_t, const char*, ...)>();
|
|
v_CClient_Clear = p_CClient_Clear.RCast<void (*)(CClient*)>();
|
|
v_CClient_ActivatePlayer = p_CClient_ActivatePlayer.RCast<void (*)(CClient* pClient)>();
|
|
v_CClient_ProcessStringCmd = p_CClient_ProcessStringCmd.RCast<bool (*)(CClient*, NET_StringCmd*)>();
|
|
v_CClient_SetSignonState = p_CClient_SetSignonState.RCast<bool (*)(CClient*, SIGNONSTATE)>();
|
|
v_CClient_SendNetMsgEx = p_CClient_SendNetMsgEx.RCast<bool (*)(CClient*, CNetMessage*, bool, bool, bool)>();
|
|
v_CClient_SendSnapshot = p_CClient_SendSnapshot.RCast<void* (*)(CClient*, CClientFrame*, int, int)>();
|
|
}
|
|
virtual void GetVar(void) const
|
|
{
|
|
g_pClient = g_GameDll.FindPatternSIMD("3B 15 ?? ?? ?? ?? 7D 33")
|
|
.FindPatternSelf("48 8D 0D", CMemory::Direction::DOWN, 150).ResolveRelativeAddressSelf(0x3, 0x7).RCast<CClient*>();
|
|
}
|
|
virtual void GetCon(void) const { }
|
|
virtual void Attach(void) const
|
|
{
|
|
DetourAttach((LPVOID*)&v_CClient_Clear, &CClient::VClear);
|
|
DetourAttach((LPVOID*)&v_CClient_Connect, &CClient::VConnect);
|
|
DetourAttach((LPVOID*)&v_CClient_ActivatePlayer, &CClient::VActivatePlayer);
|
|
DetourAttach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd);
|
|
DetourAttach((LPVOID*)&v_CClient_SendNetMsgEx, &CClient::VSendNetMsgEx);
|
|
//DetourAttach((LPVOID*)&p_CClient_SendSnapshot, &CClient::VSendSnapshot);
|
|
}
|
|
virtual void Detach(void) const
|
|
{
|
|
DetourDetach((LPVOID*)&v_CClient_Clear, &CClient::VClear);
|
|
DetourDetach((LPVOID*)&v_CClient_Connect, &CClient::VConnect);
|
|
DetourDetach((LPVOID*)&v_CClient_ActivatePlayer, &CClient::VActivatePlayer);
|
|
DetourDetach((LPVOID*)&v_CClient_ProcessStringCmd, &CClient::VProcessStringCmd);
|
|
DetourDetach((LPVOID*)&v_CClient_SendNetMsgEx, &CClient::VSendNetMsgEx);
|
|
//DetourDetach((LPVOID*)&p_CClient_SendSnapshot, &CClient::VSendSnapshot);
|
|
}
|
|
};
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|