Process a single queued injection (called on the network thread from RecvPktMonitorHook)
| 1207 | |
| 1208 | // Process a single queued injection (called on the network thread from RecvPktMonitorHook) |
| 1209 | static void ProcessQueuedInjection(QueuedInjection* ctx) { |
| 1210 | LOG("[INJECT] Processing queued inject: %s (pkt=%u bytes, jobid=%llu)", |
| 1211 | ctx->methodName, ctx->pktSize, ctx->jobIdTarget); |
| 1212 | |
| 1213 | if (!g_wrapPacket || !g_bRouteMsgToJob || !g_releaseWrapped) { |
| 1214 | LOG("[INJECT] FATAL: BRouteMsgToJob bypass not resolved"); |
| 1215 | VirtualFree(ctx->pktBuf, 0, MEM_RELEASE); |
| 1216 | free(ctx->pktStruct); |
| 1217 | delete ctx; |
| 1218 | return; |
| 1219 | } |
| 1220 | |
| 1221 | // WrapPacket takes ownership via refcount; caller frees on failure. |
| 1222 | void* wrappedPkt = nullptr; |
| 1223 | __try { |
| 1224 | wrappedPkt = g_wrapPacket(ctx->pktStruct, 1); |
| 1225 | } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 1226 | LOG("[INJECT] EXCEPTION in WrapPacket: code=0x%08X", GetExceptionCode()); |
| 1227 | VirtualFree(ctx->pktBuf, 0, MEM_RELEASE); |
| 1228 | free(ctx->pktStruct); |
| 1229 | delete ctx; |
| 1230 | return; |
| 1231 | } |
| 1232 | |
| 1233 | if (!wrappedPkt) { |
| 1234 | LOG("[INJECT] WrapPacket returned NULL -- packet validation failed"); |
| 1235 | VirtualFree(ctx->pktBuf, 0, MEM_RELEASE); |
| 1236 | free(ctx->pktStruct); |
| 1237 | delete ctx; |
| 1238 | return; |
| 1239 | } |
| 1240 | |
| 1241 | // SEH-wrap vtable + slot reads on the Steam-internal wrapped packet. |
| 1242 | using GetEMsgFn = unsigned int(__fastcall*)(void* self); |
| 1243 | unsigned int wrappedEmsg = 0; |
| 1244 | __try { |
| 1245 | uintptr_t wrappedVtable = *(uintptr_t*)wrappedPkt; |
| 1246 | GetEMsgFn getEMsg = (GetEMsgFn)(*(uintptr_t*)(wrappedVtable + 0x40)); |
| 1247 | wrappedEmsg = getEMsg(wrappedPkt); |
| 1248 | LOG("[INJECT] wrappedPkt=%p GetEMsg()=%u (expected %u)", |
| 1249 | wrappedPkt, wrappedEmsg, (unsigned)EMSG_SERVICE_METHOD_RESP); |
| 1250 | } __except(EXCEPTION_EXECUTE_HANDLER) { |
| 1251 | LOG("[INJECT] EXCEPTION in GetEMsg: code=0x%08X", GetExceptionCode()); |
| 1252 | __try { g_releaseWrapped(wrappedPkt); } __except(EXCEPTION_EXECUTE_HANDLER) {} |
| 1253 | VirtualFree(ctx->pktBuf, 0, MEM_RELEASE); |
| 1254 | delete ctx; |
| 1255 | return; |
| 1256 | } |
| 1257 | |
| 1258 | // Get CJobMgr and connection context (SEH-protected like FindCCMInterface) |
| 1259 | void* jobMgr = nullptr; |
| 1260 | void* connCtx = nullptr; |
| 1261 | __try { |
| 1262 | uintptr_t* pEngineGlobal = (uintptr_t*)SC_RESOLVE(globalEngine); |
| 1263 | uintptr_t engine = *pEngineGlobal; |
| 1264 | jobMgr = (void*)(engine + ENGINE_OFF_JOBMGR); |
| 1265 | connCtx = *(void**)((uintptr_t)g_cmInterface.load(std::memory_order_acquire) + CCM_OFF_CONN_CONTEXT); |
| 1266 | } __except(EXCEPTION_EXECUTE_HANDLER) { |
no test coverage detected