aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2022-01-18 03:13:52 +0000
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2022-01-18 03:13:52 +0000
commite512279b5cb47fca0107fb5e80a3d0a468bb5e6f (patch)
treea4595885fe1d86affe7b2d668cbe743f9a5b572c /NorthstarDedicatedTest
parentcd18553bbc302f264edf35eed1daab07a2512513 (diff)
downloadNorthstarLauncher-e512279b5cb47fca0107fb5e80a3d0a468bb5e6f.tar.gz
NorthstarLauncher-e512279b5cb47fca0107fb5e80a3d0a468bb5e6f.zip
make FCVAR_CLIENTCMD_CAN_EXECUTE checks not rely on concommand dispatch hooks that may be inconsistent across dlls
Diffstat (limited to 'NorthstarDedicatedTest')
-rw-r--r--NorthstarDedicatedTest/convar.cpp3
-rw-r--r--NorthstarDedicatedTest/convar.h14
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp42
-rw-r--r--NorthstarDedicatedTest/sourceinterface.h3
4 files changed, 37 insertions, 25 deletions
diff --git a/NorthstarDedicatedTest/convar.cpp b/NorthstarDedicatedTest/convar.cpp
index de460662..344f16c6 100644
--- a/NorthstarDedicatedTest/convar.cpp
+++ b/NorthstarDedicatedTest/convar.cpp
@@ -2,10 +2,12 @@
#include "convar.h"
#include "hookutils.h"
#include "gameutils.h"
+#include "sourceinterface.h"
#include <set>
// should this be in modmanager?
std::unordered_map<std::string, ConVar*> g_CustomConvars; // this is used in modloading code to determine whether we've registered a mod convar already
+SourceInterface<ICvar>* g_pCvar;
typedef void(*ConVarConstructorType)(ConVar* newVar, const char* name, const char* defaultValue, int flags, const char* helpString);
ConVarConstructorType conVarConstructor;
@@ -37,6 +39,7 @@ bool CvarIsFlagSetHook(ConVar* self, int flags)
void InitialiseConVars(HMODULE baseAddress)
{
conVarConstructor = (ConVarConstructorType)((char*)baseAddress + 0x416200);
+ g_pCvar = new SourceInterface<ICvar>("vstdlib.dll", "VEngineCvar007");
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417FA0, &CvarIsFlagSetHook, reinterpret_cast<LPVOID*>(&CvarIsFlagSet));
diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h
index 40b8a5d8..3de8139b 100644
--- a/NorthstarDedicatedTest/convar.h
+++ b/NorthstarDedicatedTest/convar.h
@@ -1,4 +1,5 @@
#pragma once
+#include "sourceinterface.h"
#include <set>
// taken directly from iconvar.h
@@ -90,10 +91,12 @@ class ICvar
public:
struct VTable
{
- void* unknown[10];
- void(*UnregisterConCommand) (ICvar* cvar, ConCommand* pCommandBase);
- void* unknown2[28];
- ConVar*(*FindVar)(const char* var_name); // offset for this is currently very wrong
+ //void* unknown[10];
+ //void(*UnregisterConCommand) (ICvar* cvar, ConCommand* pCommandBase);
+ //void* unknown2[28];
+ //ConVar*(*FindVar)(const char* var_name); // offset for this is currently very wrong
+ char* unknown[112];
+ ConCommand*(*FindCommandBase)(ICvar* self, const char* varName);
};
VTable* m_vtable;
@@ -103,4 +106,5 @@ public:
ConVar* RegisterConVar(const char* name, const char* defaultValue, int flags, const char* helpString);
void InitialiseConVars(HMODULE baseAddress);
-extern std::unordered_map<std::string, ConVar*> g_CustomConvars; \ No newline at end of file
+extern std::unordered_map<std::string, ConVar*> g_CustomConvars;
+extern SourceInterface<ICvar>* g_pCvar; \ No newline at end of file
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index 8cbf666e..8bc4e6e3 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -317,13 +317,11 @@ void CBaseClient__DisconnectHook(void* self, uint32_t unknownButAlways1, const c
}
// maybe this should be done outside of auth code, but effort to refactor rn and it sorta fits
-// hack: store the client that's executing the current stringcmd for pCommand->Dispatch() hook later
-void* pExecutingGameClient = 0;
+typedef bool(*CCommand__TokenizeType)(CCommand& self, const char* pCommandString, cmd_source_t commandSource);
+CCommand__TokenizeType CCommand__Tokenize;
char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const char* pCommandString)
{
- pExecutingGameClient = self;
-
if (CVar_sv_quota_stringcmdspersecond->m_nValue != -1)
{
// note: this isn't super perfect, legit clients can trigger it in lobby, mostly good enough tho imo
@@ -344,25 +342,32 @@ char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const c
}
}
- // todo later, basically just limit to CVar_sv_quota_stringcmdspersecond->m_nValue stringcmds per client per second
- return CGameClient__ExecuteStringCommand(self, unknown, pCommandString);
-}
+ // verify the command we're trying to execute is FCVAR_CLIENTCMD_CAN_EXECUTE, if it's a concommand
+ char* commandBuf[1040]; // assumedly this is the size of CCommand since we don't have an actual constructor
+ memset(commandBuf, 0, sizeof(commandBuf));
+ CCommand tempCommand = *(CCommand*)&commandBuf;
-void ConCommand__DispatchHook(ConCommand* command, const CCommand& args, void* a3)
-{
- // patch to ensure FCVAR_GAMEDLL concommands without FCVAR_CLIENTCMD_CAN_EXECUTE can't be executed by remote clients
- if (*sv_m_State == server_state_t::ss_active && !command->IsFlagSet(FCVAR_CLIENTCMD_CAN_EXECUTE) && !!pExecutingGameClient)
+ if (!CCommand__Tokenize(tempCommand, pCommandString, cmd_source_t::kCommandSrcCode) || !tempCommand.ArgC())
+ return false;
+
+ ICvar* icvar = *g_pCvar; // hellish call because i couldn't get icvar vtable stuff in convar.h to get the right offset for whatever reason
+ typedef ConCommand*(*FindCommandBaseType)(ICvar* self, const char* varName);
+ FindCommandBaseType FindCommandBase = *(FindCommandBaseType*)((*(char**)icvar) + 112);
+ ConCommand* command = FindCommandBase(icvar, tempCommand.Arg(0));
+
+ // if the command doesn't exist pass it on to ExecuteStringCommand for script clientcommands and stuff
+ if (command && !command->IsFlagSet(FCVAR_CLIENTCMD_CAN_EXECUTE))
{
+ // ensure FCVAR_GAMEDLL concommands without FCVAR_CLIENTCMD_CAN_EXECUTE can't be executed by remote clients
if (IsDedicated())
- return;
+ return false;
- // hack because don't currently have a way to check GetBaseLocalClient().m_nPlayerSlot
- if (strcmp((char*)pExecutingGameClient + 0xF500, g_LocalPlayerUserID))
- return;
+ if (strcmp((char*)self + 0xF500, g_LocalPlayerUserID))
+ return false;
}
- ConCommand__Dispatch(command, args, a3);
- pExecutingGameClient = 0;
+ // todo later, basically just limit to CVar_sv_quota_stringcmdspersecond->m_nValue stringcmds per client per second
+ return CGameClient__ExecuteStringCommand(self, unknown, pCommandString);
}
char __fastcall CNetChan___ProcessMessagesHook(void* self, void* buf)
@@ -507,7 +512,8 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x2140A0, &CNetChan___ProcessMessagesHook, reinterpret_cast<LPVOID*>(&CNetChan___ProcessMessages));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x104FB0, &CBaseClient__SendServerInfoHook, reinterpret_cast<LPVOID*>(&CBaseClient__SendServerInfo));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x117800, &ProcessConnectionlessPacketHook, reinterpret_cast<LPVOID*>(&ProcessConnectionlessPacket));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417440, &ConCommand__DispatchHook, reinterpret_cast<LPVOID*>(&ConCommand__Dispatch));
+
+ CCommand__Tokenize = (CCommand__TokenizeType)((char*)baseAddress + 0x418380);
// patch to disable kicking based on incorrect serverfilter in connectclient, since we repurpose it for use as an auth token
{
diff --git a/NorthstarDedicatedTest/sourceinterface.h b/NorthstarDedicatedTest/sourceinterface.h
index 829942ba..11d73e76 100644
--- a/NorthstarDedicatedTest/sourceinterface.h
+++ b/NorthstarDedicatedTest/sourceinterface.h
@@ -1,6 +1,5 @@
#pragma once
#include <string>
-#include "gameutils.h"
// literally just copied from ttf2sdk definition
typedef void*(*CreateInterfaceFn)(const char* pName, int* pReturnCode);
@@ -17,7 +16,7 @@ public:
CreateInterfaceFn createInterface = (CreateInterfaceFn)GetProcAddress(handle, "CreateInterface");
m_interface = (T*)createInterface(interfaceName.c_str(), NULL);
if (m_interface == nullptr)
- Error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName);
+ spdlog::error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName);
}
T* operator->() const