mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 01:30:17 +08:00
Add unknown statuses
This commit is contained in:
parent
620882957a
commit
368abbe130
@ -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 }
|
||||||
}
|
}
|
||||||
|
@ -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 =
|
||||||
|
@ -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<*, *>) {
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user