From e9d2c431916a710b3cff406718823b0cbc0699c3 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 13 Mar 2026 23:47:57 -0700 Subject: [PATCH] fix(combatlog): validate classic spelllogexecute packed GUIDs --- src/game/game_handler.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 5d3dbec4..77e76d58 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -6411,9 +6411,26 @@ void GameHandler::handlePacket(network::Packet& packet) { // Effect 49 = FEED_PET: uint32 itemEntry // Effect 114= CREATE_ITEM2: uint32 itemEntry (same layout as CREATE_ITEM) const bool exeTbcLike = isClassicLikeExpansion() || isActiveExpansion("tbc"); + const auto hasFullPackedGuid = [&packet]() -> bool { + if (packet.getReadPos() >= packet.getSize()) { + return false; + } + const auto& rawData = packet.getData(); + const uint8_t mask = rawData[packet.getReadPos()]; + size_t guidBytes = 1; + for (int bit = 0; bit < 8; ++bit) { + if ((mask & (1u << bit)) != 0) { + ++guidBytes; + } + } + return packet.getSize() - packet.getReadPos() >= guidBytes; + }; if (packet.getSize() - packet.getReadPos() < (exeTbcLike ? 8u : 1u)) { packet.setReadPos(packet.getSize()); break; } + if (!exeTbcLike && !hasFullPackedGuid()) { + packet.setReadPos(packet.getSize()); break; + } uint64_t exeCaster = exeTbcLike ? packet.readUInt64() : UpdateObjectParser::readPackedGuid(packet); if (packet.getSize() - packet.getReadPos() < 8) { @@ -6432,8 +6449,8 @@ void GameHandler::handlePacket(network::Packet& packet) { if (effectType == 10) { // SPELL_EFFECT_POWER_DRAIN: packed_guid target + uint32 amount + uint32 powerType + float multiplier for (uint32_t li = 0; li < effectLogCount; ++li) { - const size_t guidBytes = exeTbcLike ? 8u : 1u; - if (packet.getSize() - packet.getReadPos() < guidBytes) { + if (packet.getSize() - packet.getReadPos() < (exeTbcLike ? 8u : 1u) + || (!exeTbcLike && !hasFullPackedGuid())) { packet.setReadPos(packet.getSize()); break; } uint64_t drainTarget = exeTbcLike @@ -6457,8 +6474,8 @@ void GameHandler::handlePacket(network::Packet& packet) { } else if (effectType == 11) { // SPELL_EFFECT_HEALTH_LEECH: packed_guid target + uint32 amount + float multiplier for (uint32_t li = 0; li < effectLogCount; ++li) { - const size_t guidBytes = exeTbcLike ? 8u : 1u; - if (packet.getSize() - packet.getReadPos() < guidBytes) { + if (packet.getSize() - packet.getReadPos() < (exeTbcLike ? 8u : 1u) + || (!exeTbcLike && !hasFullPackedGuid())) { packet.setReadPos(packet.getSize()); break; } uint64_t leechTarget = exeTbcLike @@ -6502,8 +6519,8 @@ void GameHandler::handlePacket(network::Packet& packet) { } else if (effectType == 26) { // SPELL_EFFECT_INTERRUPT_CAST: packed_guid target + uint32 interrupted_spell_id for (uint32_t li = 0; li < effectLogCount; ++li) { - const size_t guidBytes = exeTbcLike ? 8u : 1u; - if (packet.getSize() - packet.getReadPos() < guidBytes) { + if (packet.getSize() - packet.getReadPos() < (exeTbcLike ? 8u : 1u) + || (!exeTbcLike && !hasFullPackedGuid())) { packet.setReadPos(packet.getSize()); break; } uint64_t icTarget = exeTbcLike