diff --git a/src/game/packet_parsers_classic.cpp b/src/game/packet_parsers_classic.cpp index 54fb7f95..1e801b6b 100644 --- a/src/game/packet_parsers_classic.cpp +++ b/src/game/packet_parsers_classic.cpp @@ -414,8 +414,12 @@ bool ClassicPacketParsers::parseSpellGo(network::Packet& packet, SpellGoData& da data.spellId = packet.readUInt32(); data.castFlags = packet.readUInt16(); // uint16 in Vanilla (uint32 in TBC/WotLK) - // Hit targets - if (rem() < 1) return true; + // hitCount is mandatory in SMSG_SPELL_GO. Missing byte means truncation. + if (rem() < 1) { + LOG_WARNING("[Classic] Spell go: missing hitCount after fixed fields"); + packet.setReadPos(startPos); + return false; + } const uint8_t rawHitCount = packet.readUInt8(); if (rawHitCount > 128) { LOG_WARNING("[Classic] Spell go: hitCount capped (requested=", (int)rawHitCount, ")"); @@ -441,8 +445,12 @@ bool ClassicPacketParsers::parseSpellGo(network::Packet& packet, SpellGoData& da } data.hitCount = static_cast(data.hitTargets.size()); - // Miss targets - if (rem() < 1) return true; + // missCount is mandatory in SMSG_SPELL_GO. Missing byte means truncation. + if (rem() < 1) { + LOG_WARNING("[Classic] Spell go: missing missCount after hit target list"); + packet.setReadPos(startPos); + return false; + } const uint8_t rawMissCount = packet.readUInt8(); if (rawMissCount > 128) { LOG_WARNING("[Classic] Spell go: missCount capped (requested=", (int)rawMissCount, ")"); diff --git a/src/game/packet_parsers_tbc.cpp b/src/game/packet_parsers_tbc.cpp index 16f1ffed..ca36930a 100644 --- a/src/game/packet_parsers_tbc.cpp +++ b/src/game/packet_parsers_tbc.cpp @@ -1277,8 +1277,9 @@ bool TbcPacketParsers::parseSpellGo(network::Packet& packet, SpellGoData& data) // NOTE: NO timestamp field here in TBC (WotLK added packet.readUInt32()) if (packet.getReadPos() >= packet.getSize()) { - LOG_DEBUG("[TBC] Spell go: spell=", data.spellId, " (no hit data)"); - return true; + LOG_WARNING("[TBC] Spell go: missing hitCount after fixed fields"); + packet.setReadPos(startPos); + return false; } const uint8_t rawHitCount = packet.readUInt8(); @@ -1306,43 +1307,47 @@ bool TbcPacketParsers::parseSpellGo(network::Packet& packet, SpellGoData& data) } data.hitCount = static_cast(data.hitTargets.size()); - if (packet.getReadPos() < packet.getSize()) { - const uint8_t rawMissCount = packet.readUInt8(); - if (rawMissCount > 128) { - LOG_WARNING("[TBC] Spell go: missCount capped (requested=", (int)rawMissCount, ")"); + if (packet.getReadPos() >= packet.getSize()) { + LOG_WARNING("[TBC] Spell go: missing missCount after hit target list"); + packet.setReadPos(startPos); + return false; + } + + const uint8_t rawMissCount = packet.readUInt8(); + if (rawMissCount > 128) { + LOG_WARNING("[TBC] Spell go: missCount capped (requested=", (int)rawMissCount, ")"); + } + const uint8_t storedMissLimit = std::min(rawMissCount, 128); + data.missTargets.reserve(storedMissLimit); + for (uint16_t i = 0; i < rawMissCount; ++i) { + if (packet.getReadPos() + 9 > packet.getSize()) { + LOG_WARNING("[TBC] Spell go: truncated miss targets at index ", i, + "/", (int)rawMissCount); + truncatedTargets = true; + break; } - const uint8_t storedMissLimit = std::min(rawMissCount, 128); - data.missTargets.reserve(storedMissLimit); - for (uint16_t i = 0; i < rawMissCount; ++i) { - if (packet.getReadPos() + 9 > packet.getSize()) { - LOG_WARNING("[TBC] Spell go: truncated miss targets at index ", i, + SpellGoMissEntry m; + m.targetGuid = packet.readUInt64(); // full GUID in TBC + m.missType = packet.readUInt8(); + if (m.missType == 11) { + if (packet.getReadPos() + 5 > packet.getSize()) { + LOG_WARNING("[TBC] Spell go: truncated reflect payload at miss index ", i, "/", (int)rawMissCount); truncatedTargets = true; break; } - SpellGoMissEntry m; - m.targetGuid = packet.readUInt64(); // full GUID in TBC - m.missType = packet.readUInt8(); - if (m.missType == 11) { - if (packet.getReadPos() + 5 > packet.getSize()) { - LOG_WARNING("[TBC] Spell go: truncated reflect payload at miss index ", i, - "/", (int)rawMissCount); - truncatedTargets = true; - break; - } - (void)packet.readUInt32(); - (void)packet.readUInt8(); - } - if (i < storedMissLimit) { - data.missTargets.push_back(m); - } + (void)packet.readUInt32(); + (void)packet.readUInt8(); } - if (truncatedTargets) { - packet.setReadPos(startPos); - return false; + if (i < storedMissLimit) { + data.missTargets.push_back(m); } - data.missCount = static_cast(data.missTargets.size()); } + if (truncatedTargets) { + packet.setReadPos(startPos); + return false; + } + data.missCount = static_cast(data.missTargets.size()); LOG_DEBUG("[TBC] Spell go: spell=", data.spellId, " hits=", (int)data.hitCount, " misses=", (int)data.missCount); diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index f057f90b..5a23e1c9 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -3782,9 +3782,11 @@ bool SpellGoParser::parse(network::Packet& packet, SpellGoData& data) { } data.hitCount = static_cast(data.hitTargets.size()); - // Validate missCount field exists + // missCount is mandatory in SMSG_SPELL_GO. Missing byte means truncation. if (packet.getSize() - packet.getReadPos() < 1) { - return true; // Valid, just no misses + LOG_WARNING("Spell go: missing missCount after hit target list"); + packet.setReadPos(startPos); + return false; } const uint8_t rawMissCount = packet.readUInt8();