Inline detour on CUserAppManager::BuildDepotDependency: call original then rewrite manifest IDs for pinned depots in the output vectors.
| 2973 | // Inline detour on CUserAppManager::BuildDepotDependency: call original |
| 2974 | // then rewrite manifest IDs for pinned depots in the output vectors. |
| 2975 | static void PatchDepotVector(__int64 vec, uint32_t appId, |
| 2976 | const std::unordered_map<uint32_t, uint64_t>& depotPins, |
| 2977 | const char* vecName) { |
| 2978 | if (!vec) return; |
| 2979 | |
| 2980 | // Reverse-engineered vector layout (pointer at +0, count at +16, 32-byte |
| 2981 | // entries). SEH-wrap every read and cap the bound for future-proofing. |
| 2982 | uint8_t* arrayBase = nullptr; |
| 2983 | int count = 0; |
| 2984 | if (!ReadVecHeader(vec, &arrayBase, &count)) { |
| 2985 | LOG("[ManifestPin] PatchDepotVector(%s): faulted reading vector header for app %u", |
| 2986 | vecName, appId); |
| 2987 | return; |
| 2988 | } |
| 2989 | |
| 2990 | constexpr int kMaxDepotsPerVec = 4096; |
| 2991 | if (!arrayBase || count <= 0) return; |
| 2992 | if (count > kMaxDepotsPerVec) { |
| 2993 | LOG("[ManifestPin] PatchDepotVector(%s): suspicious count=%d for app %u, skipping", |
| 2994 | vecName, count, appId); |
| 2995 | return; |
| 2996 | } |
| 2997 | |
| 2998 | for (int i = 0; i < count; i++) { |
| 2999 | uint8_t* entry = arrayBase + static_cast<size_t>(i) * 32; |
| 3000 | uint32_t depotId = 0; |
| 3001 | uint64_t oldManifest = 0; |
| 3002 | bool patched = false; |
| 3003 | |
| 3004 | // First read just the depot ID to look up the pin |
| 3005 | if (!PatchDepotEntry(entry, &depotId, 0, &oldManifest, &patched)) { |
| 3006 | LOG("[ManifestPin] PatchDepotVector(%s): faulted reading depot at index %d for app %u", |
| 3007 | vecName, i, appId); |
| 3008 | return; |
| 3009 | } |
| 3010 | |
| 3011 | auto pinIt = depotPins.find(depotId); |
| 3012 | if (pinIt != depotPins.end()) { |
| 3013 | uint64_t pinManifest = pinIt->second; |
| 3014 | if (!PatchDepotEntry(entry, &depotId, pinManifest, &oldManifest, &patched)) { |
| 3015 | LOG("[ManifestPin] PatchDepotVector(%s): faulted patching depot %u for app %u", |
| 3016 | vecName, depotId, appId); |
| 3017 | return; |
| 3018 | } |
| 3019 | if (patched) { |
| 3020 | LOG("[ManifestPin] app %u depot %u (%s): manifest %llu -> %llu", |
| 3021 | appId, depotId, vecName, oldManifest, pinManifest); |
| 3022 | } |
| 3023 | } |
| 3024 | } |
| 3025 | } |
| 3026 | |
| 3027 | static __int64 __fastcall BuildDepotDependencyHook(__int64* a1, unsigned int a2, __int64 a3, |
| 3028 | __int64 a4, __int64 a5, __int64 a6, |
no test coverage detected