diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt index aac5c8dea..4b18cbf9d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/OnlineStatus.kt @@ -26,13 +26,18 @@ enum class OnlineStatus( */ OFFLINE(0x02u), - /** - * ? - */ - UNKNOWN(0x20u) + UNKNOWN1(0x20u), + UNKNOWN2(0x46u), + UNKNOWN3(0x14u), + UNKNOWN4(0xC9u), + UNKNOWN5(0x1Eu), ; // TODO: 2019/10/29 what is 0x20u + // TODO: 2019/11/11 what is 0x46u + // TODO: 2019/11/11 what is 0x14u + // TODO: 2019/11/11 0xC9u + // TODO: 2019/11/11 0x1Eu companion object { fun ofId(id: UByte): OnlineStatus? = values().firstOrNull { it.id == id } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt index 8cc1a4d8b..2b9e5f14c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/TEA.kt @@ -3,6 +3,7 @@ package net.mamoe.mirai.utils import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.IoBuffer import kotlinx.io.pool.useInstance +import net.mamoe.mirai.network.protocol.tim.packet.Decrypter import net.mamoe.mirai.network.protocol.tim.packet.DecrypterByteArray import net.mamoe.mirai.utils.io.* import kotlin.experimental.and @@ -123,6 +124,8 @@ fun ByteReadPacket.decryptBy(key: ByteArray): ByteReadPacket = decryptAsByteArra fun ByteReadPacket.decryptBy(key: IoBuffer): ByteReadPacket = decryptAsByteArray(key) { data -> ByteReadPacket(data, 0) } +fun ByteReadPacket.decryptBy(key: Decrypter): ByteReadPacket = key.decrypt(this) + fun ByteReadPacket.decryptBy(keyHex: String): ByteReadPacket = decryptBy(keyHex.hexToBytes()) inline fun ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R = diff --git a/mirai-debug/src/main/kotlin/PacketDebuger.kt b/mirai-debug/src/main/kotlin/PacketDebuger.kt index 7a7f39fb4..a044c30f7 100644 --- a/mirai-debug/src/main/kotlin/PacketDebuger.kt +++ b/mirai-debug/src/main/kotlin/PacketDebuger.kt @@ -4,15 +4,13 @@ import PacketDebugger.dataSent import PacketDebugger.localIp import PacketDebugger.qq import PacketDebugger.sessionKey -import kotlinx.coroutines.GlobalScope -import kotlinx.io.core.discardExact -import kotlinx.io.core.readBytes -import kotlinx.io.core.readUInt -import kotlinx.io.core.readUShort +import kotlinx.coroutines.* +import kotlinx.io.core.* import net.mamoe.mirai.Bot -import net.mamoe.mirai.message.internal.readMessageChain import net.mamoe.mirai.network.BotNetworkHandler +import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.protocol.tim.TIMProtocol +import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler 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 @@ -29,10 +27,13 @@ import net.mamoe.mirai.utils.decryptBy import net.mamoe.mirai.utils.io.* import org.pcap4j.core.BpfProgram.BpfCompileMode import org.pcap4j.core.PacketListener +import org.pcap4j.core.PcapNetworkInterface import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode import org.pcap4j.core.Pcaps +import java.util.concurrent.Executors import kotlin.concurrent.thread import kotlin.coroutines.CoroutineContext +import kotlin.io.use /** * 需使用 32 位 JDK @@ -47,39 +48,58 @@ fun main() { JpcapCaptor.openDevice(JpcapCaptor.getDeviceList()[0], 65535, true, 1000).loopPacket(Int.MAX_VALUE) { println(it) }*/ - - listenDevice() + Pcaps.findAllDevs().forEach { + listenDevice(it) + } } -private fun listenDevice() { +/** + * 避免 print 重叠. 单线程处理足够调试 + */ +val DISPATCHER = Executors.newFixedThreadPool(1).asCoroutineDispatcher() + +private fun listenDevice(device: PcapNetworkInterface) { + val sender = device.openLive(65536, PromiscuousMode.PROMISCUOUS, 10) thread { - val sender = Pcaps.findAllDevs().first { it.addresses.any { it.address.hostAddress == localIp } }.openLive(65536, PromiscuousMode.PROMISCUOUS, 10) sender.setFilter("src $localIp && udp port 8000", BpfCompileMode.OPTIMIZE) println("sendListener started") try { - sender.loop(999999, PacketListener { - try { - dataSent(it.rawData.drop(42).toByteArray()) - } catch (e: Throwable) { - e.printStackTrace() + sender.loop(Int.MAX_VALUE, PacketListener { + runBlocking { + withContext(DISPATCHER) { + try { + dataSent(it.rawData.drop(42).toByteArray()) + } catch (e: Throwable) { + e.printStackTrace() + } + } } }) - } catch (e: Exception) { + } catch (e: Throwable) { e.printStackTrace() } } - /* + val receiver = device.openLive(65536, PromiscuousMode.PROMISCUOUS, 10) thread { - val receiver = Pcaps.findAllDevs().first { it.addresses.any { it.address.hostAddress == localIp } }.openLive(65536, PromiscuousMode.PROMISCUOUS, 10) receiver.setFilter("dst $localIp && udp port 8000", BpfCompileMode.OPTIMIZE) println("receiveListener started") - receiver.loop(Int.MAX_VALUE, PacketListener { - runBlocking { - dataReceived(it.rawData.drop(42).toByteArray()) - } - }) - }*/ + try { + receiver.loop(Int.MAX_VALUE, PacketListener { + runBlocking { + withContext(DISPATCHER) { + try { + PacketDebugger.dataReceived(it.rawData.drop(42).toByteArray()) + } catch (e: Throwable) { + e.printStackTrace() + } + } + } + }) + } catch (e: Throwable) { + e.printStackTrace() + } + } } /** @@ -103,9 +123,15 @@ object PacketDebugger { * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]` * 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey` */ - val sessionKey: ByteArray = "F9 37 23 8F E7 04 AF 52 6D B9 94 13 E1 3A BD 4A".hexToBytes() + val sessionKey: SessionKey = SessionKey("9B AA 9C 93 78 47 7B 6F C4 57 F2 13 76 AC C7 72".hexToBytes()) const val qq: UInt = 1040400290u - const val localIp = "192.168.3.10" + val localIp: String = "10.162.12.231".also { println("Local IP: $it") } + + val IgnoredPacketIdList: List = listOf( + KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE, + KnownPacketId.CHANGE_ONLINE_STATUS, + KnownPacketId.HEARTBEAT + ) suspend fun dataReceived(data: ByteArray) { //println("raw = " + data.toUHexString()) @@ -115,28 +141,34 @@ object PacketDebugger { val sequenceId = readUShort() if (id == KnownPacketId.HEARTBEAT || readUInt() != qq) return@read + + if (IgnoredPacketIdList.contains(id)) { + return + } + + println("--------------") - println("接收数据包") discardExact(3)//0x00 0x00 0x00. 但更可能是应该 discard 8 - println("id=$id, sequence=${sequenceId.toUHexString()}") - val remaining = this.readRemainingBytes().cutTail(1) + println( + "接收包id=$id, " + + "\nsequence=${sequenceId.toUHexString()}" + ) + // val remaining = this.readRemainingBytes().cutTail(1) try { - val decrypted = remaining.decryptBy(sessionKey) - println("解密body=${decrypted.toUHexString()}") - val packet = use { with(id.factory) { provideDecrypter(id.factory) - .decrypt(this@read) + .decrypt(this@read.readRemainingBytes().let { ByteReadPacket(it, 0, it.size - 1) }) .decode(id, sequenceId, DebugNetworkHandler) } } + println(" 解析body=$packet") handlePacket(id, sequenceId, packet, id.factory) } catch (e: DecryptionFailedException) { - println("密文body=" + remaining.toUHexString()) - println("解密body=解密失败") + // println("密文body=" + remaining.toUHexString()) + println(" 解密body=解密失败") } } } @@ -162,6 +194,7 @@ object PacketDebugger { packet: TPacket, factory: PacketFactory ) { + return when (packet) { is UnknownEventPacket -> { println("--------------") @@ -195,16 +228,21 @@ object PacketDebugger { // 01 BD 63 D6 // 3E 03 3F A2 02 00 00 00 01 2E 01 00 00 69 35 - println("---------------------------") discardExact(3)//head - val idHex = readBytes(4).toUHexString() - println("发出包ID = $idHex") + val id = matchPacketId(readUShort()) + val sequence = readUShort() + if (IgnoredPacketIdList.contains(id)) { + return + } if (readUInt() != qq) { return@read } + println("---------------------------") + println("发出包ID = $id") + println("sequence = $sequence") println( - "fixVer2=" + when (val flag = readByte().toInt()) { + " fixVer2=" + when (val flag = readByte().toInt()) { 2 -> byteArrayOf(2) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1) 4 -> byteArrayOf(4) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1 + 8)//8个0 0 -> byteArrayOf(0) + readBytes(2) @@ -216,78 +254,82 @@ object PacketDebugger { val encryptedBody = readRemainingBytes() try { - println("解密body=${encryptedBody.decryptBy(sessionKey).toUHexString()}") + println(" 解密body=${encryptedBody.decryptBy(sessionKey.value).toUHexString()}") } catch (e: DecryptionFailedException) { - println("密文=" + encryptedBody.toUHexString()) - println("解密body=解密失败") + println(" 密文=" + encryptedBody.toUHexString()) + println(" 解密body=解密失败") } encryptedBody.read { - when (idHex.substring(0, 5)) { - "00 CD" -> { - println("好友消息") + /* +when (idHex.substring(0, 5)) { + "00 CD" -> { + println("好友消息") - val raw = readRemainingBytes() - //println("解密前数据: " + raw.toUHexString()) - val messageData = raw.decryptBy(sessionKey) - //println("解密结果: " + messageData.toUHexString()) - println("尝试解消息") + val raw = readRemainingBytes() + //println("解密前数据: " + raw.toUHexString()) + val messageData = raw.decryptBy(sessionKey.value) + //println("解密结果: " + messageData.toUHexString()) + println("尝试解消息") - try { - messageData.read { - discardExact( - 4 + 4 + 12 + 2 + 4 + 4 + 16 + 2 + 2 + 4 + 2 + 16 + 4 + 4 + 7 + 15 + 2 - + 1 - ) - val chain = readMessageChain() - println(chain) - } - } catch (e: Exception) { - println("失败") - } - } + try { + messageData.read { + discardExact( + 4 + 4 + 12 + 2 + 4 + 4 + 16 + 2 + 2 + 4 + 2 + 16 + 4 + 4 + 7 + 15 + 2 + + 1 + ) + val chain = readMessageChain() + println(chain) + } + } catch (e: Exception) { + println("失败") + } + }*/ - "03 88" -> { - println("0388上传图片-获取图片ID") - discardExact(8) + /* + "03 88" -> { + println("0388上传图片-获取图片ID") + discardExact(8) - //val body = readRemainingBytes().decryptBy(sessionKey) - //println(body.toUHexString()) - } + //val body = readRemainingBytes().decryptBy(sessionKey) + //println(body.toUHexString()) } + }*/ } } } -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 +internal object DebugNetworkHandler : BotNetworkHandler, CoroutineScope { + override val socket: DataPacketSocketAdapter = 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 suspend fun sendPacket(packet: OutgoingPacket) { } + + override fun close() { + } + + override val owner: Bot + get() = bot + + } override val bot: Bot = Bot(0u, "") + val session = BotSession(bot, sessionKey, socket, this) + val action = ActionPacketHandler(session) - override fun get(key: PacketHandler.Key): T = error("UNSUPPORTED") + @Suppress("UNCHECKED_CAST") + override fun get(key: PacketHandler.Key): T = action as? T ?: error("UNSUPPORTED") - override suspend fun login(configuration: BotConfiguration): LoginResult = error("UNSUPPORTED") + override suspend fun login(configuration: BotConfiguration): LoginResult = LoginResult.SUCCESS override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) { }