Add unknown statuses

This commit is contained in:
Him188 2019-11-11 19:37:33 +08:00
parent 620882957a
commit 368abbe130
3 changed files with 143 additions and 93 deletions

View File

@ -26,13 +26,18 @@ enum class OnlineStatus(
*/ */
OFFLINE(0x02u), OFFLINE(0x02u),
/** UNKNOWN1(0x20u),
* ? UNKNOWN2(0x46u),
*/ UNKNOWN3(0x14u),
UNKNOWN(0x20u) UNKNOWN4(0xC9u),
UNKNOWN5(0x1Eu),
; ;
// TODO: 2019/10/29 what is 0x20u // 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 { companion object {
fun ofId(id: UByte): OnlineStatus? = values().firstOrNull { it.id == id } fun ofId(id: UByte): OnlineStatus? = values().firstOrNull { it.id == id }
} }

View File

@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.IoBuffer import kotlinx.io.core.IoBuffer
import kotlinx.io.pool.useInstance 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.network.protocol.tim.packet.DecrypterByteArray
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.experimental.and 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: 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()) fun ByteReadPacket.decryptBy(keyHex: String): ByteReadPacket = decryptBy(keyHex.hexToBytes())
inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R = inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R =

View File

@ -4,15 +4,13 @@ import PacketDebugger.dataSent
import PacketDebugger.localIp import PacketDebugger.localIp
import PacketDebugger.qq import PacketDebugger.qq
import PacketDebugger.sessionKey import PacketDebugger.sessionKey
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.*
import kotlinx.io.core.discardExact import kotlinx.io.core.*
import kotlinx.io.core.readBytes
import kotlinx.io.core.readUInt
import kotlinx.io.core.readUShort
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.BotNetworkHandler 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.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.DataPacketSocketAdapter
import net.mamoe.mirai.network.protocol.tim.handler.PacketHandler 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.handler.TemporaryPacketHandler
@ -29,10 +27,13 @@ import net.mamoe.mirai.utils.decryptBy
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import org.pcap4j.core.BpfProgram.BpfCompileMode import org.pcap4j.core.BpfProgram.BpfCompileMode
import org.pcap4j.core.PacketListener import org.pcap4j.core.PacketListener
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 java.util.concurrent.Executors
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.io.use
/** /**
* 需使用 32 JDK * 需使用 32 JDK
@ -47,39 +48,58 @@ fun main() {
JpcapCaptor.openDevice(JpcapCaptor.getDeviceList()[0], 65535, true, 1000).loopPacket(Int.MAX_VALUE) { JpcapCaptor.openDevice(JpcapCaptor.getDeviceList()[0], 65535, true, 1000).loopPacket(Int.MAX_VALUE) {
println(it) println(it)
}*/ }*/
Pcaps.findAllDevs().forEach {
listenDevice() 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 { 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) sender.setFilter("src $localIp && udp port 8000", BpfCompileMode.OPTIMIZE)
println("sendListener started") println("sendListener started")
try { try {
sender.loop(999999, PacketListener { sender.loop(Int.MAX_VALUE, PacketListener {
try { runBlocking {
dataSent(it.rawData.drop(42).toByteArray()) withContext(DISPATCHER) {
} catch (e: Throwable) { try {
e.printStackTrace() dataSent(it.rawData.drop(42).toByteArray())
} catch (e: Throwable) {
e.printStackTrace()
}
}
} }
}) })
} catch (e: Exception) { } catch (e: Throwable) {
e.printStackTrace() e.printStackTrace()
} }
} }
/* val receiver = device.openLive(65536, PromiscuousMode.PROMISCUOUS, 10)
thread { 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) receiver.setFilter("dst $localIp && udp port 8000", BpfCompileMode.OPTIMIZE)
println("receiveListener started") println("receiveListener started")
receiver.loop(Int.MAX_VALUE, PacketListener { try {
runBlocking { receiver.loop(Int.MAX_VALUE, PacketListener {
dataReceived(it.rawData.drop(42).toByteArray()) 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]` * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]`
* 8. 查看内存, `eax` `eax+10` 16 字节就是 `sessionKey` * 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 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<PacketId> = listOf(
KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE,
KnownPacketId.CHANGE_ONLINE_STATUS,
KnownPacketId.HEARTBEAT
)
suspend fun dataReceived(data: ByteArray) { suspend fun dataReceived(data: ByteArray) {
//println("raw = " + data.toUHexString()) //println("raw = " + data.toUHexString())
@ -115,28 +141,34 @@ object PacketDebugger {
val sequenceId = readUShort() val sequenceId = readUShort()
if (id == KnownPacketId.HEARTBEAT || readUInt() != qq) if (id == KnownPacketId.HEARTBEAT || readUInt() != qq)
return@read return@read
if (IgnoredPacketIdList.contains(id)) {
return
}
println("--------------") println("--------------")
println("接收数据包")
discardExact(3)//0x00 0x00 0x00. 但更可能是应该 discard 8 discardExact(3)//0x00 0x00 0x00. 但更可能是应该 discard 8
println("id=$id, sequence=${sequenceId.toUHexString()}") println(
val remaining = this.readRemainingBytes().cutTail(1) "接收包id=$id, " +
"\nsequence=${sequenceId.toUHexString()}"
)
// val remaining = this.readRemainingBytes().cutTail(1)
try { try {
val decrypted = remaining.decryptBy(sessionKey)
println("解密body=${decrypted.toUHexString()}")
val packet = use { val packet = use {
with(id.factory) { with(id.factory) {
provideDecrypter(id.factory) provideDecrypter(id.factory)
.decrypt(this@read) .decrypt(this@read.readRemainingBytes().let { ByteReadPacket(it, 0, it.size - 1) })
.decode(id, sequenceId, DebugNetworkHandler) .decode(id, sequenceId, DebugNetworkHandler)
} }
} }
println(" 解析body=$packet")
handlePacket(id, sequenceId, packet, id.factory) handlePacket(id, sequenceId, packet, id.factory)
} catch (e: DecryptionFailedException) { } catch (e: DecryptionFailedException) {
println("密文body=" + remaining.toUHexString()) // println("密文body=" + remaining.toUHexString())
println("解密body=解密失败") println(" 解密body=解密失败")
} }
} }
} }
@ -162,6 +194,7 @@ object PacketDebugger {
packet: TPacket, packet: TPacket,
factory: PacketFactory<TPacket, *> factory: PacketFactory<TPacket, *>
) { ) {
return
when (packet) { when (packet) {
is UnknownEventPacket -> { is UnknownEventPacket -> {
println("--------------") println("--------------")
@ -195,16 +228,21 @@ object PacketDebugger {
// 01 BD 63 D6 // 01 BD 63 D6
// 3E 03 3F A2 02 00 00 00 01 2E 01 00 00 69 35 // 3E 03 3F A2 02 00 00 00 01 2E 01 00 00 69 35
println("---------------------------")
discardExact(3)//head discardExact(3)//head
val idHex = readBytes(4).toUHexString() val id = matchPacketId(readUShort())
println("发出包ID = $idHex") val sequence = readUShort()
if (IgnoredPacketIdList.contains(id)) {
return
}
if (readUInt() != qq) { if (readUInt() != qq) {
return@read return@read
} }
println("---------------------------")
println("发出包ID = $id")
println("sequence = $sequence")
println( println(
"fixVer2=" + when (val flag = readByte().toInt()) { " fixVer2=" + when (val flag = readByte().toInt()) {
2 -> byteArrayOf(2) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1) 2 -> byteArrayOf(2) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1)
4 -> byteArrayOf(4) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1 + 8)//8个0 4 -> byteArrayOf(4) + readBytes(TIMProtocol.fixVer2.hexToBytes().size - 1 + 8)//8个0
0 -> byteArrayOf(0) + readBytes(2) 0 -> byteArrayOf(0) + readBytes(2)
@ -216,78 +254,82 @@ object PacketDebugger {
val encryptedBody = readRemainingBytes() val encryptedBody = readRemainingBytes()
try { try {
println("解密body=${encryptedBody.decryptBy(sessionKey).toUHexString()}") println(" 解密body=${encryptedBody.decryptBy(sessionKey.value).toUHexString()}")
} catch (e: DecryptionFailedException) { } catch (e: DecryptionFailedException) {
println("密文=" + encryptedBody.toUHexString()) println(" 密文=" + encryptedBody.toUHexString())
println("解密body=解密失败") println(" 解密body=解密失败")
} }
encryptedBody.read { encryptedBody.read {
when (idHex.substring(0, 5)) { /*
"00 CD" -> { when (idHex.substring(0, 5)) {
println("好友消息") "00 CD" -> {
println("好友消息")
val raw = readRemainingBytes() val raw = readRemainingBytes()
//println("解密前数据: " + raw.toUHexString()) //println("解密前数据: " + raw.toUHexString())
val messageData = raw.decryptBy(sessionKey) val messageData = raw.decryptBy(sessionKey.value)
//println("解密结果: " + messageData.toUHexString()) //println("解密结果: " + messageData.toUHexString())
println("尝试解消息") println("尝试解消息")
try { try {
messageData.read { messageData.read {
discardExact( discardExact(
4 + 4 + 12 + 2 + 4 + 4 + 16 + 2 + 2 + 4 + 2 + 16 + 4 + 4 + 7 + 15 + 2 4 + 4 + 12 + 2 + 4 + 4 + 16 + 2 + 2 + 4 + 2 + 16 + 4 + 4 + 7 + 15 + 2
+ 1 + 1
) )
val chain = readMessageChain() val chain = readMessageChain()
println(chain) println(chain)
} }
} catch (e: Exception) { } catch (e: Exception) {
println("失败") println("失败")
} }
} }*/
"03 88" -> { /*
println("0388上传图片-获取图片ID") "03 88" -> {
discardExact(8) println("0388上传图片-获取图片ID")
discardExact(8)
//val body = readRemainingBytes().decryptBy(sessionKey) //val body = readRemainingBytes().decryptBy(sessionKey)
//println(body.toUHexString()) //println(body.toUHexString())
}
} }
}*/
} }
} }
} }
internal object DebugNetworkHandler : BotNetworkHandler<DataPacketSocketAdapter> { internal object DebugNetworkHandler : BotNetworkHandler<DataPacketSocketAdapter>, CoroutineScope {
override val socket: DataPacketSocketAdapter override val socket: DataPacketSocketAdapter = object : DataPacketSocketAdapter {
get() = object : DataPacketSocketAdapter { override val serverIp: String
override val serverIp: String get() = ""
get() = "" override val channel: PlatformDatagramChannel
override val channel: PlatformDatagramChannel get() = error("UNSUPPORTED")
get() = error("UNSUPPORTED") override val isOpen: Boolean
override val isOpen: Boolean get() = true
get() = true
override suspend fun sendPacket(packet: OutgoingPacket) { override suspend fun sendPacket(packet: OutgoingPacket) {
}
override fun close() {
}
override val owner: Bot
get() = bot
} }
override fun close() {
}
override val owner: Bot
get() = bot
}
override val bot: Bot = Bot(0u, "") override val bot: Bot = Bot(0u, "")
val session = BotSession(bot, sessionKey, socket, this)
val action = ActionPacketHandler(session)
override fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = error("UNSUPPORTED") @Suppress("UNCHECKED_CAST")
override fun <T : PacketHandler> get(key: PacketHandler.Key<T>): 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<*, *>) { override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) {
} }