From 4d251a2a3a799ebbe7f8b610b66a9c2873f2cb5a Mon Sep 17 00:00:00 2001 From: sandtechnology Date: Sun, 22 Jan 2023 03:22:21 +0800 Subject: [PATCH 1/5] Handle rare case on packet pipeline Fix #2449, should help #1603 --- .../kotlin/network/components/PacketCodec.kt | 121 +++++++++++------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index dd9fc306ddc..d8007cb838b 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -119,7 +119,15 @@ internal class PacketCodecImpl : PacketCodec { when (flag2) { 2 -> TEA.decrypt(buffer, DECRYPTER_16_ZERO, size) - 1 -> TEA.decrypt(buffer, client.wLoginSigInfo.d2Key, size) + 1 -> { + TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse { + throw PacketCodecException( + "Received packet needed d2Key to decrypt but d2Key doesn't existed, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose if you see anything abnormal", + OTHER + ) + }, size) + } + 0 -> buffer else -> throw PacketCodecException("Unknown flag2=$flag2", PROTOCOL_UPDATED) }.let { decryptedData -> @@ -139,7 +147,7 @@ internal class PacketCodecImpl : PacketCodec { raw.sequenceId, raw.body.withUse { try { - parseOicqResponse(client) + parseOicqResponse(client, raw.commandName) } catch (e: Throwable) { throw PacketCodecException(e, PacketCodecException.Kind.OTHER) } @@ -242,60 +250,83 @@ internal class PacketCodecImpl : PacketCodec { private fun ByteReadPacket.parseOicqResponse( client: SsoSession, + commandName: String ): ByteArray { - readByte().toInt().let { - check(it == 2) { "$it" } - } - this.discardExact(2) - this.discardExact(2) - this.readUShort() - this.readShort() - this.readUInt().toLong() - val encryptionMethod = this.readUShort().toInt() + val qqEcdh = (client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh() + fun decrypt(encryptionMethod: Int): ByteArray { + return when (encryptionMethod) { + 4 -> { + val size = (this.remaining - 1).toInt() + val data = + TEA.decrypt( + this.readBytes(), + qqEcdh.initialQQShareKey, + length = size + ) - this.discardExact(1) - val qqEcdh = - (client as QQAndroidClient).bot.components[EcdhInitialPublicKeyUpdater].getQQEcdh() - return when (encryptionMethod) { - 4 -> { - val size = (this.remaining - 1).toInt() - val data = + val peerShareKey = + qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray())) + TEA.decrypt(data, peerShareKey) + } + + 3 -> { + val size = (this.remaining - 1).toInt() + // session TEA.decrypt( this.readBytes(), - qqEcdh.initialQQShareKey, + client.wLoginSigInfo.wtSessionTicketKey, length = size ) + } - val peerShareKey = - qqEcdh.calculateQQShareKey(Ecdh.Instance.importPublicKey(readUShortLVByteArray())) - TEA.decrypt(data, peerShareKey) - } - 3 -> { - val size = (this.remaining - 1).toInt() - // session - TEA.decrypt( - this.readBytes(), - client.wLoginSigInfo.wtSessionTicketKey, - length = size - ) - } - 0 -> { - if (client.loginState == 0) { - val size = (this.remaining - 1).toInt() - val byteArrayBuffer = this.readBytes(size) - - runCatching { - TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size) - }.getOrElse { - TEA.decrypt(byteArrayBuffer, client.randomKey, length = size) + 0 -> { + if (client.loginState == 0) { + val size = (this.remaining - 1).toInt() + val byteArrayBuffer = this.readBytes(size) + + runCatching { + TEA.decrypt(byteArrayBuffer, qqEcdh.initialQQShareKey, length = size) + }.getOrElse { + TEA.decrypt(byteArrayBuffer, client.randomKey, length = size) + } + } else { + val size = (this.remaining - 1).toInt() + TEA.decrypt(this.readBytes(), client.randomKey, length = size) } - } else { - val size = (this.remaining - 1).toInt() - TEA.decrypt(this.readBytes(), client.randomKey, length = size) } + + else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod") + } + } + readByte().toInt().let { + if (it != 2) { + val fullPacketDump = copy().readBytes().toUHexString() + var decryptedData: String? = null; + if (remaining > 15) { + discardExact(12) + val encryptionMethod = this.readUShort().toInt() + discardExact(1) + decryptedData = kotlin.runCatching { + decrypt(encryptionMethod).toUHexString() + }.getOrNull() + } + throw PacketCodecException( + "Received unknown oicq packet type = $it, command name=$commandName, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose, \n" + + "Full packet dump: $fullPacketDump" + + "Decrypted data: $decryptedData", + OTHER + ) } - else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod") } + this.discardExact(2) + this.discardExact(2) + this.readUShort() + this.readShort() + this.readUInt().toLong() + val encryptionMethod = this.readUShort().toInt() + + this.discardExact(1) + return decrypt(encryptionMethod); } /** From 1a147704ff9dbe32c6930225548cfabfbd3b6151 Mon Sep 17 00:00:00 2001 From: sandtechnology Date: Mon, 23 Jan 2023 23:08:00 +0800 Subject: [PATCH 2/5] Fix and improve tips and improve the readability of code --- .../kotlin/network/components/PacketCodec.kt | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index d8007cb838b..ebfd595ec26 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -298,26 +298,28 @@ internal class PacketCodecImpl : PacketCodec { else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod") } } - readByte().toInt().let { - if (it != 2) { - val fullPacketDump = copy().readBytes().toUHexString() - var decryptedData: String? = null; - if (remaining > 15) { - discardExact(12) - val encryptionMethod = this.readUShort().toInt() - discardExact(1) - decryptedData = kotlin.runCatching { - decrypt(encryptionMethod).toUHexString() - }.getOrNull() - } + + val packetType = readByte().toInt(); + if (packetType != 2) { + val fullPacketDump = copy().readBytes().toUHexString() + var decryptedData: String? = null; + if (remaining > 15) { + discardExact(12) + val encryptionMethod = this.readUShort().toInt() + discardExact(1) + decryptedData = kotlin.runCatching { + decrypt(encryptionMethod).toUHexString() + }.getOrNull() + } throw PacketCodecException( - "Received unknown oicq packet type = $it, command name=$commandName, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose, \n" + - "Full packet dump: $fullPacketDump" + - "Decrypted data: $decryptedData", - OTHER + "Received unknown oicq packet type = $packetType, command name = $commandName, ignoring..." + + "\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" + + "Full packet dump: $fullPacketDump\n" + + "Decrypted data (Do not provide it if you haven't change password!!!): $decryptedData", + PROTOCOL_UPDATED ) - } } + this.discardExact(2) this.discardExact(2) this.readUShort() From 409be41760c3f7dc937625ec1ad141d9fe59d492 Mon Sep 17 00:00:00 2001 From: sandtechnology <20417547+sandtechnology@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:47:09 +0800 Subject: [PATCH 3/5] Improve wording of tips Co-authored-by: Him188 --- .../src/commonMain/kotlin/network/components/PacketCodec.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index ebfd595ec26..85144928578 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -315,7 +315,7 @@ internal class PacketCodecImpl : PacketCodec { "Received unknown oicq packet type = $packetType, command name = $commandName, ignoring..." + "\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" + "Full packet dump: $fullPacketDump\n" + - "Decrypted data (Do not provide it if you haven't change password!!!): $decryptedData", + "Decrypted data (contains your encrypted password, please change your password after reporting issue): $decryptedData", PROTOCOL_UPDATED ) } From f1d825444586625468faf0c9bb8afe239d58152e Mon Sep 17 00:00:00 2001 From: sandtechnology <20417547+sandtechnology@users.noreply.github.com> Date: Sun, 19 Feb 2023 13:49:16 +0800 Subject: [PATCH 4/5] Change d2Key error type to PROTOCOL_UPDATED --- .../src/commonMain/kotlin/network/components/PacketCodec.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index 85144928578..8fdd8f383ee 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -123,7 +123,7 @@ internal class PacketCodecImpl : PacketCodec { TEA.decrypt(buffer, kotlin.runCatching { client.wLoginSigInfo.d2Key }.getOrElse { throw PacketCodecException( "Received packet needed d2Key to decrypt but d2Key doesn't existed, ignoring. Please report to https://github.com/mamoe/mirai/issues/new/choose if you see anything abnormal", - OTHER + PROTOCOL_UPDATED ) }, size) } @@ -367,4 +367,4 @@ internal class RawIncomingPacket constructor( * Can be passed to [PacketFactory] */ val body: ByteArray, -) \ No newline at end of file +) From f4edbef338373a4095a2eefefd7550ab1cb66247 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 1 Mar 2023 18:18:27 +0000 Subject: [PATCH 5/5] Reformat code --- .../kotlin/network/components/PacketCodec.kt | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt index 8fdd8f383ee..287d98dbc0e 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/PacketCodec.kt @@ -153,6 +153,7 @@ internal class PacketCodecImpl : PacketCodec { } } ) + else -> error("unreachable") } } @@ -228,6 +229,7 @@ internal class PacketCodecImpl : PacketCodec { } } } + 1 -> { input.discardExact(4) input.inflateAllAvailable().let { bytes -> @@ -239,6 +241,7 @@ internal class PacketCodecImpl : PacketCodec { } } } + 8 -> input else -> throw PacketCodecException("Unknown dataCompressed flag: $dataCompressed", PROTOCOL_UPDATED) } @@ -299,10 +302,10 @@ internal class PacketCodecImpl : PacketCodec { } } - val packetType = readByte().toInt(); + val packetType = readByte().toInt() if (packetType != 2) { val fullPacketDump = copy().readBytes().toUHexString() - var decryptedData: String? = null; + var decryptedData: String? = null if (remaining > 15) { discardExact(12) val encryptionMethod = this.readUShort().toInt() @@ -311,13 +314,13 @@ internal class PacketCodecImpl : PacketCodec { decrypt(encryptionMethod).toUHexString() }.getOrNull() } - throw PacketCodecException( - "Received unknown oicq packet type = $packetType, command name = $commandName, ignoring..." + - "\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" + - "Full packet dump: $fullPacketDump\n" + - "Decrypted data (contains your encrypted password, please change your password after reporting issue): $decryptedData", - PROTOCOL_UPDATED - ) + throw PacketCodecException( + "Received unknown oicq packet type = $packetType, command name = $commandName, ignoring..." + + "\nPlease report this message to https://github.com/mamoe/mirai/issues/new/choose, \n" + + "Full packet dump: $fullPacketDump\n" + + "Decrypted data (contains your encrypted password, please change your password after reporting issue): $decryptedData", + PROTOCOL_UPDATED + ) } this.discardExact(2) @@ -328,7 +331,7 @@ internal class PacketCodecImpl : PacketCodec { val encryptionMethod = this.readUShort().toInt() this.discardExact(1) - return decrypt(encryptionMethod); + return decrypt(encryptionMethod) } /**