Him188 6 лет назад
Родитель
Сommit
809cfcb299

+ 3 - 3
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
                         }

+ 2 - 0
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

+ 5 - 5
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)
     }
 }
 

+ 48 - 17
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<out TPacket : Packet, TDecrypter : Decrypt
     abstract suspend fun ByteReadPacket.decode(bot: QQAndroidBot): TPacket
 }
 
+@JvmName("decode0")
+private suspend inline fun <P : Packet> PacketFactory<P, *>.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<PacketFactory<*, *>> by mutableListOf() {
+internal object KnownPacketFactories : List<PacketFactory<*, *>> by mutableListOf(
+    LoginPacket
+) {
 
     fun findPacketFactory(commandName: String): PacketFactory<*, *> = this.first { it.id.commandName == commandName }
 
@@ -61,9 +73,6 @@ internal object KnownPacketFactories : List<PacketFactory<*, *>> 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<PacketFactory<*, *>> 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()
-
-                discardExact(1) // const = 0
-                val packet = when (val encryptionMethod = readByte().toInt()) {
+                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()
+
+                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())
+                    }
+                    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 4, got $encryptionMethod")
+                    else -> error("Illegal encryption method. expected 0 or 4, got $encryptionMethod")
                 }
 
                 consumer(packet, packetFactory.id, ssoSequenceId)