Commit b062c580 authored by Him188's avatar Him188

Android stuff

parent 67903e67
...@@ -66,6 +66,8 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo( ...@@ -66,6 +66,8 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(
get() = md5(kotlin.runCatching { get() = md5(kotlin.runCatching {
(context.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).subscriberId.toByteArray() (context.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).subscriberId.toByteArray()
}.getOrElse { byteArrayOf() }) }.getOrElse { byteArrayOf() })
override val imei: String get() = "858414369211993" // TODO: 2020/1/5 get actual imei and ksid
override val ksid: String get() = "|454001228437590|A8.2.0.27f6ea96"
override val ipAddress: String get() = localIpAddress() override val ipAddress: String get() = localIpAddress()
override val androidId: ByteArray get() = Build.ID.toByteArray() override val androidId: ByteArray get() = Build.ID.toByteArray()
override val apn: ByteArray get() = "wifi".toByteArray() override val apn: ByteArray get() = "wifi".toByteArray()
......
package net.mamoe.mirai.qqandroid.network package net.mamoe.mirai.qqandroid.network
import kotlinx.atomicfu.AtomicInt
import kotlinx.atomicfu.atomic
import kotlinx.io.core.toByteArray import kotlinx.io.core.toByteArray
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.qqandroid.utils.* import net.mamoe.mirai.qqandroid.utils.*
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
/* /*
...@@ -33,7 +36,11 @@ internal open class QQAndroidClient( ...@@ -33,7 +36,11 @@ internal open class QQAndroidClient(
var mainSigMap: Int = 16724722 var mainSigMap: Int = 16724722
var subSigMap: Int = 0x10400 //=66,560 var subSigMap: Int = 0x10400 //=66,560
var ssoSequenceId: Int = 85602 private val _ssoSequenceId: AtomicInt = atomic(85600)
@MiraiInternalAPI("Do not use directly. Get from the lambda param of buildSsoPacket")
internal fun nextSsoSequenceId() = _ssoSequenceId.addAndGet(2)
var openAppId: Long = 715019303L var openAppId: Long = 715019303L
val apkVersionName: ByteArray = "8.2.0".toByteArray() val apkVersionName: ByteArray = "8.2.0".toByteArray()
......
package net.mamoe.mirai.qqandroid.network.protocol.packet package net.mamoe.mirai.qqandroid.network.protocol.packet
import kotlinx.io.core.* import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.buildPacket
import kotlinx.io.core.writeFully
import net.mamoe.mirai.data.Packet import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId import net.mamoe.mirai.qqandroid.network.protocol.packet.login.PacketId
import net.mamoe.mirai.qqandroid.utils.ECDH import net.mamoe.mirai.qqandroid.utils.ECDH
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.encryptAndWrite import net.mamoe.mirai.utils.cryptor.DecrypterByteArray
import net.mamoe.mirai.utils.io.writeIntLVPacket import net.mamoe.mirai.utils.cryptor.encryptAndWrite
import net.mamoe.mirai.utils.io.writeQQ import net.mamoe.mirai.utils.cryptor.encryptBy
import net.mamoe.mirai.utils.io.writeShortLVByteArray import net.mamoe.mirai.utils.io.*
/** /**
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket], * 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket],
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
class OutgoingPacket constructor( internal class OutgoingPacket constructor(
name: String?, name: String?,
val packetId: PacketId, val packetId: PacketId,
val sequenceId: UShort, val sequenceId: UShort,
...@@ -27,28 +30,218 @@ class OutgoingPacket constructor( ...@@ -27,28 +30,218 @@ class OutgoingPacket constructor(
} }
} }
private val KEY_16_ZEROS = ByteArray(16)
private val EMPTY_BYTE_ARRAY = ByteArray(0)
/** /**
* Encryption method to be used for packet body. * Outermost packet for login
*
* **Packet structure**
* int remaining.length + 4
* int 0x0A
* byte 0x02
* int extra data size + 4
* byte[] extra data
* byte 0
* int [uinAccount].length + 4
* byte[] uinAccount
*
* byte[] body encrypted by 16 zero
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
inline class EncryptMethod(val value: UByte) { internal inline fun PacketFactory<*, *>.buildLoginOutgoingPacket(
companion object { uinAccount: String,
val BySessionToken = EncryptMethod(69u) extraData: ByteArray = EMPTY_BYTE_ARRAY,
val ByECDH7 = EncryptMethod(7u) name: String? = null,
// 登录都使用 135 id: PacketId = this.id,
val ByECDH135 = EncryptMethod(135u) sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
body: BytePacketBuilder.() -> Unit
): OutgoingPacket = OutgoingPacket(name, id, sequenceId, buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x00_00_00_0A)
writeByte(0x02)
writeInt(extraData.size + 4)
writeFully(extraData)
writeByte(0x00)
writeInt(uinAccount.length + 4)
writeStringUtf8(uinAccount)
encryptAndWrite(KEY_16_ZEROS, body)
}
})
internal class CommandId(val stringValue: String, val id: Int) {
override fun toString(): String = stringValue
}
private val BRP_STUB = ByteReadPacket(EMPTY_BYTE_ARRAY)
/**
* The second outermost packet for login
*
*
*/
@UseExperimental(MiraiInternalAPI::class)
internal inline fun BytePacketBuilder.writeLoginSsoPacket(
client: QQAndroidClient,
subAppId: Long,
commandId: CommandId,
extraData: ByteReadPacket = BRP_STUB,
body: BytePacketBuilder.(ssoSequenceId: Int) -> Unit
) {
val ssoSequenceId = client.nextSsoSequenceId()
// head
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(ssoSequenceId)
writeInt(subAppId.toInt())
writeInt(subAppId.toInt())
writeHex("01 00 00 00 00 00 00 00 00 00 01 00")
if (extraData === BRP_STUB) {
writeInt(0x04)
} else {
writeInt((extraData.remaining + 4).toInt())
writePacket(extraData)
}
writeInt(commandId.stringValue.length + 4)
writeStringUtf8(commandId.stringValue)
writeInt(4 + 4)
writeInt(45112203) // 02 B0 5B 8B
val imei = client.device.imei
writeInt(imei.length + 4)
writeStringUtf8(imei)
writeInt(4)
val ksid = client.device.ksid
writeShort((ksid.length + 2).toShort())
writeStringUtf8(ksid)
writeInt(4)
}
// body
writeIntLVPacket(lengthOffset = { it + 4 }) {
body(ssoSequenceId)
} }
} }
/** /**
* Builds a outgoing packet. * Outermost packet, not for login
* [OutgoingPacket] is the **outermost** packet structure.
* This packet will be sent to the server.
* *
* **Packet structure**
* int remaining.length + 4
* int 0x0B
* byte 0x01
* byte 0
* int [uinAccount].length + 4
* byte[] uinAccount
*
* byte[] body encrypted by [sessionKey]
*/
internal inline fun PacketFactory<*, *>.buildSessionOutgoingPacket(
uinAccount: String,
sessionKey: DecrypterByteArray,
body: BytePacketBuilder.() -> Unit
): ByteReadPacket = buildPacket {
writeIntLVPacket(lengthOffset = { it + 4 }) {
writeInt(0x00_00_00_0B)
writeByte(0x01)
writeByte(0)
writeInt(uinAccount.length + 4)
writeStringUtf8(uinAccount)
encryptAndWrite(sessionKey, body)
}
}
/**
* Encryption method to be used for packet body.
*/
@UseExperimental(ExperimentalUnsignedTypes::class)
interface EncryptMethod {
val id: Int
fun BytePacketBuilder.encryptAndWrite(body: ByteReadPacket)
}
internal interface EncryptMethodSessionKey : EncryptMethod {
override val id: Int get() = 69
val currentLoginState: Int
val sessionKey: ByteArray
/**
* buildPacket{
* byte 1
* byte if (currentLoginState == 2) 3 else 2
* fully key
* short 258
* short 0
* fully encrypted
* }
*/
override fun BytePacketBuilder.encryptAndWrite(body: ByteReadPacket) {
require(currentLoginState == 2 || currentLoginState == 3) { "currentLoginState must be either 2 or 3" }
writeByte(1) // const
writeByte(if (currentLoginState == 2) 3 else 2)
writeFully(sessionKey)
writeShort(258) // const
writeShort(0) // const, length of publicKey
body.encryptBy(sessionKey) { encrypted -> writeFully(encrypted) }
}
}
inline class EncryptMethodSessionKeyLoginState2(override val sessionKey: ByteArray) : EncryptMethodSessionKey {
override val currentLoginState: Int get() = 2
}
inline class EncryptMethodSessionKeyLoginState3(override val sessionKey: ByteArray) : EncryptMethodSessionKey {
override val currentLoginState: Int get() = 3
}
inline class EncryptMethodECDH135(override val ecdh: ECDH) : EncryptMethodECDH {
override val id: Int get() = 135
}
inline class EncryptMethodECDH7(override val ecdh: ECDH) : EncryptMethodECDH {
override val id: Int get() = 7
}
internal interface EncryptMethodECDH : EncryptMethod {
val ecdh: ECDH
/**
* **Packet Structure**
* byte 1
* byte 1
* byte[] [ECDH.privateKey]
* short 258
* short [ECDH.publicKey].size
* byte[] [ECDH.publicKey]
* byte[] encrypted `body()` by [ECDH.shareKey]
*/
override fun BytePacketBuilder.encryptAndWrite(body: ByteReadPacket) = ecdh.run {
writeByte(1) // const
writeByte(1) // const
writeFully(privateKey)
writeShort(258) // const
writeShortLVByteArray(publicKey)
body.encryptBy(shareKey) { encrypted -> writeFully(encrypted) }
}
}
/**
* Writes a request packet
* This is the innermost packet structure
* *
* **Packet Structure** * **Packet Structure**
* byte 2 // head flag * byte 2 // head flag
* short 27 + 2 + body.size * short 27 + 2 + remaining.length
* ushort client.protocolVersion // const 8001 * ushort client.protocolVersion // const 8001
* ushort sequenceId * ushort sequenceId
* uint client.account.id * uint client.account.id
...@@ -60,44 +253,39 @@ inline class EncryptMethod(val value: UByte) { ...@@ -60,44 +253,39 @@ inline class EncryptMethod(val value: UByte) {
* int 0 // const * int 0 // const
* bodyBlock() * bodyBlock()
* byte 3 // tail * byte 3 // tail
*
* @param name optional name to be displayed in logs
*
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal inline fun PacketFactory<*, *>.buildOutgoingPacket( internal inline fun BytePacketBuilder.writeRequestPacket(
client: QQAndroidClient, client: QQAndroidClient,
encryptMethod: EncryptMethod, encryptMethod: EncryptMethod,
name: String? = null, commandId: CommandId,
id: PacketId = this.id,
sequenceId: UShort = PacketFactory.atomicNextSequenceId(), sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
bodyBlock: BytePacketBuilder.() -> Unit bodyBlock: BytePacketBuilder.() -> Unit
): OutgoingPacket { ) {
val body = buildPacket { bodyBlock() } val body = encryptMethod.run {
return OutgoingPacket(name, id, sequenceId, buildPacket { buildPacket { encryptAndWrite(buildPacket { bodyBlock() }) }
writeIntLVPacket(lengthOffset = { it + 4 }) { }
writeIntLVPacket(lengthOffset = { it + 4 }) {
// Head // Head
writeByte(0x02) // head writeByte(0x02) // head
writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm writeShort((27 + 2 + body.remaining).toShort()) // orthodox algorithm
writeShort(client.protocolVersion) writeShort(client.protocolVersion)
writeShort(sequenceId.toShort()) writeShort(sequenceId.toShort())
writeShort(id.commandId.toShort()) writeShort(commandId.id.toShort())
writeQQ(client.account.id) writeQQ(client.account.id)
writeByte(3) // originally const writeByte(3) // originally const
writeUByte(encryptMethod.value) writeByte(encryptMethod.id.toByte())
writeByte(0) // const8_always_0 writeByte(0) // const8_always_0
writeInt(2) // originally const writeInt(2) // originally const
writeInt(client.appClientVersion) writeInt(client.appClientVersion)
writeInt(0) // constp_always_0 writeInt(0) // constp_always_0
// Body // Body
writePacket(body) writePacket(body)
// Tail // Tail
writeByte(0x03) // tail writeByte(0x03) // tail
} }
})
} }
/* /*
00 00 01 64 00 00 01 64
...@@ -158,57 +346,4 @@ F8 22 FC 39 2E 93 D7 73 A9 75 A2 D4 67 D2 C4 0D F1 02 1F A5 74 8F D8 0E 8E 86 AF ...@@ -158,57 +346,4 @@ F8 22 FC 39 2E 93 D7 73 A9 75 A2 D4 67 D2 C4 0D F1 02 1F A5 74 8F D8 0E 8E 86 AF
00 00 00 0E 31 39 39 34 37 30 31 30 32 31 D2 D5 37 8A 3C 47 B1 84 E2 94 B2 AF BF 14 70 4D 73 17 BB 38 BE 82 73 DF A2 87 E0 0A 7A BA 8A 81 71 77 1D E1 71 7F B7 C1 66 1D 8C 3D 41 4F 51 09 6A B7 B7 7B 88 28 A6 5A AB 7E 40 25 9B C8 35 9C C6 E2 3A 5F 94 1D 70 0F D7 89 4D 41 6B 7A 29 A2 70 77 3D F8 1D 32 65 D7 D8 D1 6D 13 42 9C 0C 72 DB 48 95 4B 66 EF B9 E6 E4 C1 3B 2C 36 B0 D7 3F E2 85 C8 2A 8C 65 0F 0B 1C F1 A7 C7 E1 1F 0C 32 F5 08 14 AA 5A 43 CD 8E A8 82 14 24 97 63 F0 53 79 4E 33 8D 5F 1C F8 1C 89 3B 39 44 CC A7 63 5F FC BF 87 42 89 2D A5 F4 BC B2 69 49 54 DD AE E6 3F A2 A2 98 DC 3B D4 A2 27 10 F2 06 42 93 C5 30 4A D4 FA F5 BA A5 B2 4B 56 45 59 94 CA 4C 4B 17 55 C7 23 AF F0 8B E5 DC 3A 1B B6 A7 2E 10 BB 9A E7 70 54 BA F5 4B 70 91 00 00 00 0E 31 39 39 34 37 30 31 30 32 31 D2 D5 37 8A 3C 47 B1 84 E2 94 B2 AF BF 14 70 4D 73 17 BB 38 BE 82 73 DF A2 87 E0 0A 7A BA 8A 81 71 77 1D E1 71 7F B7 C1 66 1D 8C 3D 41 4F 51 09 6A B7 B7 7B 88 28 A6 5A AB 7E 40 25 9B C8 35 9C C6 E2 3A 5F 94 1D 70 0F D7 89 4D 41 6B 7A 29 A2 70 77 3D F8 1D 32 65 D7 D8 D1 6D 13 42 9C 0C 72 DB 48 95 4B 66 EF B9 E6 E4 C1 3B 2C 36 B0 D7 3F E2 85 C8 2A 8C 65 0F 0B 1C F1 A7 C7 E1 1F 0C 32 F5 08 14 AA 5A 43 CD 8E A8 82 14 24 97 63 F0 53 79 4E 33 8D 5F 1C F8 1C 89 3B 39 44 CC A7 63 5F FC BF 87 42 89 2D A5 F4 BC B2 69 49 54 DD AE E6 3F A2 A2 98 DC 3B D4 A2 27 10 F2 06 42 93 C5 30 4A D4 FA F5 BA A5 B2 4B 56 45 59 94 CA 4C 4B 17 55 C7 23 AF F0 8B E5 DC 3A 1B B6 A7 2E 10 BB 9A E7 70 54 BA F5 4B 70 91
*/ */
\ No newline at end of file
/**
* Encrypt the [body] by [ECDH.shareKey], then write encryption arguments stuff.
* This is **the second outermost** packet structure
*
* **Packet Structure**
* byte 1
* byte 1
* byte[] [ECDH.privateKey]
* short 258
* short [ECDH.publicKey].size
* byte[] [ECDH.publicKey]
* byte[] encrypted `body()` by [ECDH.shareKey]
*/
inline fun BytePacketBuilder.writeECDHEncryptedPacket(
ecdh: ECDH,
body: BytePacketBuilder.() -> Unit
) = ecdh.run {
writeByte(1) // const
writeByte(1) // const
writeFully(privateKey)
writeShort(258) // const
writeShortLVByteArray(publicKey)
encryptAndWrite(shareKey, body)
}
/**
* buildPacket{
* byte 1
* if loginState == 2:
* byte 3
* else:
* byte 2
* fully key
* short 258
* short 0
* fully encrypted
* }
*/
inline fun BytePacketBuilder.writeTEAEncryptedPacket(
loginState: Int,
key: ByteArray,
body: BytePacketBuilder.() -> Unit
) {
require(loginState == 2 || loginState == 3)
writeByte(1) // const
writeByte(if (loginState == 2) 3 else 2) // const
writeFully(key)
writeShort(258) // const
writeShort(0) // const, length of publicKey
encryptAndWrite(key, body)
}
\ No newline at end of file
...@@ -18,7 +18,7 @@ import net.mamoe.mirai.utils.cryptor.DecrypterType ...@@ -18,7 +18,7 @@ import net.mamoe.mirai.utils.cryptor.DecrypterType
* @param TDecrypter 服务器回复包解密器 * @param TDecrypter 服务器回复包解密器
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) { internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
@Suppress("PropertyName") @Suppress("PropertyName")
internal var _id: PacketId = NullPacketId internal var _id: PacketId = NullPacketId
......
...@@ -22,140 +22,142 @@ class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray { ...@@ -22,140 +22,142 @@ class LoginPacketDecrypter(override val value: ByteArray) : DecrypterByteArray {
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) { internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, LoginPacketDecrypter>(LoginPacketDecrypter) {
init { init {
this._id = PacketId(0x0810, 9) this._id = PacketId(CommandId("wtlogin.login", 0x0810), 9)
} }
operator fun invoke( operator fun invoke(
client: QQAndroidClient client: QQAndroidClient
): OutgoingPacket = buildOutgoingPacket(client, EncryptMethod.ByECDH135) { ): OutgoingPacket = buildLoginOutgoingPacket(client.account.id.toString()) {
writeECDHEncryptedPacket(client.ecdh) { val appId = 16L
writeShort(9) // subCommand val subAppId = 537062845L
writeShort(LoginType.PASSWORD.value.toShort())
writeLoginSsoPacket(client, subAppId, _id.commandId) { ssoSequenceId ->
val appId = 16L writeRequestPacket(client, EncryptMethodECDH135(client.ecdh), _id.commandId) {
val subAppId = 537062845L writeShort(9) // subCommand
writeShort(LoginType.PASSWORD.value.toShort())
t18(appId, client.appClientVersion, client.account.id)
t1(client.account.id, client.device.ipAddress) t18(appId, client.appClientVersion, client.account.id)
t106( t1(client.account.id, client.device.ipAddress)
appId, t106(
subAppId /* maybe 1*/, appId,
client.appClientVersion, subAppId /* maybe 1*/,
client.account.id, client.appClientVersion,
1, client.account.id,
client.account.passwordMd5, 1,
0, client.account.passwordMd5,
client.account.id.toByteArray(), 0,
client.tgtgtKey, client.account.id.toByteArray(),
true, client.tgtgtKey,
client.device.guid, true,
LoginType.PASSWORD 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
)
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(client.ssoSequenceId)
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) /* // from GetStWithPasswd
t188(client.device.androidId) int mMiscBitmap = this.mMiscBitmap;
if (client.device.imsiMd5.isNotEmpty()) { if (t.uinDeviceToken) {
t194(client.device.imsiMd5) mMiscBitmap = (this.mMiscBitmap | 0x2000000);
} }
t191()
// 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
)
/* t145(client.device.guid)
t201(N = byteArrayOf())*/ t147(appId, client.apkVersionName, client.apkSignatureMd5)
if (client.miscBitMap and 0x80 != 0) {
t166(1)
}
// ignored t16a because array5 is null
t154(ssoSequenceId)
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"
)
)
val bssid = client.device.wifiBSSID // ignored t172 because rollbackSig is null
val ssid = client.device.wifiSSID // ignored t185 because loginType is not SMS
if (bssid != null && ssid != null) { // ignored t400 because of first login
t202(bssid, ssid)
t187(client.device.macAddress)
t188(client.device.androidId)
if (client.device.imsiMd5.isNotEmpty()) {
t194(client.device.imsiMd5)
}
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())
})
// ignored t318 because not logging in by QR
} }
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
} }
} }
...@@ -170,20 +172,20 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log ...@@ -170,20 +172,20 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse, Log
@Suppress("FunctionName") @Suppress("FunctionName")
fun PacketId(commandId: Int, subCommandId: Int) = object : PacketId { internal fun PacketId(commandId: CommandId, subCommandId: Int) = object : PacketId {
override val commandId: Int override val commandId: CommandId
get() = commandId get() = commandId
override val subCommandId: Int override val subCommandId: Int
get() = subCommandId get() = subCommandId
} }
interface PacketId { internal interface PacketId {
val commandId: Int // ushort actually val commandId: CommandId // ushort actually
val subCommandId: Int // ushort actually val subCommandId: Int // ushort actually
} }
object NullPacketId : PacketId { internal object NullPacketId : PacketId {
override val commandId: Int override val commandId: CommandId
get() = error("uninitialized") get() = error("uninitialized")
override val subCommandId: Int override val subCommandId: Int
get() = error("uninitialized") get() = error("uninitialized")
......
...@@ -33,6 +33,8 @@ abstract class DeviceInfo( ...@@ -33,6 +33,8 @@ abstract class DeviceInfo(
abstract val wifiSSID: ByteArray? abstract val wifiSSID: ByteArray?
abstract val imsiMd5: ByteArray abstract val imsiMd5: ByteArray
abstract val imei: String
abstract val ksid: String
abstract val ipAddress: String abstract val ipAddress: String
......
...@@ -26,6 +26,8 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo( ...@@ -26,6 +26,8 @@ actual class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
override val imsiMd5: ByteArray override val imsiMd5: ByteArray
get() = ubyteArrayOf(0xD4u, 0x1Du, 0x8Cu, 0xD9u, 0x8Fu, 0x00u, 0xB2u, 0x04u, 0xE9u, 0x80u, 0x09u, 0x98u, 0xECu, 0xF8u, 0x42u, 0x7Eu).toByteArray() get() = ubyteArrayOf(0xD4u, 0x1Du, 0x8Cu, 0xD9u, 0x8Fu, 0x00u, 0xB2u, 0x04u, 0xE9u, 0x80u, 0x09u, 0x98u, 0xECu, 0xF8u, 0x42u, 0x7Eu).toByteArray()
override val imei: String get() = "858414369211993"
override val ksid: String get() = "|454001228437590|A8.2.0.27f6ea96"
override val ipAddress: String get() = localIpAddress() override val ipAddress: String get() = localIpAddress()
override val androidId: ByteArray get() = "QSR1.190920.001".toByteArray() override val androidId: ByteArray get() = "QSR1.190920.001".toByteArray()
override val apn: ByteArray get() = "wifi".toByteArray() override val apn: ByteArray get() = "wifi".toByteArray()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment