This commit is contained in:
Him188 2020-01-29 20:30:20 +08:00
parent 1cd1a19dbe
commit ac52cbb47e
5 changed files with 28 additions and 132 deletions

View File

@ -1,82 +0,0 @@
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import kotlinx.io.core.ByteReadPacket
import kotlinx.serialization.protobuf.ProtoBuf
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.Cmd0x352Packet
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.RequestPushNotify
internal object GetMsgRequest : PacketFactory<MsgSvc.PbGetMsgResp>("MessageSvc.PbGetMsg") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MsgSvc.PbGetMsgResp {
println("received MsgSvc.PbGetMsgResp")
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
/**
@Serializable
class PbGetMsgReq(
@SerialId(1) val syncFlag: Int /* enum */ = 0,
@SerialId(2) val syncCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val rambleFlag: Int = 1,
@SerialId(4) val latestRambleNumber: Int = 20,
@SerialId(5) val otherRambleNumber: Int = 3,
@SerialId(6) val onlineSyncFlag: Int = 1,
@SerialId(7) val contextFlag: Int = 0,
@SerialId(8) val whisperSessionId: Int = 0,
@SerialId(9) val msgReqType: Int = 0,
@SerialId(10) val pubaccountCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(11) val msgCtrlBuf: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(12) val serverBuf: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class RequestPushNotify(
@SerialId(0) val uin: Long = 0L,
@SerialId(1) val ctype: Byte = 0,
@SerialId(2) val strService: String?,
@SerialId(3) val strCmd: String?,
@SerialId(4) val vNotifyCookie: ByteArray? = EMPTY_BYTE_ARRAY,
@SerialId(5) val usMsgType: Int?,
@SerialId(6) val wUserActive: Int?,
@SerialId(7) val wGeneralFlag: Int?,
@SerialId(8) val bindedUin: Long?,
@SerialId(9) val stMsgInfo: MsgInfo?,
@SerialId(10) val msgCtrlBuf: String?,
@SerialId(11) val serverBuf: ByteArray?,
@SerialId(12) val pingFlag: Long?,
@SerialId(13) val svrip: Int?
) : JceStruct, Packet
*/
operator fun invoke(
client: QQAndroidClient,
notify: RequestPushNotify
): OutgoingPacket = buildOutgingPacket(client, key = client.wLoginSigInfo.d2Key) {
val req = MsgSvc.PbGetMsgReq(
serverBuf = notify.serverBuf ?: EMPTY_BYTE_ARRAY,
msgReqType = notify.usMsgType ?: 0,
syncFlag = 0,
rambleFlag = 0,
contextFlag = 1,
latestRambleNumber = 20,
otherRambleNumber = 3,
onlineSyncFlag = 1
)
val data = ProtoBuf.dump(
MsgSvc.PbGetMsgReq.serializer(),
req
)
writeInt(data.size)
writeFully(data, 0, data.size)
}
}

View File

@ -25,6 +25,9 @@ import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.toReadPacket import net.mamoe.mirai.utils.io.toReadPacket
class MessageSvc { class MessageSvc {
/**
* 告知要刷新消息
*/
internal object PushNotify : PacketFactory<RequestPushNotify>("MessageSvc.PushNotify") { internal object PushNotify : PacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify {
discardExact(8) discardExact(8)
@ -42,13 +45,18 @@ class MessageSvc {
} }
} }
/**
* 进行刷新消息
*/
internal object PbGetMsg : PacketFactory<MultiPacket<FriendMessage>>("MessageSvc.PbGetMsg") { internal object PbGetMsg : PacketFactory<MultiPacket<FriendMessage>>("MessageSvc.PbGetMsg") {
val EXTRA_DATA = "08 00 12 33 6D 6F 64 65 6C 3A 78 69 61 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
operator fun invoke( operator fun invoke(
client: QQAndroidClient, client: QQAndroidClient,
from: RequestPushNotify from: RequestPushNotify
): OutgoingPacket = buildOutgoingUniPacket( ): OutgoingPacket = buildOutgoingUniPacket(
client, client,
extraData = "08 00 12 33 6D 6F 64 65 6C 3A 78 69 61 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes().toReadPacket() extraData = EXTRA_DATA.toReadPacket()
) { ) {
writeProtoBuf( writeProtoBuf(
MsgSvc.PbGetMsgReq.serializer(), MsgSvc.PbGetMsgReq.serializer(),

View File

@ -14,7 +14,11 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgOnlinePush import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.data.MsgOnlinePush
import net.mamoe.mirai.qqandroid.utils.toMessageChain import net.mamoe.mirai.qqandroid.utils.toMessageChain
internal class OnlinePush { internal class OnlinePush {
/**
* 接受群消息
*/
internal object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") { internal object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") {
@UseExperimental(ExperimentalStdlibApi::class) @UseExperimental(ExperimentalStdlibApi::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage {

View File

@ -274,12 +274,12 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
println("type=$type") println("type=$type")
discardExact(2) discardExact(2)
val tlvMap: Map<Int, ByteArray> = this.readTLVMap() val tlvMap: TlvMap = this.readTLVMap()
return when (type.toInt()) { return when (type.toInt()) {
0 -> onLoginSuccess(tlvMap, bot) 0 -> onLoginSuccess(tlvMap, bot)
1, 15 -> onErrorMessage(tlvMap) 1, 15 -> onErrorMessage(tlvMap)
2 -> onSolveLoginCaptcha(tlvMap, bot) 2 -> onSolveLoginCaptcha(tlvMap, bot)
-96 -> onUnsafeDeviceLogin(tlvMap, bot) -96 -> onUnsafeDeviceLogin(tlvMap)
-52 -> onSMSVerifyNeeded(tlvMap, bot) -52 -> onSMSVerifyNeeded(tlvMap, bot)
else -> error("unknown login result type: $type") else -> error("unknown login result type: $type")
} }
@ -287,18 +287,18 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
private fun onSMSVerifyNeeded( private fun onSMSVerifyNeeded(
tlvMap: Map<Int, ByteArray>, tlvMap: TlvMap,
bot: QQAndroidBot bot: QQAndroidBot
): LoginPacketResponse.SMSVerifyCodeNeeded { ): LoginPacketResponse.SMSVerifyCodeNeeded {
bot.client.t104 = tlvMap[0x104]!! bot.client.t104 = tlvMap.getOrFail(0x104)
return LoginPacketResponse.SMSVerifyCodeNeeded(tlvMap[0x174] ?: EMPTY_BYTE_ARRAY, tlvMap[0x402]!!) return LoginPacketResponse.SMSVerifyCodeNeeded(tlvMap[0x174] ?: EMPTY_BYTE_ARRAY, tlvMap.getOrFail(0x402))
} }
private fun onUnsafeDeviceLogin(tlvMap: Map<Int, ByteArray>, bot: QQAndroidBot): LoginPacketResponse.UnsafeLogin { private fun onUnsafeDeviceLogin(tlvMap: TlvMap): LoginPacketResponse.UnsafeLogin {
return LoginPacketResponse.UnsafeLogin(tlvMap[0x204]!!.toReadPacket().readRemainingBytes().encodeToString()) return LoginPacketResponse.UnsafeLogin(tlvMap.getOrFail(0x204).toReadPacket().readRemainingBytes().encodeToString())
} }
private fun onErrorMessage(tlvMap: Map<Int, ByteArray>): LoginPacketResponse.Error { private fun onErrorMessage(tlvMap: TlvMap): LoginPacketResponse.Error {
return tlvMap[0x146]?.toReadPacket()?.run { return tlvMap[0x146]?.toReadPacket()?.run {
readShort() // ver readShort() // ver
readShort() // code readShort() // code
@ -313,8 +313,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
@InternalAPI @InternalAPI
@UseExperimental(MiraiDebugAPI::class) @UseExperimental(MiraiDebugAPI::class)
private fun onSolveLoginCaptcha(tlvMap: Map<Int, ByteArray>, bot: QQAndroidBot): LoginPacketResponse. Captcha { private fun onSolveLoginCaptcha(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse. Captcha {
val client = bot.client
// val ret = tlvMap[0x104]?.let { println(it.toUHexString()) } // val ret = tlvMap[0x104]?.let { println(it.toUHexString()) }
println() println()
val question = tlvMap[0x165] ?: error("CAPTCHA QUESTION UNKNOWN") val question = tlvMap[0x165] ?: error("CAPTCHA QUESTION UNKNOWN")
@ -322,8 +321,8 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
0x36 -> { 0x36 -> {
//图片验证 //图片验证
DebugLogger.debug("是一个图片验证码") DebugLogger.debug("是一个图片验证码")
bot.client.t104 = tlvMap[0x104]!! bot.client.t104 = tlvMap.getOrFail(0x104)
val imageData = tlvMap[0x105]!!.toReadPacket() val imageData = tlvMap.getOrFail(0x105).toReadPacket()
val signInfoLength = imageData.readShort() val signInfoLength = imageData.readShort()
imageData.discardExact(2)//image Length imageData.discardExact(2)//image Length
val sign = imageData.readBytes(signInfoLength.toInt()) val sign = imageData.readBytes(signInfoLength.toInt())
@ -332,15 +331,12 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
sign = sign sign = sign
) )
} }
else -> { else -> error("UNKNOWN CAPTCHA QUESTION: $question")
error("UNKNOWN CAPTCHA QUESTION: $question")
} }
} }
return TODO()
}
@UseExperimental(MiraiDebugAPI::class) @UseExperimental(MiraiDebugAPI::class)
private fun onLoginSuccess(tlvMap: Map<Int, ByteArray>, bot: QQAndroidBot): LoginPacketResponse.Success { private fun onLoginSuccess(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Success {
val client = bot.client val client = bot.client
println("TLV KEYS: " + tlvMap.keys.joinToString { it.contentToString() }) println("TLV KEYS: " + tlvMap.keys.joinToString { it.contentToString() })
@ -544,7 +540,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
} }
private fun Map<Int, ByteArray>.getOrEmpty(key: Int): ByteArray { private fun TlvMap.getOrEmpty(key: Int): ByteArray {
return this[key] ?: byteArrayOf() return this[key] ?: byteArrayOf()
} }
@ -623,7 +619,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
* 设置 [QQAndroidClient.uin] * 设置 [QQAndroidClient.uin]
*/ */
private fun QQAndroidClient.analysisTlv113(t113: ByteArray) = t113.read { private fun QQAndroidClient.analysisTlv113(t113: ByteArray) = t113.read {
val uin = readUInt().toLong() _uin = readUInt().toLong()
/* /*
// nothing to do // nothing to do

View File

@ -68,38 +68,22 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
val flag3 = readByte().toInt() val flag3 = readByte().toInt()
check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" }
<<<<<<< Updated upstream
val uinAccount = readString(readInt() - 4)//uin val uinAccount = readString(readInt() - 4)//uin
=======
println("uinAccount=" + readString(readInt() - 4))//uin
>>>>>>> Stashed changes
//debugPrint("remaining") //debugPrint("remaining")
(if (flag2 == 2) { (if (flag2 == 2) {
<<<<<<< Updated upstream
//PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.") //PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.")
=======
PacketLogger.verbose("SSO, 尝试使用 16 zero 解密.")
>>>>>>> Stashed changes
kotlin.runCatching { kotlin.runCatching {
decryptBy(DECRYPTER_16_ZERO).also { PacketLogger.verbose("成功使用 16 zero 解密") } decryptBy(DECRYPTER_16_ZERO).also { PacketLogger.verbose("成功使用 16 zero 解密") }
} }
} else { } else {
<<<<<<< Updated upstream
//PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.") //PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.")
=======
PacketLogger.verbose("Uni, 尝试使用 d2Key 解密.")
>>>>>>> Stashed changes
kotlin.runCatching { kotlin.runCatching {
decryptBy(D2Key).also { PacketLogger.verbose("成功使用 d2Key 解密") } decryptBy(D2Key).also { PacketLogger.verbose("成功使用 d2Key 解密") }
} }
}).getOrElse { }).getOrElse {
<<<<<<< Updated upstream
PacketLogger.verbose("解密失败, 尝试其他各种key") PacketLogger.verbose("解密失败, 尝试其他各种key")
=======
PacketLogger.verbose("失败, 尝试其他各种key")
>>>>>>> Stashed changes
this.readBytes().tryDecryptOrNull()?.toReadPacket() this.readBytes().tryDecryptOrNull()?.toReadPacket()
}?.debugPrint("sso/uni body=")?.let { }?.debugPrint("sso/uni body=")?.let {
if (flag1 == 0x0A) { if (flag1 == 0x0A) {
@ -111,11 +95,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
val bytes = it.data.readBytes() val bytes = it.data.readBytes()
if (flag2 == 2 && it.packetFactory != null) { if (flag2 == 2 && it.packetFactory != null) {
PacketLogger.debug("Oicq Reuqest= " + bytes.toUHexString()) PacketLogger.debug("Oicq Reuqest= " + bytes.toUHexString())
<<<<<<< Updated upstream
try {
=======
try{ try{
>>>>>>> Stashed changes
bytes.toReadPacket().parseOicqResponse { bytes.toReadPacket().parseOicqResponse {
if (it.packetFactory.commandName == "wtlogin.login") { if (it.packetFactory.commandName == "wtlogin.login") {
DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key") DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key")
@ -149,11 +129,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
} }
} }
} }
<<<<<<< Updated upstream
} catch (e: Exception) { } catch (e: Exception) {
=======
}catch (e: Exception){
>>>>>>> Stashed changes
e.printStackTrace() e.printStackTrace()
} }
} else // always discarded. 00 1C } else // always discarded. 00 1C
@ -189,15 +165,9 @@ private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) {
val packet = when (encryptionMethod) { val packet = when (encryptionMethod) {
4 -> { // peer public key, ECDH 4 -> { // peer public key, ECDH
var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1) var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1)
<<<<<<< Updated upstream
data.read { data.read {
println("第一层解密: ${data.toUHexString()}") println("第一层解密: ${data.toUHexString()}")
val peerShareKey = ECDH.calculateShareKey(loadPrivateKey(ecdhPrivateKeyS), readUShortLVByteArray().adjustToPublicKey()) val peerShareKey = ECDH.calculateShareKey(loadPrivateKey(ecdhPrivateKeyS), readUShortLVByteArray().adjustToPublicKey())
=======
data.read{
println("第一层解密: ${data.toUHexString()}")
val peerShareKey = ECDH.calculateShareKey(loadPrivateKey(ecdhPrivateKeyS), readUShortLVByteArray().adjustToPublicKey())
>>>>>>> Stashed changes
body(this.decryptBy(peerShareKey)) body(this.decryptBy(peerShareKey))
} }
} }