MCPcopy Create free account
hub / github.com/Selectively11/CloudRedirect / ServiceMethodDirectHook

Function ServiceMethodDirectHook

src/platform/win/cloud_intercept.cpp:1737–1892  ·  view source on GitHub ↗

Vtable slot 4 hook: direct request/response (no CProtoBufMsg wrapper). ClientBeginFileUpload / ClientCommitFileUpload / ClientFileDownload all call slot 4 directly, so handling here avoids the slot-5 deferred queue. Flags layout (int[68]): [0]=routing_appid, [1]=mode, [2]=error_code, [3]=eresult, [4..67]=error_message

Source from the content-addressed store, hash-verified

1735// call slot 4 directly, so handling here avoids the slot-5 deferred queue.
1736// Flags layout (int[68]): [0]=routing_appid, [1]=mode, [2]=error_code, [3]=eresult, [4..67]=error_message
1737static bool __fastcall ServiceMethodDirectHook(void* thisptr, const char* methodName,
1738 void* requestBody, void* responseBody, int* flags) {
1739 HookGuard guard;
1740 if (g_shuttingDown.load(std::memory_order_acquire))
1741 return g_originalSlot4(thisptr, methodName, requestBody, responseBody, flags);
1742
1743 // cloudSaveOnly: drain playtime updates here (no RecvPkt/SendPkt hooks).
1744 if (g_cloudSaveOnly.load(std::memory_order_relaxed))
1745 DrainPlaytimeUpdateQueueOnNetThread();
1746
1747 if (!methodName) {
1748 return g_originalSlot4(thisptr, methodName, requestBody, responseBody, flags);
1749 }
1750
1751 if (g_parentalBypassPlaytime.load() &&
1752 strcmp(methodName, "Parental.GetSignedParentalSettings#1") == 0) {
1753 bool result = g_originalSlot4(thisptr, methodName, requestBody, responseBody, flags);
1754 if (result && responseBody) {
1755 auto respBytes = SerializeBodyToBytes(responseBody);
1756 auto respFields = PB::Parse(respBytes.data(), respBytes.size());
1757 const PB::Field* sf = PB::FindField(respFields, 1);
1758 if (sf && sf->wireType == PB::LengthDelimited && sf->data) {
1759 auto stripped = ParentalBypass::StripPlaytimeRestrictions(sf->data, sf->dataLen);
1760 PB::Writer newResp;
1761 newResp.WriteBytes(1, stripped.data(), stripped.size());
1762 for (const auto& f : respFields) {
1763 if (f.fieldNum == 1) continue;
1764 if (f.wireType == PB::Varint) newResp.WriteVarint(f.fieldNum, f.varintVal);
1765 else if (f.wireType == PB::Fixed64) newResp.WriteFixed64(f.fieldNum, f.varintVal);
1766 else if (f.wireType == PB::LengthDelimited) newResp.WriteBytes(f.fieldNum, f.data, f.dataLen);
1767 }
1768 if (ParseBytesToBody(responseBody, newResp.Data().data(), newResp.Size()))
1769 LOG("[Parental] Stripped restrictions from GetSignedParentalSettings (slot4)");
1770 }
1771 }
1772 return result;
1773 }
1774
1775 // Player.GetUserStats#1 (slot 4, raw bodies). Third-party uses raw schemaFetch flag.
1776 if (strcmp(methodName, StatsHandlers::RPC_GET_USER_STATS) == 0
1777 && (g_cloudSaveOnly.load(std::memory_order_relaxed)
1778 ? MetadataSync::schemaFetch.load(std::memory_order_relaxed)
1779 : MetadataSync::SchemaFetchEnabled())) {
1780 if (requestBody && responseBody && g_serializeToArray) {
1781 auto reqBytes = SerializeBodyToBytes(requestBody);
1782 auto reqFields = PB::Parse(reqBytes.data(), reqBytes.size());
1783 uint32_t appId = 0;
1784 if (auto* f = PB::FindField(reqFields, 2)) appId = (uint32_t)f->varintVal; // appid #2
1785 LOG("[Stats] slot4 GetUserStats seen: app=%u namespace=%d", appId, IsNamespaceApp(appId) ? 1 : 0);
1786 if (appId != 0 && IsNamespaceApp(appId)) {
1787 auto res = StatsHandlers::HandleGetUserStats(appId, reqFields);
1788 if (res.body.Size() > 0 &&
1789 ParseBytesToBody(responseBody, res.body.Data().data(), res.body.Size())) {
1790 if (flags) { flags[2] = 1; flags[3] = res.eresult; }
1791 LOG("[Stats] GetUserStats app=%u handled locally via slot4 (%zu bytes)",
1792 appId, res.body.Size());
1793 return true;
1794 }

Callers

nothing calls this directly

Calls 15

SerializeBodyToBytesFunction · 0.85
FindFieldFunction · 0.85
ParseBytesToBodyFunction · 0.85
SchemaFetchEnabledFunction · 0.85
HandleGetUserStatsFunction · 0.85
ExtractAppIdFunction · 0.85
SpyLogFieldsFunction · 0.85
sizeMethod · 0.80
WriteBytesMethod · 0.80
WriteVarintMethod · 0.80

Tested by

no test coverage detected