diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 1d8f6d487..1aafc0620 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -36,9 +36,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler println("Sending login") LoginPacket.SubCommand9(bot.client).sendAndExpect() println("SessionTicket=${bot.client.wLoginSigInfo.wtSessionTicket.data.toUHexString()}") - println("SessionTicketKey=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") + println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") println("SessionTicketKey=${bot.client.wLoginSigInfo.wtSessionTicketKey.toUHexString()}") delay(2000) + println() + println() + println() + println("Sending ReqRegister") SvcReqRegisterPacket(bot.client, RegPushReason.setOnlineStatus).sendAndExpect() } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt index 618853670..c39faae4b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/OutgoingPacketAndroid.kt @@ -6,6 +6,7 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.cryptor.DecrypterByteArray @@ -110,10 +111,12 @@ internal inline fun PacketFactory<*>.buildOutgingPacket( internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( client: QQAndroidClient, subAppId: Long, + bodyType: Byte, // login=2, uni=1 extraData: ByteArray = EMPTY_BYTE_ARRAY, name: String? = null, id: PacketId = this.id, ssoExtraData: ByteReadPacket = BRP_STUB, + key: ByteArray = KEY_16_ZEROS, body: BytePacketBuilder.(sequenceId: Int) -> Unit ): OutgoingPacket { val sequenceId: Int = client.nextSsoSequenceId() @@ -121,7 +124,7 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( return OutgoingPacket(name, id, sequenceId, buildPacket { writeIntLVPacket(lengthOffset = { it + 4 }) { writeInt(0x00_00_00_0A) - writeByte(0x02) + writeByte(bodyType) extraData.let { writeInt(it.size + 4) writeFully(it) @@ -133,10 +136,8 @@ internal inline fun PacketFactory<*>.buildLoginOutgoingPacket( writeStringUtf8(it) } - encryptAndWrite(KEY_16_ZEROS) { - writeLoginSsoPacket(client, subAppId, id, ssoExtraData, sequenceId) { - body(sequenceId) - } + encryptAndWrite(key) { + body(sequenceId) } } }) @@ -169,7 +170,7 @@ private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY) * byte[] body() */ @UseExperimental(MiraiInternalAPI::class) -private inline fun BytePacketBuilder.writeLoginSsoPacket( +internal inline fun BytePacketBuilder.writeLoginSsoPacket( client: QQAndroidClient, subAppId: Long, packetId: PacketId, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index e6f8553ae..99c72d925 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -68,22 +68,32 @@ internal object KnownPacketFactories : List> by mutableListOf( } check(remaining.toInt() == expectedLength) { "Invalid packet length. Expected $expectedLength, got ${rawInput.remaining} Probably packets merged? " } // login - when (val flag1 = readInt()) { - 0x0A -> when (val flag2 = readByte().toInt()) { - 0x02 -> { - val flag3 = readByte().toInt() - check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } - - bot.logger.verbose(readString(readInt() - 4)) // uinAccount - - //debugPrint("remaining") - parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer) - } - else -> error("Illegal flag2. Expected 0x02, got $flag2") + val flag1 = readInt() + when (val flag2 = readByte().toInt()) { + 0x02 -> { + val flag3 = readByte().toInt() + check(flag3 == 0) { "Illegal flag3. Expected 0, got $flag3" } + bot.logger.verbose("got uinAccount = " + readString(readInt() - 4)) // uinAccount + //debugPrint("remaining") } - // 00 00 00 60 00 00 00 0B 02 00 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 CE 35 53 19 84 A8 1A B8 5B 48 E3 7C D0 A6 BA 58 6A EB CE 50 B9 A0 98 D5 B9 D0 1C 72 E2 86 24 FC 55 44 6C 6E E3 F9 15 6C EC 6C 6B 94 40 F7 B4 45 CF B4 D0 79 84 FE 30 EA 98 84 44 84 02 32 70 DD D7 07 07 72 DE 87 59 AC - 0x0B -> - else -> error("Illegal flag1. Expected 0x0A or 0x0B, got $flag1") + else -> error("Illegal flag2. Expected 0x02, got $flag2") + } + when (flag1) { + 0x0A -> parseLoginSsoPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer) + 0x0B -> parseUniPacket(bot, decryptBy(DECRYPTER_16_ZERO), consumer) + } + } + + private suspend fun parseUniPacket(bot: QQAndroidBot, rawInput: ByteReadPacket, consumer: PacketConsumer) = + rawInput.debugIfFail("Login sso packet") { + readIoBuffer(readInt() - 4).withUse { + //00 01 4E 64 FF FF D8 E8 00 00 00 14 6E 65 65 64 20 41 32 20 61 6E 64 20 49 4D 45 49 00 00 00 04 00 00 00 08 60 7F B6 23 00 00 00 00 00 00 00 04 + val sequenceId = readInt() + + } + + readIoBuffer(readInt() - 4).withUse { + debugPrintln("收到 UniPacket 的 body=${this.readBytes().toUHexString()}") } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt index 87b748041..3e2d6f215 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/LoginPacket.kt @@ -35,137 +35,139 @@ internal object LoginPacket : PacketFactory() { @UseExperimental(MiraiInternalAPI::class) operator fun invoke( client: QQAndroidClient - ): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId) { sequenceId -> - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) { - writeShort(9) // subCommand - writeShort(17) // count of TLVs, probably ignored by server? - //writeShort(LoginType.PASSWORD.value.toShort()) + ): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId = subAppId, bodyType = 2) { sequenceId -> + writeLoginSsoPacket(client, subAppId, id, sequenceId = sequenceId) { + writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), id) { + writeShort(9) // subCommand + writeShort(17) // count of TLVs, probably ignored by server? + //writeShort(LoginType.PASSWORD.value.toShort()) - t18(appId, client.appClientVersion, client.uin) - t1(client.uin, client.device.ipAddress) - t106( - appId, - subAppId /* maybe 1*/, - client.appClientVersion, - client.uin, - 1, - client.account.passwordMd5, - 0, - client.uin.toByteArray(), - client.tgtgtKey, - true, - client.device.guid, - LoginType.PASSWORD - ) - - /* // from GetStWithPasswd - int mMiscBitmap = this.mMiscBitmap; - if (t.uinDeviceToken) { - mMiscBitmap = (this.mMiscBitmap | 0x2000000); - } - - - // defaults true - if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L) - */ - t116(client.miscBitMap, client.subSigMap) - t100(appId, subAppId, client.appClientVersion, client.mainSigMap or 0xC0) - t107(0) - - // t108(byteArrayOf()) - // ignored: t104() - t142(client.apkId) - - // if login with non-number uin - // t112() - t144( - androidId = client.device.androidId, - androidDevInfo = client.device.generateDeviceInfoData(), - osType = client.device.osType, - osVersion = client.device.version.release, - networkType = client.networkType, - simInfo = client.device.simInfo, - unknown = byteArrayOf(), - apn = client.device.apn, - isGuidFromFileNull = false, - isGuidAvailable = true, - isGuidChanged = false, - guidFlag = guidFlag(GuidSource.FROM_STORAGE, MacOrAndroidIdChangeFlag.NoChange), - buildModel = client.device.model, - guid = client.device.guid, - buildBrand = client.device.brand, - tgtgtKey = client.tgtgtKey - ) - - //this.build().debugPrint("傻逼") - t145(client.device.guid) - t147(appId, client.apkVersionName, client.apkSignatureMd5) - - if (client.miscBitMap and 0x80 != 0) { - t166(1) - } - - // ignored t16a because array5 is null - - t154(sequenceId) - t141(client.device.simInfo, client.networkType, client.device.apn) - t8(2052) - - t511( - listOf( - "tenpay.com", - "openmobile.qq.com", - "docs.qq.com", - "connect.qq.com", - "qzone.qq.com", - "vip.qq.com", - "qun.qq.com", - "game.qq.com", - "qqweb.qq.com", - "office.qq.com", - "ti.qq.com", - "mail.qq.com", - "qzone.com", - "mma.qq.com" + t18(appId, client.appClientVersion, client.uin) + t1(client.uin, client.device.ipAddress) + t106( + appId, + subAppId /* maybe 1*/, + client.appClientVersion, + client.uin, + 1, + client.account.passwordMd5, + 0, + client.uin.toByteArray(), + client.tgtgtKey, + true, + client.device.guid, + LoginType.PASSWORD ) - ) - // ignored t172 because rollbackSig is null - // ignored t185 because loginType is not SMS - // ignored t400 because of first login + /* // from GetStWithPasswd + int mMiscBitmap = this.mMiscBitmap; + if (t.uinDeviceToken) { + mMiscBitmap = (this.mMiscBitmap | 0x2000000); + } - t187(client.device.macAddress) - t188(client.device.androidId) - val imsi = client.device.imsiMd5 - if (imsi.isNotEmpty()) { - t194(imsi) + // defaults true + if (ConfigManager.get_loginWithPicSt()) appIdList = longArrayOf(1600000226L) + */ + t116(client.miscBitMap, client.subSigMap) + t100(appId, subAppId, client.appClientVersion, client.mainSigMap or 0xC0) + t107(0) + + // t108(byteArrayOf()) + // ignored: t104() + t142(client.apkId) + + // if login with non-number uin + // t112() + t144( + androidId = client.device.androidId, + androidDevInfo = client.device.generateDeviceInfoData(), + osType = client.device.osType, + osVersion = client.device.version.release, + networkType = client.networkType, + simInfo = client.device.simInfo, + unknown = byteArrayOf(), + apn = client.device.apn, + isGuidFromFileNull = false, + isGuidAvailable = true, + isGuidChanged = false, + guidFlag = guidFlag(GuidSource.FROM_STORAGE, MacOrAndroidIdChangeFlag.NoChange), + buildModel = client.device.model, + guid = client.device.guid, + buildBrand = client.device.brand, + tgtgtKey = client.tgtgtKey + ) + + //this.build().debugPrint("傻逼") + t145(client.device.guid) + t147(appId, client.apkVersionName, client.apkSignatureMd5) + + if (client.miscBitMap and 0x80 != 0) { + t166(1) + } + + // ignored t16a because array5 is null + + t154(sequenceId) + t141(client.device.simInfo, client.networkType, client.device.apn) + t8(2052) + + t511( + listOf( + "tenpay.com", + "openmobile.qq.com", + "docs.qq.com", + "connect.qq.com", + "qzone.qq.com", + "vip.qq.com", + "qun.qq.com", + "game.qq.com", + "qqweb.qq.com", + "office.qq.com", + "ti.qq.com", + "mail.qq.com", + "qzone.com", + "mma.qq.com" + ) + ) + + // ignored t172 because rollbackSig is null + // ignored t185 because loginType is not SMS + // ignored t400 because of first login + + t187(client.device.macAddress) + t188(client.device.androidId) + + val imsi = client.device.imsiMd5 + if (imsi.isNotEmpty()) { + t194(imsi) + } + t191() + + /* + t201(N = byteArrayOf())*/ + + val bssid = client.device.wifiBSSID + val ssid = client.device.wifiSSID + if (bssid != null && ssid != null) { + t202(bssid, ssid) + } + + t177() + t516() + t521() + + t525(buildPacket { + t536(buildPacket { + //com.tencent.loginsecsdk.ProtocolDet#packExtraData + writeByte(1) // const + writeByte(0) // data count + }.readBytes()) + }) + // this.build().debugPrint("傻逼") + + // ignored t318 because not logging in by QR } - t191() - - /* - t201(N = byteArrayOf())*/ - - val bssid = client.device.wifiBSSID - val ssid = client.device.wifiSSID - if (bssid != null && ssid != null) { - t202(bssid, ssid) - } - - t177() - t516() - t521() - - t525(buildPacket { - t536(buildPacket { - //com.tencent.loginsecsdk.ProtocolDet#packExtraData - writeByte(1) // const - writeByte(0) // data count - }.readBytes()) - }) - // this.build().debugPrint("傻逼") - - // ignored t318 because not logging in by QR } } } @@ -335,7 +337,7 @@ internal object LoginPacket : PacketFactory() { var a1: ByteArray? = null var noPicSig: ByteArray? = null tlvMap119[0x531]?.let { - analysisTlv0x531(it){ arg1, arg2 -> + analysisTlv0x531(it) { arg1, arg2 -> a1 = arg1 noPicSig = arg2 } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/SvcReqRegisterPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/SvcReqRegisterPacket.kt index 04dc823e9..16758fc94 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/SvcReqRegisterPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/SvcReqRegisterPacket.kt @@ -11,8 +11,9 @@ import net.mamoe.mirai.qqandroid.network.protocol.jce.SvcReqRegister import net.mamoe.mirai.qqandroid.network.protocol.jce.writeUniRequestPacket 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.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769 +import net.mamoe.mirai.qqandroid.network.protocol.packet.writeLoginSsoPacket import net.mamoe.mirai.qqandroid.utils.NetworkType import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.io.encodeToString @@ -34,65 +35,79 @@ internal object SvcReqRegisterPacket : PacketFactory + writeLoginSsoPacket(client, subAppId= subAppId, packetId = id, sequenceId = sequenceId){ + writeUniRequestPacket { + sServantName = "PushService" + sFuncName = "SvcReqRegister" + sBuffer = jceMap( 0, - SvcReqRegister( - cConnType = 0, - lBid = 1 or 2 or 4, - lUin = client.uin, - iStatus = client.onlineStatus.id, - bKikPC = 0, // 是否把 PC 踢下线 - bKikWeak = 0, - timeStamp = currentTimeSeconds, // millis or seconds?? - iLargeSeq = 0, - bRegType = - (if (regPushReason == RegPushReason.appRegister || - regPushReason == RegPushReason.fillRegProxy || - regPushReason == RegPushReason.createDefaultRegInfo || - regPushReason == RegPushReason.setOnlineStatus - ) 0 else 1).toByte(), - bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0, - iOSVersion = client.device.version.sdk.toLong(), - cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0, - vecGuid = client.device.guid, - strDevName = client.device.model.encodeToString(), - strDevType = client.device.model.encodeToString(), - strOSVer = client.device.version.release.encodeToString(), + "SvcReqRegister" to jceStruct( + 0, + SvcReqRegister( + cConnType = 0, + lBid = 1 or 2 or 4, + lUin = client.uin, + iStatus = client.onlineStatus.id, + bKikPC = 0, // 是否把 PC 踢下线 + bKikWeak = 0, + timeStamp = currentTimeSeconds, // millis or seconds?? + iLargeSeq = 0, + bRegType = + (if (regPushReason == RegPushReason.appRegister || + regPushReason == RegPushReason.fillRegProxy || + regPushReason == RegPushReason.createDefaultRegInfo || + regPushReason == RegPushReason.setOnlineStatus + ) 0 else 1).toByte(), + bIsSetStatus = if (regPushReason == RegPushReason.setOnlineStatus) 1 else 0, + iOSVersion = client.device.version.sdk.toLong(), + cNetType = if (client.networkType == NetworkType.WIFI) 1 else 0, + vecGuid = client.device.guid, + strDevName = client.device.model.encodeToString(), + strDevType = client.device.model.encodeToString(), + strOSVer = client.device.version.release.encodeToString(), - // register 时还需要 - /* - var44.uNewSSOIp = field_127445; - var44.uOldSSOIp = field_127444; - var44.strVendorName = ROMUtil.getRomName(); - var44.strVendorOSName = ROMUtil.getRomVersion(20); - */ - bytes_0x769_reqbody = ProtoBuf.dump( - Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody( - rpt_config_list = listOf( - Oidb0x769.ConfigSeq( - type = 46, - version = 4 - ), - Oidb0x769.ConfigSeq( - type = 283, - version = 0 + // register 时还需要 + /* + var44.uNewSSOIp = field_127445; + var44.uOldSSOIp = field_127444; + var44.strVendorName = ROMUtil.getRomName(); + var44.strVendorOSName = ROMUtil.getRomVersion(20); + */ + bytes_0x769_reqbody = ProtoBuf.dump( + Oidb0x769.RequestBody.serializer(), Oidb0x769.RequestBody( + rpt_config_list = listOf( + Oidb0x769.ConfigSeq( + type = 46, + version = 4 + ), + Oidb0x769.ConfigSeq( + type = 283, + version = 0 + ) ) ) - ) - ), - bSetMute = 0 + ), + bSetMute = 0 + ) ) ) - ) + } } } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt index 9d9fd86fe..227c1e8db 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/TransEmpPacket.kt @@ -20,7 +20,7 @@ internal object TransEmpPacket : PacketFactory() { @Suppress("FunctionName") fun SubCommand1( client: QQAndroidClient - ): OutgoingPacket = buildLoginOutgoingPacket(client, subAppId, ssoExtraData = byteArrayOf().toReadPacket()) { + ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2, subAppId = subAppId, ssoExtraData = byteArrayOf().toReadPacket()) { writeOicqRequestPacket(client, EncryptMethodECDH135(client.ecdh), id) { // oicq.wlogin_sdk.request.trans_emp_1#packTransEmpBody