|
|
@@ -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)
|