From 809cfcb2999b891b1370b427ea18fb12fff20e2e Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 7 Jan 2020 20:08:51 +0800 Subject: [PATCH] LoginPacket done. --- .../network/QQAndroidBotNetworkHandler.kt | 6 +- .../qqandroid/network/QQAndroidClient.kt | 2 + .../protocol/packet/OutgoingPacketAndroid.kt | 10 +-- .../network/protocol/packet/PacketFactory.kt | 67 ++++++++++++++----- 4 files changed, 59 insertions(+), 26 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 7d0f37f91..3696242dd 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -54,12 +54,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } launch(CoroutineName("Incoming Packet handler")) { - rawInput.debugPrint("Received").use { - if (it.remaining == 0L) { + rawInput.debugPrint("Received").use { input -> + if (input.remaining == 0L) { bot.logger.error("Empty packet received. Consider if bad packet was sent.") return@launch } - KnownPacketFactories.parseIncomingPacket(bot, rawInput) { packet: Packet, packetId: PacketId, sequenceId: Int -> + KnownPacketFactories.parseIncomingPacket(bot, input) { packet: Packet, packetId: PacketId, sequenceId: Int -> if (PacketReceivedEvent(packet).broadcast().cancelled) { return@parseIncomingPacket } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt index a4deec7f6..cef4eee2b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt @@ -49,6 +49,8 @@ internal open class QQAndroidClient( val apkVersionName: ByteArray = "8.2.0".toByteArray() + var loginState = 0 + val appClientVersion: Int = 0 var networkType: NetworkType = NetworkType.WIFI diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt index 7d5976bd2..95e8d3774 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt @@ -257,16 +257,16 @@ internal interface EncryptMethodECDH : EncryptMethod { writeFully(ByteArray(16)) writeShort(258) // const - writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) + // writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) - /*writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { + writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { it.toUHexString().debugPrint("PUBLIC KEY") check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } - })*/ + }) - encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) - //encryptAndWrite(ecdh.keyPair.shareKey, body) + // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) + encryptAndWrite(ecdh.keyPair.shareKey, body) } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index b0abb665b..e1e404945 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -4,8 +4,10 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.IoBuffer import kotlinx.io.core.discardExact import kotlinx.io.core.readBytes +import kotlinx.io.pool.useInstance import net.mamoe.mirai.data.Packet import net.mamoe.mirai.qqandroid.QQAndroidBot +import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.NullPacketId import net.mamoe.mirai.qqandroid.network.protocol.packet.login.NullPacketId.commandName import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId @@ -16,6 +18,7 @@ import net.mamoe.mirai.utils.cryptor.decryptBy import net.mamoe.mirai.utils.io.* import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract +import kotlin.jvm.JvmName /** * 一种数据包的处理工厂. 它可以解密解码服务器发来的这个包, 也可以编码加密要发送给服务器的这个包 @@ -41,11 +44,20 @@ internal abstract class PacketFactory PacketFactory.decode(bot: QQAndroidBot, packet: ByteReadPacket): P { + return this.run { + packet.decode(bot) + } +} + private val DECRYPTER_16_ZERO = ByteArray(16) internal typealias PacketConsumer = suspend (packet: Packet, packetId: PacketId, ssoSequenceId: Int) -> Unit -internal object KnownPacketFactories : List> by mutableListOf() { +internal object KnownPacketFactories : List> by mutableListOf( + LoginPacket +) { fun findPacketFactory(commandName: String): PacketFactory<*, *> = this.first { it.id.commandName == commandName } @@ -61,9 +73,6 @@ internal object KnownPacketFactories : List> by mutableListO when (val flag1 = readInt()) { 0x0A -> when (val flag2 = readByte().toInt()) { 0x02 -> { - val extraData = readIoBuffer(readInt() - 4).debugCopyUse { - this.debugPrint("Extra data") - } val flag3 = readByte().toInt() check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } @@ -90,33 +99,55 @@ internal object KnownPacketFactories : List> by mutableListO commandName = readString(readInt() - 4) val unknown = readBytes(readInt() - 4) - if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: $unknown") + if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}") check(readInt() == 0) } + bot.logger.verbose(commandName) val packetFactory = findPacketFactory(commandName) val qq: Long val subCommandId: Int readIoBuffer(readInt() - 4).withUse { check(readByte().toInt() == 2) - discardExact(2) // 27 + 2 + body.size - discardExact(2) // const, =8001 - readShort() // commandId - readShort() // innerSequenceId - qq = readInt().toLong() + this.discardExact(2) // 27 + 2 + body.size + this.discardExact(2) // const, =8001 + this.readShort() // commandId + this.readShort() // const, =0x0001 + qq = this.readInt().toLong() + val encryptionMethod = this.readShort().toInt() - discardExact(1) // const = 0 - val packet = when (val encryptionMethod = readByte().toInt()) { + this.discardExact(1) // const = 0 + val packet = when (encryptionMethod) { 4 -> { // peer public key, ECDH - packetFactory.run { - bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey()).read { - decode(bot) - } - } + var data = this.decryptBy(bot.client.ecdh.keyPair.shareKey, this.readRemaining - 1) + + val peerShareKey = bot.client.ecdh.calculateShareKeyByPeerPublicKey(readUShortLVByteArray().adjustToPublicKey()) + data = data.decryptBy(peerShareKey) + + packetFactory.decode(bot, data.toReadPacket()) } - else -> error("Illegal encryption method. expected 4, got $encryptionMethod") + 0 -> { + val data = if (bot.client.loginState == 0) { + ByteArrayPool.useInstance { byteArrayBuffer -> + val size = this.readRemaining - 1 + this.readFully(byteArrayBuffer, 0, size) + + runCatching { + byteArrayBuffer.decryptBy(bot.client.ecdh.keyPair.shareKey, size) + }.getOrElse { + byteArrayBuffer.decryptBy(bot.client.tgtgtKey, size) + } // 这里实际上应该用 privateKey(另一个random出来的key) + } + } else { + this.decryptBy(bot.client.tgtgtKey, 0, this.readRemaining - 1) + } + + packetFactory.decode(bot, data.toReadPacket()) + + } + else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod") } consumer(packet, packetFactory.id, ssoSequenceId)