From 25c5a5c9af71ee94e94a8b09b48c7e579101287a Mon Sep 17 00:00:00 2001 From: r-ex <67599507+r-ex@users.noreply.github.com> Date: Tue, 14 Sep 2021 16:25:22 +0100 Subject: [PATCH] custom native ui & client script functions (#52) * custom native ui & client script functions * spacing is hard * sq_pushbool, sq_pushstring, sq_getstring, sq_getinteger * sq_pushinteger, sq_newarray, sq_arrayappend, sq_newtable, sq_newslot * Re-factored code. Co-authored-by: IcePixelx <41352111+PixieCore@users.noreply.github.com> --- r5dev/include/gameclasses.h | 33 ++++++++++++++++++++++++ r5dev/include/hooks.h | 4 +++ r5dev/include/patterns.h | 39 +++++++++++++++++++++++++++- r5dev/include/squirrel.h | 14 ++++++++++ r5dev/r5dev.vcxproj | 5 ++++ r5dev/r5dev.vcxproj.filters | 6 +++++ r5dev/src/gameclasses.cpp | 34 +++++++++++++++++++++++++ r5dev/src/hooks/hooks.cpp | 3 +++ r5dev/src/hooks/sqvm.cpp | 14 ++++++++++ r5dev/src/squirrel.cpp | 51 +++++++++++++++++++++++++++++++++++++ 10 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 r5dev/include/squirrel.h create mode 100644 r5dev/src/squirrel.cpp diff --git a/r5dev/include/gameclasses.h b/r5dev/include/gameclasses.h index bd096e01..bc41c25f 100644 --- a/r5dev/include/gameclasses.h +++ b/r5dev/include/gameclasses.h @@ -456,6 +456,33 @@ struct Interface __int64* NextInterfacePtr; }; +struct SQFuncRegistration +{ + const char* scriptName; // 00 + const char* nativeName; // 08 + const char* helpString; // 10 + const char* retValType; // 18 + const char* argTypes; // 20 + int16_t unk28; // 28 + int16_t padding1; // 2A + int32_t unk2c; // 2C + int64_t unk30; // 30 + int32_t unk38; // 38 + int32_t padding2; // 3C + int64_t unk40; // 40 + int64_t unk48; // 48 + int64_t unk50; // 50 + int32_t unk58; // 58 + int32_t padding3; // 5C + void* funcPtr; // 60 + + SQFuncRegistration() + { + memset(this, 0, sizeof(SQFuncRegistration)); + this->padding2 = 6; + } +}; + ///////////////////////////////////////////////////////////////////////////// // Initialize Game Globals @@ -474,11 +501,17 @@ namespace GameGlobals ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk); void* CreateCustomConCommand(const char* name, const char* helpString, int flags, void* callback, void* callbackAfterExecution); + // Script + void Script_RegisterFunction(void* sqvm, const char* name, const char* helpString, const char* retValType, const char* argTypes, void* funcPtr); + void RegisterUIScriptFunctions(void* sqvm); + void RegisterClientScriptFunctions(void* sqvm); + // Init void InitGameGlobals(); void InitAllCommandVariations(); void InitPlaylist(); + extern std::vector allPlaylists; extern bool IsInitialized; diff --git a/r5dev/include/hooks.h b/r5dev/include/hooks.h index fec365eb..735af5eb 100644 --- a/r5dev/include/hooks.h +++ b/r5dev/include/hooks.h @@ -25,6 +25,7 @@ namespace Hooks __int64 SQVM_Warning(void* sqvm, int a2, int a3, int* stringSize, void** string); __int64 SQVM_LoadRson(const char* rson_name); bool SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag); + void SQVM_RegisterOriginFuncs(void* sqvm); using SQVM_WarningFn = __int64(*)(void*, int, int, int*, void**); extern SQVM_WarningFn originalSQVM_Warning; @@ -34,6 +35,9 @@ namespace Hooks using SQVM_LoadScriptFn = bool(*)(void*, const char*, const char*, int); extern SQVM_LoadScriptFn originalSQVM_LoadScript; + + using SQVM_RegisterOriginFuncsFn = void(*)(void*); + extern SQVM_RegisterOriginFuncsFn originalSQVM_RegisterOriginFuncs; #pragma endregion #pragma region CServer diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index 9d6534f0..9f7eb11f 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -29,6 +29,27 @@ namespace /*0x140B1E55*/ FUNC_AT_ADDRESS(addr_SQVM_Warning_ReturnAddr, void*, r5_patterns.PatternSearch("E8 ? ? ? ? 85 C0 0F 99 C3").OffsetSelf(0x5).GetPtr()); + /*0x141061A50*/ + FUNC_AT_ADDRESS(addr_sq_pushstring, void(*)(void*, char*, __int64), r5_patterns.PatternSearch("E8 ? ? ? ? 8D 55 FE").FollowNearCall().GetPtr()); + + /*0x141061CD0*/ + FUNC_AT_ADDRESS(addr_sq_pushbool, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 41 0F B6 17").FollowNearCall().GetPtr()); + + /*0x141061C70*/ + FUNC_AT_ADDRESS(addr_sq_pushinteger, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 41 0F B7 17").FollowNearCall().GetPtr()); + + /*0x141062040*/ + FUNC_AT_ADDRESS(addr_sq_newarray, void(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 F5").FollowNearCall().GetPtr()); + + /*0x1410621F0*/ + FUNC_AT_ADDRESS(addr_sq_arrayappend, __int64(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 46 38").FollowNearCall().GetPtr()); + + /*0x141061FB0*/ + FUNC_AT_ADDRESS(addr_sq_newtable, void(*)(void*), r5_patterns.PatternSearch("E8 ? ? ? ? 83 C6 04").FollowNearCall().GetPtr()); + + /*0x141064250*/ + FUNC_AT_ADDRESS(addr_sq_newslot, __int64(*)(void*, int), r5_patterns.PatternSearch("E8 ? ? ? ? 49 63 46 18").FollowNearCall().GetPtr()); + //DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // For S0 and S1 /*0x141055630*/ @@ -37,6 +58,9 @@ namespace /*0x140C957E0*/ FUNC_AT_ADDRESS(addr_SQVM_LoadRson, int(*)(const char*), r5_patterns.PatternSearch("4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33").GetPtr()); + + /*0x140834A00*/ + FUNC_AT_ADDRESS(addr_SQVM_RegisterOriginFuncs, void(*)(void*), r5_patterns.PatternSearch("E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 48 8B 05 ? ? ? ? C7 05 ? ? ? ? ? ? ? ?").FollowNearCall().GetPtr()); #pragma endregion #pragma region NetChannel @@ -56,7 +80,6 @@ namespace MemoryAddress addr_NetChan_EncKeyPtr = MemoryAddress(0x160686DC0); char* addr_NetChan_EncKey = addr_NetChan_EncKeyPtr.Offset(4816).RCast(); - /*0x140263E70*/ FUNC_AT_ADDRESS(addr_NetChan_SetEncKey, void(*)(uintptr_t, const char*), MemoryAddress(0x140263E70).GetPtr()); @@ -132,18 +155,32 @@ namespace PRINT_ADDRESS("SQVM_LoadRson", addr_SQVM_LoadRson); PRINT_ADDRESS("SQVM_Warning", addr_SQVM_Warning); PRINT_ADDRESS("SQVM_Warning_ReturnAddr", addr_SQVM_Warning_ReturnAddr); + PRINT_ADDRESS("SQVM_RegisterOriginFuncs", addr_SQVM_RegisterOriginFuncs); + PRINT_ADDRESS("sq_arrayappend", addr_sq_arrayappend); + PRINT_ADDRESS("sq_newarray", addr_sq_newarray); + PRINT_ADDRESS("sq_newslot", addr_sq_newslot); + PRINT_ADDRESS("sq_newtable", addr_sq_newtable); + PRINT_ADDRESS("sq_pushbool", addr_sq_pushbool); + PRINT_ADDRESS("sq_pushinteger", addr_sq_pushinteger); + PRINT_ADDRESS("sq_pushstring", addr_sq_pushstring); PRINT_ADDRESS("NET_PrintFunc", addr_NET_PrintFunc); PRINT_ADDRESS("NET_ReceiveDatagram", addr_NET_ReceiveDatagram); PRINT_ADDRESS("NET_SendDatagram ", addr_NET_SendDatagram); PRINT_ADDRESS("CClientState::m_bRestrictServerCommands", addr_m_bRestrictServerCommands); + PRINT_ADDRESS("CClient::Clear", addr_CClient_Clear); PRINT_ADDRESS("INetChannel::Shutdown", addr_NetChan_Shutdown); + PRINT_ADDRESS("INetChannel::SetEncryptionKey", addr_NetChan_SetEncKey); + PRINT_ADDRESS("INetChannel::EncryptionKey", addr_NetChan_EncKey) PRINT_ADDRESS("CHLClient::FrameStageNotify", addr_CHLClient_FrameStageNotify); PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable); + PRINT_ADDRESS("CServer::ConnectClient", addr_CServer_ConnectClient); + PRINT_ADDRESS("CServer::RejectConnection", addr_CServer_RejectConnection); PRINT_ADDRESS("CBaseFileSystem::FileSystemWarning", addr_CBaseFileSystem_FileSystemWarning); PRINT_ADDRESS("MSG_EngineError", addr_MSG_EngineError); PRINT_ADDRESS("LoadPlaylist", addr_LoadPlaylist); PRINT_ADDRESS("MapVPKCache", addr_MapVPKCache); PRINT_ADDRESS("MemAlloc_Wrapper", addr_MemAlloc_Wrapper); + PRINT_ADDRESS("KeyValues::FindKey", addr_KeyValues_FindKey); std::cout << "+--------------------------------------------------------+" << std::endl; // TODO implement error handling when sigscan fails or result is 0 } diff --git a/r5dev/include/squirrel.h b/r5dev/include/squirrel.h new file mode 100644 index 00000000..e49c4dc3 --- /dev/null +++ b/r5dev/include/squirrel.h @@ -0,0 +1,14 @@ +#pragma once + +char* sq_getstring(void* sqvm, int i); +int sq_getinteger(void* sqvm, int i); + +void sq_pushbool(void* sqvm, int val); +void sq_pushstring(void* sqvm, char* string, int len); +void sq_pushinteger(void* sqvm, int val); + +void sq_newarray(void* sqvm, int size); +void sq_arrayappend(void* sqvm, int idx); + +void sq_newtable(void* sqvm); +void sq_newslot(void* sqvm, int idx); \ No newline at end of file diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj index 84db9479..f8910fa5 100644 --- a/r5dev/r5dev.vcxproj +++ b/r5dev/r5dev.vcxproj @@ -328,6 +328,7 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib ( + @@ -413,6 +414,10 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib ( Create pch.h + + Use + pch.h + diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters index aafd9c56..e0eb1929 100644 --- a/r5dev/r5dev.vcxproj.filters +++ b/r5dev/r5dev.vcxproj.filters @@ -201,6 +201,9 @@ hooks\src\cserver + + r5-sdk\src + @@ -573,6 +576,9 @@ shared\include + + r5-sdk\include + diff --git a/r5dev/src/gameclasses.cpp b/r5dev/src/gameclasses.cpp index 3d0b7919..84adec90 100644 --- a/r5dev/src/gameclasses.cpp +++ b/r5dev/src/gameclasses.cpp @@ -2,6 +2,7 @@ #include "gameclasses.h" #include "id3dx.h" #include "cgameconsole.h" +#include "squirrel.h" // Need this for a re-factor later. // Interface* interfaces = *reinterpret_cast(0x167F4FA48); @@ -460,6 +461,39 @@ namespace GameGlobals return allocatedConvar; // Return allocated ConVar. } + void Script_RegisterFunction(void* sqvm, const char* name, const char* helpString, const char* retValType, const char* argTypes, void* funcPtr) + { + static MemoryAddress Script_RegisterFunction = MemoryAddress(0x141056040); + + SQFuncRegistration* func = new SQFuncRegistration(); + + func->scriptName = name; + func->nativeName = name; + func->helpString = helpString; + func->retValType = retValType; + func->argTypes = argTypes; + func->funcPtr = funcPtr; + + Script_RegisterFunction.RCast()(sqvm, func, 1); + } + + int Script_NativeTest(void* sqvm) + { + // function code goes here + + return 1; + } + + void RegisterUIScriptFunctions(void* sqvm) + { + // Script_RegisterFunction(sqvm, "UINativeTest", "native ui function", "void", "", &Script_NativeTest); + } + + void RegisterClientScriptFunctions(void* sqvm) + { + // Script_RegisterFunction(sqvm, "ClientNativeTest", "native client function", "void", "", &Script_NativeTest); + } + void DisconnectClient(CClient* client, const char* reason, unsigned __int8 unk1, char unk2) { if (!client) // Client valid? diff --git a/r5dev/src/hooks/hooks.cpp b/r5dev/src/hooks/hooks.cpp index 6d8e9a59..78d27de1 100644 --- a/r5dev/src/hooks/hooks.cpp +++ b/r5dev/src/hooks/hooks.cpp @@ -21,6 +21,7 @@ void Hooks::InstallHooks() MH_CreateHook(addr_SQVM_Warning, &Hooks::SQVM_Warning, reinterpret_cast(&originalSQVM_Warning)); MH_CreateHook(addr_SQVM_LoadRson, &Hooks::SQVM_LoadRson, reinterpret_cast(&originalSQVM_LoadRson)); MH_CreateHook(addr_SQVM_LoadScript, &Hooks::SQVM_LoadScript, reinterpret_cast(&originalSQVM_LoadScript)); + MH_CreateHook(addr_SQVM_RegisterOriginFuncs, &Hooks::SQVM_RegisterOriginFuncs, reinterpret_cast(&originalSQVM_RegisterOriginFuncs)); /////////////////////////////////////////////////////////////////////////////// // Hook Game Functions @@ -77,6 +78,7 @@ void Hooks::InstallHooks() MH_EnableHook(addr_SQVM_Warning); MH_EnableHook(addr_SQVM_LoadRson); MH_EnableHook(addr_SQVM_LoadScript); + MH_EnableHook(addr_SQVM_RegisterOriginFuncs); /////////////////////////////////////////////////////////////////////////////// // Enable Game hooks @@ -111,6 +113,7 @@ void Hooks::RemoveHooks() MH_RemoveHook(addr_SQVM_Print); MH_RemoveHook(addr_SQVM_LoadRson); MH_RemoveHook(addr_SQVM_LoadScript); + MH_RemoveHook(addr_SQVM_RegisterOriginFuncs); /////////////////////////////////////////////////////////////////////////////// // Unhook Game Functions diff --git a/r5dev/src/hooks/sqvm.cpp b/r5dev/src/hooks/sqvm.cpp index 65b1ecc4..5e0d06aa 100644 --- a/r5dev/src/hooks/sqvm.cpp +++ b/r5dev/src/hooks/sqvm.cpp @@ -6,6 +6,7 @@ namespace Hooks SQVM_WarningFn originalSQVM_Warning = nullptr; SQVM_LoadRsonFn originalSQVM_LoadRson = nullptr; SQVM_LoadScriptFn originalSQVM_LoadScript = nullptr; + SQVM_RegisterOriginFuncsFn originalSQVM_RegisterOriginFuncs = nullptr; } static std::ostringstream oss_print; @@ -178,4 +179,17 @@ bool Hooks::SQVM_LoadScript(void* sqvm, const char* script_path, const char* scr } return originalSQVM_LoadScript(sqvm, script_path, script_name, flag); +} + +void Hooks::SQVM_RegisterOriginFuncs(void* sqvm) { + static MemoryAddress UIVM = MemoryAddress(0x14D4151F0); + + originalSQVM_RegisterOriginFuncs(sqvm); + + if (sqvm == *(UIVM.RCast())) { + GameGlobals::RegisterUIScriptFunctions(sqvm); + } + else { + GameGlobals::RegisterClientScriptFunctions(sqvm); + } } \ No newline at end of file diff --git a/r5dev/src/squirrel.cpp b/r5dev/src/squirrel.cpp new file mode 100644 index 00000000..f0d107e7 --- /dev/null +++ b/r5dev/src/squirrel.cpp @@ -0,0 +1,51 @@ +#include "pch.h" +#include "patterns.h" + +char* sq_getstring(void* sqvm, int i) +{ + std::uintptr_t thisptr = reinterpret_cast(sqvm); + + return *(char**)(*(__int64*)(thisptr + 0x58) + 0x10 * i + 0x8) + 0x40; +} + +int sq_getinteger(void* sqvm, int i) +{ + std::uintptr_t thisptr = reinterpret_cast(sqvm); + + return *(int*)(*(__int64*)(thisptr + 0x58) + 0x10 * i + 0x8); +} + +void sq_pushbool(void* sqvm, int val) +{ + addr_sq_pushbool(sqvm, val); +} + +void sq_pushstring(void* sqvm, char* string, int len) +{ + addr_sq_pushstring(sqvm, string, len); +} + +void sq_pushinteger(void* sqvm, int val) +{ + addr_sq_pushinteger(sqvm, val); +} + +void sq_newarray(void* sqvm, int size) +{ + addr_sq_newarray(sqvm, size); +} + +void sq_arrayappend(void* sqvm, int idx) +{ + addr_sq_arrayappend(sqvm, idx); +} + +void sq_newtable(void* sqvm) +{ + addr_sq_newtable(sqvm); +} + +void sq_newslot(void* sqvm, int idx) +{ + addr_sq_newslot(sqvm, idx); +} \ No newline at end of file