mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-26 23:50:16 +08:00
Fix debugger
This commit is contained in:
parent
f3278c8afe
commit
16a487129a
@ -17,7 +17,7 @@ inline class SessionKey(override val value: ByteArray) : DecrypterByteArray {
|
|||||||
*/
|
*/
|
||||||
interface DecrypterByteArray : Decrypter {
|
interface DecrypterByteArray : Decrypter {
|
||||||
val value: ByteArray
|
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 {
|
interface DecrypterIoBuffer : Decrypter {
|
||||||
val value: IoBuffer
|
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 {
|
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<NoDecrypter> {
|
object NoDecrypter : Decrypter, DecrypterType<NoDecrypter> {
|
||||||
override fun decrypt(packet: ByteReadPacket): ByteReadPacket = packet
|
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解密器
|
* 解密器
|
||||||
*/
|
*/
|
||||||
interface Decrypter {
|
interface Decrypter {
|
||||||
fun decrypt(packet: ByteReadPacket): ByteReadPacket
|
fun decrypt(input: ByteReadPacket): ByteReadPacket
|
||||||
/**
|
/**
|
||||||
* 连接后将会先用 this 解密, 再用 [another] 解密
|
* 连接后将会先用 this 解密, 再用 [another] 解密
|
||||||
*/
|
*/
|
||||||
|
@ -18,7 +18,7 @@ object PacketFactoryList : MutableList<PacketFactory<*, *>> by mutableListOf()
|
|||||||
* @param TPacket 服务器回复包解析结果
|
* @param TPacket 服务器回复包解析结果
|
||||||
* @param TDecrypter 服务器回复包解密器
|
* @param TDecrypter 服务器回复包解密器
|
||||||
*/
|
*/
|
||||||
abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(internal val decrypterType: DecrypterType<TDecrypter>) {
|
abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2 Ubyte.
|
* 2 Ubyte.
|
||||||
|
@ -22,8 +22,8 @@ inline class PrivateKey(override val value: ByteArray) : DecrypterByteArray {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter {
|
inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter {
|
||||||
override fun decrypt(packet: ByteReadPacket): ByteReadPacket {
|
override fun decrypt(input: ByteReadPacket): ByteReadPacket {
|
||||||
var decrypted = ShareKey.decrypt(packet)
|
var decrypted = ShareKey.decrypt(input)
|
||||||
(decrypted.remaining).let {
|
(decrypted.remaining).let {
|
||||||
if (it.toInt() % 8 == 0 && it >= 16) {
|
if (it.toInt() % 8 == 0 && it >= 16) {
|
||||||
decrypted = try {
|
decrypted = try {
|
||||||
@ -253,7 +253,7 @@ object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline class SessionResponseDecryptionKey(private val delegate: IoBuffer) : Decrypter {
|
inline class SessionResponseDecryptionKey(private val delegate: IoBuffer) : Decrypter {
|
||||||
override fun decrypt(packet: ByteReadPacket): ByteReadPacket = packet.decryptBy(delegate)
|
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(delegate)
|
||||||
|
|
||||||
override fun toString(): String = "SessionResponseDecryptionKey"
|
override fun toString(): String = "SessionResponseDecryptionKey"
|
||||||
companion object Type : DecrypterType<SessionResponseDecryptionKey>
|
companion object Type : DecrypterType<SessionResponseDecryptionKey>
|
||||||
|
@ -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.toReadPacket(offset: Int = 0, length: Int = this.size) = ByteReadPacket(this, offset = offset, length = length)
|
||||||
|
|
||||||
fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R = this.toReadPacket().use(t)
|
inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R = this.toReadPacket().use(t)
|
||||||
|
|
||||||
fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length)
|
fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length)
|
@ -8,10 +8,13 @@ plugins {
|
|||||||
javafx {
|
javafx {
|
||||||
version = "11"
|
version = "11"
|
||||||
modules = listOf("javafx.controls")
|
modules = listOf("javafx.controls")
|
||||||
|
|
||||||
//mainClassName = "Application"
|
//mainClassName = "Application"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClassName = "Application"
|
||||||
|
}
|
||||||
|
|
||||||
val kotlinVersion = rootProject.ext["kotlin_version"].toString()
|
val kotlinVersion = rootProject.ext["kotlin_version"].toString()
|
||||||
val atomicFuVersion = rootProject.ext["atomicfu_version"].toString()
|
val atomicFuVersion = rootProject.ext["atomicfu_version"].toString()
|
||||||
val coroutinesVersion = rootProject.ext["coroutines_version"].toString()
|
val coroutinesVersion = rootProject.ext["coroutines_version"].toString()
|
||||||
|
@ -6,12 +6,25 @@ import Main.localIp
|
|||||||
import Main.qq
|
import Main.qq
|
||||||
import Main.sessionKey
|
import Main.sessionKey
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.io.packet.ByteReadPacket
|
|
||||||
import kotlinx.io.core.discardExact
|
import kotlinx.io.core.discardExact
|
||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
import kotlinx.io.core.readUInt
|
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.message.internal.readMessageChain
|
||||||
|
import net.mamoe.mirai.network.BotNetworkHandler
|
||||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
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.DecryptionFailedException
|
||||||
import net.mamoe.mirai.utils.decryptBy
|
import net.mamoe.mirai.utils.decryptBy
|
||||||
import net.mamoe.mirai.utils.io.*
|
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
|
||||||
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode
|
import org.pcap4j.core.PcapNetworkInterface.PromiscuousMode
|
||||||
import org.pcap4j.core.Pcaps
|
import org.pcap4j.core.Pcaps
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
suspend fun main() {
|
suspend fun main() {
|
||||||
val nif: PcapNetworkInterface = Pcaps.findAllDevs()[0]
|
val nif: PcapNetworkInterface = Pcaps.findAllDevs()[0]
|
||||||
@ -40,7 +54,9 @@ suspend fun main() {
|
|||||||
receiver.setFilter("dst $localIp && udp port 8000", BpfCompileMode.OPTIMIZE)
|
receiver.setFilter("dst $localIp && udp port 8000", BpfCompileMode.OPTIMIZE)
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
receiver.loop(Int.MAX_VALUE, PacketListener {
|
receiver.loop(Int.MAX_VALUE, PacketListener {
|
||||||
|
runBlocking {
|
||||||
dataReceived(it.rawData.drop(42).toByteArray())
|
dataReceived(it.rawData.drop(42).toByteArray())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +89,7 @@ object Main {
|
|||||||
const val qq: UInt = 1040400290u
|
const val qq: UInt = 1040400290u
|
||||||
const val localIp = "192.168.3.10"
|
const val localIp = "192.168.3.10"
|
||||||
|
|
||||||
fun dataReceived(data: ByteArray) {
|
suspend fun dataReceived(data: ByteArray) {
|
||||||
//println("raw = " + data.toUHexString())
|
//println("raw = " + data.toUHexString())
|
||||||
data.read {
|
data.read {
|
||||||
discardExact(3)
|
discardExact(3)
|
||||||
@ -94,7 +110,22 @@ object Main {
|
|||||||
val decrypted = remaining.decryptBy(sessionKey)
|
val decrypted = remaining.decryptBy(sessionKey)
|
||||||
println("解密body=${decrypted.toUHexString()}")
|
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) {
|
} catch (e: DecryptionFailedException) {
|
||||||
println("密文body=" + remaining.toUHexString())
|
println("密文body=" + remaining.toUHexString())
|
||||||
println("解密body=解密失败")
|
println("解密body=解密失败")
|
||||||
@ -102,29 +133,45 @@ object Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun packetReceived(packet: ServerPacket) {
|
@Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
|
||||||
|
internal fun <D : Decrypter> 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 <TPacket : Packet> handlePacket(
|
||||||
|
id: PacketId,
|
||||||
|
sequenceId: UShort,
|
||||||
|
packet: TPacket,
|
||||||
|
factory: PacketFactory<TPacket, *>
|
||||||
|
) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ServerEventPacket.Raw.Encrypted -> {
|
is UnknownEventPacket -> {
|
||||||
packetReceived(packet.decrypt(sessionKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
is ServerEventPacket.Raw -> packetReceived(packet.distribute())
|
|
||||||
|
|
||||||
is UnknownServerEventPacket -> {
|
|
||||||
println("--------------")
|
println("--------------")
|
||||||
println("未知事件ID=" + packet.idHexString)
|
println("未知事件ID=$id")
|
||||||
println("未知事件: " + packet.input.readBytes().toUHexString())
|
println("未知事件: $packet")
|
||||||
}
|
}
|
||||||
|
|
||||||
is ServerEventPacket -> {
|
is UnknownPacket -> {
|
||||||
|
println("--------------")
|
||||||
|
println("未知包ID=$id")
|
||||||
|
println("未知包: $packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
is EventPacket -> {
|
||||||
println("事件")
|
println("事件")
|
||||||
println(packet)
|
println(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
is UnknownServerPacket -> {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,3 +252,44 @@ object Main {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal object DebugNetworkHandler : BotNetworkHandler<DataPacketSocketAdapter> {
|
||||||
|
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 <T : PacketHandler> get(key: PacketHandler.Key<T>): 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
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
apply plugin: "kotlin"
|
apply plugin: "kotlin"
|
||||||
apply plugin: "java"
|
apply plugin: "java"
|
||||||
|
apply plugin: "application"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":mirai-core")
|
api project(":mirai-core")
|
||||||
@ -11,3 +12,5 @@ dependencies {
|
|||||||
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.62'
|
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.62'
|
||||||
implementation 'org.jsoup:jsoup:1.12.1'
|
implementation 'org.jsoup:jsoup:1.12.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainClassName = "demo.gentleman.MainKt"
|
Loading…
Reference in New Issue
Block a user