Move hooks to their own individual files

This commit is contained in:
pizzaboxer 2022-05-31 10:26:16 +01:00
parent 0653224cf9
commit 24912eeffd
22 changed files with 589 additions and 489 deletions

View File

@ -1,7 +1,6 @@
#pragma once
#include "Config.h"
#include <oaidl.h>
#ifdef ARBITERBUILD

View File

@ -1,6 +1,6 @@
#pragma once
#define MFC2011
#define MFC2010
#define PLAYERBUILD
#define ARBITERBUILD
@ -28,6 +28,7 @@
#define ADDRESS_CRYPT__VERIFYSIGNATUREBASE64 0x0079ECF0
#define ADDRESS_SERVERREPLICATOR__SENDTOP 0x00506910
#define ADDRESS_SERVERREPLICATOR__PROCESSPACKET 0x00507420
#define ADDRESS_SERVERREPLICATOR__PROCESSTICKET 0x0
// MFC specific definitions
#define CLASSLOCATION_CROBLOXAPP 0x00BFF898
@ -43,6 +44,9 @@
#define ADDRESS_CROBLOXCOMMANDLINEINFO__PARSEPARAM 0x00450AC0
#define ADDRESS_CCOMMANDLINEINFO__PARSELAST 0x007A80A0
// Player specific definitions
#define ADDRESS_APPLICATION__PARSEARGUMENTS 0x0
// RakNet packet definitions
#define ID_TIMESTAMP 25
#define ID_SET_GLOBALS 95

View File

@ -0,0 +1,125 @@
#include "pch.h"
#include "Hooks.h"
#include "Patches.h"
#include "Config.h"
#include "Util.h"
#include "LUrlParser.h"
#ifdef ARBITERBUILD
#include "Logger.h"
#endif
static bool hasJobId = false;
static bool setJobId = false;
static std::string jobId;
// Functions //
#ifdef ARBITERBUILD
DataModel__getJobId_t DataModel__getJobId = (DataModel__getJobId_t)ADDRESS_DATAMODEL__GETJOBID;
// Network__RakNetAddressToString_t Network__RakNetAddressToString = (Network__RakNetAddressToString_t)ADDRESS_NETWORK__RAKNETADDRESSTOSTRING;
#ifdef MFC2011
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// CApp__CreateGame_t CApp__CreateGame = (CApp__CreateGame_t)ADDRESS_CAPP__CREATEGAME;
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
ServerReplicator__processPacket_t ServerReplicator__processPacket = (ServerReplicator__processPacket_t)ADDRESS_SERVERREPLICATOR__PROCESSPACKET;
#endif
// Hook Definitions //
#ifdef ARBITERBUILD
int __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2)
{
// the actual function signature is (DataModel* _this)
// this only sets the job id when game.jobId is called by lua
// so the gameserver script must call game.jobId at the beginning for this to take effect
// also, this only applies to the first datamodel that is created
if (!setJobId && hasJobId && !jobId.empty())
{
_this->jobId = jobId;
setJobId = true;
}
return DataModel__getJobId(_this, a2);
}
// std::string __fastcall Network__RakNetAddressToString_hook(const int raknetAddress, char portDelineator)
// {
// return Network__RakNetAddressToString(raknetAddress, portDelineator);
// }
#endif
#if defined(MFC2010) || defined(MFC2011)
/* INT __fastcall CApp__CreateGame_hook(CApp* _this, void*, int* a2, LPCWSTR a3)
{
printf("CApp::CreateGame called\n");
// printf("Location of _this: %p\n", _this);
// printf("Location of a2: %p\n", a2);
// printf("Location of a3: %p\n", a3);
// int result = (int)CApp__CreateGame(_this, a2, a3);
// int result = (int)CApp__CreateGame(_this, a2, L"44340105256");
int result = (int)CApp__CreateGame(_this, a2, L"44340105256");
return result;
} */
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
INT __fastcall ServerReplicator__processPacket_hook(int _this, void*, Packet* packet)
{
switch ((unsigned char)packet->data[0])
{
case ID_TIMESTAMP:
printf("ServerReplicator::processPacket received ID_TIMESTAMP with length %d\n", packet->length);
break;
case ID_REQUEST_CHARACTER:
printf("ServerReplicator::processPacket received ID_REQUEST_CHARACTER with length %d\n", packet->length);
break;
case ID_DATA:
printf("ServerReplicator::processPacket received ID_DATA with length %d\n", packet->length);
break;
case ID_SUBMIT_TICKET:
printf("ServerReplicator::processPacket received ID_SUBMIT_TICKET with length %d\n", packet->length);
break;
default:
printf("ServerReplicator::processPacket received packet %d with length %d\n", packet->data[0], packet->length);
break;
}
/* if ((unsigned char)packet->data[0] == ID_SUBMIT_TICKET)
{
printf("ServerReplicator::processPacket received ID_SUBMIT_TICKET with length %d\n", packet->length);
}
else
{
printf("ServerReplicator::processPacket received packet %d with length %d\n", packet->data[0], packet->length);
} */
/* switch ((unsigned char)packet->data[0])
{
case ID_SUBMIT_TICKET:
// printf("ServerReplicator::processPacket called: ID_SUBMIT_TICKET\n");
return ServerReplicator__processPacket(_this, packet);
default:
if (true)
{
Logger::Print(2, "Player not authenticated s");
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return ServerReplicator__processPacket(_this, packet);
} */
return ServerReplicator__processPacket(_this, packet);
}
#endif

View File

@ -0,0 +1,57 @@
#pragma once
#include "Classes.h"
// Type Definitions //
#ifdef ARBITERBUILD
typedef INT(__thiscall* DataModel__getJobId_t)(DataModel* _this, int a2);
// typedef std::string(__thiscall* Network__RakNetAddressToString_t)(const int raknetAddress, char portDelineator);
#ifdef MFC2011
#endif
#ifdef PLAYER2012
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// typedef INT(__thiscall* CApp__CreateGame_t)(CApp* _this, int *a2, LPCWSTR a3);
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
typedef int(__thiscall* ServerReplicator__processPacket_t)(int _this, Packet* packet);
#endif
// Hook Declarations //
#ifdef ARBITERBUILD
INT __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2);
// std::string __fastcall Network__RakNetAddressToString_hook(const int raknetAddress, char portDelineator);
#ifdef MFC2011
#endif
#ifdef PLAYER2012
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// INT __fastcall CApp__CreateGame_hook(CApp* _this, void*, int *a2, LPCWSTR a3);
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
INT __fastcall ServerReplicator__processPacket_hook(int _this, void*, Packet* packet);
#endif
// Externals //
#ifdef ARBITERBUILD
extern DataModel__getJobId_t DataModel__getJobId;
// extern Network__RakNetAddressToString_t Network__RakNetAddressToString;
#ifdef MFC2011
#endif
#ifdef PLAYER2012
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// extern CApp__CreateGame_t CApp__CreateGame;
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
extern ServerReplicator__processPacket_t ServerReplicator__processPacket;
#endif

View File

@ -75,6 +75,6 @@ std::string Logger::UtcTime()
{
std::stringstream time;
std::time_t now = std::time(NULL);
time << std::put_time(std::localtime(&now), "%F %T");
// time << std::put_time(std::localtime(&now), "%F %T");
return time.str();
}

View File

@ -0,0 +1,112 @@
#include "pch.h"
#include "MFCCommandLine.h"
static bool hasAuthUrlArg = false;
static bool hasAuthTicketArg = false;
static bool hasJoinArg = false;
static std::wstring authenticationUrl;
static std::wstring authenticationTicket;
static std::wstring joinScriptUrl;
CRobloxApp__InitInstance_t CRobloxApp__InitInstance = (CRobloxApp__InitInstance_t)ADDRESS_CROBLOXAPP__INITINSTANCE;
CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam = (CRobloxCommandLineInfo__ParseParam_t)ADDRESS_CROBLOXCOMMANDLINEINFO__PARSEPARAM;
BOOL __fastcall CRobloxApp__InitInstance_hook(CRobloxApp* _this)
{
if (!CRobloxApp__InitInstance(_this))
return FALSE;
CApp* app = reinterpret_cast<CApp*>(CLASSLOCATION_CAPP);
if (hasAuthUrlArg && hasAuthTicketArg && !authenticationUrl.empty() && !authenticationTicket.empty())
{
CApp__RobloxAuthenticate(app, nullptr, authenticationUrl.c_str(), authenticationTicket.c_str());
}
#ifdef PLAYERBUILD
if (hasJoinArg && !joinScriptUrl.empty())
{
try
{
// so... i would've wanted to just use CApp::CreateGame instead but there's a few issues
// in the typelib, CreateGame is exposed as being IApp::CreateGame(string p) - 'p' is "44340105256"
// however internally the function is actually CApp::CreateGame(int something, LPCWSTR p)
// it's obvious that 'something' is a pointer to a class but i have no clue what the class is
// until i figure out wtf its supposed to be we've gotta stick to doing CRobloxApp::CreateDocument for now
CRobloxDoc* document = CRobloxApp__CreateDocument(_this);
CWorkspace__ExecUrlScript(document->workspace, joinScriptUrl.c_str(), VARIANTARG(), VARIANTARG(), VARIANTARG(), VARIANTARG(), nullptr);
}
catch (std::runtime_error)// & exception)
{
// MessageBoxA(nullptr, exception.what(), nullptr, MB_ICONERROR);
return FALSE;
}
}
#endif
return TRUE;
}
void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* _this, void*, const char* pszParam, BOOL bFlag, BOOL bLast)
{
#ifdef PLAYERBUILD
if (hasJoinArg && joinScriptUrl.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
joinScriptUrl.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &joinScriptUrl[0], size);
_this->m_bRunAutomated = TRUE;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
if (hasAuthUrlArg && authenticationUrl.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
authenticationUrl.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &authenticationUrl[0], size);
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
if (hasAuthTicketArg && authenticationTicket.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
authenticationTicket.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &authenticationTicket[0], size);
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
if (bFlag && _stricmp(pszParam, "a") == 0)
{
hasAuthUrlArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
if (bFlag && _stricmp(pszParam, "t") == 0)
{
hasAuthTicketArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#ifdef PLAYERBUILD
if (bFlag && _stricmp(pszParam, "j") == 0)
{
hasJoinArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
CRobloxCommandLineInfo__ParseParam(_this, pszParam, bFlag, bLast);
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "Classes.h"
typedef BOOL(__thiscall* CRobloxApp__InitInstance_t)(CRobloxApp* _this);
typedef void(__thiscall* CRobloxCommandLineInfo__ParseParam_t)(CRobloxCommandLineInfo* _this, const char* pszParam, BOOL bFlag, BOOL bLast);
BOOL __fastcall CRobloxApp__InitInstance_hook(CRobloxApp* _this);
void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* _this, void*, const char* pszParam, BOOL bFlag, BOOL bLast);
extern CRobloxApp__InitInstance_t CRobloxApp__InitInstance;
extern CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam;

View File

@ -0,0 +1,25 @@
#include "pch.h"
#include "PlayerCommandLine.h"
#include "Util.h"
Application__ParseArguments_t Application__ParseArguments = (Application__ParseArguments_t)ADDRESS_APPLICATION__PARSEARGUMENTS;
BOOL __fastcall Application__ParseArguments_hook(int _this, void*, int a2, const char* argv)
{
std::map<std::string, std::string> argslist = Util::parseArgs(argv);
if (argslist.count("-jobId"))
{
// now we have to exclude the -jobId arg from argv
// i'm being really lazy here, so don't do this
// i'm just gonna erase everything that comes after the -jobId arg
// thats gonna cause issues if the joinscript params are after the jobId arg,
// but really it shouldn't matter because the arbiter always starts it up in the correct order
char* pch = (char*)strstr(argv, " -jobId");
if (pch != NULL)
strncpy_s(pch, strlen(pch) + 1, "", 0);
}
return Application__ParseArguments(_this, a2, argv);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Classes.h"
typedef BOOL(__thiscall* Application__ParseArguments_t)(int _this, int a2, const char* argv);
BOOL __fastcall Application__ParseArguments_hook(int _this, void*, int a2, const char* argv);
extern Application__ParseArguments_t Application__ParseArguments;

View File

@ -161,16 +161,23 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Config.h" />
<ClInclude Include="MFCCommandLine.h" />
<ClInclude Include="PlayerCommandLine.h" />
<ClInclude Include="RCCOutput.h" />
<ClInclude Include="ReplicatorSecurity.h" />
<ClInclude Include="TrustCheck.h" />
<ClInclude Include="Logger.h" />
<ClInclude Include="LUrlParser.h" />
<ClInclude Include="Patches.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RobloxMFCClasses.h" />
<ClInclude Include="RobloxMFCHooks.h" />
<ClInclude Include="Classes.h" />
<ClInclude Include="Hooks.h" />
<ClInclude Include="Util.h" />
<ClInclude Include="VerifySignatureBase64.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="MFCCommandLine.cpp" />
<ClCompile Include="Logger.cpp" />
<ClCompile Include="LUrlParser.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
@ -183,8 +190,13 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="RobloxMFCHooks.cpp" />
<ClCompile Include="PlayerCommandLine.cpp" />
<ClCompile Include="RCCOutput.cpp" />
<ClCompile Include="ReplicatorSecurity.cpp" />
<ClCompile Include="Hooks.cpp" />
<ClCompile Include="TrustCheck.cpp" />
<ClCompile Include="Util.cpp" />
<ClCompile Include="VerifySignatureBase64.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -13,15 +13,21 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\Hooks">
<UniqueIdentifier>{e1630ddd-f689-40cc-9f7b-506bcf8aca31}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Hooks">
<UniqueIdentifier>{51130969-bcf1-4ae5-b838-7f4fb658856e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RobloxMFCHooks.h">
<ClInclude Include="Hooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RobloxMFCClasses.h">
<ClInclude Include="Classes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Patches.h">
@ -39,6 +45,24 @@
<ClInclude Include="Util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TrustCheck.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
<ClInclude Include="VerifySignatureBase64.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
<ClInclude Include="MFCCommandLine.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
<ClInclude Include="PlayerCommandLine.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
<ClInclude Include="ReplicatorSecurity.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
<ClInclude Include="RCCOutput.h">
<Filter>Header Files\Hooks</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@ -47,7 +71,7 @@
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RobloxMFCHooks.cpp">
<ClCompile Include="Hooks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Patches.cpp">
@ -62,5 +86,23 @@
<ClCompile Include="Util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TrustCheck.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
<ClCompile Include="VerifySignatureBase64.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
<ClCompile Include="MFCCommandLine.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
<ClCompile Include="PlayerCommandLine.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
<ClCompile Include="ReplicatorSecurity.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
<ClCompile Include="RCCOutput.cpp">
<Filter>Source Files\Hooks</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
#include "pch.h"
#include "RCCOutput.h"
#include "Logger.h"
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 (Logger::handle)
{
#ifdef NDEBUG
// i have absolutely no clue why but the location of the message pointer is offset 4 bytes when the dll compiled as release
int messagePtr = (int)message + 4;
std::string* message = reinterpret_cast<std::string*>(messagePtr);
#endif
Logger::Print(type, *message);
}
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Classes.h"
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;

View File

@ -0,0 +1,46 @@
#include "pch.h"
#include "ReplicatorSecurity.h"
static std::map<ServerReplicator*, RakPeerInterface*> rakPeers;
ServerReplicator__sendTop_t ServerReplicator__sendTop = (ServerReplicator__sendTop_t)ADDRESS_SERVERREPLICATOR__SENDTOP;
ServerReplicator__processTicket_t ServerReplicator__processTicket = (ServerReplicator__processTicket_t)ADDRESS_SERVERREPLICATOR__PROCESSTICKET;
void __fastcall ServerReplicator__sendTop_hook(ServerReplicator* _this, void*, RakPeerInterface* peer)
{
if (_this->isAuthenticated)
{
// printf("ServerReplicator::sendTop called: player is authenticated\n");
ServerReplicator__sendTop(_this, peer);
}
else if (rakPeers.find(_this) == rakPeers.end())
{
// printf("ServerReplicator::sendTop called: player is not authenticated\n");
rakPeers.insert(std::pair<ServerReplicator*, RakPeerInterface*>(_this, peer));
}
}
void __fastcall ServerReplicator__processTicket_hook(ServerReplicator* _this, void*, Packet* packet)
{
ServerReplicator__processTicket(_this, packet);
// THIS IS TEMPORARY
// i literally cant find a way to obtain rakpeerinterface from _this, like it's really damn hard
// so i'm cheating on doing that by getting rakpeerinterface from the first sendtop call,
// throwing that into a lookup table and then using that here
auto pos = rakPeers.find(_this);
if (pos == rakPeers.end())
{
// printf("ServerReplicator::sendTop called: could not find rakpeer for %08X\n", (int)_this);
}
else if (_this->isAuthenticated)
{
// printf("ServerReplicator::sendTop called: Value of peer: %08X - associated with %08X\n", (int)pos->second, (int)_this);
ServerReplicator__sendTop_hook(_this, nullptr, pos->second);
}
else
{
// printf("ServerReplicator::sendTop called: player is not authenticated\n");
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "Classes.h"
typedef void(__thiscall* ServerReplicator__sendTop_t)(ServerReplicator* _this, RakPeerInterface* peer);
typedef void(__thiscall* ServerReplicator__processTicket_t)(ServerReplicator* _this, Packet* packet);
void __fastcall ServerReplicator__sendTop_hook(ServerReplicator* _this, void*, RakPeerInterface* peer);
void __fastcall ServerReplicator__processTicket_hook(ServerReplicator* _this, void*, Packet* packet);
extern ServerReplicator__sendTop_t ServerReplicator__sendTop;
extern ServerReplicator__processTicket_t ServerReplicator__processTicket;

View File

@ -1,396 +0,0 @@
#include "pch.h"
#include "RobloxMFCHooks.h"
#include "Patches.h"
#include "Config.h"
#include "Util.h"
#include "LUrlParser.h"
#ifdef ARBITERBUILD
#include "Logger.h"
#endif
static bool hasAuthUrlArg = false;
static bool hasAuthTicketArg = false;
static bool hasJoinArg = false;
static bool hasJobId = false;
static bool setJobId = false;
static std::wstring authenticationUrl;
static std::wstring authenticationTicket;
static std::wstring joinScriptUrl;
static std::string jobId;
static std::map<ServerReplicator*, RakPeerInterface*> rakPeers;
// Functions //
Http__trustCheck_t Http__trustCheck = (Http__trustCheck_t)ADDRESS_HTTP__TRUSTCHECK;
Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64;
#ifdef ARBITERBUILD
DataModel__getJobId_t DataModel__getJobId = (DataModel__getJobId_t)ADDRESS_DATAMODEL__GETJOBID;
StandardOut__print_t StandardOut__print = (StandardOut__print_t)ADDRESS_STANDARDOUT__PRINT;
// Network__RakNetAddressToString_t Network__RakNetAddressToString = (Network__RakNetAddressToString_t)ADDRESS_NETWORK__RAKNETADDRESSTOSTRING;
#ifdef MFC2011
ServerReplicator__sendTop_t ServerReplicator__sendTop = (ServerReplicator__sendTop_t)ADDRESS_SERVERREPLICATOR__SENDTOP;
ServerReplicator__processTicket_t ServerReplicator__processTicket = (ServerReplicator__processTicket_t)ADDRESS_SERVERREPLICATOR__PROCESSTICKET;
#endif
#ifdef PLAYER2012
Application__ParseArguments_t Application__ParseArguments = (Application__ParseArguments_t)ADDRESS_APPLICATION__PARSEARGUMENTS;
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// CApp__CreateGame_t CApp__CreateGame = (CApp__CreateGame_t)ADDRESS_CAPP__CREATEGAME;
CRobloxApp__InitInstance_t CRobloxApp__InitInstance = (CRobloxApp__InitInstance_t)ADDRESS_CROBLOXAPP__INITINSTANCE;
CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam = (CRobloxCommandLineInfo__ParseParam_t)ADDRESS_CROBLOXCOMMANDLINEINFO__PARSEPARAM;
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
ServerReplicator__processPacket_t ServerReplicator__processPacket = (ServerReplicator__processPacket_t)ADDRESS_SERVERREPLICATOR__PROCESSPACKET;
#endif
// Hook Definitions //
BOOL __fastcall Http__trustCheck_hook(const char* url)
{
if (strlen(url) == 7 && !Util::isASCII(url))
{
// so the client does this really fucking stupid thing where if it opens an ie window,
// it passes a char**, and not a char*
// no idea if thats a detours quirk (i doubt it) or if thats how its just actually handled
// practically no url is ever going to be seven characters long so it doesn't really matter
url = *(char**)url;
}
LUrlParser::ParseURL parsedUrl = LUrlParser::ParseURL::parseURL(url);
if (!parsedUrl.isValid())
return false;
#ifdef ARBITERBUILD
Logger::Log(LogType::Http, url);
#endif
if (std::string("about:blank") == url)
return true;
if (std::find(Util::allowedSchemes.begin(), Util::allowedSchemes.end(), parsedUrl.scheme_) != Util::allowedSchemes.end())
return std::find(Util::allowedHosts.begin(), Util::allowedHosts.end(), parsedUrl.host_) != Util::allowedHosts.end();
if (std::find(Util::allowedEmbeddedSchemes.begin(), Util::allowedEmbeddedSchemes.end(), parsedUrl.scheme_) != Util::allowedEmbeddedSchemes.end())
return true;
return false;
}
void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15)
{
// the actual function signature is (HCRYPTPROV* _this, std::string message, std::string signatureBase64)
// but for some reason it throws a memory access violation when you pass the parameters back into the function, without even modifying them
// each char represents the beginning of new std::string (with the int parameters, that totalls to a length of 24 bytes)
// the signature length is stored in a14 though so we can just use that
if (a14 > 1024)
{
std::ostringstream error;
error << "Signature too large. " << a14 << " > 1024";
throw std::runtime_error(error.str());
}
Crypt__verifySignatureBase64(_this, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
}
#ifdef ARBITERBUILD
int __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2)
{
// the actual function signature is (DataModel* _this)
// this only sets the job id when game.jobId is called by lua
// so the gameserver script must call game.jobId at the beginning for this to take effect
// also, this only applies to the first datamodel that is created
if (!setJobId && hasJobId && !jobId.empty())
{
_this->jobId = jobId;
setJobId = true;
}
return DataModel__getJobId(_this, a2);
}
void __fastcall StandardOut__print_hook(int _this, void*, int type, std::string* message)
{
StandardOut__print(_this, type, message);
if (Logger::handle)
{
#ifdef NDEBUG
// i have absolutely no clue why but the location of the message pointer is offset 4 bytes when the dll compiled as release
int messagePtr = (int)message + 4;
std::string* message = reinterpret_cast<std::string*>(messagePtr);
#endif
Logger::Print(type, *message);
}
}
// std::string __fastcall Network__RakNetAddressToString_hook(const int raknetAddress, char portDelineator)
// {
// return Network__RakNetAddressToString(raknetAddress, portDelineator);
// }
#ifdef MFC2011
void __fastcall ServerReplicator__sendTop_hook(ServerReplicator* _this, void*, RakPeerInterface* peer)
{
if (_this->isAuthenticated)
{
// printf("ServerReplicator::sendTop called: player is authenticated\n");
ServerReplicator__sendTop(_this, peer);
}
else if (rakPeers.find(_this) == rakPeers.end())
{
// printf("ServerReplicator::sendTop called: player is not authenticated\n");
rakPeers.insert(std::pair<ServerReplicator*, RakPeerInterface*>(_this, peer));
}
}
void __fastcall ServerReplicator__processTicket_hook(ServerReplicator* _this, void*, Packet* packet)
{
ServerReplicator__processTicket(_this, packet);
// THIS IS TEMPORARY
// i literally cant find a way to obtain rakpeerinterface from _this, like it's really damn hard
// so i'm cheating on doing that by getting rakpeerinterface from the first sendtop call,
// throwing that into a lookup table and then using that here
auto pos = rakPeers.find(_this);
if (pos == rakPeers.end())
{
// printf("ServerReplicator::sendTop called: could not find rakpeer for %08X\n", (int)_this);
}
else if (_this->isAuthenticated)
{
// printf("ServerReplicator::sendTop called: Value of peer: %08X - associated with %08X\n", (int)pos->second, (int)_this);
ServerReplicator__sendTop_hook(_this, nullptr, pos->second);
}
else
{
// printf("ServerReplicator::sendTop called: player is not authenticated\n");
}
}
#endif
#ifdef PLAYER2012
BOOL __fastcall Application__ParseArguments_hook(int _this, void*, int a2, const char* argv)
{
std::map<std::string, std::string> argslist = Util::parseArgs(argv);
if (argslist.count("-jobId"))
{
hasJobId = true;
jobId = argslist["-jobId"];
Logger::Initialize(jobId);
// now we have to exclude the -jobId arg from argv
// i'm being really lazy here, so don't do this
// i'm just gonna erase everything that comes after the -jobId arg
// thats gonna cause issues if the joinscript params are after the jobId arg,
// but really it shouldn't matter because the arbiter always starts it up in the correct order
char* pch = (char*)strstr(argv, " -jobId");
if (pch != NULL)
strncpy_s(pch, strlen(pch) + 1, "", 0);
}
return Application__ParseArguments(_this, a2, argv);
}
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
/* INT __fastcall CApp__CreateGame_hook(CApp* _this, void*, int* a2, LPCWSTR a3)
{
printf("CApp::CreateGame called\n");
// printf("Location of _this: %p\n", _this);
// printf("Location of a2: %p\n", a2);
// printf("Location of a3: %p\n", a3);
// int result = (int)CApp__CreateGame(_this, a2, a3);
// int result = (int)CApp__CreateGame(_this, a2, L"44340105256");
int result = (int)CApp__CreateGame(_this, a2, L"44340105256");
return result;
} */
BOOL __fastcall CRobloxApp__InitInstance_hook(CRobloxApp* _this)
{
if (!CRobloxApp__InitInstance(_this))
return FALSE;
CApp* app = reinterpret_cast<CApp*>(CLASSLOCATION_CAPP);
if (hasAuthUrlArg && hasAuthTicketArg && !authenticationUrl.empty() && !authenticationTicket.empty())
{
CApp__RobloxAuthenticate(app, nullptr, authenticationUrl.c_str(), authenticationTicket.c_str());
}
#ifdef PLAYERBUILD
if (hasJoinArg && !joinScriptUrl.empty())
{
try
{
// so... i would've wanted to just use CApp::CreateGame instead but there's a few issues
// in the typelib, CreateGame is exposed as being IApp::CreateGame(string p) - 'p' is "44340105256"
// however internally the function is actually CApp::CreateGame(int something, LPCWSTR p)
// it's obvious that 'something' is a pointer to a class but i have no clue what the class is
// until i figure out wtf its supposed to be we've gotta stick to doing CRobloxApp::CreateDocument for now
CRobloxDoc* document = CRobloxApp__CreateDocument(_this);
CWorkspace__ExecUrlScript(document->workspace, joinScriptUrl.c_str(), VARIANTARG(), VARIANTARG(), VARIANTARG(), VARIANTARG(), nullptr);
}
catch (std::runtime_error)// & exception)
{
// MessageBoxA(nullptr, exception.what(), nullptr, MB_ICONERROR);
return FALSE;
}
}
#endif
return TRUE;
}
void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* _this, void*, const char* pszParam, BOOL bFlag, BOOL bLast)
{
#ifdef PLAYERBUILD
if (hasJoinArg && joinScriptUrl.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
joinScriptUrl.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &joinScriptUrl[0], size);
_this->m_bRunAutomated = TRUE;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
if (hasAuthUrlArg && authenticationUrl.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
authenticationUrl.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &authenticationUrl[0], size);
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
if (hasAuthTicketArg && authenticationTicket.empty())
{
int size = MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), nullptr, 0);
authenticationTicket.resize(size);
MultiByteToWideChar(CP_ACP, 0, pszParam, strlen(pszParam), &authenticationTicket[0], size);
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#ifdef ARBITERBUILD
if (hasJobId && jobId.empty())
{
// command line args are parsed AFTER CRobloxApp::InitInstance is run, so the logger will too be initialized after
jobId = std::string(pszParam);
Logger::Initialize(jobId);
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
if (bFlag && _stricmp(pszParam, "a") == 0)
{
hasAuthUrlArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
if (bFlag && _stricmp(pszParam, "t") == 0)
{
hasAuthTicketArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#ifdef PLAYERBUILD
if (bFlag && _stricmp(pszParam, "j") == 0)
{
hasJoinArg = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
#ifdef ARBITERBUILD
if (bFlag && _stricmp(pszParam, "jobId") == 0)
{
hasJobId = true;
CCommandLineInfo__ParseLast(_this, bLast);
return;
}
#endif
CRobloxCommandLineInfo__ParseParam(_this, pszParam, bFlag, bLast);
}
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
INT __fastcall ServerReplicator__processPacket_hook(int _this, void*, Packet* packet)
{
switch ((unsigned char)packet->data[0])
{
case ID_TIMESTAMP:
printf("ServerReplicator::processPacket received ID_TIMESTAMP with length %d\n", packet->length);
break;
case ID_REQUEST_CHARACTER:
printf("ServerReplicator::processPacket received ID_REQUEST_CHARACTER with length %d\n", packet->length);
break;
case ID_DATA:
printf("ServerReplicator::processPacket received ID_DATA with length %d\n", packet->length);
break;
case ID_SUBMIT_TICKET:
printf("ServerReplicator::processPacket received ID_SUBMIT_TICKET with length %d\n", packet->length);
break;
default:
printf("ServerReplicator::processPacket received packet %d with length %d\n", packet->data[0], packet->length);
break;
}
/* if ((unsigned char)packet->data[0] == ID_SUBMIT_TICKET)
{
printf("ServerReplicator::processPacket received ID_SUBMIT_TICKET with length %d\n", packet->length);
}
else
{
printf("ServerReplicator::processPacket received packet %d with length %d\n", packet->data[0], packet->length);
} */
/* switch ((unsigned char)packet->data[0])
{
case ID_SUBMIT_TICKET:
// printf("ServerReplicator::processPacket called: ID_SUBMIT_TICKET\n");
return ServerReplicator__processPacket(_this, packet);
default:
if (true)
{
Logger::Print(2, "Player not authenticated s");
return RR_STOP_PROCESSING_AND_DEALLOCATE;
}
return ServerReplicator__processPacket(_this, packet);
} */
return ServerReplicator__processPacket(_this, packet);
}
#endif

View File

@ -1,78 +0,0 @@
#pragma once
#include "RobloxMFCClasses.h"
// Type Definitions //
typedef BOOL(__thiscall* Http__trustCheck_t)(const char* url);
typedef void(__thiscall* Crypt__verifySignatureBase64_t)(HCRYPTPROV* _this, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15);
#ifdef ARBITERBUILD
typedef INT(__thiscall* DataModel__getJobId_t)(DataModel* _this, int a2);
typedef void(__thiscall* StandardOut__print_t)(int _this, int type, std::string* message);
// typedef std::string(__thiscall* Network__RakNetAddressToString_t)(const int raknetAddress, char portDelineator);
#ifdef MFC2011
typedef void(__thiscall* ServerReplicator__sendTop_t)(ServerReplicator* _this, RakPeerInterface* peer);
typedef void(__thiscall* ServerReplicator__processTicket_t)(ServerReplicator* _this, Packet* packet);
#endif
#ifdef PLAYER2012
typedef BOOL(__thiscall* Application__ParseArguments_t)(int _this, int a2, const char* argv);
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// typedef INT(__thiscall* CApp__CreateGame_t)(CApp* _this, int *a2, LPCWSTR a3);
typedef BOOL(__thiscall* CRobloxApp__InitInstance_t)(CRobloxApp* _this);
typedef void(__thiscall* CRobloxCommandLineInfo__ParseParam_t)(CRobloxCommandLineInfo* _this, const char* pszParam, BOOL bFlag, BOOL bLast);
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
typedef int(__thiscall* ServerReplicator__processPacket_t)(int _this, Packet* packet);
#endif
// Hook Declarations //
BOOL __fastcall Http__trustCheck_hook(const char* url);
void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15);
#ifdef ARBITERBUILD
INT __fastcall DataModel__getJobId_hook(DataModel* _this, void*, int a2);
void __fastcall StandardOut__print_hook(int _this, void*, int type, std::string* message);
// std::string __fastcall Network__RakNetAddressToString_hook(const int raknetAddress, char portDelineator);
#ifdef MFC2011
void __fastcall ServerReplicator__sendTop_hook(ServerReplicator* _this, void*, RakPeerInterface* peer);
void __fastcall ServerReplicator__processTicket_hook(ServerReplicator* _this, void*, Packet* packet);
#endif
#ifdef PLAYER2012
BOOL __fastcall Application__ParseArguments_hook(int _this, void*, int a2, const char* argv);
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// INT __fastcall CApp__CreateGame_hook(CApp* _this, void*, int *a2, LPCWSTR a3);
BOOL __fastcall CRobloxApp__InitInstance_hook(CRobloxApp* _this);
void __fastcall CRobloxCommandLineInfo__ParseParam_hook(CRobloxCommandLineInfo* _this, void*, const char* pszParam, BOOL bFlag, BOOL bLast);
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
INT __fastcall ServerReplicator__processPacket_hook(int _this, void*, Packet* packet);
#endif
// Externals //
extern Http__trustCheck_t Http__trustCheck;
extern Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64;
#ifdef ARBITERBUILD
extern DataModel__getJobId_t DataModel__getJobId;
extern StandardOut__print_t StandardOut__print;
// extern Network__RakNetAddressToString_t Network__RakNetAddressToString;
#ifdef MFC2011
extern ServerReplicator__sendTop_t ServerReplicator__sendTop;
extern ServerReplicator__processTicket_t ServerReplicator__processTicket;
#endif
#ifdef PLAYER2012
extern Application__ParseArguments_t Application__ParseArguments;
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// extern CApp__CreateGame_t CApp__CreateGame;
extern CRobloxApp__InitInstance_t CRobloxApp__InitInstance;
extern CRobloxCommandLineInfo__ParseParam_t CRobloxCommandLineInfo__ParseParam;
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
extern ServerReplicator__processPacket_t ServerReplicator__processPacket;
#endif

View File

@ -0,0 +1,35 @@
#include "pch.h"
#include "TrustCheck.h"
#include "Util.h"
#include "LUrlParser.h"
Http__trustCheck_t Http__trustCheck = (Http__trustCheck_t)ADDRESS_HTTP__TRUSTCHECK;
BOOL __fastcall Http__trustCheck_hook(const char* url)
{
if (strlen(url) == 7 && !Util::isASCII(url))
{
// so the client does this really fucking stupid thing where if it opens an ie window,
// it passes a char**, and not a char*
// no idea if thats a detours quirk (i doubt it) or if thats how its just actually handled
// practically no url is ever going to be seven characters long so it doesn't really matter
url = *(char**)url;
}
LUrlParser::ParseURL parsedUrl = LUrlParser::ParseURL::parseURL(url);
if (!parsedUrl.isValid())
return false;
if (std::string("about:blank") == url)
return true;
if (std::find(Util::allowedSchemes.begin(), Util::allowedSchemes.end(), parsedUrl.scheme_) != Util::allowedSchemes.end())
return std::find(Util::allowedHosts.begin(), Util::allowedHosts.end(), parsedUrl.host_) != Util::allowedHosts.end();
if (std::find(Util::allowedEmbeddedSchemes.begin(), Util::allowedEmbeddedSchemes.end(), parsedUrl.scheme_) != Util::allowedEmbeddedSchemes.end())
return true;
return false;
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Classes.h"
typedef BOOL(__thiscall* Http__trustCheck_t)(const char* url);
BOOL __fastcall Http__trustCheck_hook(const char* url);
extern Http__trustCheck_t Http__trustCheck;

View File

@ -0,0 +1,21 @@
#include "pch.h"
#include "VerifySignatureBase64.h"
Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64 = (Crypt__verifySignatureBase64_t)ADDRESS_CRYPT__VERIFYSIGNATUREBASE64;
void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15)
{
// the actual function signature is (HCRYPTPROV* _this, std::string message, std::string signatureBase64)
// but for some reason it throws a memory access violation when you pass the parameters back into the function, without even modifying them
// each char represents the beginning of new std::string (with the int parameters, that totalls to a length of 24 bytes)
// the signature length is stored in a14 though so we can just use that
if (a14 > 1024)
{
std::ostringstream error;
error << "Signature too large. " << a14 << " > 1024";
throw std::runtime_error(error.str());
}
Crypt__verifySignatureBase64(_this, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Classes.h"
typedef void(__thiscall* Crypt__verifySignatureBase64_t)(HCRYPTPROV* _this, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15);
void __fastcall Crypt__verifySignatureBase64_hook(HCRYPTPROV* _this, void*, char a2, int a3, int a4, int a5, int a6, int a7, int a8, char a9, int a10, int a11, int a12, int a13, int a14, int a15);
extern Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64;

View File

@ -1,39 +1,62 @@
#include "pch.h"
#include "Config.h"
#include "Patches.h"
#include "RobloxMFCHooks.h"
#include "Logger.h" // remove when testing is done
// #include "RobloxMFCHooks.h"
#include "TrustCheck.h"
#include "VerifySignatureBase64.h"
#ifdef ARBITERBUILD
#include "RCCOutput.h"
#ifdef MFC2011
#include "ReplicatorSecurity.h"
#endif
#ifdef PLAYER2012
#include "PlayerCommandLine.h"
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
#include "MFCCommandLine.h"
#endif
START_PATCH_LIST()
ADD_PATCH(Http__trustCheck, Http__trustCheck_hook)
ADD_PATCH(Crypt__verifySignatureBase64, Crypt__verifySignatureBase64_hook)
#ifdef ARBITERBUILD
ADD_PATCH(DataModel__getJobId, DataModel__getJobId_hook)
// ADD_PATCH(DataModel__getJobId, DataModel__getJobId_hook)
ADD_PATCH(StandardOut__print, StandardOut__print_hook)
// ADD_PATCH(Network__RakNetAddressToString, Network__RakNetAddressToString_hook)
#ifdef MFC2011
ADD_PATCH(ServerReplicator__sendTop, ServerReplicator__sendTop_hook)
ADD_PATCH(ServerReplicator__processTicket, ServerReplicator__processTicket_hook)
#endif
#ifdef PLAYER2012
ADD_PATCH(Application__ParseArguments, Application__ParseArguments_hook)
#endif
#endif
#if defined(MFC2010) || defined(MFC2011)
// ADD_PATCH(CApp__CreateGame, CApp__CreateGame_hook)
ADD_PATCH(CRobloxApp__InitInstance, CRobloxApp__InitInstance_hook)
ADD_PATCH(CRobloxCommandLineInfo__ParseParam, CRobloxCommandLineInfo__ParseParam_hook)
#endif
#ifdef DEBUG_SERVERREPLICATOR__PROCESSPACKET
ADD_PATCH(ServerReplicator__processPacket, ServerReplicator__processPacket_hook)
// ADD_PATCH(ServerReplicator__processPacket, ServerReplicator__processPacket_hook)
#endif
END_PATCH_LIST()
// DLLs for release will be loaded with VMProtect, so this isn't necessary
// Arbiter will still use Stud_PE for ease in swapping DLLs however
#ifdef ARBITERBUILD
// #ifdef ARBITERBUILD
void __declspec(dllexport) import() {}
#endif
// #endif
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{