diff --git a/Kiseki.Patcher/Header/Globals.hpp b/Kiseki.Patcher/Header/Globals.hpp index a7956ac..638eeb1 100644 --- a/Kiseki.Patcher/Header/Globals.hpp +++ b/Kiseki.Patcher/Header/Globals.hpp @@ -11,6 +11,7 @@ #define PUBLIC_KEY 0x06, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xA5, 0x11, 0xD0, 0x9F, 0xAB, 0x9B, 0x3A, 0x96, 0xC5, 0xBE, 0x50, 0xBB, 0xCA, 0x0C, 0xBB, 0xC8, 0x1A, 0x9C, 0xC1, 0x2F, 0x22, 0x7A, 0x80, 0x2C, 0x31, 0x01, 0xE1, 0x21, 0xC2, 0x7F, 0xE0, 0x10, 0xA1, 0x2D, 0x09, 0xED, 0x10, 0x3E, 0x28, 0xB9, 0xBD, 0x0F, 0x38, 0xDB, 0x52, 0x78, 0xC0, 0xEC, 0x04, 0xD4, 0x00, 0xAD, 0x45, 0xD3, 0xC7, 0x78, 0xF2, 0x83, 0xB5, 0x5B, 0x16, 0x0C, 0x32, 0x5D, 0xB3, 0x3B, 0xDA, 0xA2, 0x9C, 0x73, 0xB2, 0x0C, 0x09, 0x93, 0xD8, 0xF8, 0xD9, 0xC5, 0x75, 0xAB, 0x33, 0x19, 0xD3, 0x6A, 0xAF, 0x20, 0x21, 0x6C, 0x78, 0x31, 0x41, 0xD1, 0xCD, 0x6D, 0x4D, 0xA1, 0x6D, 0x49, 0x3A, 0x6A, 0x33, 0x10, 0x6D, 0x52, 0x33, 0x4A, 0x10, 0x32, 0x3D, 0x42, 0xE6, 0xEC, 0x38, 0x97, 0x2F, 0x05, 0x41, 0xDD, 0xD6, 0xB6, 0xAC, 0x17, 0x4B, 0x7E, 0xFA, 0xFE, 0xA4, 0xD2 +#define ADDRESS_HTTP__HTTPGETPOSTWININET 0x006F03B0 #define ADDRESS_HTTP__TRUSTCHECK 0x005B7050 #define ADDRESS_CRYPT__VERIFYSIGNATUREBASE64 0x00809EC0 #define ADDRESS_STANDARDOUT__PRINT 0x005B25E0 diff --git a/Kiseki.Patcher/Header/Hooks/Http.hpp b/Kiseki.Patcher/Header/Hooks/Http.hpp index 068826b..f886c82 100644 --- a/Kiseki.Patcher/Header/Hooks/Http.hpp +++ b/Kiseki.Patcher/Header/Hooks/Http.hpp @@ -3,12 +3,30 @@ #include #include +#include + +#ifdef SERVER +#include "Hooks/StandardOut.hpp" +#endif #include "Globals.hpp" #include "Helpers.hpp" +struct Http +{ +#if PADDING_STRUCT != 0 + void* padding1[1]; +#endif + std::string alternateUrl; + void* padding2[3 + PADDING_STRUCT]; + std::string url; +}; + +typedef void (__thiscall* Http__httpGetPostWinInet_t)(Http* _this, bool isPost, int a3, bool compressData, LPCSTR additionalHeaders, int a6); typedef bool(__thiscall* Http__trustCheck_t)(const char* url); +void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, int a3, bool compressData, LPCSTR additionalHeaders, int a6); bool __fastcall Http__trustCheck_hook(const char* url); +extern Http__httpGetPostWinInet_t Http__httpGetPostWinInet; extern Http__trustCheck_t Http__trustCheck; \ No newline at end of file diff --git a/Kiseki.Patcher/Source/Hooks/Http.cpp b/Kiseki.Patcher/Source/Hooks/Http.cpp index 0f976b2..38a094e 100644 --- a/Kiseki.Patcher/Source/Hooks/Http.cpp +++ b/Kiseki.Patcher/Source/Hooks/Http.cpp @@ -1,7 +1,95 @@ #include "Hooks/Http.hpp" +#define CHECK(condition, code) \ + if(!error) { \ + if ((condition)) { \ + error = code; \ + } \ + } + +Http__httpGetPostWinInet_t Http__httpGetPostWinInet = (Http__httpGetPostWinInet_t)ADDRESS_HTTP__HTTPGETPOSTWININET; Http__trustCheck_t Http__trustCheck = (Http__trustCheck_t)ADDRESS_HTTP__TRUSTCHECK; +void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, int a3, bool compressData, LPCSTR additionalHeaders, int a6) +{ + std::pair> parsed = Helpers::parseURL(_this->url); + Http _changed = *_this; + + if (parsed.first) + { + std::map url = parsed.second; + + if (!url["path"].empty() && !url["host"].empty() && !url["query"].empty()) + { + url["path"] = Helpers::toLower(url["path"]); + + if (url["host"] == "roblox.com" || url["host"] == "www.roblox.com") + { + if (url["path"] == "/asset" || url["path"] == "/asset/" || url["path"] == "/asset/default.ashx") + { + _changed.url = "https://assetdelivery.roblox.com/v1/asset/?" + url["query"]; + _this = &_changed; + } + else if (url["path"] == "/thumbs/asset.ashx" || url["path"] == "/thumbs/avatar.ashx") + { + std::string api = "https://www.roblox.com/" + std::string(url["path"] == "/thumbs/asset.ashx" ? "asset" : "avatar") + "/request-thumbnail-fix"; + + std::map source = Helpers::parseQueryString(url["query"]); + std::map fixed = { + { url["path"] == "/thumbs/asset.ashx" ? "overrideModeration" : "dummy", "false" }, + { "thumbnailFormatId", "0" } + }; + + for (auto& pair : source) + { + fixed[Helpers::toLower(pair.first)] = pair.second; + } + + if (fixed.find("id") != fixed.end()) + { + auto handler = fixed.extract("id"); + handler.key() = url["path"] == "/thumbs/asset.ashx" ? "assetId" : "userId"; + + fixed.insert(std::move(handler)); + } + + api += Helpers::joinQueryString(fixed); + + // Get the API response + std::pair response = Helpers::httpGet(api); + if (!response.first) + { + throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x0"); + } + + std::string data = response.second; + + rapidjson::Document document; + document.Parse(data.c_str()); + + int error = 0; + + CHECK(document.HasParseError(), 0x01); + CHECK(!document.HasMember("d"), 0x02); + CHECK(!document["d"].IsObject(), 0x03); + CHECK(!document["d"].HasMember("url"), 0x04); + CHECK(!document["d"]["url"].IsString(), 0x05); + + if (error != 0) + { + throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x0" + std::to_string(error)); + } + + _changed.url = document["d"]["url"].GetString(); + _this = &_changed; + } + } + } + } + + Http__httpGetPostWinInet(_this, isPost, a3, compressData, additionalHeaders, a6); +} + bool __fastcall Http__trustCheck_hook(const char* url) { if (strlen(url) == 7 && !Helpers::isASCII(url))