From 16a487129a002e25e4d60477c7ea59c584b21dd7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 8 Nov 2019 21:17:25 +0800 Subject: [PATCH] Fix debugger --- .../network/protocol/tim/packet/Decrypters.kt | 10 +- .../protocol/tim/packet/PacketFactory.kt | 2 +- .../tim/packet/login/PasswordSubmission.kt | 6 +- .../net.mamoe.mirai/utils/io/ByteArrayUtil.kt | 2 +- mirai-debug/build.gradle.kts | 5 +- mirai-debug/src/main/kotlin/PacketDebuger.kt | 126 +++++++++++++++--- mirai-demos/mirai-demo-gentleman/build.gradle | 3 + 7 files changed, 124 insertions(+), 30 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt index a1a117aa6..f8b1bdee6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/Decrypters.kt @@ -17,7 +17,7 @@ inline class SessionKey(override val value: ByteArray) : DecrypterByteArray { */ interface DecrypterByteArray : Decrypter { val value: ByteArray - override fun decrypt(packet: ByteReadPacket): ByteReadPacket = packet.decryptBy(value) + override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value) } /** @@ -25,25 +25,25 @@ interface DecrypterByteArray : Decrypter { */ interface DecrypterIoBuffer : Decrypter { val value: IoBuffer - override fun decrypt(packet: ByteReadPacket): ByteReadPacket = packet.decryptBy(value) + override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value) } /** * 连接在一起的解密器 */ inline class LinkedDecrypter(inline val block: (ByteReadPacket) -> ByteReadPacket) : Decrypter { - override fun decrypt(packet: ByteReadPacket): ByteReadPacket = block(packet) + override fun decrypt(input: ByteReadPacket): ByteReadPacket = block(input) } object NoDecrypter : Decrypter, DecrypterType { - override fun decrypt(packet: ByteReadPacket): ByteReadPacket = packet + override fun decrypt(input: ByteReadPacket): ByteReadPacket = input } /** * 解密器 */ interface Decrypter { - fun decrypt(packet: ByteReadPacket): ByteReadPacket + fun decrypt(input: ByteReadPacket): ByteReadPacket /** * 连接后将会先用 this 解密, 再用 [another] 解密 */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketFactory.kt index 046d1aaa5..23c77e9b0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketFactory.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/PacketFactory.kt @@ -18,7 +18,7 @@ object PacketFactoryList : MutableList> by mutableListOf() * @param TPacket 服务器回复包解析结果 * @param TDecrypter 服务器回复包解密器 */ -abstract class PacketFactory(internal val decrypterType: DecrypterType) { +abstract class PacketFactory(val decrypterType: DecrypterType) { /** * 2 Ubyte. diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt index 0068e6aec..966c4795a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/login/PasswordSubmission.kt @@ -22,8 +22,8 @@ inline class PrivateKey(override val value: ByteArray) : DecrypterByteArray { } inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter { - override fun decrypt(packet: ByteReadPacket): ByteReadPacket { - var decrypted = ShareKey.decrypt(packet) + override fun decrypt(input: ByteReadPacket): ByteReadPacket { + var decrypted = ShareKey.decrypt(input) (decrypted.remaining).let { if (it.toInt() % 8 == 0 && it >= 16) { decrypted = try { @@ -253,7 +253,7 @@ object SubmitPasswordPacket : PacketFactory diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt index 07870aae6..f1b548308 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt @@ -35,6 +35,6 @@ fun UByteArray.toUHexString(separator: String = " "): String = this.joinToString fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size) = ByteReadPacket(this, offset = offset, length = length) -fun ByteArray.read(t: ByteReadPacket.() -> R): R = this.toReadPacket().use(t) +inline fun ByteArray.read(t: ByteReadPacket.() -> R): R = this.toReadPacket().use(t) fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length) \ No newline at end of file diff --git a/mirai-debug/build.gradle.kts b/mirai-debug/build.gradle.kts index 29907710d..add8878bc 100644 --- a/mirai-debug/build.gradle.kts +++ b/mirai-debug/build.gradle.kts @@ -8,10 +8,13 @@ plugins { javafx { version = "11" modules = listOf("javafx.controls") - //mainClassName = "Application" } +application { + mainClassName = "Application" +} + val kotlinVersion = rootProject.ext["kotlin_version"].toString() val atomicFuVersion = rootProject.ext["atomicfu_version"].toString() val coroutinesVersion = rootProject.ext["coroutines_version"].toString() diff --git a/mirai-debug/src/main/kotlin/PacketDebuger.kt b/mirai-debug/src/main/kotlin/PacketDebuger.kt index 0441c9a3a..a59cde836 100644 --- a/mirai-debug/src/main/kotlin/PacketDebuger.kt +++ b/mirai-debug/src/main/kotlin/PacketDebuger.kt @@ -6,12 +6,25 @@ import Main.localIp import Main.qq import Main.sessionKey import kotlinx.coroutines.* -import kotlinx.coroutines.io.packet.ByteReadPacket import kotlinx.io.core.discardExact import kotlinx.io.core.readBytes import kotlinx.io.core.readUInt +import kotlinx.io.core.readUShort +import net.mamoe.mirai.Bot import net.mamoe.mirai.message.internal.readMessageChain +import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.protocol.tim.TIMProtocol +import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter +import net.mamoe.mirai.network.protocol.tim.handler.PacketHandler +import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler +import net.mamoe.mirai.network.protocol.tim.packet.* +import net.mamoe.mirai.network.protocol.tim.packet.event.EventPacket +import net.mamoe.mirai.network.protocol.tim.packet.event.UnknownEventPacket +import net.mamoe.mirai.network.protocol.tim.packet.login.CaptchaKey +import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult +import net.mamoe.mirai.network.protocol.tim.packet.login.ShareKey +import net.mamoe.mirai.network.protocol.tim.packet.login.TouchKey +import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.DecryptionFailedException import net.mamoe.mirai.utils.decryptBy import net.mamoe.mirai.utils.io.* @@ -20,6 +33,7 @@ import org.pcap4j.core.PacketListener import org.pcap4j.core.PcapNetworkInterface import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode import org.pcap4j.core.Pcaps +import kotlin.coroutines.CoroutineContext suspend fun main() { val nif: PcapNetworkInterface = Pcaps.findAllDevs()[0] @@ -40,7 +54,9 @@ suspend fun main() { receiver.setFilter("dst $localIp && udp port 8000", BpfCompileMode.OPTIMIZE) withContext(Dispatchers.IO) { receiver.loop(Int.MAX_VALUE, PacketListener { - dataReceived(it.rawData.drop(42).toByteArray()) + runBlocking { + dataReceived(it.rawData.drop(42).toByteArray()) + } }) } } @@ -73,7 +89,7 @@ object Main { const val qq: UInt = 1040400290u const val localIp = "192.168.3.10" - fun dataReceived(data: ByteArray) { + suspend fun dataReceived(data: ByteArray) { //println("raw = " + data.toUHexString()) data.read { discardExact(3) @@ -94,7 +110,22 @@ object Main { val decrypted = remaining.decryptBy(sessionKey) println("解密body=${decrypted.toUHexString()}") - packetReceived(data.read { parseServerPacket(data.size, sessionKey) }) + discardExact(3) + + val id = matchPacketId(readUShort()) + val sequenceId = readUShort() + + discardExact(7)//4 for qq number, 3 for 0x00 0x00 0x00 + + val packet = use { + with(id.factory) { + provideDecrypter(id.factory) + .decrypt(this@read) + .decode(id, sequenceId, DebugNetworkHandler) + } + } + + handlePacket(id, sequenceId, packet, id.factory) } catch (e: DecryptionFailedException) { println("密文body=" + remaining.toUHexString()) println("解密body=解密失败") @@ -102,29 +133,45 @@ object Main { } } - fun packetReceived(packet: ServerPacket) { + @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") + internal fun provideDecrypter(factory: PacketFactory<*, D>): D = + when (factory.decrypterType) { + TouchKey -> TouchKey + CaptchaKey -> CaptchaKey + ShareKey -> ShareKey + + NoDecrypter -> NoDecrypter + + SessionKey -> sessionKey + + else -> error("No decrypter is found") + } as? D ?: error("Internal error: could not cast decrypter which is found for factory to class Decrypter") + + @Suppress("UNUSED_PARAMETER") + fun handlePacket( + id: PacketId, + sequenceId: UShort, + packet: TPacket, + factory: PacketFactory + ) { when (packet) { - is ServerEventPacket.Raw.Encrypted -> { - packetReceived(packet.decrypt(sessionKey)) - } - - is ServerEventPacket.Raw -> packetReceived(packet.distribute()) - - is UnknownServerEventPacket -> { + is UnknownEventPacket -> { println("--------------") - println("未知事件ID=" + packet.idHexString) - println("未知事件: " + packet.input.readBytes().toUHexString()) + println("未知事件ID=$id") + println("未知事件: $packet") } - is ServerEventPacket -> { + is UnknownPacket -> { + println("--------------") + println("未知包ID=$id") + println("未知包: $packet") + } + + is EventPacket -> { println("事件") println(packet) } - is UnknownServerPacket -> { - //ignore - } - else -> { } } @@ -204,4 +251,45 @@ object Main { } } +} + + +internal object DebugNetworkHandler : BotNetworkHandler { + override val socket: DataPacketSocketAdapter + get() = object : DataPacketSocketAdapter { + override val serverIp: String + get() = "" + override val channel: PlatformDatagramChannel + get() = error("UNSUPPORTED") + override val isOpen: Boolean + get() = true + + override suspend fun sendPacket(packet: OutgoingPacket) { + + } + + override fun close() { + } + + override val owner: Bot + get() = bot + + } + override val bot: Bot = Bot(0u, "") + + override fun get(key: PacketHandler.Key): T = error("UNSUPPORTED") + + override suspend fun login(configuration: BotConfiguration): LoginResult = error("UNSUPPORTED") + + override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) { + } + + override suspend fun sendPacket(packet: OutgoingPacket) { + } + + override suspend fun awaitDisconnection() { + } + + override val coroutineContext: CoroutineContext + get() = GlobalScope.coroutineContext } \ No newline at end of file diff --git a/mirai-demos/mirai-demo-gentleman/build.gradle b/mirai-demos/mirai-demo-gentleman/build.gradle index 828c25a6f..14cc9f8ba 100644 --- a/mirai-demos/mirai-demo-gentleman/build.gradle +++ b/mirai-demos/mirai-demo-gentleman/build.gradle @@ -1,5 +1,6 @@ apply plugin: "kotlin" apply plugin: "java" +apply plugin: "application" dependencies { api project(":mirai-core") @@ -11,3 +12,5 @@ dependencies { compile group: 'com.alibaba', name: 'fastjson', version: '1.2.62' implementation 'org.jsoup:jsoup:1.12.1' } + +mainClassName = "demo.gentleman.MainKt" \ No newline at end of file