diff --git a/Cobalt/Cobalt.vcxproj b/Cobalt/Cobalt.vcxproj index 765507c..500f3f8 100644 --- a/Cobalt/Cobalt.vcxproj +++ b/Cobalt/Cobalt.vcxproj @@ -113,11 +113,14 @@ Use pch.h stdcpplatest + ../vendor Windows true false + ../vendor + MinHook/minhook.x64.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) @@ -131,6 +134,7 @@ NotUsing pch.h stdcpplatest + ../vendor Windows @@ -138,6 +142,8 @@ true true false + ../vendor + MinHook/minhook.x64.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) diff --git a/Cobalt/curlhook.h b/Cobalt/curlhook.h index 6140e58..c1fe52b 100644 --- a/Cobalt/curlhook.h +++ b/Cobalt/curlhook.h @@ -9,8 +9,6 @@ #include "../vendor/cURL/curl.h" #include "url.h" -// #define HYBRID_ENABLED - inline CURLcode(*CurlSetOpt)(struct Curl_easy*, CURLoption, va_list) = nullptr; inline CURLcode(*CurlEasySetOpt)(struct Curl_easy*, CURLoption, ...) = nullptr; @@ -55,10 +53,12 @@ inline CURLcode CurlEasySetOptDetour(struct Curl_easy* data, CURLoption tag, ... Uri uri = Uri::Parse(url); - // std::cout << "URL: " << uri.Host << uri.Path << '\n'; + std::cout << "URL: " << uri.Host << uri.Path << '\n'; -#ifdef URL_HOST +#if defined(URL_HOST) && defined(URL_PROTOCOL) && defined(URL_PORT) if (uri.Host.ends_with(XOR("ol.epicgames.com")) + || uri.Host.ends_with(XOR("epicgames.dev")) // wooo eos + || uri.Host.ends_with(XOR("ol.epicgames.net")) // i forgor what endpoint this was for || uri.Host.ends_with(XOR(".akamaized.net")) || uri.Host.ends_with(XOR("on.epicgames.com")) || uri.Host.ends_with(XOR("game-social.epicgames.com")) @@ -71,25 +71,23 @@ inline CURLcode CurlEasySetOptDetour(struct Curl_easy* data, CURLoption tag, ... } else if (CobaltUsage == ECobaltUsage::Hybrid) { - if (CobaltUsage == ECobaltUsage::Hybrid) { - if (uri.Path.contains("/fortnite/api/v2/versioncheck/")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } - else if (uri.Path.contains("/fortnite/api/game/v2/profile")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } - else if (uri.Path.contains("/content/api/pages/fortnite-game")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } - else if (uri.Path.contains("/affiliate/api/public/affiliates/slug")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } - else if (uri.Path.contains("/socialban/api/public/v1")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } - else if (uri.Path.contains("/fortnite/api/cloudstorage/system")) { - url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); - } + if (uri.Path.contains("/fortnite/api/v2/versioncheck/")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); + } + else if (uri.Path.contains("/fortnite/api/game/v2/profile")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); + } + else if (uri.Path.contains("/content/api/pages/fortnite-game")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); + } + else if (uri.Path.contains("/affiliate/api/public/affiliates/slug")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); + } + else if (uri.Path.contains("/socialban/api/public/v1")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); + } + else if (uri.Path.contains("/fortnite/api/cloudstorage/system")) { + url = Uri::CreateUri(URL_PROTOCOL, URL_HOST, URL_PORT, uri.Path, uri.QueryString); } } } diff --git a/Cobalt/dllmain.cpp b/Cobalt/dllmain.cpp index 8036ba6..913b8bd 100644 --- a/Cobalt/dllmain.cpp +++ b/Cobalt/dllmain.cpp @@ -3,6 +3,7 @@ #include #include "curlhook.h" #include "exithook.h" +#include #define DetoursEasy(address, hook) \ DetourTransactionBegin(); \ @@ -10,9 +11,44 @@ DetourAttach(reinterpret_cast(&address), hook); \ DetourTransactionCommit(); +void returnNone() { return; } + auto FindPushWidget() { - return sigscan("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B E9 49 8B D9 48 8D 0D ? ? ? ? 49 8B F8 48 8B F2 E8 ? ? ? ? 4C 8B CF 48 89 5C 24 ? 4C 8B C6 48 8B D5 48 8B 48 78"); + // OnlinePresence call + auto pattern = sigscan("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B E9 49 8B D9 48 8D 0D ? ? ? ? 49 8B F8 48 8B F2 E8 ? ? ? ? 4C 8B CF 48 89 5C 24 ? 4C 8B C6 48 8B D5 48 8B 48 78"); + + if (!pattern) + pattern = sigscan("48 8B C4 4C 89 40 18 48 89 50 10 48 89 48 08 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 68 B8 48 81 EC ? ? ? ? 65 48 8B 04 25"); // 26.00+ or sum + + return pattern; +} + +void Hook(void* Target, void* Detour) +{ +#ifdef USE_MINHOOK + MH_CreateHook(Target, Detour, nullptr); + MH_EnableHook(Target); +#else + Memcury::VEHHook::AddHook(Target, Detour); +#endif +} + +bool FixMemoryLeak() // 8.51 +{ + auto memoryleak = sigscan("4C 8B DC 55 57 41 56 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 48 8B 01 41 B6"); + + if (!memoryleak) + { + return false; + } + + Hook((void*)memoryleak, returnNone); + return true; +} + +void InitializeEOSCurlHook() +{ } bool InitializeCurlHook() @@ -59,7 +95,7 @@ bool InitializeCurlHook() { // TODO find a better way to "bypass" UAC (aka switch off VEH hooks) - Memcury::VEHHook::AddHook(CurlEasySetOpt, CurlEasySetOptDetour); + Hook(CurlEasySetOpt, CurlEasySetOptDetour); } return true; @@ -68,7 +104,38 @@ bool InitializeCurlHook() void InitializeExitHook() { if (!FindPushWidget()) + { + std::cout << "Failed to find PushWidget (This may be fine)!\n"; + + /* + auto RequestExitWithStatusAddr = sigscan("40 53 48 83 EC 40 80 3D ? ? ? ? ? 0F B6 D9 72 3A 48 8B 05"); // S9 + + std::cout << "RequestExitWithStatusAddr: " << RequestExitWithStatusAddr << '\n'; + + RequestExitWithStatus = decltype(RequestExitWithStatus)(RequestExitWithStatusAddr); + Memcury::VEHHook::AddHook(RequestExitWithStatus, RequestExitWithStatusHook); + + auto UnsafeEnvironmentPopupAddr = sigscan("4C 8B DC 55 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 49 89 73 E8 33 F6 49 89 7B E0 0F B6 FA"); // S9 + + std::cout << "UnsafeEnvironmentPopupAddr: " << UnsafeEnvironmentPopupAddr << '\n'; + + UnsafeEnvironmentPopup = decltype(UnsafeEnvironmentPopup)(UnsafeEnvironmentPopupAddr); + Memcury::VEHHook::AddHook(UnsafeEnvironmentPopup, UnsafeEnvironmentPopupHook); + + auto RequestExitAddrs = Memcury::Scanner::FindPatterns("40 53 48 83 EC 30 80 3D ? ? ? ? ? 0F B6 D9 72 33 48 8B 05 ? ? ? ? 4C 8D 44 24 ? 48 89 44 24 ? 41 B9 ? ? ? ? 0F"); // S9 + + std::cout << "RequestExitAddrs: " << RequestExitAddrs.size() << '\n'; + + for (auto RequestExitAddr : RequestExitAddrs) + { + RequestExit = decltype(RequestExit)(Memcury::Scanner(RequestExitAddr).Get()); + Memcury::VEHHook::AddHook(RequestExit, RequestExitHook); + } + */ + + return; + } auto UnsafeEnvironmentPopupAddr = sigscan("4C 8B DC 55 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 49 89 73 F0 49 89 7B E8 48 8B F9 4D 89 63 E0 4D 8B E0 4D 89 6B D8"); @@ -77,11 +144,21 @@ void InitializeExitHook() UnsafeEnvironmentPopupAddr = sigscan("4C 8B DC 55 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ?"); } + if (!UnsafeEnvironmentPopupAddr) + { + std::cout << "Failed to find UnsafeEnvironmentPopupAddr (This may be fine)!\n"; + } + auto RequestExitWithStatusAddr = sigscan("48 89 5C 24 ? 57 48 83 EC 40 41 B9 ? ? ? ? 0F B6 F9 44 38 0D ? ? ? ? 0F B6 DA 72 24 89 5C 24 30 48 8D 05 ? ? ? ? 89 7C 24 28 4C 8D 05 ? ? ? ? 33 D2 48 89 44 24 ? 33 C9 E8 ? ? ? ?"); if (!RequestExitWithStatusAddr) { - RequestExitWithStatusAddr = sigscan("48 8B C4 48 89 58 18 88 50 10 88 48 08 57 48 83 EC 30"); + RequestExitWithStatusAddr = sigscan("48 8B C4 48 89 58 18 88 50 10 88 48 08 57 48 83 EC 30"); // wrong on latest but idgaf + } + + if (!RequestExitWithStatusAddr) + { + std::cout << "Failed to find RequestExitWithStatusAddr (This may be fine)!\n"; } DetoursEasy(UnsafeEnvironmentPopupAddr, UnsafeEnvironmentPopupHook); @@ -97,7 +174,7 @@ DWORD WINAPI Main(LPVOID) freopen_s(&fptr, "CONOUT$", "w+", stdout); #endif SHOW_WINDOWS_CONSOLE -#ifndef URL_HOST +#ifndef URL_HOST // todo staticassert? std::cout << "\n\n\n!!!!!!! URL_HOST IS NOT DEFINED !!!!!!!\n\n\n\n"; #else std::cout << "Redirecting to " << URL_PROTOCOL << "://" << URL_HOST << ":" << URL_PORT << '\n'; @@ -105,14 +182,19 @@ DWORD WINAPI Main(LPVOID) std::cout << "Initializing Cobalt (made by Milxnor#3531).\n"; - std::cout << "Credits\n\n"; + std::cout << "Credits:\n\n"; std::cout << "Memcury - https://github.com/kem0x/Memcury\n"; - std::cout << "Neonite++ for the signatures and curl hook - https://github.com/PeQuLeaks/NeonitePP-Fixed/tree/1.4\n\n"; + std::cout << "Neonite++ for most of the signatures and curl hook - https://github.com/PeQuLeaks/NeonitePP-Fixed/tree/1.4\n\n"; +#ifdef USE_MINHOOK + MH_Initialize(); +#else Memcury::VEHHook::Init(); +#endif bool curlResult = InitializeCurlHook(); + InitializeEOSCurlHook(); InitializeExitHook(); bool result = curlResult; @@ -126,6 +208,19 @@ DWORD WINAPI Main(LPVOID) MessageBoxA(0, "Failed to initialize!", "Cobalt", MB_ICONERROR); } +#if 0 + Sleep(3000); + + if (!FixMemoryLeak()) + { + std::cout << "Failed to apply memory leak fix (this may be fine)!\n"; + } + else + { + std::cout << "Applied memory leak fix!\n"; + } +#endif + return 0; } diff --git a/Cobalt/exithook.h b/Cobalt/exithook.h index 4485dbe..ed68e22 100644 --- a/Cobalt/exithook.h +++ b/Cobalt/exithook.h @@ -1,11 +1,19 @@ #pragma once +#include + void (*RequestExitWithStatus)(bool Force, unsigned char Code); void RequestExitWithStatusHook(bool Force, unsigned char Code) { // printf("[VEH] RequestExitWithStatus Call Forced: %i ReturnCode: %u\n", Force, Code); } +void (*RequestExit)(int Code); +void RequestExitHook(int Code) +{ + std::cout << "REQUEST EXIT CODE: " << Code << '\n'; +} + void (*UnsafeEnvironmentPopup)(wchar_t** unknown1, unsigned __int8 _case, __int64 unknown2, char unknown3); void UnsafeEnvironmentPopupHook(wchar_t** unknown1, unsigned __int8 _case, __int64 unknown2, char unknown3) diff --git a/Cobalt/memcury.h b/Cobalt/memcury.h index 882db5a..eac2b10 100644 --- a/Cobalt/memcury.h +++ b/Cobalt/memcury.h @@ -711,6 +711,41 @@ namespace Memcury return FindPatternEx(handle, pattern, mask, module, module + Memcury::PE::GetNTHeaders()->OptionalHeader.SizeOfImage); } + static std::vector FindPatterns(const char* signature) + { + const auto sizeOfImage = PE::GetNTHeaders()->OptionalHeader.SizeOfImage; + auto patternBytes = ASM::pattern2bytes(signature); + const auto scanBytes = reinterpret_cast(PE::GetModuleBase()); + + const auto s = patternBytes.size(); + const auto d = patternBytes.data(); + + std::vector addresses; + + for (auto i = 0ul; i < sizeOfImage - s; ++i) + { + bool found = true; + for (auto j = 0ul; j < s; ++j) + { + if (scanBytes[i + j] != d[j] && d[j] != -1) + { + found = false; + break; + } + } + + if (found) + { + addresses.push_back(reinterpret_cast(&scanBytes[i])); + // break; + } + } + + // MemcuryAssertM(add != 0, "FindPattern return nullptr"); + + return addresses; + } + static auto FindPattern(const char* signature) -> Scanner { PE::Address add{ nullptr }; diff --git a/Cobalt/settings.h b/Cobalt/settings.h index 7dae26e..2fdca58 100644 --- a/Cobalt/settings.h +++ b/Cobalt/settings.h @@ -10,6 +10,7 @@ enum class ECobaltUsage #define URL_PROTOCOL "http" #define URL_HOST "127.0.0.1" #define URL_PORT "3551" +// #define USE_MINHOOK // ONLY USE IF U INJECT LATE #define SHOW_WINDOWS_CONSOLE diff --git a/vendor/MinHook/MinHook.h b/vendor/MinHook/MinHook.h new file mode 100644 index 0000000..15c0a87 --- /dev/null +++ b/vendor/MinHook/MinHook.h @@ -0,0 +1,186 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND +} +MH_STATUS; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Creates a Hook for the specified target function, in disabled state. + // Parameters: + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a Hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszTarget [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif + diff --git a/vendor/MinHook/minhook.x64.lib b/vendor/MinHook/minhook.x64.lib new file mode 100644 index 0000000..09eb5f1 Binary files /dev/null and b/vendor/MinHook/minhook.x64.lib differ