#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include //#include #include #include #include //#include #include "include/MinHook.h" #ifdef __clang__ #pragma comment(lib, "lib/libMinHook-MD.x64.Clang.lib") #else #pragma comment(lib, "lib/libMinHook-MD.x64.lib") #endif //#include "F:/Programmieren/C++/myhelpers/xorstr.h" #define JM_XORSTR_DISABLE_AVX_INTRINSICS 1 #include "F:/Programmieren/C++/xorstr-master/include/xorstr.hpp" //#include "F:/Programmieren/C++/myhelpers/SuspendResume.hpp" #include "include/patternscan.hpp" // #include "F:/Programmieren/C++/myhelpers/DebugHelper.hpp" #include "SparkClasses.h" // Link with ws2_32.lib #pragma comment(lib, "Ws2_32.lib") #include "F:/Programmieren/C++/json.hpp" using json = nlohmann::json; #include "include/easywsclient.hpp" #include "include/easywsclient.cpp" using easywsclient::WebSocket; WebSocket::pointer ws = nullptr; //#include //#include //typedef BOOL(__stdcall* tWinHttpGetIEProxyConfigForCurrentUser)(IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*); //tWinHttpGetIEProxyConfigForCurrentUser oWinHttpGetIEProxyConfigForCurrentUser; typedef void*(__stdcall* tCurl_Easy_Init)(); tCurl_Easy_Init oCurl_Easy_Init; typedef void(__stdcall* tCurl_Easy_Cleanup)(void* handle); tCurl_Easy_Cleanup oCurl_Easy_Cleanup; typedef DWORD(__stdcall* tCurl_Easy_SetOpt)(void*, long, void*); tCurl_Easy_SetOpt oCurl_Easy_SetOpt; typedef DWORD(__stdcall* tCurl_Easy_Perform)(void*); tCurl_Easy_Perform oCurl_Easy_Perform; typedef DWORD(__stdcall* tCurl_Multi_Perform)(void* multi_handle, int* running_handles); tCurl_Multi_Perform oCurl_Multi_Perform; typedef void*(__stdcall* tCurl_Multi_Init)(); tCurl_Multi_Init oCurl_Multi_Init = NULL; typedef void* (__fastcall* tFSparkManagerCtor)(void*); tFSparkManagerCtor oFSparkManagerCtor = NULL; //const std::wstring proxyURLW = L"https=127.0.0.1:9999"; std::string proxyURLA = "https://127.0.0.1:"; std::string proxyPort = "9999"; auto curl_easy_init_pattern = xorstr("48 83 EC 28 83 3D ?? ?? ?? ?? 00 75 ?? 48 8B 05"); auto curl_easy_cleanup_pattern = xorstr("40 53 48 83 EC 20 48 8B D9 48 85 C9 0F 84 ?? ?? ?? ?? 33 D2"); auto curl_easy_setopt_pattern = xorstr("89 54 24 10 4c 89 44 24 18 4c 89 4c 24 20 48 83 ec 28 48 85 c9 75"); auto curl_easy_perform_pattern = xorstr("33 d2 e9 09 01 00 00 cc cc cc cc cc cc cc"); auto curl_easy_getinfo_pattern = xorstr("89 54 24 ?? 4C 89 44 24 ?? 4C 89 4C 24 ?? 48 83 EC 28 4C 8D 44 24 ?? 4D 8B 00"); auto curl_multi_perform_pattern = xorstr("48 89 5c 24 18 56 57 41 57 48 83 ec 20 4c 8b fa 48 8b f9"); auto curl_multi_init_pattern = xorstr("BA 61 00 00 00 B9 8F 03 00 00"); auto sparkManagerCtorPattern = xorstr("40 53 48 83 EC 20 48 8B D9 E8 ?? ?? ?? ?? 4C 8B C8 48 8D 15 ?? ?? ?? ?? 0F 57 D2 48 8B CB E8 ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? 48 89 03 33 C0"); auto generateMicropatchArrayPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 54 41 55 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 8B 72 08"); auto generateMicropatchArrayBackupPattern = xorstr("48 8D 54 24 ?? E8 ?? ?? ?? ?? 48 8D 55 60"); auto getNewsItemsPattern = xorstr("48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 55 41 ?? 41 ?? 41 ?? 41 ?? 48 8D ?? ?? ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? ?? 8D"); auto FGbxSparkModuleStartupModulePattern = xorstr("40 53 48 83 EC 50 48 8B D9 48 89 0D"); auto onMicropatchesReceivedPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 55 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 63 51 08"); auto areMicropatchesDifferentPattern = xorstr("48 89 5C 24 ?? 55 56 57 48 83 EC 20 C7 02"); // + 0x33 auto parseJSONString = xorstr("40 55 53 56 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 45 10 48 8B D9"); // result at +0x88 (E8 ** ** ** **) auto getNewsServicePattern = xorstr("45 8B C7 48 8D 15 ?? ?? ?? ?? 48 8D 8D ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C 8D 85"); auto mallocPattern = xorstr("48 89 5C 24 ?? 57 48 83 EC 20 48 8B F9 8B DA 48 8B 0D ?? ?? ?? ?? 48 85 C9 75 0C E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01 44 8B C3 48 8B D7 48 8B 5C 24 ?? 48 83 C4 20 5F 48 FF 60 10"); auto reallocPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F1 41 8B D8 48 8B 0D ?? ?? ?? ?? 48 8B FA 48 85 C9 75 0C E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01 44 8B CB 4C 8B C7 48 8B D6 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 20 5F 48 FF 60 18"); auto hardcodedHotfixCallPattern = xorstr("40 55 53 56 57 41 54 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 85 ?? ?? ?? ?? 48 8B BD"); CRITICAL_SECTION critsec; static bool isInInternalMode = false; // //std::string startReceiveHotfixes_Pattern = xorstr("48 63 81 c4 00 00 00 83 f8 06 77 49 4c 8d 05"); //// //std::string beforeInit_Pattern = xorstr("40 53 48 83 ec 40 80 b9 c0 00 00 00 00 48 8b d9 0f 85 41 01 00 00 83 b9 cc 00 00 00 00 0f 84 34 01 00 00 f3 0f 58 89 bc 00 00 00 f3 0f 11 89 bc 00 00 00 8b 89 d0 00 00 00 85 c9 0f 84 fe 00 00 00"); //// //std::string someInterestingFunc_Pattern = xorstr("40 53 48 83 ec 30 48 8b d9 48 85 d2 74 21 45 8b c8 c7 44 24 28 ff ff ff ff"); // //std::ofstream myfile; /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ #define CURLOPTTYPE_LONG 0 #define CURLOPTTYPE_OBJECTPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 #define CURLOPTTYPE_BLOB 40000 #define CURLOPT(na,t,nu) na = t + nu /* 'char *' argument to a string with a trailing zero */ #define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT /* 'struct curl_slist *' argument */ #define CURLOPTTYPE_SLISTPOINT CURLOPTTYPE_OBJECTPOINT /* 'void *' argument passed untouched to callback */ #define CURLOPTTYPE_CBPOINT CURLOPTTYPE_OBJECTPOINT /* 'long' argument with a set of values/bitmask */ #define CURLOPTTYPE_VALUES CURLOPTTYPE_LONG typedef enum { /* The full URL to get/put */ CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2), /* Name of proxy to use. */ CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4), /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. */ CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10), /* Function that will be called to store the output (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11), /* Function that will be called to read the input (instead of fread). The * parameters will use fread() syntax, make sure to follow them. */ CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12), /* POST static input fields. */ CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65), /* Set if we should verify the Common name from the peer certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches the * provided hostname. */ CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81), /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97), /* Enable SSL/TLS for FTP, pick one of: CURLUSESSL_TRY - try using SSL, proceed anyway otherwise CURLUSESSL_CONTROL - SSL for the control connection or fail CURLUSESSL_ALL - SSL for all communication or fail */ CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119), /* send linked-list of name:port:address sets */ CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203), /* Set if we should verify the certificate status. */ CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), /* The CApath or CAfile used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246), /* Set if we should verify the proxy in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248), /* Set if we should verify the Common name from the proxy certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches * the provided hostname. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249), /* The public key in DER form used to validate the proxy public key this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263), /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306), /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307), /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308), /* The CA certificates as "blob" used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309), /* The CA certificates as "blob" used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310), }; #define CURL_ERROR_SIZE 256 typedef enum { CURLE_OK = 0 }; typedef enum { CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use CONNECT HTTP/1.1 */ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the host name rather than the IP address. added in 7.18.0 */ } curl_proxytype; /* this enum was added in 7.10 */ /* parameter for the CURLOPT_USE_SSL option */ typedef enum { CURLUSESSL_NONE, /* do not attempt to use SSL */ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ CURLUSESSL_ALL, /* SSL for all communication or fail */ CURLUSESSL_LAST /* not an option, never use */ } curl_usessl; #define CURLINFO_STRING 0x100000 #define CURLINFO_LONG 0x200000 #define CURLINFO_DOUBLE 0x300000 #define CURLINFO_SLIST 0x400000 #define CURLINFO_PTR 0x400000 /* same as SLIST */ #define CURLINFO_SOCKET 0x500000 #define CURLINFO_OFF_T 0x600000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 typedef enum { CURLINFO_NONE, /* first, never use this */ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, CURLINFO_FILETIME = CURLINFO_LONG + 14, CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, CURLINFO_PRIVATE = CURLINFO_STRING + 21, CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, CURLINFO_CERTINFO = CURLINFO_PTR + 34, CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, CURLINFO_PROTOCOL = CURLINFO_LONG + 48, CURLINFO_SCHEME = CURLINFO_STRING + 49, CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, CURLINFO_RETRY_AFTER = CURLINFO_OFF_T + 57, CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58, CURLINFO_PROXY_ERROR = CURLINFO_LONG + 59, CURLINFO_REFERER = CURLINFO_STRING + 60, CURLINFO_LASTONE = 60 } CURLINFO; typedef DWORD(__stdcall* tCurl_Easy_GetInfo)(void*, CURLINFO info, void*); tCurl_Easy_GetInfo oCurl_Easy_GetInfo; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as CURLINFO_HTTP_CODE */ #define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE typedef enum { CURLCLOSEPOLICY_NONE, /* first, never use this */ CURLCLOSEPOLICY_OLDEST, CURLCLOSEPOLICY_LEAST_RECENTLY_USED, CURLCLOSEPOLICY_LEAST_TRAFFIC, CURLCLOSEPOLICY_SLOWEST, CURLCLOSEPOLICY_CALLBACK, CURLCLOSEPOLICY_LAST /* last, never use this */ } curl_closepolicy; char errbuf[CURL_ERROR_SIZE]; typedef void* (__fastcall* tMalloc)(uint32_t, uint32_t); tMalloc oMalloc; typedef void* (__fastcall* tRealloc)(void*, size_t, uint32_t); tRealloc oRealloc; typedef void (__fastcall* tGetNewsItems)(void*); tGetNewsItems oGetNewsItems = NULL; using EMicropatchOperation = uintptr_t; typedef bool (__fastcall* tHardcodedHotfixes)(EMicropatchOperation, const wchar_t* patchString, const wchar_t*, bool, void* pFunc, void* someObject); tHardcodedHotfixes oHardcodedHotfixes = NULL; template struct TArray { friend struct FString; public: inline TArray() { Data = nullptr; Count = Max = 0; }; inline int Num() const { return Count; }; inline T& operator[](int i) { return Data[i]; }; inline const T& operator[](int i) const { return Data[i]; }; inline bool IsValidIndex(int i) const { return i < Num(); } FORCEINLINE int32_t DefaultCalculateSlackGrow(int32_t NumElements, int32_t NumAllocatedElements, int32_t BytesPerElement, bool bAllowQuantize, uint32_t Alignment = 0) { int32_t Retval = 0; int32_t Grow = 4; // this is the amount for the first alloc if (NumAllocatedElements || size_t(NumElements) > Grow) { // Allocate slack for the array proportional to its size. Grow = size_t(NumElements) + 3 * size_t(NumElements) / 8 + 16; } if (bAllowQuantize) { //Retval = FMemory::QuantizeSize(Grow * BytesPerElement, Alignment) / BytesPerElement; Retval = Retval * BytesPerElement; } else { Retval = Grow; } // NumElements and MaxElements are stored in 32 bit signed integers so we must be careful not to overflow here. if (NumElements > Retval) { Retval = ((int32_t)0x7fffffff); } return Retval; } void ResizeGrow(int32_t OldNum, int32_t numElems, size_t sizePElem) { if (Data || Count) { Data = (T*)Realloc(Data, numElems * sizePElem, 0); } } void* Realloc(void* Original, size_t count, uint32_t alignment) { if (oRealloc) { return oRealloc(Original, count, alignment); } return NULL; } void* Malloc(uint32_t count, uint32_t alignment) { if (oMalloc) { return oMalloc(count, alignment); } return NULL; } void ResizeGrow(int32_t OldNum) { Max = DefaultCalculateSlackGrow(Count + 1, Max, sizeof(T), 0); ResizeGrow(Count, Max, sizeof(T)); } /** * Adds a new item to the end of the array, possibly reallocating the whole array to fit. * * @param Item The item to add * @return Index to the new item * @see AddDefaulted, AddUnique, AddZeroed, Append, Insert */ FORCEINLINE int32_t Add(const T& Item) { if (Count + 1 > Max) { Max = DefaultCalculateSlackGrow(Count + 1, Max, sizeof(T), 0); ResizeGrow(Count, Max, sizeof(T)); } if (Data == NULL) { Data = (T*)Malloc(Max, sizeof(T)); //memset(Data, 0, Max * sizeof(T)); } Data[Count] = Item; Count++; return Count - 1; } /** * Inserts a given element into the array at given location. * * @param Item The element to insert. * @param Index Tells where to insert the new elements. * @returns Location at which the insert was done. * @see Add, Remove */ FORCEINLINE int32_t Insert(const T& Item, int32_t Index) { if (Index >= 0 && IsValidIndex(Index)) { const int32_t OldNum = Count; if ((Count += 1) > Max) { ResizeGrow(OldNum); } for (int i = Count; i >= Index; i--) { Data[i + 1] = Data[i]; } Data[Index] = Item; } return Index; } public: T* Data; int32_t Count; int32_t Max; }; struct FString : TArray { inline FString() { }; FString(const wchar_t* other) { Max = Count = *other ? static_cast(std::wcslen(other) + 1) : 0; if (Count) { this->Data = const_cast(other); } }; FString(const char* other) { if (other && *other) { size_t len = strlen(other) + 1; int32_t destLen = int32_t(MultiByteToWideChar(CP_ACP, 0, other, -1, NULL, 0)) + 1; const int32_t oldNum = Count; if ((Count += destLen) > Max) { this->ResizeGrow(oldNum); } mbstowcs_s(NULL, this->Data, len, other, len - 1); } //if (Data != other) { // int nchars = MultiByteToWideChar(CP_ACP, 0, other, -1, NULL, 0); // wchar_t* wc = new wchar_t[nchars]; // MultiByteToWideChar(CP_ACP, 0, other, -1, (LPWSTR)wc, nchars); // Max = Count = *wc ? static_cast(std::wcslen(wc) + 1) : 0; //} ///*int nchars = MultiByteToWideChar(CP_ACP, 0, other, -1, NULL, 0); //wchar_t* wc = new wchar_t[nchars]; //MultiByteToWideChar(CP_ACP, 0, other, -1, (LPWSTR)wc, nchars); //Max = Count = *wc ? static_cast(std::wcslen(wc) + 1) : 0;*/ /*if (Count) { Data = const_cast(wc); }*/ }; inline bool IsValid() const { return this->Data != nullptr; } inline const wchar_t* c_str() const { return this->Data; } std::string ToString() const { if (!this->Data) return "NULL"; auto length = std::wcslen(this->Data); std::string str(length, '\0'); std::use_facet>(std::locale()).narrow(this->Data, this->Data + length, '?', &str[0]); return str; } }; struct FArticleTag { FString Tag; FString TagName; FString TagValue; }; struct FNewsItem { FString NewsText; char Unknown1[0x8]; char Unknown2[0x8]; char Unknown3[0x8]; char Unknown4[0x8]; char Unknown5[0x8]; char Unknown6[0x8]; FString IconName; FString TargetLink; char Unknown7[0x8]; char Unknown8[0x8]; char Unknown9[0x8]; char Unknown10[0x8]; char Unknown11[0x8]; char Unknown12[0x8]; TArray ArticleTags; }; class FSparkNewsService { public: char pad_0000[64]; //0x0000 class TArray NewsItems; //0x0040 char pad_0050[64]; //0x0050 }; //Size: 0x0090 static_assert(sizeof(FSparkNewsService) == 0x90); class FSparkModule { public: wchar_t* ConfigFile; //0x0008 char pad_0010[8]; //0x0010 class FSparkManager* SparkManager; //0x0018 char pad_0020[240]; //0x0020 class FSparkNewsService* SparkNewsService; //0x0110 char pad_0118[1192]; //0x0118 virtual void Function0(); virtual void Function1(); virtual void Function2(); virtual void Function3(); virtual void Function4(); virtual void Function5(); virtual void Function6(); virtual void Function7(); }; //Size: 0x05C0 static_assert(sizeof(FSparkModule) == 0x5C0); enum HotfixType : uint32_t { SparkPatchEntry = 1, SparkLevelPatchEntry = 2, SparkStreamedPackageEntry = 3, SparkSaveGameEntry = 4, SparkPostLoadedEntry = 5, SparkCharacterLoadedEntry = 6, SparkEarlyLevelPatchEntry = 7 }; class FMicropatch { public: HotfixType PatchType; //0x0000 uint32_t N00001B5E; //0x0004 FString Patchname; //0x0008 FString Patchdata; //0x0018 }; //Size: 0x0028 static_assert(sizeof(FMicropatch) == 0x28); class UserWriteData { public: char pad_0000[16]; //0x0000 TArray Content; //0x0010 //char* Content; //uint32_t WriteSize; //0x0018 //uint32_t MaxSize; //0x001C uint32_t DataSize; //0x0020 char pad_0024[4]; //0x0024 }; //Size: 0x0028 static_assert(sizeof(UserWriteData) == 0x28); class Curl_Write_Data { public: char pad_0000[88]; //0x0000 class FString RequestURL; //0x0058 char pad_0068[32]; //0x0068 class UserWriteData* Body; //0x0088 char pad_0090[32]; //0x0090 class TArray* Headers; //0x00B0 }; //Size: 0x00B8 static_assert(sizeof(Curl_Write_Data) == 0xB8); typedef void(__fastcall* tGenerateMicropatchArray)(void* someTMap, TArray* outMicropatches); tGenerateMicropatchArray oGenerateMicropatchArray = NULL; typedef void* (__fastcall* tParseJSONString)(void** jsonReader, const FString* text); tParseJSONString oParseJSONString = NULL; typedef bool(__fastcall* tAreMicropatchesDifferent)(TArray* micropatches, void* severity); tAreMicropatchesDifferent oAreMicropatchesDifferent = NULL; FSparkModule** pSparkModule = NULL; //std::vector GetObjectNamesWith(const std::string nameToFind) { // std::vector entries; // for (int i = 0; i < SDK::UObject::GetGlobalObjects().Num(); i++) { // SDK::UObject* current = SDK::UObject::GetGlobalObjects().GetByIndex(i).Object; // if (current && strstr(current->GetFullName().c_str(), nameToFind.c_str()) != NULL) { // entries.push_back(const_cast(current)); // } // } // return entries; //} //class HotfixInitStuff //{ //public: // char pad_0000[196]; //0x0000 // uint32_t CurrentInitStep; //0x00C4 // char pad_00C8[952]; //0x00C8 //}; //Size: 0x0480 // // //HotfixInitStuff* someObject; //typedef void(*tstartReceiveHotfixes)(HotfixInitStuff* obj); //tstartReceiveHotfixes ostartReceiveHotfixes; // //void hkstartReceiveHotfixes(HotfixInitStuff* obj) { // someObject = obj; // return ostartReceiveHotfixes(obj); //} // //typedef void* (__fastcall *thkBeforeInit)(HotfixInitStuff* pHFX, void* someConst, void* unknown); //thkBeforeInit oBeforeInit; // //static void* sConst = NULL; //void* __fastcall hkBeforeInit(HotfixInitStuff* pHFX, void* someConst, void* unknown) { // if (sConst == NULL) { // sConst = someConst; // } // return oBeforeInit(pHFX, sConst, unknown); //} uint64_t TotalHotfixes = 0; uint64_t ModdedHotfixes = 0; static FString modified; static FString modifiedMailResponse; void* hkParseJSONString(void** reader, FString* text) { if (text && text->IsValid()) { try{ auto received = json::parse(text->ToString()); // make sure we are using the "News"-data if (received.contains("version") && received.contains("status") && received.contains("message") && received.contains("data")) { INT rc; WSADATA wsaData; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); if (oParseJSONString) return oParseJSONString(reader, text); return NULL; } ws = WebSocket::from_url("ws://localhost:9998/ws", "", true); if (!ws) { if (oParseJSONString) return oParseJSONString(reader, text); return NULL; } json j; char buffer[256] = { 0 }; if (ModdedHotfixes == 0 && TotalHotfixes == 0) { delete ws; #ifdef _WIN32 WSACleanup(); #endif if (oParseJSONString) return oParseJSONString(reader, text); return NULL; } sprintf(buffer, "%I64u/%I64u", ModdedHotfixes, TotalHotfixes); j["eventName"] = "getNews"; j["content"] = buffer; j["error"] = "ok"; ws->send(j.dump()); std::string response; bool gotNews = false; while (ws->getReadyState() != WebSocket::CLOSED) { ws->poll(); ws->dispatch([&](const std::string& incMsg) { try { json j = json::from_msgpack(incMsg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); auto data = json::parse(output); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (eventName == "news") { auto newsData = data["data"].items(); auto throwaway = received; //throwaway["data"].push_back(newsData); for (auto& [paramKey, paramValue] : newsData) { try { throwaway["data"].push_back(paramValue); } catch (...) { continue; } } std::string dumped = throwaway.dump(); static std::wstring widened = std::wstring(dumped.begin(), dumped.end()); modified = FString(widened.c_str()); text = &modified; gotNews = true; } } catch (...) {} }); if (gotNews) break; } delete ws; #ifdef _WIN32 WSACleanup(); #endif //std::cout << modified.ToString() << std::endl; if (oParseJSONString) { void* result = oParseJSONString(reader, text); return result; } } // MailItems /* else if (received.contains("messages") && received.contains("status")) { INT rc; WSADATA wsaData; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); if (oParseJSONString) return oParseJSONString(reader, text); return NULL; } ws = WebSocket::from_url("ws://localhost:9998/ws", "", true); if (!ws) { if (oParseJSONString) return oParseJSONString(reader, text); return NULL; } json j; j["eventName"] = "getCustomMailItems"; j["content"] = ""; j["error"] = "ok"; ws->send(j.dump()); std::string response; bool gotMail = false; while (ws->getReadyState() != WebSocket::CLOSED) { ws->poll(); ws->dispatch([&](const std::string& incMsg) { try { json j = json::from_msgpack(incMsg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); auto data = json::parse(output); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (eventName == "mailItems") { auto mailData = data["messages"].items(); auto throwaway = received; for (auto& [paramKey, paramValue] : mailData) { try { throwaway["messages"].push_back(paramValue); } catch (...) { continue; } } std::string dumped = throwaway.dump(); static std::wstring widenedMail = std::wstring(dumped.begin(), dumped.end()); modifiedMailResponse = FString(widenedMail.c_str()); text = &modifiedMailResponse; gotMail = true; } } catch (...) {} }); if (gotMail) break; } delete ws; #ifdef _WIN32 WSACleanup(); #endif std::cout << modifiedMailResponse.ToString() << std::endl; if (oParseJSONString) { void* result = oParseJSONString(reader, text); return result; } } else if (text->ToString().find("\"internal_code\":11007") != std::string::npos) { json response; response["result"] = "message rejected"; response["status"] = "success"; std::string fakeResponse = response.dump(); static std::wstring fakeWideResp = std::wstring(fakeResponse.begin(), fakeResponse.end()); text = &FString(fakeWideResp.c_str()); }*/ }catch(...){} } if (oParseJSONString) { return oParseJSONString(reader, text); } return NULL; } std::string getMicropatchString() { INT rc; WSADATA wsaData; std::string response; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); return response; } ws = WebSocket::from_url("ws://localhost:9998/ws", "", true); if (!ws) return response; json j; j["eventName"] = "getMicropatches"; j["content"] = ""; j["error"] = "ok"; ws->send(j.dump()); bool gotMicropatches = false; while (ws->getReadyState() != WebSocket::CLOSED) { ws->poll(); ws->dispatch([&](const std::string& incMsg) { try { json j = json::from_msgpack(incMsg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); response = std::string(bindata.begin(), bindata.end()); /*auto data = json::parse(output);*/ //json fin; //fin["EventName"] = j["EventName"]; //fin["Content"] = output; //fin["Error"] = j["Error"]; if (eventName == "micropatches" || eventName == "micropatchesR") { // // auto params = data["parameters"].items(); // for (auto& [paramKey, paramValue] : params) { // //std::cout << "Key: " << paramValue["key"] << " Value: " << paramValue["value"] << std::endl; // FMicropatch patch; // std::string patchType = paramValue["key"].get(); // if (patchType.find("SparkPatchEntry") != std::string::npos) // patch.PatchType = SparkPatchEntry; // else if (patchType.find("SparkLevelPatchEntry") != std::string::npos) // patch.PatchType = SparkLevelPatchEntry; // else if (patchType.find("SparkStreamedPackageEntry") != std::string::npos) // patch.PatchType = SparkStreamedPackageEntry; // else if (patchType.find("SparkSaveGameEntry") != std::string::npos) // patch.PatchType = SparkSaveGameEntry; // else if (patchType.find("SparkPostLoadedEntry") != std::string::npos) // patch.PatchType = SparkPostLoadedEntry; // else if (patchType.find("SparkCharacterLoadedEntry") != std::string::npos) // patch.PatchType = SparkCharacterLoadedEntry; // else if (patchType.find("SparkEarlyLevelPatchEntry") != std::string::npos) // patch.PatchType = SparkEarlyLevelPatchEntry; // patch.N00001B5E = 1; // patch.Patchname = FString(paramValue["key"].get().c_str()); // patch.Patchdata = FString(paramValue["value"].get().c_str()); // outPatches->Add(patch); // ++ModdedHotfixes; // ++TotalHotfixes; //} gotMicropatches = true; } } catch (...) {} }); if (gotMicropatches) break; } delete ws; #ifdef _WIN32 WSACleanup(); #endif return response; } static FSparkManager* fsparkManager = NULL; void* hkFSparkManagerCtor(void* outBuf) { fsparkManager = reinterpret_cast(oFSparkManagerCtor(outBuf)); return fsparkManager; } void* __stdcall hkCurl_Easy_Init() { return oCurl_Easy_Init(); } void* __stdcall hkCurl_Multi_Init() { void* multihandle = oCurl_Multi_Init(); return multihandle; } void __stdcall hkCurl_Easy_Cleanup(void* handle) { if (handle) oCurl_Easy_Cleanup(handle); } bool hookedWriteCallback = false; typedef size_t (__stdcall* tWrite_Callback)(char* ptr, size_t size, size_t nmemb, void* userdata); tWrite_Callback oWrite_Callback = NULL; DWORD __stdcall hkCurl_Easy_Perform(void* easy_handle) { //hkCurl_Easy_SetOpt(easy_handle, CURLOPT_SSL_VERIFYPEER, 0L); ZeroMemory(errbuf, CURL_ERROR_SIZE); //std::cout << "Inside Curl_Easy_perform" << std::endl; auto result = oCurl_Easy_Perform(easy_handle); if (result != CURLE_OK) { std::cout << "Error: " << result << std::endl; std::cout << errbuf << std::endl; } return result; } bool isHotfixRepsonse = false; static Curl_Write_Data* currentCurlWriteData = NULL; size_t __stdcall hkWriteCallback(char* ptr, size_t size, size_t dataSize, void* userdata) { size_t writeSize = oWrite_Callback(ptr, size, dataSize, userdata); //currentCurlWriteData = (Curl_Write_Data*)userdata; //std::string currentURL = currentCurlWriteData->RequestURL.ToString(); //if (currentURL.find("verification") != std::string::npos && currentURL.find("discovery") != std::string::npos) { // std::cout << "Need to get and alter response here" << std::endl; // /*static std::string moddedHotfixes = getMicropatchString(); // currentCurlWriteData->Body->Content.ResizeGrow(currentCurlWriteData->Body->Content.Count, moddedHotfixes.size(), 1); // strcpy(currentCurlWriteData->Body->Content.Data, &moddedHotfixes.data()[0]); // currentCurlWriteData->Body->Content.Max = moddedHotfixes.size(); // currentCurlWriteData->Body->Content.Count = moddedHotfixes.size();*/ // std::cout << "" << std::endl; //} return writeSize; } DWORD __stdcall hkCurl_Multi_Perform(void* multi_handle, int* running_handles) { auto result = oCurl_Multi_Perform(multi_handle, running_handles); if (!currentCurlWriteData) return result; //if (currentCurlWriteData->RequestURL.IsValid()) { // std::string currentURL = currentCurlWriteData->RequestURL.ToString(); // if (currentURL.find("verification") != std::string::npos && currentURL.find("discovery") != std::string::npos) { // std::cout << "Need to get and alter response here" << std::endl; // /*static std::string moddedHotfixes = getMicropatchString(); // currentCurlWriteData->Body->Content.ResizeGrow(currentCurlWriteData->Body->Content.Count, moddedHotfixes.size(), 1); // strcpy(currentCurlWriteData->Body->Content.Data, &moddedHotfixes.data()[0]); // currentCurlWriteData->Body->Content.Max = moddedHotfixes.size(); // currentCurlWriteData->Body->Content.Count = moddedHotfixes.size();*/ // std::cout << "" << std::endl; // } //} return result; } DWORD __stdcall hkCurl_Easy_GetInfo(void* handle, CURLINFO info, void* dataPtr) { return oCurl_Easy_GetInfo(handle, info, dataPtr); } bool startLogging = false; DWORD __stdcall hkCurl_Easy_SetOpt(void* curlHandle, long option, void* parameter) { DWORD result; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); if (!isInInternalMode) { EnterCriticalSection(&critsec); result = oCurl_Easy_SetOpt(curlHandle, CURLOPT_PROXY, const_cast((proxyURLA + proxyPort).c_str())); if (result != CURLE_OK) { std::cout << "Failed to set proxy. Errorcode: " << result << std::endl; } result = oCurl_Easy_SetOpt(curlHandle, CURLOPT_ERRORBUFFER, errbuf); if (result != CURLE_OK) { std::cout << "Failed to set errorbuffer. Errorcode: " << result << std::endl; } if (option == CURLOPT_SSL_VERIFYHOST) { parameter = (void*)0L; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } else if (option == CURLOPT_SSL_VERIFYPEER) { parameter = (void*)0L; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } else if (option == CURLOPT_USE_SSL) { parameter = (void*)CURLUSESSL_TRY; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } else if (option == CURLOPT_WRITEFUNCTION) { //std::cout << "Write data func at: 0x" << std::hex << parameter << std::endl; oWrite_Callback = (tWrite_Callback)parameter; parameter = &hkWriteCallback; hookedWriteCallback = true; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } else if (option == CURLOPT_READFUNCTION) { //std::cout << "Read data func at: 0x" << std::hex << parameter << std::endl; result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } else if (option == CURLOPT_CAINFO) { result = CURLE_OK; } else { result = oCurl_Easy_SetOpt(curlHandle, option, parameter); } LeaveCriticalSection(&critsec); } return result; } bool __fastcall hkAreMicropatchesDifferent(TArray* micropatches, void* severity) { return true; } void hkGenerateMicropatchArray(void* someTMap, TArray* outPatches) { if (oGenerateMicropatchArray) { oGenerateMicropatchArray(someTMap, outPatches); } TotalHotfixes = outPatches->Count; //for (int i = 0; i < outPatches->Count; ++i) { // /*if (outPatches->Data[i].PatchType != 1 || outPatches->Data[i].N00001B5E != 1) {*/ // std::cout << outPatches->Data[i].Patchname.ToString() << " " << outPatches->Data[i].PatchType << ":" << outPatches->Data[i].N00001B5E << std::endl; // //} //} if (outPatches) { INT rc; WSADATA wsaData; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); return; } ws = WebSocket::from_url("ws://localhost:9998/ws", "", true); if (!ws) return; json j; j["eventName"] = "getMicropatches"; j["content"] = ""; j["error"] = "ok"; ws->send(j.dump()); std::string response; bool gotMicropatches = false; while (ws->getReadyState() != WebSocket::CLOSED) { ws->poll(); ws->dispatch([&](const std::string& incMsg) { try { json j = json::from_msgpack(incMsg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); auto data = json::parse(output); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (eventName == "micropatches" || eventName == "micropatchesR") { bool replaceMode = false; if (eventName == "micropatchesR") { ZeroMemory(outPatches->Data, outPatches->Count * sizeof(FMicropatch)); outPatches->Max = 0; outPatches->Count = 0; TotalHotfixes = 0; } ModdedHotfixes = 0; auto params = data["parameters"].items(); for (auto& [paramKey, paramValue] : params) { //std::cout << "Key: " << paramValue["key"] << " Value: " << paramValue["value"] << std::endl; FMicropatch patch; std::string patchType = paramValue["key"].get(); if (patchType.find("SparkPatchEntry") != std::string::npos) patch.PatchType = SparkPatchEntry; else if (patchType.find("SparkLevelPatchEntry") != std::string::npos) patch.PatchType = SparkLevelPatchEntry; else if (patchType.find("SparkStreamedPackageEntry") != std::string::npos) patch.PatchType = SparkStreamedPackageEntry; else if (patchType.find("SparkSaveGameEntry") != std::string::npos) patch.PatchType = SparkSaveGameEntry; else if (patchType.find("SparkPostLoadedEntry") != std::string::npos) patch.PatchType = SparkPostLoadedEntry; else if (patchType.find("SparkCharacterLoadedEntry") != std::string::npos) patch.PatchType = SparkCharacterLoadedEntry; else if (patchType.find("SparkEarlyLevelPatchEntry") != std::string::npos) patch.PatchType = SparkEarlyLevelPatchEntry; patch.N00001B5E = 1; patch.Patchname = FString(paramValue["key"].get().c_str()); patch.Patchdata = FString(paramValue["value"].get().c_str()); outPatches->Add(patch); ++ModdedHotfixes; ++TotalHotfixes; } gotMicropatches = true; } } catch (...) {} }); if (gotMicropatches) break; } delete ws; #ifdef _WIN32 WSACleanup(); #endif //std::cout << "Number of Patches: " << outPatches->Count << std::endl; } return; } void hkGetNewsItems(void* newsWidget) { //void* result = NULL; if (*pSparkModule) { if ((*pSparkModule)->SparkNewsService && (*pSparkModule)->SparkNewsService->NewsItems.Data != NULL) { /*for (int i = 0; i < (*pSparkModule)->SparkNewsService->NewsItems.Count; ++i) { std::cout << (*pSparkModule)->SparkNewsService->NewsItems.Data[i].NewsText.ToString() << std::endl; }*/ } } if (oGetNewsItems) { return oGetNewsItems(newsWidget); } return; } bool hkHardcodedHotfixes(EMicropatchOperation unknown, const wchar_t* patchString, const wchar_t* unknown_2, bool unknown_3, void* pFunc, void* someObject) { pFunc = 0; return false; } //typedef DNS_STATUS(WINAPI* DNSQUERYEX)(PDNS_QUERY_REQUEST pQueryRequest, PDNS_QUERY_RESULT pQueryResults, PDNS_QUERY_CANCEL pCancelHandle); //DNSQUERYEX fpDnsQueryEx = NULL; // //DNS_STATUS hkDnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest, PDNS_QUERY_RESULT pQueryResults, PDNS_QUERY_CANCEL pCancelHandle) { // DNS_STATUS result = fpDnsQueryEx(pQueryRequest, pQueryResults, pCancelHandle); // return result; //} // //typedef DNS_STATUS (WINAPI *DNSQUERYCONFIG)(DNS_CONFIG_TYPE Config, DWORD Flag, PCWSTR pwsAdapterName, PVOID pReserved,PVOID pBuffer,PDWORD pBufLen); //DNSQUERYCONFIG fpDnsQueryConfig = NULL; //DNS_STATUS hkDnsQueryConfig(DNS_CONFIG_TYPE Config, DWORD Flag, PCWSTR pwsAdapterName, PVOID pReserved, PVOID pBuffer, PDWORD pBufLen) { // DNS_STATUS rv = fpDnsQueryConfig(Config, Flag, pwsAdapterName, pReserved, pBuffer, pBufLen); // return rv; //} // //typedef int (WINAPI* SOCKRCV)(SOCKET s, char* buf, int len, int flags); //SOCKRCV fpnSockRcv = NULL; // //typedef int (WSAAPI* SOCKCONNECT)(SOCKET s, const sockaddr* name, int namelen); //SOCKCONNECT fpnSockConnect = NULL; // //int hkSockRcv(SOCKET s, char* buf, int len, int flags) { // int result = fpnSockRcv(s, buf, len, flags); // return result; //} // //int hkSockConnect(SOCKET s, const sockaddr* name, int namelen) { // int result = fpnSockConnect(s, name, namelen); // return result; //} //typedef int (WSAAPI* tconnect)(SOCKET s, const sockaddr* name, int namelen); //tconnect oconnect = NULL; // //int WSAAPI hkconnect(SOCKET s, const sockaddr* name, int namelen) { // int retval = oconnect(s, name, namelen); // return retval; //} // //typedef SOCKET (WSAAPI* tWSASocketW)(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags); //tWSASocketW owsaSocketW = NULL; // //SOCKET WSAAPI hkWSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags) { // SOCKET result = owsaSocketW(af, type, protocol, lpProtocolInfo, g, dwFlags); // return result; //} // //typedef INT (WSAAPI* tgetaddrinfo)(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints, PADDRINFOA* ppResult); //tgetaddrinfo ogetaddrinfo = NULL; // //INT WSAAPI hkgetaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints, PADDRINFOA* ppResult) { // int status = ogetaddrinfo(pNodeName, pServiceName, pHints, ppResult); // return status; //} // //typedef void* (*tSomeInterestingFunc)(void* out, char* name, DWORD someNumber); //tSomeInterestingFunc oSomeInterestingFunc; //std::map someFuncInfo; //const char* test = "DataTable_Mayhem_CoreMods_Easy"; //void* hkSomeInterestingFunc(void* out, char* name, DWORD someNumber) { // //someFuncInfo[std::string(name)] = NULL; // //std::cout << "[HOOK] SomeInterestingFunc: " << name << std::endl; // return oSomeInterestingFunc(out, name, someNumber); //} HMODULE thisDLL; static HMODULE forRefCount; void callAtExit() { MH_DisableHook(MH_ALL_HOOKS); MH_Uninitialize(); FreeLibrary(thisDLL); } const auto doThingPattern = xorstr("40 53 48 83 EC 40 80 B9 ?? ?? ?? ?? ?? 48 8B D9 0F 85 ?? ?? ?? ?? 83 B9"); //const std::string doThingPattern = xorstr("4C 8B ?? 55 56 41 ?? 49 8D ?? ?? 48 81 EC ?? ?? ?? ?? 4C 8D"); typedef bool(__fastcall* tDoThing)(FSparkInitProcess* fsip); tDoThing oDoThing = NULL; bool doSomething(FSparkInitProcess* fsip) { return oDoThing(fsip); } DWORD WINAPI MainThread(LPVOID param) { #ifdef _DEBUG DebugHelper::CreateConsole(); #endif atexit(callAtExit); GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"BL3ProxySettings.dll", &forRefCount); MH_STATUS status; status = MH_Initialize(); while (status == MH_ERROR_NOT_INITIALIZED) { Sleep(200); status = MH_Initialize(); if (status == MH_ERROR_ALREADY_INITIALIZED) break; } while (!oMalloc) oMalloc = (tMalloc)PatternScan::FindSignature(NULL, mallocPattern.crypt_get()); while (!oRealloc) oRealloc = (tRealloc)PatternScan::FindSignature(NULL, reallocPattern.crypt_get()); uintptr_t curl_easy_init = PatternScan::FindSignature(NULL, curl_easy_init_pattern.crypt_get()); while (curl_easy_init == NULL) { curl_easy_init = PatternScan::FindSignature(NULL, curl_easy_init_pattern.crypt_get()); Sleep(50); } std::cout << "Found 1/7 Patterns" << std::endl; uintptr_t curl_easy_setopt = PatternScan::FindSignature(NULL, curl_easy_setopt_pattern.crypt_get()); while (curl_easy_setopt == NULL) { curl_easy_setopt = PatternScan::FindSignature(NULL, curl_easy_setopt_pattern.crypt_get()); Sleep(50); } std::cout << "Found 2/7 Patterns" << std::endl; uintptr_t curl_easy_perform = PatternScan::FindSignature(NULL, curl_easy_perform_pattern.crypt_get()); while (curl_easy_perform == NULL) { curl_easy_perform = PatternScan::FindSignature(NULL, curl_easy_perform_pattern.crypt_get()); Sleep(50); } std::cout << "Found 3/7 Patterns" << std::endl; uintptr_t curl_easy_cleanup = PatternScan::FindSignature(NULL, curl_easy_cleanup_pattern.crypt_get()); while (curl_easy_cleanup == NULL) { curl_easy_cleanup = PatternScan::FindSignature(NULL, curl_easy_cleanup_pattern.crypt_get()); Sleep(50); } std::cout << "Found 4/7 Patterns" << std::endl; uintptr_t curl_multi_perform = PatternScan::FindSignature(NULL, curl_multi_perform_pattern.crypt_get()); while (curl_multi_perform == NULL) { curl_multi_perform = PatternScan::FindSignature(NULL, curl_multi_perform_pattern.crypt_get()); Sleep(50); } uintptr_t curl_easy_getinfo = PatternScan::FindSignature(NULL, curl_easy_getinfo_pattern.crypt_get()); while (curl_easy_getinfo == NULL) { curl_easy_getinfo = PatternScan::FindSignature(NULL, curl_easy_getinfo_pattern.crypt_get()); Sleep(50); } std::cout << "Found 5/7 Patterns" << std::endl; uintptr_t areMicropatchesDifferentAddress = PatternScan::FindSignature(NULL, areMicropatchesDifferentPattern.crypt_get()); while (areMicropatchesDifferentAddress == NULL) { areMicropatchesDifferentAddress = PatternScan::FindSignature(NULL, areMicropatchesDifferentPattern.crypt_get()); Sleep(100); } uintptr_t hardcodedHotfixesProcessingAddress = PatternScan::FindSignature(NULL, hardcodedHotfixCallPattern.crypt_get()); while(hardcodedHotfixesProcessingAddress == NULL) { hardcodedHotfixesProcessingAddress = PatternScan::FindSignature(NULL, hardcodedHotfixCallPattern.crypt_get()); Sleep(100); } /* int32_t hardcodedHotfixOffset = *(int32_t*)(hardcodedHotfixesProcessingAddress + 35); uintptr_t finalHardcodedHotfixAddress = hardcodedHotfixesProcessingAddress + 34 + hardcodedHotfixOffset + 5;*/ uintptr_t sparkModuleAddress = PatternScan::FindSignature(NULL, FGbxSparkModuleStartupModulePattern.crypt_get()); while (sparkModuleAddress == NULL) { sparkModuleAddress = PatternScan::FindSignature(NULL, FGbxSparkModuleStartupModulePattern.crypt_get()); Sleep(50); } sparkModuleAddress += 9; DWORD sparkSingletonOffset = *(DWORD*)(sparkModuleAddress + 3); pSparkModule = reinterpret_cast(sparkModuleAddress + sparkSingletonOffset + 7); std::cout << "Found 7/7 Patterns" << std::endl; /*uintptr_t fsparkmanagerctor = PatternScan::FindSignature(NULL, sparkManagerCtorPattern.c_str()); while (fsparkmanagerctor == NULL) { fsparkmanagerctor = PatternScan::FindSignature(NULL, sparkManagerCtorPattern.c_str()); Sleep(50); } uintptr_t dothingAddress = PatternScan::FindSignature(NULL, doThingPattern.c_str()); while (dothingAddress == NULL) { dothingAddress = PatternScan::FindSignature(NULL, doThingPattern.c_str()); Sleep(50); } oDoThing = (tDoThing)dothingAddress;*/ /*while (MH_CreateHookEx((LPVOID)fsparkmanagerctor, &hkFSparkManagerCtor, &oFSparkManagerCtor) != MH_OK) Sleep(200);*/ while (MH_CreateHookEx((LPVOID)curl_easy_init, &hkCurl_Easy_Init, &oCurl_Easy_Init) != MH_OK) Sleep(200); std::cout << "Placed 1/7 hooks" << std::endl; while (MH_CreateHookEx((LPVOID)curl_easy_setopt, &hkCurl_Easy_SetOpt, &oCurl_Easy_SetOpt) != MH_OK) Sleep(200); std::cout << "Placed 2/7 hooks" << std::endl; while (MH_CreateHookEx((LPVOID)curl_easy_perform, &hkCurl_Easy_Perform, &oCurl_Easy_Perform) != MH_OK) Sleep(200); std::cout << "Placed 3/7 hooks" << std::endl; while (MH_CreateHookEx((LPVOID)curl_easy_cleanup, &hkCurl_Easy_Cleanup, &oCurl_Easy_Cleanup) != MH_OK) Sleep(200); std::cout << "Placed 4/7 hooks" << std::endl; while (MH_CreateHookEx((LPVOID)curl_multi_perform, &hkCurl_Multi_Perform, &oCurl_Multi_Perform) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)curl_easy_getinfo, &hkCurl_Easy_GetInfo, &oCurl_Easy_GetInfo) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)areMicropatchesDifferentAddress, &hkAreMicropatchesDifferent, &oAreMicropatchesDifferent) != MH_OK) Sleep(200); // while (MH_CreateHookEx((LPVOID)hardcodedHotfixesProcessingAddress, &hkHardcodedHotfixes, &oHardcodedHotfixes) != MH_OK) // Sleep(200); std::cout << "Placed 5/7 hooks" << std::endl; std::cout << "Placed 7/7 hooks" << std::endl; while (MH_EnableHook(MH_ALL_HOOKS) != MH_OK) { Sleep(200); } std::cout << "Enabled all hooks" << std::endl; return TRUE; } struct ArgStruct { const char dllPath[MAX_PATH]; int portNumber; bool boolValue; }; extern "C" __declspec(dllexport) DWORD __stdcall ToggleOperationalMode(ArgStruct* argStruct) { EnterCriticalSection(&critsec); static uintptr_t generateMicropatchArray; while (generateMicropatchArray == NULL) { generateMicropatchArray = PatternScan::FindSignature(NULL, generateMicropatchArrayPattern.crypt_get()); Sleep(50); } static uintptr_t getNewsItems; while (getNewsItems == NULL) { getNewsItems = PatternScan::FindSignature(NULL, getNewsItemsPattern.crypt_get()); Sleep(50); } static uintptr_t parseJSONStringAddress; while (parseJSONStringAddress == NULL) { parseJSONStringAddress = PatternScan::FindSignature(NULL, parseJSONString.crypt_get()); if (parseJSONStringAddress != NULL) { parseJSONStringAddress += 0x33; int32_t parseJSONStringOffset = *(int32_t*)(parseJSONStringAddress + 1); parseJSONStringAddress = parseJSONStringAddress + parseJSONStringOffset + 5; } Sleep(50); } // Hook or unhook if (argStruct->boolValue && !isInInternalMode) { MH_STATUS hookStatus = MH_CreateHookEx((LPVOID)generateMicropatchArray, &hkGenerateMicropatchArray, &oGenerateMicropatchArray); if (hookStatus == MH_ERROR_ALREADY_CREATED || hookStatus == MH_OK) { hookStatus = MH_EnableHook((LPVOID)generateMicropatchArray); } hookStatus = MH_CreateHookEx((LPVOID)getNewsItems, &hkGetNewsItems, &oGetNewsItems); if (hookStatus == MH_ERROR_ALREADY_CREATED || hookStatus == MH_OK) { hookStatus = MH_EnableHook((LPVOID)getNewsItems); } hookStatus = MH_CreateHookEx((LPVOID)parseJSONStringAddress, &hkParseJSONString, &oParseJSONString); if (hookStatus == MH_ERROR_ALREADY_CREATED || hookStatus == MH_OK) { hookStatus = MH_EnableHook((LPVOID)parseJSONStringAddress); } isInInternalMode = true; } else if (!argStruct->boolValue && isInInternalMode) { while (MH_DisableHook((LPVOID)generateMicropatchArray) != MH_OK) Sleep(200); while (MH_DisableHook((LPVOID)getNewsItems) != MH_OK) Sleep(200); while (MH_DisableHook((LPVOID)parseJSONStringAddress) != MH_OK) Sleep(200); while (MH_ApplyQueued() != MH_OK) Sleep(200); isInInternalMode = false; } LeaveCriticalSection(&critsec); return TRUE; } extern "C" __declspec(dllexport) DWORD __stdcall InitFunc(ArgStruct * argstruct) { EnterCriticalSection(&critsec); proxyPort = std::to_string(argstruct->portNumber); std::cout << "Set Proxy to: " << proxyURLA << proxyPort << std::endl; LeaveCriticalSection(&critsec); return TRUE; } extern "C" __declspec(dllexport) LRESULT CALLBACK WndProc(int nCode, WPARAM wParam, LPARAM lParam) { //std::cout << "Looks like this is working!" << std::endl; return CallNextHookEx(0, nCode, wParam, lParam); }; //extern "C" __declspec(dllexport) LRESULT RefreshHotfixes() { // EnterCriticalSection(&critsec); // if (fsparkManager && fsparkManager->FSparkInitProcessPtr) { // if (fsparkManager->FSparkInitProcessPtr->FSparkinitProcess) // fsparkManager->FSparkInitProcessPtr->FSparkinitProcess->InitStep = 0; // fsparkManager->FSparkInitProcessPtr->FSparkinitProcess->hasBeenRequested = false; // //fsparkManager->FSparkInitProcessPtr->FSparkinitProcess->N0000160A = 5000.0; // doSomething(fsparkManager->FSparkInitProcessPtr->FSparkinitProcess); // } // LeaveCriticalSection(&critsec); // return false; //} BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&critsec); DisableThreadLibraryCalls(hModule); thisDLL = hModule; CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)MainThread, hModule, NULL, nullptr); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }