From 88add06f8e37978a6c2bc29aa6804f5598b47f09 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Mon, 30 Dec 2019 16:31:47 +0800 Subject: [PATCH] Add Long.toByteArray --- .../qqandroid/network/protocol/packet/Tlv.kt | 629 ++++++++++++++++++ .../network/protocol/packet/TouchPacket.kt | 27 - .../protocol/packet/login/LoginPacket.kt | 138 +++- .../network/protocol/packet/tlv/Tlv.kt | 401 ----------- .../utils/io/TypeConversion.kt | 14 + 5 files changed, 767 insertions(+), 442 deletions(-) create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt delete mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/TouchPacket.kt delete mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/tlv/Tlv.kt diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt new file mode 100644 index 000000000..8f61cf347 --- /dev/null +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/Tlv.kt @@ -0,0 +1,629 @@ +package net.mamoe.mirai.qqandroid.network.protocol.packet + +import kotlinx.io.core.BytePacketBuilder +import kotlinx.io.core.ByteReadPacket +import kotlinx.io.core.toByteArray +import kotlinx.io.core.writeFully +import net.mamoe.mirai.utils.currentTime +import net.mamoe.mirai.utils.io.* +import net.mamoe.mirai.utils.md5 +import kotlin.random.Random + +inline class LoginType( + val value: Int +) { + companion object { + /** + * 短信验证登录 + */ + val SMS = LoginType(3) + /** + * 密码登录 + */ + val PASSWORD = LoginType(1) + /** + * 微信一键登录 + */ + val WE_CHAT = LoginType(4) + } +} + +@Suppress("MemberVisibilityCanBePrivate") +fun BytePacketBuilder.t1(uin: Long, ip: ByteArray) { + require(ip.size == 4) + writeShort(0x1) + writeShortLVPacket { + writeShort(1) // _ip_ver + writeInt(Random.nextInt()) + writeInt(uin.toInt()) + writeTime() + writeFully(ip) + writeShort(0) + } shouldEqualsTo 20 +} + +fun BytePacketBuilder.t2(captchaCode: String, captchaToken: ByteArray, sigVer: Short = 0) { + writeShort(0x2) + writeShortLVPacket { + writeShort(sigVer) + writeShortLVString(captchaCode) + writeShortLVByteArray(captchaToken) + } +} + +fun BytePacketBuilder.t8( + localId: Int = 2052 +) { + writeShort(0x8) + writeShortLVPacket { + writeShort(0) + writeInt(localId) // localId + writeShort(0) + } +} + +fun BytePacketBuilder.t18( + appId: Long, + appClientVersion: Int, + uin: Long, + constant1_always_0: Int = 0 +) { + writeShort(0x18) + writeShortLVPacket { + writeShort(1) //_ping_version + writeInt(1536) //_sso_version + writeInt(appId.toInt()) + writeInt(appClientVersion) + writeInt(uin.toInt()) + writeShort(constant1_always_0.toShort()) + writeShort(0) + } shouldEqualsTo 22 +} + +fun BytePacketBuilder.t106( + appId: Long, + subAppId: Long, + appClientVersion: Int, + uin: Long, + ipAddress: ByteArray, + n5_always_1: Int = 1, + passwordMd5: ByteArray, + salt: Long, + uinAccount: ByteArray, + tgtgtKey: ByteArray, + isGuidAvailable: Boolean = true, + guid: ByteArray?, // notnull if isGuidAvailable + loginType: LoginType +) { + writeShort(0x106) + + writeShortLVPacket { + encryptAndWrite(md5(passwordMd5 + (salt.takeIf { it != 0L } ?: uin).toInt().toByteArray())) { + writeShort(4)//TGTGTVer + writeInt(Random.nextInt()) + writeInt(5)//ssoVer + writeInt(appId.toInt()) + writeInt(appClientVersion) + + if (uin == 0L) { + writeLong(salt) + } else { + writeLong(uin) + } + + writeTime() + writeFully(ipAddress) + writeByte(n5_always_1.toByte()) + writeFully(passwordMd5) + writeFully(tgtgtKey) + writeInt(0) + writeByte(isGuidAvailable.toByte()) + if (isGuidAvailable) { + require(guid != null) { "Guid must not be null when isGuidAvailable==true" } + } + if (guid == null) { + repeat(4) { + writeInt(Random.nextInt()) + } + } else { + writeFully(guid) + } + writeInt(subAppId.toInt()) + writeInt(loginType.value) + writeShortLVByteArray(uinAccount) + } + } shouldEqualsTo 98 +} + +fun BytePacketBuilder.t116( + miscBitmap: Int, + subSigMap: Int, + appIdList: LongArray +) { + writeShort(0x116) + writeShortLVPacket { + writeByte(0) // _ver + writeInt(miscBitmap) + writeInt(subSigMap) + writeByte(appIdList.size.toByte()) + appIdList.forEach { + writeInt(it.toInt()) + } + } +} + +fun BytePacketBuilder.t100( + appId: Long, + subAppId: Long, + appClientVersion: Int, + sigMap: Int +) { + writeShort(0x100) + writeShortLVPacket { + writeShort(1)//db_buf_ver + writeInt(5)//sso_ver + writeInt(appId.toInt()) + writeInt(subAppId.toInt()) + writeInt(appClientVersion) + writeInt(sigMap) + } shouldEqualsTo 22 +} + +fun BytePacketBuilder.t107( + picType: Int, + const1_always_0: Int = 0, + const2_always_0: Int = 0, + const3_always_1: Int = 1 +) { + writeShort(0x107) + writeShortLVPacket { + writeShort(picType.toShort()) + writeByte(const1_always_0.toByte()) + writeShort(const2_always_0.toShort()) + writeByte(const3_always_1.toByte()) + } shouldEqualsTo 6 +} + +fun BytePacketBuilder.t108( + ksid: ByteArray +) { + writeShort(0x108) + writeShortLVPacket { + writeFully(ksid) + } +} + +fun BytePacketBuilder.t104( + t104Data: ByteArray +) { + writeShort(0x104) + writeShortLVPacket { + writeFully(t104Data) + } +} + +/** + * @param apkId application.getPackageName().getBytes() + */ +fun BytePacketBuilder.t142( + apkId: ByteArray +) { + writeShort(0x142) + writeShortLVPacket { + writeShort(0) //_version + writeShortLVByteArrayLimitedLength(apkId, 32) + } +} + +fun BytePacketBuilder.t112( + nonNumberUin: ByteArray +) { + writeShort(0x112) + writeShortLVPacket { + writeFully(nonNumberUin) + } +} + +fun BytePacketBuilder.t144( + // t109 + androidId: ByteArray, + + // t52d + androidDevInfo: ByteArray, + + // t124 + osType: ByteArray = "android".toByteArray(), + osVersion: ByteArray, + ipv6NetType: Int, + simInfo: ByteArray, + unknown: ByteArray, + apn: ByteArray = "wifi".toByteArray(), + + // t128 + isGuidFromFileNull: Boolean = false, + isGuidAvailable: Boolean = true, + isGuidChanged: Boolean = false, + guidFlag: Long, + buildModel: ByteArray, + guid: ByteArray, + buildBrand: ByteArray, + + // encrypt + tgtgtKey: ByteArray +) { + writeShort(0x144) + writeShortLVPacket { + encryptAndWrite(tgtgtKey) { + t109(androidId) + t52d(androidDevInfo) + t124(osType, osVersion, ipv6NetType, simInfo, unknown, apn) + t128(isGuidFromFileNull, isGuidAvailable, isGuidChanged, guidFlag, buildModel, guid, buildBrand) + t16e(buildModel) + } + } +} + +fun BytePacketBuilder.t109( + androidId: ByteArray +) { + writeShort(0x109) + writeShortLVPacket { + writeFully(androidId) + } +} + +fun BytePacketBuilder.t52d( + androidDevInfo: ByteArray // oicq.wlogin_sdk.tools.util#get_android_dev_info +) { + writeShort(0x52d) + writeShortLVPacket { + writeFully(androidDevInfo) + } +} + +fun BytePacketBuilder.t124( + osType: ByteArray = "android".toByteArray(), + osVersion: ByteArray, // Build.VERSION.RELEASE.toByteArray() + ipv6NetType: Int, //oicq.wlogin_sdk.tools.util#get_network_type + simInfo: ByteArray, // oicq.wlogin_sdk.tools.util#get_sim_operator_name + unknown: ByteArray, + apn: ByteArray = "wifi".toByteArray() // oicq.wlogin_sdk.tools.util#get_apn_string +) { + writeShort(0x124) + writeShortLVPacket { + writeShortLVByteArrayLimitedLength(osType, 16) + writeShortLVByteArrayLimitedLength(osVersion, 16) + writeShort(ipv6NetType.toShort()) + writeShortLVByteArrayLimitedLength(simInfo, 16) + writeShortLVByteArrayLimitedLength(unknown, 32) + writeShortLVByteArrayLimitedLength(apn, 16) + } +} + +fun BytePacketBuilder.t128( + isGuidFromFileNull: Boolean = false, // 保存到文件的 GUID 是否为 null + isGuidAvailable: Boolean = true, // GUID 是否可用(计算/读取成功) + isGuidChanged: Boolean = false, // GUID 是否有变动 + /** + * guidFlag: + * ```java + * GUID_FLAG = 0; + * GUID_FLAG |= GUID_SRC << 24 & 0xFF000000; + * GUID_FLAG |= FLAG_MAC_ANDROIDID_GUID_CHANGE << 8 & 0xFF00; + * ``` + * + * + * GUID_SRC: + * 0: 初始值; + * 1: 以前保存的文件; + * 20: 以前没保存且现在生成失败; + * 17: 以前没保存但现在生成成功; + * + * + * FLAG_MAC_ANDROIDID_GUID_CHANGE: + * ```java + * if (!Arrays.equals(currentMac, get_last_mac)) { + * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x1; + * } + * if (!Arrays.equals(currentAndroidId, get_last_android_id)) { + * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x2; + * } + * if (!Arrays.equals(currentGuid, get_last_guid)) { + * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x4; + * } + * ``` + */ + guidFlag: Long, + buildModel: ByteArray, // android.os.Build.MODEL + /** + * defaults `"%4;7t>;28<fc.5*6".toByteArray()` + */ + guid: ByteArray, + buildBrand: ByteArray // android.os.Build.BRAND +) { + writeShort(0x128) + writeShortLVPacket { + writeShort(0) + writeByte(isGuidFromFileNull.toByte()) + writeByte(isGuidAvailable.toByte()) + writeByte(isGuidChanged.toByte()) + writeInt(guidFlag.toInt()) + writeShortLVByteArrayLimitedLength(buildModel, 32) + writeShortLVByteArrayLimitedLength(guid, 16) + writeShortLVByteArrayLimitedLength(buildBrand, 16) + } +} + +fun BytePacketBuilder.t16e( + buildModel: ByteArray +) { + writeShort(0x16e) + writeShortLVPacket { + writeFully(buildModel) + } +} + +fun BytePacketBuilder.t145( + guid: ByteArray +) { + writeShort(0x145) + writeShortLVPacket { + writeFully(guid) + } +} + +fun BytePacketBuilder.t147( + appId: Long, + apkVersionName: ByteArray, + apkSignatureMd5: ByteArray +) { + writeShort(0x147) + writeShortLVPacket { + writeLong(appId) + writeShortLVByteArrayLimitedLength(apkVersionName, 32) + writeShortLVByteArrayLimitedLength(apkSignatureMd5, 32) + } +} + +fun BytePacketBuilder.t166( + imageType: Int +) { + writeShort(0x166) + writeShortLVPacket { + writeByte(imageType.toByte()) + } +} + +fun BytePacketBuilder.t16a( + noPicSig: ByteArray // unknown source +) { + writeShort(0x16a) + writeShortLVPacket { + writeFully(noPicSig) + } +} + +fun BytePacketBuilder.t154( + ssoSequenceId: Int // starts from 0 +) { + writeShort(0x154) + writeShortLVPacket { + writeInt(ssoSequenceId) + } +} + +fun BytePacketBuilder.t141( + simInfo: ByteArray, + ipv6NetType: Int, + apn: ByteArray +) { + writeShort(0x141) + writeShortLVPacket { + writeShort(1) // version + writeShortLVByteArray(simInfo) + writeShort(ipv6NetType.toShort()) + writeShortLVByteArray(apn) + } +} + +fun BytePacketBuilder.t511( + domains: List<String> +) { + writeShort(0x511) + writeShortLVPacket { + val list = domains.filter { it.isNotEmpty() } + writeShort(list.size.toShort()) + list.forEach { element -> + if (element.startsWith('(')) { + val split = element.drop(1).split(')') + + val flag = split[0].toInt() + var n = (flag and 0x100000 > 0).toInt() + if (flag and 0x8000000 > 0) { + n = n or 0x2 + } + writeByte(n.toByte()) + + writeShortLVString(split[1]) + } else { + writeByte(1) + writeShortLVString(element) + } + } + } +} + +fun BytePacketBuilder.t172( + rollbackSig: ByteArray // 由服务器发来的 tlv_t172 获得 +) { + writeShort(0x172) + writeShortLVPacket { + writeFully(rollbackSig) + } +} + +fun BytePacketBuilder.t185() { + writeShort(0x185) + writeShortLVPacket { + writeByte(1) + writeByte(1) + } +} + +fun BytePacketBuilder.t400( + g: ByteArray, // 用于加密这个 tlv + uin: Long, + guid: ByteArray, + dpwd: ByteArray, + appId: Long, + subAppId: Long, + randomSeed: ByteArray +) { + writeShort(0x400) + writeShortLVPacket { + writeByte(1) // version + writeLong(uin) + + encryptAndWrite(g) { + writeFully(guid) + writeFully(dpwd) + writeInt(appId.toInt()) + writeInt(subAppId.toInt()) + writeLong(currentTime) + writeFully(randomSeed) + } + } +} + +fun BytePacketBuilder.t187( + macAddress: ByteArray +) { + writeShort(0x187) + writeShortLVPacket { + writeFully(macAddress) + } +} + +fun BytePacketBuilder.t188( + androidId: ByteArray +) { + writeShort(0x188) + writeShortLVPacket { + writeFully(androidId) + } +} + +fun BytePacketBuilder.t194( + imsiMd5: ByteArray +) { + writeShort(0x194) + writeShortLVPacket { + writeFully(imsiMd5) + } +} + +fun BytePacketBuilder.t191( + K: Int = 0 +) { + writeShort(0x191) + writeShortLVPacket { + writeByte(K.toByte()) + } +} + +fun BytePacketBuilder.t201( + L: ByteArray = byteArrayOf(), // unknown + channelId: ByteArray = byteArrayOf(), + clientType: ByteArray = "qq".toByteArray(), + N: ByteArray +) { + writeShort(0x201) + writeShortLVPacket { + writeShortLVByteArray(L) + writeShortLVByteArray(channelId) + writeShortLVByteArray(clientType) + writeShortLVByteArray(N) + } +} + +fun BytePacketBuilder.t202( + wifiBSSID: ByteArray, + wifiSSID: ByteArray +) { + writeShort(0x202) + writeShortLVPacket { + writeShortLVByteArrayLimitedLength(wifiBSSID, 16) + writeShortLVByteArrayLimitedLength(wifiSSID, 32) + } +} + +fun BytePacketBuilder.t177( + unknown1: Long = 1571193922L, + unknown2: String = "6.0.0.2413" +) { + writeShort(0x177) + writeShortLVPacket { + writeByte(1) + writeLong(unknown1) + writeShortLVString(unknown2) + } +} + +fun BytePacketBuilder.t516( // 1302 + sourceType: Int = 0 // always 0 +) { + writeShort(0x516) + writeShortLVPacket { + writeInt(sourceType) + } +} + +fun BytePacketBuilder.t521( // 1313 + productType: Int = 0, // coz setProductType is never used + unknown: Short = 0 // const +) { + writeShort(0x521) + writeShortLVPacket { + writeInt(productType) + writeShort(unknown) + } +} + +fun BytePacketBuilder.t536( // 1334 + loginExtraData: ByteArray +) { + writeShort(0x536) + writeShortLVPacket { + writeFully(loginExtraData) + } +} + +fun BytePacketBuilder.t525( + t536: ByteReadPacket +) { + writeShort(0x525) + writeShortLVPacket { + writeShort(1) + writePacket(t536) + } +} + +fun BytePacketBuilder.t318( + tgtQR: ByteArray // unknown +) { + writeShort(0x318) + writeShortLVPacket { + writeFully(tgtQR) + } +} + +private fun Boolean.toByte(): Byte = if (this) 1 else 0 +private fun Boolean.toInt(): Int = if (this) 1 else 0 + +private infix fun Int.shouldEqualsTo(int: Int) = require(this == int) + +fun randomAndroidId(): String = buildString(15) { + repeat(15) { append(Random.nextInt(10)) } +} + +// AndroidDevInfo: oicq.wlogin_sdk.tools.util#get_android_dev_info diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/TouchPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/TouchPacket.kt deleted file mode 100644 index a21f2843d..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/TouchPacket.kt +++ /dev/null @@ -1,27 +0,0 @@ -package net.mamoe.mirai.qqandroid.network.protocol.packet - -import kotlinx.io.core.ByteReadPacket -import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.network.BotNetworkHandler -import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId -import net.mamoe.mirai.utils.cryptor.DecrypterByteArray -import net.mamoe.mirai.utils.cryptor.DecrypterType - - -object TouchKey : DecrypterByteArray, - DecrypterType<TouchKey> { - override val value: ByteArray - get() = TODO("not implemented") -} - -object TouchPacket : PacketFactory<TouchPacketResponse, TouchKey>( - TouchKey -) { - @UseExperimental(ExperimentalUnsignedTypes::class) - override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler): TouchPacketResponse { - TODO("not implemented") - } -} - - -interface TouchPacketResponse : Packet \ No newline at end of file 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 d3ce46b2b..19a9aa770 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 @@ -2,32 +2,142 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.login import kotlinx.io.core.ByteReadPacket +import kotlinx.io.core.buildPacket +import kotlinx.io.core.readBytes import net.mamoe.mirai.data.Packet import net.mamoe.mirai.network.BotNetworkHandler -import net.mamoe.mirai.qqandroid.network.QQAndroidDevice -import net.mamoe.mirai.qqandroid.network.protocol.packet.EncryptMethod -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.buildOutgoingPacket -import net.mamoe.mirai.qqandroid.network.protocol.packet.tlv.writeTLVList +import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.qqandroid.network.protocol.packet.* +import net.mamoe.mirai.qqandroid.utils.GuidSource +import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag +import net.mamoe.mirai.qqandroid.utils.guidFlag import net.mamoe.mirai.utils.cryptor.DecrypterByteArray import net.mamoe.mirai.utils.cryptor.DecrypterType +import net.mamoe.mirai.utils.io.toByteArray class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray { - companion object : DecrypterType<LoginPacketDecrypter> { - - } + companion object : DecrypterType<LoginPacketDecrypter> } @UseExperimental(ExperimentalUnsignedTypes::class) -object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) { +internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) { - fun invoke( - device: QQAndroidDevice - ): OutgoingPacket = buildOutgoingPacket(device, EncryptMethod.ByECDH135) { - writeTLVList { + operator fun invoke( + client: QQAndroidClient + ): OutgoingPacket = buildOutgoingPacket(client, EncryptMethod.ByECDH135) { + writeECDHEncryptedPacket(client.ecdh) { + writeShort(9) // subCommand + writeShort(LoginType.PASSWORD.value.toShort()) + client.run { + client.device.run { + val appId = 16L + val subAppId = 2L + + t18(appId, appClientVersion, account.id) + t1(account.id, ipAddress) + t106( + appId, + subAppId /* maybe 1*/, + appClientVersion, + account.id, + ipAddress, + 1, + account.passwordMd5, + 0, + account.id.toByteArray(), + tgtgtKey, + true, + 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(miscBitMap, subSigMap, longArrayOf(1600000226L)) + t100(appId, subAppId, appClientVersion, mainSigMap or 0xC0) + t107(0) + t108(byteArrayOf()) + // ignored: t104() + t142(apkId) + + // if login with non-number uin + // t112() + t144( + androidId = androidId, + androidDevInfo = generateDeviceInfoData(), + osType = osType, + osVersion = version.release, + ipv6NetType = ipv6NetType, + simInfo = simInfo, + unknown = byteArrayOf(), apn = apn, + isGuidFromFileNull = false, + isGuidAvailable = true, + isGuidChanged = false, + guidFlag = guidFlag(GuidSource.FROM_STORAGE, MacOrAndroidIdChangeFlag.NoChange), + buildModel = model, + guid = guid, + buildBrand = brand, + tgtgtKey = tgtgtKey + ) + + t145(guid) + t147(appId, apkVersionName, apkSignatureMd5) + + if (miscBitMap and 0x80 != 0) { + t166(1) + } + + // ignored t16a because array5 is null + + t154(ssoSequenceId) + t141(simInfo, ipv6NetType, apn) + t8(2052) + + // ignored t511 because domain is null + // ignored t172 because rollbackSig is null + // ignored t185 because loginType is not SMS + // ignored t400 because of first login + + t187(macAddress) + t188(androidId) + if (imsiMd5.isNotEmpty()) { + t194(imsiMd5) + } + t191() + t201(N = byteArrayOf()) + + val bssid = wifiBSSID + val ssid = 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()) + }) + + // ignored t318 because not logging in by QR + } + } } + } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/tlv/Tlv.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/tlv/Tlv.kt deleted file mode 100644 index 63e124d41..000000000 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/tlv/Tlv.kt +++ /dev/null @@ -1,401 +0,0 @@ -package net.mamoe.mirai.qqandroid.network.protocol.packet.tlv - -import kotlinx.io.core.* -import net.mamoe.mirai.utils.io.* -import net.mamoe.mirai.utils.md5 -import kotlin.random.Random - - -fun BytePacketBuilder.writeTLVList(block: TlvBuilder.() -> Unit) { - var tlvCount = 0 - val tlvList = buildPacket { block(TlvBuilder { tlvCount++ }) } - writeShort(tlvCount.toShort()) - writePacket(tlvList) -} - - -inline class LoginType( - val value: Int -) { - companion object { - val SMS = LoginType(3) - val PASSWORD = LoginType(1) - val WE_CHAT = LoginType(4) - } -} - -inline class TlvBuilder( - val counter: () -> Unit -) { - fun BytePacketBuilder.t1(uin: Long, ip: ByteArray) { - require(ip.size == 4) - writeShort(0x1) - writeShortLVPacket { - writeShort(1) // _ip_ver - writeInt(Random.nextInt()) - writeInt(uin.toInt()) - writeTime() - writeFully(ip) - writeShort(0) - } shouldEqualsTo 20 - } - - fun BytePacketBuilder.t2(captchaCode: String, captchaToken: ByteArray, sigVer: Short = 0) { - writeShort(0x2) - writeShortLVPacket { - writeShort(sigVer) - writeShortLVString(captchaCode) - writeShortLVByteArray(captchaToken) - } - } - - fun BytePacketBuilder.t8() { - writeShort(0x0008) - writeShortLVPacket { - writeShort(0) - writeInt(2052) // localId - writeShort(0) - } - } - - fun BytePacketBuilder.t18(appId: Long, appClientVersion: Int, uin: Long, constant1_always_0: Int) { - writeShort(0x18) - writeShortLVPacket { - writeShort(1) //_ping_version - writeInt(1536) //_sso_version - writeInt(appId.toInt()) - writeInt(appClientVersion) - writeInt(uin.toInt()) - writeShort(constant1_always_0.toShort()) - writeShort(0) - } shouldEqualsTo 22 - } - - fun BytePacketBuilder.t106( - appId: Long, - subAppId: Long, - appClientVersion: Int, - uin: Long, - ipAddress: ByteArray, - n5_always_1: Int = 1, - temp_pwd: ByteArray, - salt: Long, - uinAccount: ByteArray, - tgtgtKey: ByteArray, - n7: Int, - array_6_may_be_null: ByteArray?, - loginType: LoginType - ) { - writeShort(0x106) - - writeShortLVPacket { - encryptAndWrite( - if (salt == 0L) { - md5(buildPacket { writeFully(temp_pwd); writeInt(uin.toInt()) }.readBytes()) - } else { - md5(buildPacket { writeFully(temp_pwd); writeInt(salt.toInt()) }.readBytes()) - } - ) { - writeShort(4)//TGTGTVer - writeInt(Random.nextInt()) - writeInt(5)//ssoVer - writeInt(appId.toInt()) - writeInt(appClientVersion) - - if (uin == 0L) { - writeLong(salt) - } else { - writeLong(uin) - } - - writeTime() - writeFully(ipAddress) - writeByte(n5_always_1.toByte()) - writeFully(temp_pwd) - writeFully(tgtgtKey) - writeInt(0) - writeByte(n7.toByte()) - if (array_6_may_be_null == null) { - repeat(4) { - writeInt(Random.nextInt()) - } - } else { - writeFully(array_6_may_be_null) - } - writeInt(subAppId.toInt()) - writeInt(loginType.value) - writeShortLVByteArray(uinAccount) - } - } shouldEqualsTo 98 - } - - fun BytePacketBuilder.t116( - miscBitmap: Int, - subSigMap: Int, - appIdList: LongArray - ) { - writeShort(0x116) - writeShortLVPacket { - writeByte(0) // _ver - writeInt(miscBitmap) - writeInt(subSigMap) - writeByte(appIdList.size.toByte()) - appIdList.forEach { - writeInt(it.toInt()) - } - } - } - - fun BytePacketBuilder.t100( - appId: Long, - subAppId: Long, - appClientVersion: Int, - mainSigMap: Int - ) { - writeShort(0x100) - writeShortLVPacket { - writeShort(1)//db_buf_ver - writeInt(5)//sso_ver - writeInt(appId.toInt()) - writeInt(subAppId.toInt()) - writeInt(appClientVersion) - writeInt(mainSigMap) - } shouldEqualsTo 22 - } - - fun BytePacketBuilder.t107( - picType: Int, - const1_always_0: Int = 0, - const2_always_0: Int = 0, - const3_always_1: Int = 1 - ) { - writeShort(0x107) - writeShortLVPacket { - writeShort(picType.toShort()) - writeByte(const1_always_0.toByte()) - writeShort(const2_always_0.toShort()) - writeByte(const3_always_1.toByte()) - } shouldEqualsTo 6 - } - - fun BytePacketBuilder.t108( - to_verify_passwd_img: ByteArray - ) { - writeShort(0x108) - writeShortLVPacket { - writeFully(to_verify_passwd_img) - } - } - - fun BytePacketBuilder.t104( - t104Data: ByteArray - ) { - writeShort(0x104) - writeShortLVPacket { - writeFully(t104Data) - } - } - - /** - * @param apkId application.getPackageName().getBytes() - */ - fun BytePacketBuilder.t142( - apkId: ByteArray - ) { - writeShort(0x142) - writeShortLVPacket { - writeShort(0) //_version - writeShortLVByteArrayLimitedLength(apkId, 32) - } - } - - fun BytePacketBuilder.t112( - nonNumberUin: ByteArray - ) { - writeShort(0x112) - writeShortLVPacket { - writeFully(nonNumberUin) - } - } - - fun BytePacketBuilder.t144( - // t109 - androidId: ByteArray, - - // t52d - androidDevInfo: ByteArray, - - // t124 - osType: ByteArray = "android".toByteArray(), - osVersion: ByteArray, - ipv6NetType: Int, - simInfo: ByteArray, - unknown: ByteArray, - apn: ByteArray = "wifi".toByteArray(), - - // t128 - isGuidFromFileNull: Boolean = false, - isGuidAvailable: Boolean = true, - isGuidChanged: Boolean = false, - guidFlag: Int, - buildModel: ByteArray, - guid: ByteArray, - buildBrand: ByteArray, - - // encrypt - tgtgtKey: ByteArray - ) { - writeShort(0x144) - writeShortLVPacket { - encryptAndWrite(tgtgtKey) { - t109(androidId) - t52d(androidDevInfo) - t124(osType, osVersion, ipv6NetType, simInfo, unknown, apn) - t128(isGuidFromFileNull, isGuidAvailable, isGuidChanged, guidFlag, buildModel, guid, buildBrand) - t16e(buildModel) - } - } - } - - fun BytePacketBuilder.t109( - androidId: ByteArray - ) { - writeShort(0x109) - writeShortLVPacket { - writeFully(androidId) - } - } - - fun BytePacketBuilder.t52d( - androidDevInfo: ByteArray // oicq.wlogin_sdk.tools.util#get_android_dev_info - ) { - writeShort(0x52d) - writeShortLVPacket { - writeFully(androidDevInfo) - } - } - - fun BytePacketBuilder.t124( - osType: ByteArray = "android".toByteArray(), - osVersion: ByteArray, // Build.VERSION.RELEASE.toByteArray() - ipv6NetType: Int, //oicq.wlogin_sdk.tools.util#get_network_type - simInfo: ByteArray, // oicq.wlogin_sdk.tools.util#get_sim_operator_name - unknown: ByteArray, - apn: ByteArray = "wifi".toByteArray() // oicq.wlogin_sdk.tools.util#get_apn_string - ) { - writeShort(0x124) - writeShortLVPacket { - writeShortLVByteArrayLimitedLength(osType, 16) - writeShortLVByteArrayLimitedLength(osVersion, 16) - writeShort(ipv6NetType.toShort()) - writeShortLVByteArrayLimitedLength(simInfo, 16) - writeShortLVByteArrayLimitedLength(unknown, 32) - writeShortLVByteArrayLimitedLength(apn, 16) - } - } - - fun BytePacketBuilder.t128( - isGuidFromFileNull: Boolean = false, // 保存到文件的 GUID 是否为 null - isGuidAvailable: Boolean = true, // GUID 是否可用(计算/读取成功) - isGuidChanged: Boolean = false, // GUID 是否有变动 - /** - * guidFlag: - * ```java - * GUID_FLAG |= GUID_SRC << 24 & 0xFF000000; - * GUID_FLAG |= FLAG_MAC_ANDROIDID_GUID_CHANGE << 8 & 0xFF00; - * ``` - * - * FLAG_MAC_ANDROIDID_GUID_CHANGE: - * ```java - * if (!Arrays.equals(currentMac, get_last_mac)) { - * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x1; - * } - * if (!Arrays.equals(currentAndroidId, get_last_android_id)) { - * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x2; - * } - * if (!Arrays.equals(currentGuid, get_last_guid)) { - * oicq.wlogin_sdk.request.t.FLAG_MAC_ANDROIDID_GUID_CHANGEMENT |= 0x4; - * } - * ``` - */ - guidFlag: Int, - buildModel: ByteArray, // android.os.Build.MODEL - /** - * [generateGuid] or `"%4;7t>;28<fc.5*6".toByteArray()` - */ - guid: ByteArray, - buildBrand: ByteArray // android.os.Build.BRAND - ) { - writeShort(0x128) - writeShortLVPacket { - writeShort(0) - writeByte(isGuidFromFileNull.toByte()) - writeByte(isGuidAvailable.toByte()) - writeByte(isGuidChanged.toByte()) - writeInt(guidFlag) - writeShortLVByteArrayLimitedLength(buildModel, 32) - writeShortLVByteArrayLimitedLength(guid, 16) - writeShortLVByteArrayLimitedLength(buildBrand, 16) - } - } - - fun BytePacketBuilder.t16e( - buildModel: ByteArray - ) { - writeShort(0x16e) - writeShortLVPacket { - writeFully(buildModel) - } - } - - fun BytePacketBuilder.t145( - guid: ByteArray - ) { - writeShort(0x145) - writeShortLVPacket { - writeFully(guid) - } - } - - fun BytePacketBuilder.t147( - appId: Long, - apkVersionName: ByteArray, - apkSignatureMd5: ByteArray - ) { - writeShort(0x147) - writeShortLVPacket { - writeLong(appId) - writeShortLVByteArrayLimitedLength(apkVersionName, 32) - writeShortLVByteArrayLimitedLength(apkSignatureMd5, 32) - } - } - - fun BytePacketBuilder.t166( - imageType: Int - ) { - writeShort(0x166) - writeShortLVPacket { - writeByte(imageType.toByte()) - } - } -} - -private fun Boolean.toByte(): Byte = if (this) 1 else 0 - -private infix fun Int.shouldEqualsTo(int: Int) = require(this == int) - -fun randomAndroidId(): String = buildString(15) { - repeat(15) { append(Random.nextInt(10)) } -} - -/** - * Defaults "%4;7t>;28<fc.5*6".toByteArray() - */ -fun generateGuid(androidId: String, macAddress: String): ByteArray { - return md5(androidId + macAddress) -} - -fun getMacAddr(): String = "02:00:00:00:00:00" - - -// AndroidDevInfo: oicq.wlogin_sdk.tools.util#get_android_dev_info diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt index 7d0c10f57..e95b0823f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt @@ -22,6 +22,20 @@ fun Int.toByteArray(): ByteArray = byteArrayOf( (shr(0) and 0xFF).toByte() ) +/** + * 255 -> 00 00 00 FF + */ +fun Long.toByteArray(): ByteArray = byteArrayOf( + (shr(56) and 0xFF).toByte(), + (shr(48) and 0xFF).toByte(), + (shr(40) and 0xFF).toByte(), + (shr(32) and 0xFF).toByte(), + (shr(24) and 0xFF).toByte(), + (shr(16) and 0xFF).toByte(), + (shr(8) and 0xFF).toByte(), + (shr(0) and 0xFF).toByte() +) + fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator) /**