1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#include "pch.h"
#include "serverauthentication.h"
#include "convar.h"
#include "hookutils.h"
#include <fstream>
#include <filesystem>
// hooks
typedef void(*RejectClientType)(void* a1, const char* a2, void* player, const char* fmt, ...);
RejectClientType RejectClient;
typedef void*(*CBaseServer__ConnectClientType)(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, void* a15, uint32_t a16, uint32_t a17);
CBaseServer__ConnectClientType CBaseServer__ConnectClient;
typedef char(*CBaseClient__ConnectType)(void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, int a7);
CBaseClient__ConnectType CBaseClient__Connect;
// global vars
ServerAuthenticationManager* g_ServerAuthenticationManager;
ConVar* CVar_ns_auth_allow_insecure;
ConVar* CVar_ns_auth_allow_insecure_write;
ServerAuthenticationManager::ServerAuthenticationManager() : m_authData(std::unordered_map<std::string, AuthData*>())
{}
void ServerAuthenticationManager::AddPlayerAuth(char* authToken, char* uid, char* pdata, size_t pdataSize)
{
}
bool ServerAuthenticationManager::AuthenticatePlayer(__int64 player, char* authToken)
{
// straight up just given up
if (!m_authData.empty() && m_authData.count(authToken))
{
// use stored auth data
AuthData* authData = m_authData[authToken];
// uuid
strcpy((char*)player + 0xF500, authData->uid);
// copy pdata into buffer
memcpy((char*)player + 0x4FA, authData->pdata, authData->pdataSize);
}
else
{
if (!CVar_ns_auth_allow_insecure->m_nValue) // no auth data and insecure connections aren't allowed, so dc the client
return false;
spdlog::info("wtf");
spdlog::info(player);
// no auth data available and insecure connections are allowed, try reading from disk, using authtoken as uid
// uuid
strcpy((char*)(player + 0xF500), authToken);
// try reading pdata file for player
std::string pdataPath = "playerdata/playerdata_";
pdataPath += authToken;
pdataPath += ".pdata";
std::fstream pdataStream(pdataPath, std::ios_base::in);
if (pdataStream.fail()) // file doesn't exist, use placeholder
pdataStream = std::fstream("playerdata/placeholder_playerdata.pdata");
// get file length
pdataStream.seekg(0, pdataStream.end);
int length = pdataStream.tellg();
pdataStream.seekg(0, pdataStream.beg);
// copy pdata into buffer
pdataStream.read((char*)(player + 0x4FA), length);
}
// set persistent data as ready
*(char*)(player + 0x4a0) = (char)0x3;
return true; // auth successful, client stays on
}
// store this in a var so we can use it in CBaseClient::Connect
// this is fine because serverfilter ptr won't decay by the time we use this
char* nextPlayerToken;
void* CBaseServer__ConnectClientHook(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, void* a15, uint32_t a16, uint32_t a17)
{
// auth tokens are sent with serverfilter, can't be accessed from player struct to my knowledge, so have to do this here
nextPlayerToken = serverFilter;
return CBaseServer__ConnectClient(server, a2, a3, a4, a5, a6, a7, a8, serverFilter, a10, a11, a12, a13, a14, a15, a16, a17);
}
char CBaseClient__ConnectHook(void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, int a7)
{
if (!g_ServerAuthenticationManager->AuthenticatePlayer((__int64)self, nextPlayerToken))
{
//RejectClient(nullptr, "Authentication failed", self, "Authentication failed");
//return 0;
}
return CBaseClient__Connect(self, name, netchan_ptr_arg, b_fake_player_arg, a5, Buffer, a7);
}
void InitialiseServerAuthentication(HMODULE baseAddress)
{
g_ServerAuthenticationManager = new ServerAuthenticationManager;
RejectClient = (RejectClientType)((char*)baseAddress + 0x1182E0);
CVar_ns_auth_allow_insecure = RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect");
CVar_ns_auth_allow_insecure_write = RegisterConVar("ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed");
spdlog::info((void*)CVar_ns_auth_allow_insecure);
spdlog::info((void*)&CVar_ns_auth_allow_insecure->m_nValue);
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast<LPVOID*>(&CBaseServer__ConnectClient));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x101740, &CBaseClient__ConnectHook, reinterpret_cast<LPVOID*>(&CBaseClient__Connect));
// patch to disable kicking based on incorrect serverfilter in connectclient, since we repurpose it for use as an auth token
{
void* ptr = (char*)baseAddress + 0x114655;
TempReadWrite rw(ptr);
*((char*)ptr) = (char)0xEB; // jz => jmp
}
}
|