| @@ -80,6 +80,8 @@ auto generateMicropatchArrayPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 48 8 | |||
| 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"); | |||
| @@ -91,6 +93,8 @@ auto reallocPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B | |||
| 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"); | |||
| //// | |||
| @@ -644,6 +648,9 @@ tGenerateMicropatchArray oGenerateMicropatchArray = NULL; | |||
| typedef void* (__fastcall* tParseJSONString)(void** jsonReader, const FString* text); | |||
| tParseJSONString oParseJSONString = NULL; | |||
| typedef bool(__fastcall* tAreMicropatchesDifferent)(TArray<FMicropatch>* micropatches, void* severity); | |||
| tAreMicropatchesDifferent oAreMicropatchesDifferent = NULL; | |||
| FSparkModule** pSparkModule = NULL; | |||
| @@ -720,6 +727,16 @@ void* hkParseJSONString(void** reader, FString* text) { | |||
| } | |||
| 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"; | |||
| @@ -774,7 +791,7 @@ void* hkParseJSONString(void** reader, FString* text) { | |||
| #ifdef _WIN32 | |||
| WSACleanup(); | |||
| #endif | |||
| std::cout << modified.ToString() << std::endl; | |||
| //std::cout << modified.ToString() << std::endl; | |||
| if (oParseJSONString) { | |||
| void* result = oParseJSONString(reader, text); | |||
| return result; | |||
| @@ -997,17 +1014,17 @@ 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; | |||
| } | |||
| //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; | |||
| } | |||
| @@ -1038,56 +1055,61 @@ bool startLogging = false; | |||
| DWORD __stdcall hkCurl_Easy_SetOpt(void* curlHandle, long option, void* parameter) | |||
| { | |||
| DWORD result; | |||
| /*result = oCurl_Easy_SetOpt(curlHandle, option, parameter);*/ | |||
| EnterCriticalSection(&critsec); | |||
| result = oCurl_Easy_SetOpt(curlHandle, option, parameter); | |||
| if (!isInInternalMode) { | |||
| EnterCriticalSection(&critsec); | |||
| result = oCurl_Easy_SetOpt(curlHandle, CURLOPT_PROXY, const_cast<char*>((proxyURLA + proxyPort).c_str())); | |||
| if (result != CURLE_OK) { | |||
| std::cout << "Failed to set proxy. Errorcode: " << result << std::endl; | |||
| } | |||
| result = oCurl_Easy_SetOpt(curlHandle, CURLOPT_PROXY, const_cast<char*>((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; | |||
| } | |||
| 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; | |||
| 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); | |||
| } | |||
| 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); | |||
| LeaveCriticalSection(&critsec); | |||
| } | |||
| return result; | |||
| } | |||
| bool __fastcall hkAreMicropatchesDifferent(TArray<FMicropatch>* micropatches, void* severity) { | |||
| return true; | |||
| } | |||
| void hkGenerateMicropatchArray(void* someTMap, TArray<FMicropatch>* outPatches) { | |||
| if (oGenerateMicropatchArray) { | |||
| oGenerateMicropatchArray(someTMap, outPatches); | |||
| @@ -1195,9 +1217,9 @@ void hkGetNewsItems(void* newsWidget) { | |||
| if (*pSparkModule) { | |||
| if ((*pSparkModule)->SparkNewsService && (*pSparkModule)->SparkNewsService->NewsItems.Data != NULL) { | |||
| for (int i = 0; i < (*pSparkModule)->SparkNewsService->NewsItems.Count; ++i) { | |||
| /*for (int i = 0; i < (*pSparkModule)->SparkNewsService->NewsItems.Count; ++i) { | |||
| std::cout << (*pSparkModule)->SparkNewsService->NewsItems.Data[i].NewsText.ToString() << std::endl; | |||
| } | |||
| }*/ | |||
| } | |||
| } | |||
| if (oGetNewsItems) { | |||
| @@ -1344,17 +1366,11 @@ DWORD WINAPI MainThread(LPVOID param) | |||
| } | |||
| std::cout << "Found 5/7 Patterns" << std::endl; | |||
| /*uintptr_t generateMicropatchArray = PatternScan::FindSignature(NULL, generateMicropatchArrayPattern.crypt_get()); | |||
| while (generateMicropatchArray == NULL) { | |||
| generateMicropatchArray = PatternScan::FindSignature(NULL, generateMicropatchArrayPattern.crypt_get()); | |||
| Sleep(50); | |||
| }*/ | |||
| std::cout << "Found 6/7 Patterns" << std::endl; | |||
| /*uintptr_t getNewsItems = PatternScan::FindSignature(NULL, getNewsItemsPattern.crypt_get()); | |||
| while (getNewsItems == NULL) { | |||
| getNewsItems = PatternScan::FindSignature(NULL, getNewsItemsPattern.crypt_get()); | |||
| Sleep(50); | |||
| }*/ | |||
| uintptr_t areMicropatchesDifferentAddress = PatternScan::FindSignature(NULL, areMicropatchesDifferentPattern.crypt_get()); | |||
| while (areMicropatchesDifferentAddress == NULL) { | |||
| areMicropatchesDifferentAddress = PatternScan::FindSignature(NULL, areMicropatchesDifferentPattern.crypt_get()); | |||
| Sleep(100); | |||
| } | |||
| uintptr_t sparkModuleAddress = PatternScan::FindSignature(NULL, FGbxSparkModuleStartupModulePattern.crypt_get()); | |||
| while (sparkModuleAddress == NULL) { | |||
| @@ -1366,15 +1382,7 @@ DWORD WINAPI MainThread(LPVOID param) | |||
| pSparkModule = reinterpret_cast<FSparkModule**>(sparkModuleAddress + sparkSingletonOffset + 7); | |||
| /*uintptr_t parseJSONStringAddress = PatternScan::FindSignature(NULL, parseJSONString.crypt_get()); | |||
| while (parseJSONStringAddress == NULL) { | |||
| parseJSONStringAddress = PatternScan::FindSignature(NULL, parseJSONString.crypt_get()); | |||
| Sleep(50); | |||
| } | |||
| parseJSONStringAddress += 0x33; | |||
| int32_t parseJSONStringOffset = *(int32_t*)(parseJSONStringAddress + 1); | |||
| parseJSONStringAddress = parseJSONStringAddress + parseJSONStringOffset + 5;*/ | |||
| std::cout << "Found 7/7 Patterns" << std::endl; | |||
| /*uintptr_t fsparkmanagerctor = PatternScan::FindSignature(NULL, sparkManagerCtorPattern.c_str()); | |||
| @@ -1415,14 +1423,10 @@ DWORD WINAPI MainThread(LPVOID param) | |||
| 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); | |||
| std::cout << "Placed 5/7 hooks" << std::endl; | |||
| /*while (MH_CreateHookEx((LPVOID)generateMicropatchArray, &hkGenerateMicropatchArray, &oGenerateMicropatchArray) != MH_OK) | |||
| Sleep(200);*/ | |||
| std::cout << "Placed 6/7 hooks" << std::endl; | |||
| /*while (MH_CreateHookEx((LPVOID)getNewsItems, &hkGetNewsItems, &oGetNewsItems) != MH_OK) | |||
| Sleep(200); */ | |||
| /*while (MH_CreateHookEx((LPVOID)parseJSONStringAddress, &hkParseJSONString, &oParseJSONString) != MH_OK) | |||
| Sleep(200);*/ | |||
| std::cout << "Placed 7/7 hooks" << std::endl; | |||
| while (MH_EnableHook(MH_ALL_HOOKS) != MH_OK) { | |||
| Sleep(200); | |||
| @@ -1435,8 +1439,67 @@ DWORD WINAPI MainThread(LPVOID param) | |||
| struct ArgStruct { | |||
| const char dllPath[MAX_PATH]; | |||
| int portNumber; | |||
| bool boolValue; | |||
| }; | |||
| // TODO: Send log messages on success/errors | |||
| 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); | |||