diff options
author | BobTheBob <32057864+BobTheBob9@users.noreply.github.com> | 2022-01-18 03:13:52 +0000 |
---|---|---|
committer | BobTheBob <32057864+BobTheBob9@users.noreply.github.com> | 2022-01-18 03:13:52 +0000 |
commit | e512279b5cb47fca0107fb5e80a3d0a468bb5e6f (patch) | |
tree | a4595885fe1d86affe7b2d668cbe743f9a5b572c /NorthstarDedicatedTest | |
parent | cd18553bbc302f264edf35eed1daab07a2512513 (diff) | |
download | NorthstarLauncher-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.cpp | 3 | ||||
-rw-r--r-- | NorthstarDedicatedTest/convar.h | 14 | ||||
-rw-r--r-- | NorthstarDedicatedTest/serverauthentication.cpp | 42 | ||||
-rw-r--r-- | NorthstarDedicatedTest/sourceinterface.h | 3 |
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 |