aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDedicatedTest')
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj2
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters18
-rw-r--r--NorthstarDedicatedTest/convar.h8
-rw-r--r--NorthstarDedicatedTest/dllmain.cpp2
-rw-r--r--NorthstarDedicatedTest/filesystem.cpp40
-rw-r--r--NorthstarDedicatedTest/modmanager.cpp12
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp130
-rw-r--r--NorthstarDedicatedTest/serverauthentication.h28
-rw-r--r--NorthstarDedicatedTest/squirrel.cpp4
9 files changed, 226 insertions, 18 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
index ef652d9d..87ea35a2 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
@@ -308,6 +308,7 @@
<ClInclude Include="modmanager.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="scriptsrson.h" />
+ <ClInclude Include="serverauthentication.h" />
<ClInclude Include="sigscanning.h" />
<ClInclude Include="sourceconsole.h" />
<ClInclude Include="sourceinterface.h" />
@@ -332,6 +333,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="scriptsrson.cpp" />
+ <ClCompile Include="serverauthentication.cpp" />
<ClCompile Include="sigscanning.cpp" />
<ClCompile Include="sourceconsole.cpp" />
<ClCompile Include="sourceinterface.cpp" />
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
index 7bd160c6..f6ff5453 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
@@ -88,6 +88,18 @@
<Filter Include="Source Files\Shared\Mods\Compiled">
<UniqueIdentifier>{14fc0931-acad-46ec-a55e-94f4469d4235}</UniqueIdentifier>
</Filter>
+ <Filter Include="Source Files\Server">
+ <UniqueIdentifier>{3d41d3fc-8a3b-4358-b3e8-4f06dc96abfe}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Server\Authentication">
+ <UniqueIdentifier>{d69760a9-d5ec-4f3e-8f43-f74041654d44}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Server">
+ <UniqueIdentifier>{365e5c1f-4b2f-4d8b-a1d8-cdef401ca689}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\Server\Authentication">
+ <UniqueIdentifier>{24fd0855-9288-4129-93ba-c6cafdc98d1b}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
@@ -519,6 +531,9 @@
<ClInclude Include="scriptsrson.h">
<Filter>Header Files\Shared\Mods\Compiled</Filter>
</ClInclude>
+ <ClInclude Include="serverauthentication.h">
+ <Filter>Header Files\Server\Authentication</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@@ -572,6 +587,9 @@
<ClCompile Include="scriptsrson.cpp">
<Filter>Source Files\Shared\Mods\Compiled</Filter>
</ClCompile>
+ <ClCompile Include="serverauthentication.cpp">
+ <Filter>Source Files\Server\Authentication</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="include\spdlog\fmt\bundled\LICENSE.rst">
diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h
index 2c1e21a9..adfd585f 100644
--- a/NorthstarDedicatedTest/convar.h
+++ b/NorthstarDedicatedTest/convar.h
@@ -64,14 +64,14 @@ class ConCommand;
// also i sure do hope this size is right because there's a fairly decent chance it isn't
class ConVar
{
-private:
+public:
// if there are ever crashes caused by modifying custom cvars, check this
- unsigned char unknown[0x58];
+ unsigned char unknown[0x40];
char* m_pszString;
- int64_t m_StringLength;
+ size_t m_StringLength;
float m_fValue;
int32_t m_nValue;
- unsigned char unknown2[0x10];
+ unsigned char unknown2[0x28];
public:
virtual void EngineDestructor(void) {}
diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp
index 303afcfc..cc40a00c 100644
--- a/NorthstarDedicatedTest/dllmain.cpp
+++ b/NorthstarDedicatedTest/dllmain.cpp
@@ -8,6 +8,7 @@
#include "concommand.h"
#include "modmanager.h"
#include "filesystem.h"
+#include "serverauthentication.h"
#include <iostream>
bool initialised = false;
@@ -56,6 +57,7 @@ void InitialiseNorthstar()
}
AddDllLoadCallback("server.dll", InitialiseServerSquirrel);
+ AddDllLoadCallback("engine.dll", InitialiseServerAuthentication);
AddDllLoadCallback("filesystem_stdio.dll", InitialiseFilesystem);
diff --git a/NorthstarDedicatedTest/filesystem.cpp b/NorthstarDedicatedTest/filesystem.cpp
index aa6975fe..04b8c98e 100644
--- a/NorthstarDedicatedTest/filesystem.cpp
+++ b/NorthstarDedicatedTest/filesystem.cpp
@@ -17,7 +17,12 @@ typedef bool(*ReadFromCacheType)(IFileSystem* filesystem, const char* path, void
ReadFromCacheType readFromCache;
bool ReadFromCacheHook(IFileSystem* filesystem, const char* path, void* result);
+typedef void(*AddSearchPathType)(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType);
+AddSearchPathType addSearchPathOriginal;
+void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType);
+
bool readingOriginalFile;
+std::string currentModPath;
SourceInterface<IFileSystem>* g_Filesystem;
void InitialiseFilesystem(HMODULE baseAddress)
@@ -28,6 +33,7 @@ void InitialiseFilesystem(HMODULE baseAddress)
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x5CBA0, &ReadFileFromVPKHook, reinterpret_cast<LPVOID*>(&readFileFromVPK));
ENABLER_CREATEHOOK(hook, (*g_Filesystem)->m_vtable->ReadFromCache, &ReadFromCacheHook, reinterpret_cast<LPVOID*>(&readFromCache));
+ ENABLER_CREATEHOOK(hook, (*g_Filesystem)->m_vtable->AddSearchPath, &AddSearchPathHook, reinterpret_cast<LPVOID*>(&addSearchPathOriginal));
}
std::string ReadVPKFile(const char* path)
@@ -60,13 +66,21 @@ std::string ReadVPKOriginalFile(const char* path)
void SetNewModSearchPaths(Mod* mod)
{
- // put our new path to the head
- // in future we should look into manipulating paths at head manually, might be effort tho
- // potentially we could also determine whether the file we're setting paths for needs a mod dir, or compiled assets
+ // put our new path to the head if we need to read from a different mod path
+ // in the future we could also determine whether the file we're setting paths for needs a mod dir, or compiled assets
if (mod != nullptr)
- (*g_Filesystem)->m_vtable->AddSearchPath(&*(*g_Filesystem), (fs::absolute(mod->ModDirectory) / MOD_OVERRIDE_DIR).string().c_str(), "GAME", PATH_ADD_TO_HEAD);
-
- (*g_Filesystem)->m_vtable->AddSearchPath(&*(*g_Filesystem), fs::absolute(COMPILED_ASSETS_PATH).string().c_str(), "GAME", PATH_ADD_TO_HEAD);
+ {
+ if ((fs::absolute(mod->ModDirectory) / MOD_OVERRIDE_DIR).string().compare(currentModPath))
+ {
+ spdlog::info("changing mod search path from {} to {}", currentModPath, mod->ModDirectory.string());
+
+ addSearchPathOriginal(&*(*g_Filesystem), (fs::absolute(mod->ModDirectory) / MOD_OVERRIDE_DIR).string().c_str(), "GAME", PATH_ADD_TO_HEAD);
+ currentModPath = (fs::absolute(mod->ModDirectory) / MOD_OVERRIDE_DIR).string();
+ }
+ }
+ else if (!currentModPath.size()) // if currentModPath isn't set yet, then push compiled to head
+ addSearchPathOriginal(&*(*g_Filesystem), fs::absolute(COMPILED_ASSETS_PATH).string().c_str(), "GAME", PATH_ADD_TO_HEAD);
+
}
bool TryReplaceFile(const char* path)
@@ -76,7 +90,7 @@ bool TryReplaceFile(const char* path)
(*g_ModManager).CompileAssetsForFile(path);
- // is this efficient? no clue
+ // is this efficient? could probably be improved
for (ModOverrideFile* modFile : g_ModManager->m_modFiles)
{
if (!modFile->path.compare(fs::path(path).lexically_normal()))
@@ -111,4 +125,16 @@ bool ReadFromCacheHook(IFileSystem* filesystem, const char* path, void* result)
return false;
return readFromCache(filesystem, path, result);
+}
+
+void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType)
+{
+ addSearchPathOriginal(fileSystem, pPath, pathID, addType);
+
+ // make sure current mod paths are at head
+ if (!strcmp(pathID, "GAME") && currentModPath.compare(pPath) && addType == PATH_ADD_TO_HEAD)
+ {
+ addSearchPathOriginal(fileSystem, currentModPath.c_str(), "GAME", PATH_ADD_TO_HEAD);
+ addSearchPathOriginal(fileSystem, COMPILED_ASSETS_PATH.string().c_str(), "GAME", PATH_ADD_TO_HEAD);
+ }
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp
index 66fff17f..ea16f591 100644
--- a/NorthstarDedicatedTest/modmanager.cpp
+++ b/NorthstarDedicatedTest/modmanager.cpp
@@ -162,12 +162,6 @@ Mod::Mod(fs::path modDir, char* jsonBuf)
}
}
- // vpk stuff
- if (fs::exists(modDir / "vpk"))
- for (fs::directory_entry file : fs::directory_iterator(modDir / "vpk"))
- if (fs::is_regular_file(file) && file.path().extension() == "vpk")
- Vpks.push_back(file.path().string());
-
wasReadSuccessfully = true;
}
@@ -239,6 +233,12 @@ void ModManager::LoadMods()
for (ModConVar* convar : mod->ConVars)
if (g_CustomConvars.find(convar->Name) == g_CustomConvars.end()) // make sure convar isn't registered yet, unsure if necessary but idk what behaviour is for defining same convar multiple times
RegisterConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str());
+
+ // read vpk paths
+ if (fs::exists(mod->ModDirectory / "vpk"))
+ for (fs::directory_entry file : fs::directory_iterator(mod->ModDirectory / "vpk"))
+ if (fs::is_regular_file(file) && file.path().extension() == "vpk")
+ mod->Vpks.push_back(file.path().string());
}
// in a seperate loop because we register mod files in reverse order, since mods loaded later should have their files prioritised
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
new file mode 100644
index 00000000..5e27e9a5
--- /dev/null
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -0,0 +1,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
+ }
+} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/serverauthentication.h b/NorthstarDedicatedTest/serverauthentication.h
new file mode 100644
index 00000000..75187221
--- /dev/null
+++ b/NorthstarDedicatedTest/serverauthentication.h
@@ -0,0 +1,28 @@
+#pragma once
+#include <unordered_map>
+#include <string>
+
+struct AuthData
+{
+ char* uid;
+
+ // pdata
+ char* pdata;
+ size_t pdataSize;
+};
+
+class ServerAuthenticationManager
+{
+public:
+ std::unordered_map<std::string, AuthData*> m_authData;
+
+public:
+ ServerAuthenticationManager();
+ void AddPlayerAuth(char* authToken, char* uid, char* pdata, size_t pdataSize);
+ bool AuthenticatePlayer(__int64 player, char* authToken);
+ void WritePersistentData(void* player);
+};
+
+void InitialiseServerAuthentication(HMODULE baseAddress);
+
+extern ServerAuthenticationManager* g_ServerAuthenticationManager; \ No newline at end of file
diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp
index 15c144c5..b57e22ae 100644
--- a/NorthstarDedicatedTest/squirrel.cpp
+++ b/NorthstarDedicatedTest/squirrel.cpp
@@ -89,18 +89,20 @@ void InitialiseClientSquirrel(HMODULE baseAddress)
void InitialiseServerSquirrel(HMODULE baseAddress)
{
g_ServerSquirrelManager = new SquirrelManager<SERVER>();
+ g_ServerSquirrelManager->AddFuncRegistration("void", "SavePdataForEntityIndex", "int i", "idk", NSTestFunc);
HookEnabler hook;
ServerSq_compilebuffer = (sq_compilebufferType)((char*)baseAddress + 0x3110);
ServerSq_pushroottable = (sq_pushroottableType)((char*)baseAddress + 0x5840);
ServerSq_call = (sq_callType)((char*)baseAddress + 0x8620);
- ServerRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x1DDD10);
+ ServerRegisterSquirrelFunc = (RegisterSquirrelFuncType)((char*)baseAddress + 0x1DD10);
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FE90, &SQPrintHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQPrint)); // server print function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x260E0, &CreateNewVMHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerCreateNewVM)); // server createnewvm function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x26E20, &DestroyVMHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerDestroyVM)); // server destroyvm function
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x799E0, &ScriptCompileErrorHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerSQCompileError)); // server compileerror function
+ ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1D5C0, &CallScriptInitCallbackHook<SERVER>, reinterpret_cast<LPVOID*>(&ServerCallScriptInitCallback)); // server callscriptinitcallback function
RegisterConCommand("script", ExecuteCodeCommand<SERVER>, "Executes script code on the server vm", FCVAR_GAMEDLL);
}