Files
Embeddium/Embeddium/Hooks/CurlHook.cpp
T
ApfelTeeSaft 446e6a5b7f Initial Release
theres some bugs related to crashes, idk what causes them....
2026-03-11 21:40:17 +01:00

246 lines
7.1 KiB
C++

#include "CurlHook.h"
#include "HookManager.h"
#include "../vendor/cURL/curl.h"
#include "../Network/UriParser.h"
#include "../Core/Config.h"
#include "../Core/Log.h"
#include "../Utilities/StringUtils.h"
#include <Windows.h>
#include <intrin.h>
#include <cstdarg>
#include <cstdio>
#include <string>
#include <cstdint>
namespace Embeddium::CurlHook {
using FnCurlSetOpt = CURLcode(*)(struct Curl_easy*, CURLoption, va_list);
using FnCurlEasySetOpt = CURLcode(*)(struct Curl_easy*, CURLoption, ...);
static FnCurlSetOpt gCurlSetOpt = nullptr;
static FnCurlEasySetOpt gCurlEasySetOpt = nullptr;
static CURLcode ForwardOpt(struct Curl_easy* data, CURLoption tag, ...) {
va_list arg;
va_start(arg, tag);
CURLcode r;
if (gCurlSetOpt) {
r = gCurlSetOpt(data, tag, arg);
} else {
uintptr_t val = va_arg(arg, uintptr_t);
r = gCurlEasySetOpt(data, tag, val);
}
va_end(arg);
return r;
}
static uintptr_t FindPattern(const char* pattern, const char* mask) {
HMODULE hMod = GetModuleHandleA(nullptr);
if (!hMod) return 0;
auto* dos = reinterpret_cast<IMAGE_DOS_HEADER*>(hMod);
auto* nt = reinterpret_cast<IMAGE_NT_HEADERS*>(
reinterpret_cast<uint8_t*>(hMod) + dos->e_lfanew);
uintptr_t base = reinterpret_cast<uintptr_t>(hMod);
uintptr_t size = nt->OptionalHeader.SizeOfImage;
size_t patLen = strlen(mask);
for (uintptr_t i = 0; i < size - patLen; ++i) {
bool found = true;
for (size_t j = 0; j < patLen && found; ++j) {
if (mask[j] == 'x')
found = reinterpret_cast<uint8_t*>(base + i)[j] == static_cast<uint8_t>(pattern[j]);
}
if (found) return base + i;
}
return 0;
}
static uintptr_t SigScan(const char* sig) {
std::string bytes, mask;
const char* p = sig;
while (*p) {
while (*p == ' ') ++p;
if (!*p) break;
if (*p == '?') {
bytes.push_back(0);
mask.push_back('?');
++p;
if (*p == '?') ++p;
} else {
bytes.push_back(static_cast<char>(static_cast<uint8_t>(strtoul(p, nullptr, 16))));
mask.push_back('x');
p += 2;
}
}
return FindPattern(bytes.data(), mask.c_str());
}
static bool ShouldRedirect(const Uri& uri) {
return StringUtils::EndsWith(uri.Host, "ol.epicgames.com")
|| StringUtils::EndsWith(uri.Host, "epicgames.dev")
|| StringUtils::EndsWith(uri.Host, "ol.epicgames.net")
|| StringUtils::EndsWith(uri.Host, ".akamaized.net")
|| StringUtils::EndsWith(uri.Host, "on.epicgames.com")
|| StringUtils::EndsWith(uri.Host, "game-social.epicgames.com")
|| StringUtils::Contains(uri.Host, "superawesome.com")
|| StringUtils::Contains(uri.Host, "ak.epicgames.com");
}
static CURLcode CurlEasySetOptDetour_Impl(struct Curl_easy* data, CURLoption tag, va_list arg)
{
CURLcode result = CURLE_OK;
if (!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
if (tag == CURLOPT_SSL_VERIFYPEER)
{
Log::Debug("CurlHook: CURLOPT_SSL_VERIFYPEER — disabling");
result = ForwardOpt(data, tag, 0L);
Log::Debug("CurlHook: CURLOPT_SSL_VERIFYPEER — ok");
}
else if (tag == CURLOPT_URL)
{
const char* rawUrl = va_arg(arg, const char*);
std::string url = rawUrl ? rawUrl : "";
Uri uri = Uri::Parse(url);
if (ShouldRedirect(uri))
{
std::string redirected = Uri::CreateUri(
Config::kRedirectProtocol,
Config::kRedirectHost,
Config::kRedirectPort,
uri.Path,
uri.QueryString
);
Log::Debug("CurlHook: " + url + " -> " + redirected);
result = ForwardOpt(data, tag, redirected.c_str());
Log::Debug("CurlHook: CURLOPT_URL forward — ok");
}
else
{
Log::Debug("CurlHook: CURLOPT_URL passthrough — " + url);
result = ForwardOpt(data, tag, url.c_str());
}
}
else
{
char dbg[64];
wsprintfA(dbg, "CurlHook: tag=%d forwarding", (int)tag);
Log::Debug(dbg);
if (gCurlSetOpt)
{
result = gCurlSetOpt(data, tag, arg);
}
else
{
uintptr_t val = va_arg(arg, uintptr_t);
result = gCurlEasySetOpt(data, tag, val);
}
wsprintfA(dbg, "CurlHook: tag=%d ok", (int)tag);
Log::Debug(dbg);
}
return result;
}
static CURLcode CurlEasySetOptDetour(struct Curl_easy* data, CURLoption tag, ...)
{
va_list arg;
va_start(arg, tag);
CURLcode result = CURLE_FAILED_INIT;
__try
{
result = CurlEasySetOptDetour_Impl(data, tag, arg);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DWORD code = GetExceptionCode();
char msg[128];
wsprintfA(msg, "CurlHook: CRASH in detour tag=%d code=0x%08X",
(int)tag, (unsigned)code);
Log::Error(msg);
OutputDebugStringA(msg);
}
va_end(arg);
return result;
}
bool Install() {
Log::Debug("CurlHook: scanning for curl_easy_setopt...");
uintptr_t addrEasySetOpt = SigScan(
"89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 "
"48 83 EC 28 48 85 C9 75 08 8D 41 2B 48 83 C4 28 C3 4C");
for (int attempt = 0; attempt < 10 && !addrEasySetOpt; ++attempt) {
Sleep(300);
addrEasySetOpt = SigScan(
"89 54 24 10 4C 89 44 24 18 4C 89 4C 24 20 "
"48 83 EC 28 48 85 C9 75 08 8D 41 2B 48 83 C4 28 C3 4C");
}
if (!addrEasySetOpt) {
Log::Error("CurlHook: curl_easy_setopt not found — redirects disabled");
return false;
}
char hexBuf[24];
wsprintfA(hexBuf, "0x%llX", (unsigned long long)addrEasySetOpt);
Log::Info(std::string("CurlHook: curl_easy_setopt at ") + hexBuf);
uintptr_t addrSetOpt = SigScan(
"48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 "
"33 ED 49 8B F0 48 8B D9");
if (!addrSetOpt)
addrSetOpt = SigScan(
"48 89 5C 24 08 48 89 6C 24 10 56 57 41 56 48 83 EC 50 "
"33 ED 49 8B F0 8B DA 48 8B F9");
if (!addrSetOpt)
addrSetOpt = SigScan(
"48 89 5C 24 ? 55 56 57 41 56 41 57 48 83 EC 50 33 DB "
"49 8B F0 48 8B F9 8B EB 81 FA");
if (addrSetOpt) {
wsprintfA(hexBuf, "0x%llX", (unsigned long long)addrSetOpt);
Log::Info(std::string("CurlHook: curl_setopt (va_list) at ") + hexBuf);
} else {
Log::Warn("CurlHook: curl_setopt (va_list) not found — will use trampoline fallback");
}
gCurlSetOpt = reinterpret_cast<FnCurlSetOpt>(addrSetOpt);
gCurlEasySetOpt = reinterpret_cast<FnCurlEasySetOpt>(addrEasySetOpt);
bool ok = HookManager::Install(
reinterpret_cast<void*>(addrEasySetOpt),
reinterpret_cast<void*>(&CurlEasySetOptDetour),
reinterpret_cast<void**>(&gCurlEasySetOpt));
if (ok)
Log::Info("CurlHook: hook installed");
else
Log::Error("CurlHook: MinHook installation failed");
return ok;
}
} // namespace Embeddium::CurlHook