From b044f10e527cb1dacd55ec75487f67299fb7c333 Mon Sep 17 00:00:00 2001 From: rjindael Date: Thu, 7 Sep 2023 16:17:02 -0700 Subject: [PATCH] feat: enhanced server, hook DataModel and StandardOut --- Kiseki.Patcher/CMakeLists.txt | 19 ++++- Kiseki.Patcher/Header/Globals.hpp | 10 +++ Kiseki.Patcher/Header/Hooks/CRoblox.hpp | 9 +++ Kiseki.Patcher/Header/Hooks/DataModel.hpp | 20 ++++++ Kiseki.Patcher/Header/Hooks/StandardOut.hpp | 14 ++++ Kiseki.Patcher/Header/Server.hpp | 37 ++++++++++ Kiseki.Patcher/Source/Hooks/CRoblox.cpp | 39 +++++++++++ Kiseki.Patcher/Source/Hooks/DataModel.cpp | 20 ++++++ Kiseki.Patcher/Source/Hooks/StandardOut.cpp | 22 ++++++ Kiseki.Patcher/Source/Server.cpp | 78 +++++++++++++++++++++ Kiseki.Patcher/Source/main.cpp | 9 +++ 11 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 Kiseki.Patcher/Header/Hooks/DataModel.hpp create mode 100644 Kiseki.Patcher/Header/Hooks/StandardOut.hpp create mode 100644 Kiseki.Patcher/Header/Server.hpp create mode 100644 Kiseki.Patcher/Source/Hooks/DataModel.cpp create mode 100644 Kiseki.Patcher/Source/Hooks/StandardOut.cpp create mode 100644 Kiseki.Patcher/Source/Server.cpp diff --git a/Kiseki.Patcher/CMakeLists.txt b/Kiseki.Patcher/CMakeLists.txt index 7a1884a..1ce965c 100644 --- a/Kiseki.Patcher/CMakeLists.txt +++ b/Kiseki.Patcher/CMakeLists.txt @@ -27,9 +27,22 @@ if(COMPILE_PLAYER OR COMPILE_SERVER) list(APPEND HEADER Header/Hooks/CRoblox.hpp) if(COMPILE_SERVER) - # Hook ServerReplicator - list(APPEND SOURCE Source/Hooks/ServerReplicator.cpp) - list(APPEND HEADER Header/Hooks/ServerReplicator.hpp) + # Hook DataModel, ServerReplicator, and StandardOut as well as include our custom server interface + list(APPEND SOURCE + Source/Server.cpp + + Source/Hooks/DataModel.cpp + Source/Hooks/ServerReplicator.cpp + Source/Hooks/StandardOut.cpp + ) + + list(APPEND HEADER + Header/Server.hpp + + Header/Hooks/DataModel.hpp + Header/Hooks/ServerReplicator.hpp + Header/Hooks/StandardOut.hpp + ) endif() endif() diff --git a/Kiseki.Patcher/Header/Globals.hpp b/Kiseki.Patcher/Header/Globals.hpp index a7956ac..46acf84 100644 --- a/Kiseki.Patcher/Header/Globals.hpp +++ b/Kiseki.Patcher/Header/Globals.hpp @@ -11,8 +11,18 @@ #define PUBLIC_KEY 0x06, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xA5, 0x11, 0xD0, 0x9F, 0xAB, 0x9B, 0x3A, 0x96, 0xC5, 0xBE, 0x50, 0xBB, 0xCA, 0x0C, 0xBB, 0xC8, 0x1A, 0x9C, 0xC1, 0x2F, 0x22, 0x7A, 0x80, 0x2C, 0x31, 0x01, 0xE1, 0x21, 0xC2, 0x7F, 0xE0, 0x10, 0xA1, 0x2D, 0x09, 0xED, 0x10, 0x3E, 0x28, 0xB9, 0xBD, 0x0F, 0x38, 0xDB, 0x52, 0x78, 0xC0, 0xEC, 0x04, 0xD4, 0x00, 0xAD, 0x45, 0xD3, 0xC7, 0x78, 0xF2, 0x83, 0xB5, 0x5B, 0x16, 0x0C, 0x32, 0x5D, 0xB3, 0x3B, 0xDA, 0xA2, 0x9C, 0x73, 0xB2, 0x0C, 0x09, 0x93, 0xD8, 0xF8, 0xD9, 0xC5, 0x75, 0xAB, 0x33, 0x19, 0xD3, 0x6A, 0xAF, 0x20, 0x21, 0x6C, 0x78, 0x31, 0x41, 0xD1, 0xCD, 0x6D, 0x4D, 0xA1, 0x6D, 0x49, 0x3A, 0x6A, 0x33, 0x10, 0x6D, 0x52, 0x33, 0x4A, 0x10, 0x32, 0x3D, 0x42, 0xE6, 0xEC, 0x38, 0x97, 0x2F, 0x05, 0x41, 0xDD, 0xD6, 0xB6, 0xAC, 0x17, 0x4B, 0x7E, 0xFA, 0xFE, 0xA4, 0xD2 +#define RBX__MESSAGE_INFO 0 +#define RBX__MESSAGE_OUTPUT 1 +#define RBX__MESSAGE_WARNING 2 +#define RBX__MESSAGE_ERROR 3 + +#define CLASSPADDING_DATAMODEL__JOBID 739 + +#define ADDRESS_HTTP__HTTPGETPOSTWININET 0x006F03B0 #define ADDRESS_HTTP__TRUSTCHECK 0x005B7050 #define ADDRESS_CRYPT__VERIFYSIGNATUREBASE64 0x00809EC0 +#define ADDRESS_DATAMODEL__GETJOBID 0x005E70C0 +#define ADDRESS_CRYPT__VERIFYSIGNATUREBASE64 0x00809EC0 #define ADDRESS_STANDARDOUT__PRINT 0x005B25E0 #define ADDRESS_SERVERREPLICATOR__SENDTOP 0x00513E80 #define ADDRESS_SERVERREPLICATOR__PROCESSTICKET 0x00514B60 diff --git a/Kiseki.Patcher/Header/Hooks/CRoblox.hpp b/Kiseki.Patcher/Header/Hooks/CRoblox.hpp index 06db5d0..ffd37ed 100644 --- a/Kiseki.Patcher/Header/Hooks/CRoblox.hpp +++ b/Kiseki.Patcher/Header/Hooks/CRoblox.hpp @@ -7,6 +7,10 @@ #include "Globals.hpp" #include "Helpers.hpp" +#ifdef SERVER +#include "Server.hpp" +#endif + class CWorkspace; const auto CWorkspace__ExecUrlScript = (HRESULT(__stdcall*)(CWorkspace * workspace, LPCWSTR, VARIANTARG, VARIANTARG, VARIANTARG, VARIANTARG, LPVOID))ADDRESS_CWORKSPACE__EXECURLSCRIPT; @@ -44,4 +48,9 @@ void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* extern CRobloxApp__InitInstance_t CRobloxApp__InitInstance; extern CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam; +#ifdef SERVER +extern std::wstring jobId; +extern bool hasJobId; +#endif + #endif \ No newline at end of file diff --git a/Kiseki.Patcher/Header/Hooks/DataModel.hpp b/Kiseki.Patcher/Header/Hooks/DataModel.hpp new file mode 100644 index 0000000..74ce905 --- /dev/null +++ b/Kiseki.Patcher/Header/Hooks/DataModel.hpp @@ -0,0 +1,20 @@ +#ifdef SERVER + +#pragma once + +#include "Hooks/CRoblox.hpp" + +#include "Globals.hpp" +#include "Helpers.hpp" + +struct DataModel +{ + void* padding1[CLASSPADDING_DATAMODEL__JOBID]; + std::string jobId; +}; + +typedef INT(__thiscall* DataModel__getJobId_t)(DataModel* _this, int a2); +int __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2); +extern DataModel__getJobId_t DataModel__getJobId; + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Header/Hooks/StandardOut.hpp b/Kiseki.Patcher/Header/Hooks/StandardOut.hpp new file mode 100644 index 0000000..09ad762 --- /dev/null +++ b/Kiseki.Patcher/Header/Hooks/StandardOut.hpp @@ -0,0 +1,14 @@ +#ifdef SERVER + +#pragma once + +#include "Globals.hpp" +#include "Helpers.hpp" +#include "Patcher.hpp" +#include "Server.hpp" + +typedef void(__thiscall* StandardOut__print_t)(int _this, int type, std::string* message); +void __fastcall StandardOut__print_hook(int _this, void*, int type, std::string* message); +extern StandardOut__print_t StandardOut__print; + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Header/Server.hpp b/Kiseki.Patcher/Header/Server.hpp new file mode 100644 index 0000000..d993756 --- /dev/null +++ b/Kiseki.Patcher/Header/Server.hpp @@ -0,0 +1,37 @@ +#ifdef SERVER + +#pragma once + +#include +#include + +#include "Hooks/StandardOut.hpp" + +#include "Globals.hpp" +#include "Helpers.hpp" + +enum class LogSeverity { + Information = RBX__MESSAGE_INFO, + Output = RBX__MESSAGE_OUTPUT, + Warning = RBX__MESSAGE_WARNING, + Error = RBX__MESSAGE_ERROR +}; + +class Server { +public: + static HANDLE Handle; + + static void Initialize(const std::wstring jobId); + static void Cleanup(); + + struct Log + { + static void Output(const LogSeverity severity, const std::string message); + }; +private: + static std::string OutputLogPath; + + static std::ofstream OutputLog; +}; + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Source/Hooks/CRoblox.cpp b/Kiseki.Patcher/Source/Hooks/CRoblox.cpp index 7c73baa..21ba2da 100644 --- a/Kiseki.Patcher/Source/Hooks/CRoblox.cpp +++ b/Kiseki.Patcher/Source/Hooks/CRoblox.cpp @@ -10,6 +10,11 @@ std::wstring authenticationUrl; std::wstring authenticationTicket; std::wstring joinScriptUrl; +#ifdef SERVER +bool hasJobId = false; +std::wstring jobId; +#endif + CRobloxApp__InitInstance_t CRobloxApp__InitInstance = (CRobloxApp__InitInstance_t)ADDRESS_CROBLOXAPP__INITINSTANCE; CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam = (CRobloxCommandLineInfo__ParseParam_t)ADDRESS_CROBLOXCOMMANDLINEINFO__PARSEPARAM; @@ -45,6 +50,16 @@ BOOL __fastcall CRobloxApp__InitInstance_hook(CRobloxApp* _this) } #endif +#ifdef SERVER + if (!hasJobId) + { +#ifdef _DEBUG + MessageBoxW(nullptr, L"Missing job ID", L"Kiseki", MB_OK | MB_ICONERROR); +#endif + return FALSE; + } +#endif + CApp* app = reinterpret_cast(CLASSLOCATION_CAPP); if (hasAuthenticationUrl && hasAuthenticationTicket && !authenticationUrl.empty() && !authenticationTicket.empty()) @@ -100,6 +115,18 @@ void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* CCommandLineInfo__ParseLast(_this, bLast); return; } + +#ifdef SERVER + if (hasJobId && jobId.empty()) + { + int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0); + jobId.resize(size); + MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &jobId[0], size); + + CCommandLineInfo__ParseLast(_this, bLast); + return; + } +#endif if (bFlag && _stricmp(pszParam, "a") == 0) { @@ -122,6 +149,18 @@ void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* return; } +#ifdef SERVER + if (bFlag && _stricmp(pszParam, "jobId") == 0) + { + hasJobId = true; + CCommandLineInfo__ParseLast(_this, bLast); + + Server::Initialize(jobId); + + return; + } +#endif + CRobloxCommandLineInfo__ParseParam(_this, pszParam, bFlag, bLast); } diff --git a/Kiseki.Patcher/Source/Hooks/DataModel.cpp b/Kiseki.Patcher/Source/Hooks/DataModel.cpp new file mode 100644 index 0000000..3713cfb --- /dev/null +++ b/Kiseki.Patcher/Source/Hooks/DataModel.cpp @@ -0,0 +1,20 @@ +#ifdef SERVER + +#include "Hooks/DataModel.hpp" + +bool setJobId = false; + +DataModel__getJobId_t DataModel__getJobId = (DataModel__getJobId_t)ADDRESS_DATAMODEL__GETJOBID; + +int __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2) +{ + if (!setJobId && hasJobId && !jobId.empty()) + { + _this->jobId = Helpers::ws2s(jobId); + setJobId = true; + } + + return DataModel__getJobId(_this, a2); +} + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Source/Hooks/StandardOut.cpp b/Kiseki.Patcher/Source/Hooks/StandardOut.cpp new file mode 100644 index 0000000..8b5b754 --- /dev/null +++ b/Kiseki.Patcher/Source/Hooks/StandardOut.cpp @@ -0,0 +1,22 @@ +#ifdef SERVER + +#include "Hooks/StandardOut.hpp" + +StandardOut__print_t StandardOut__print = (StandardOut__print_t)ADDRESS_STANDARDOUT__PRINT; + +void __fastcall StandardOut__print_hook(int _this, void*, int type, std::string* message) +{ + StandardOut__print(_this, type, message); + + if (Server::Handle) + { +#ifndef _DEBUG + // Message pointer is offset 4 bytes when the DLL is compiled as release + message = reinterpret_cast((int)message + 4); +#endif + + Server::Log::Output((LogSeverity)type, message->c_str()); + } +} + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Source/Server.cpp b/Kiseki.Patcher/Source/Server.cpp new file mode 100644 index 0000000..2cd0799 --- /dev/null +++ b/Kiseki.Patcher/Source/Server.cpp @@ -0,0 +1,78 @@ +#ifdef SERVER + +#include "Server.hpp" + +HANDLE Server::Handle; + +std::ofstream Server::OutputLog; + +std::string Server::OutputLogPath; + +void Server::Initialize(const std::wstring jobId) +{ + std::string _jobId = Helpers::ws2s(jobId); + std::string signature = "Kiseki.Patcher v1.0.0"; + +#ifdef _DEBUG + signature += " (compiled as Debug)"; +#endif + + AllocConsole(); + freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); + Server::Handle = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + SetStdHandle(STD_OUTPUT_HANDLE, Server::Handle); + + printf((signature + "\n\n").c_str()); + + // Initialize file logging + std::filesystem::create_directory(std::filesystem::path(Helpers::getModulePath()).parent_path() / "logs"); + + OutputLogPath = (std::filesystem::path(Helpers::getModulePath()).parent_path() / "logs" / (_jobId + "-Output.log")).string(); + + OutputLog.open(OutputLogPath, std::ios::out); + + OutputLog << signature << " - StandardOut" << std::endl << std::endl; + + OutputLog.close(); +} + +void Server::Log::Output(const LogSeverity severity, const std::string message) +{ + std::string type; + std::string time = Helpers::getISOTimestamp(); + + switch (severity) + { + case LogSeverity::Output: + SetConsoleTextAttribute(Server::Handle, FOREGROUND_BLUE | FOREGROUND_INTENSITY); + type = "out"; + break; + case LogSeverity::Information: + SetConsoleTextAttribute(Server::Handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + type = "info"; + break; + case LogSeverity::Warning: + SetConsoleTextAttribute(Server::Handle, FOREGROUND_RED | FOREGROUND_GREEN); + type = "warn"; + break; + case LogSeverity::Error: + type = "err"; + SetConsoleTextAttribute(Server::Handle, FOREGROUND_RED | FOREGROUND_INTENSITY); + break; + } + + printf("%s\n", message.c_str()); + SetConsoleTextAttribute(Server::Handle, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + + OutputLog.open(OutputLogPath, std::ios::out); + OutputLog << "[" << time << "] [" << type << "] " << message << std::endl; + OutputLog.close(); +} + +void Server::Cleanup() +{ + CloseHandle(Server::Handle); + OutputLog.close(); +} + +#endif \ No newline at end of file diff --git a/Kiseki.Patcher/Source/main.cpp b/Kiseki.Patcher/Source/main.cpp index 862d74a..59d6966 100644 --- a/Kiseki.Patcher/Source/main.cpp +++ b/Kiseki.Patcher/Source/main.cpp @@ -3,11 +3,16 @@ #include "Globals.hpp" #include "Patcher.hpp" +#ifdef SERVER +#include "Server.hpp" +#endif + #include "Hooks/Http.hpp" #include "Hooks/Crypt.hpp" #include "Hooks/CRoblox.hpp" #ifdef SERVER +#include "Hooks/DataModel.hpp" #include "Hooks/ServerReplicator.hpp" #endif @@ -23,6 +28,10 @@ ADD_PATCH(CRobloxCommandLineInfo__ParseParam, CRobloxCommandLineInfo__ParseParam #endif #ifdef SERVER +ADD_PATCH(DataModel__getJobId, DataModel__getJobId_hook) + +ADD_PATCH(StandardOut__print, StandardOut__print_hook) + ADD_PATCH(ServerReplicator__sendTop, ServerReplicator__sendTop_hook) ADD_PATCH(ServerReplicator__processTicket, ServerReplicator__processTicket_hook) #endif