diff --git a/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api b/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api
index 67f0a130a..b222f997e 100644
--- a/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api
+++ b/binary-compatibility-validator/android/api/binary-compatibility-validator-android.api
@@ -5518,6 +5518,7 @@ public class net/mamoe/mirai/utils/BotConfiguration {
 	public final fun getProtocol ()Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol;
 	public final fun getReconnectPeriodMillis ()J
 	public final fun getReconnectionRetryTimes ()I
+	public final fun getStatHeartbeatPeriodMillis ()J
 	public final fun getWorkingDir ()Ljava/io/File;
 	public final synthetic fun inheritCoroutineContext (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public final fun isConvertLineSeparator ()Z
@@ -5560,6 +5561,7 @@ public class net/mamoe/mirai/utils/BotConfiguration {
 	public final fun setProtocol (Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol;)V
 	public final fun setReconnectPeriodMillis (J)V
 	public final fun setReconnectionRetryTimes (I)V
+	public final fun setStatHeartbeatPeriodMillis (J)V
 	public final fun setWorkingDir (Ljava/io/File;)V
 }
 
diff --git a/binary-compatibility-validator/api/binary-compatibility-validator.api b/binary-compatibility-validator/api/binary-compatibility-validator.api
index 298a44093..d99b976cc 100644
--- a/binary-compatibility-validator/api/binary-compatibility-validator.api
+++ b/binary-compatibility-validator/api/binary-compatibility-validator.api
@@ -5518,6 +5518,7 @@ public class net/mamoe/mirai/utils/BotConfiguration {
 	public final fun getProtocol ()Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol;
 	public final fun getReconnectPeriodMillis ()J
 	public final fun getReconnectionRetryTimes ()I
+	public final fun getStatHeartbeatPeriodMillis ()J
 	public final fun getWorkingDir ()Ljava/io/File;
 	public final synthetic fun inheritCoroutineContext (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
 	public final fun isConvertLineSeparator ()Z
@@ -5560,6 +5561,7 @@ public class net/mamoe/mirai/utils/BotConfiguration {
 	public final fun setProtocol (Lnet/mamoe/mirai/utils/BotConfiguration$MiraiProtocol;)V
 	public final fun setReconnectPeriodMillis (J)V
 	public final fun setReconnectionRetryTimes (I)V
+	public final fun setStatHeartbeatPeriodMillis (J)V
 	public final fun setWorkingDir (Ljava/io/File;)V
 }
 
diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt
index 83fcba85d..a0b1becb7 100644
--- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt
+++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt
@@ -142,9 +142,16 @@ public open class BotConfiguration { // open for Java
     // Connection
     ///////////////////////////////////////////////////////////////////////////
 
-    /** 心跳周期. 过长会导致被服务器断开连接. */
+    /** 连接心跳包周期. 过长会导致被服务器断开连接. */
     public var heartbeatPeriodMillis: Long = 60.secondsToMillis
 
+    /**
+     * 状态心跳包周期. 过长会导致掉线.
+     * 该值会在登录时根据服务器下发的配置自动进行更新.
+     * @since 2.6
+     */
+    public var statHeartbeatPeriodMillis: Long = 300.secondsToMillis
+
     /**
      * 每次心跳时等待结果的时间.
      * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
@@ -545,4 +552,4 @@ internal val deviceInfoStub: (Bot) -> DeviceInfo = {
     MiraiLogger.TopLevel.warning("未指定设备信息, 已使用随机设备信息. 请查看 BotConfiguration.deviceInfo 以获取更多信息.")
     MiraiLogger.TopLevel.warning("Device info isn't specified. Please refer to BotConfiguration.deviceInfo for more information")
     DeviceInfo.random()
-}
\ No newline at end of file
+}
diff --git a/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt
index d78f50b48..6e0566947 100644
--- a/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core/src/commonMain/kotlin/network/handler/QQAndroidBotNetworkHandler.kt
@@ -35,10 +35,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.ConfigPushSvc
 import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat
 import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
 import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
-import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin15
-import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin2
-import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin20
-import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.WtLogin9
+import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.*
 import net.mamoe.mirai.internal.utils.*
 import net.mamoe.mirai.network.*
 import net.mamoe.mirai.utils.*
@@ -63,6 +60,7 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
 
     private var _packetReceiverJob: Job? = null
     private var heartbeatJob: Job? = null
+    private var statHeartbeatJob: Job? = null
 
     private val packetReceiveLock: Mutex = Mutex()
 
@@ -96,6 +94,25 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
         }.also { _packetReceiverJob = it }
     }
 
+    private fun startStatHeartbeatJobOrKill(cancelCause: CancellationException? = null): Job {
+        statHeartbeatJob?.cancel(cancelCause)
+
+        return this@QQAndroidBotNetworkHandler.launch(CoroutineName("statHeartbeatJob")) statHeartbeatJob@{
+            while (this.isActive) {
+                delay(bot.configuration.statHeartbeatPeriodMillis)
+                val failException = doStatHeartbeat()
+                if (failException != null) {
+                    delay(bot.configuration.firstReconnectDelayMillis)
+
+                    bot.launch {
+                        BotOfflineEvent.Dropped(bot, failException).broadcast()
+                    }
+                    return@statHeartbeatJob
+                }
+            }
+        }.also { statHeartbeatJob = it }
+    }
+
     private fun startHeartbeatJobOrKill(cancelCause: CancellationException? = null): Job {
         heartbeatJob?.cancel(cancelCause)
 
@@ -121,6 +138,8 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
     override suspend fun closeEverythingAndRelogin(host: String, port: Int, cause: Throwable?, step: Int) {
         heartbeatJob?.cancel(CancellationException("relogin", cause))
         heartbeatJob?.join()
+        statHeartbeatJob?.cancel(CancellationException("relogin", cause))
+        statHeartbeatJob?.join()
         _packetReceiverJob?.cancel(CancellationException("relogin", cause))
         _packetReceiverJob?.join()
         if (::channel.isInitialized) {
@@ -134,7 +153,6 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
         }
 
         channel = PlatformSocket()
-        bot.initClient()
 
         while (isActive) {
             try {
@@ -156,9 +174,81 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
                 }
             }
         }
+
         logger.info { "Connected to server $host:$port" }
+        if (bot.client.wLoginSigInfoInitialized) {
+            // do fast login
+        } else {
+            bot.initClient()
+        }
+
         startPacketReceiverJobOrKill(CancellationException("relogin", cause))
 
+        if (bot.client.wLoginSigInfoInitialized) {
+            // do fast login
+            kotlin.runCatching {
+                doFastLogin()
+            }.onFailure {
+                bot.initClient()
+                doSlowLogin(host, port, cause, step)
+            }
+        } else {
+            doSlowLogin(host, port, cause, step)
+        }
+
+
+        // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
+        registerClientOnline()
+        startStatHeartbeatJobOrKill()
+        startHeartbeatJobOrKill()
+        bot.eventChannel.subscribeOnce<BotOnlineEvent>(this.coroutineContext) {
+            val bot = (bot as QQAndroidBot)
+            if (bot.firstLoginSucceed && bot.client.wLoginSigInfoInitialized) {
+                launch {
+                    while (isActive) {
+                        bot.client.wLoginSigInfo.vKey.run {
+                            //由过期时间最短的且不会被skey更换更新的vkey计算重新登录的时间
+                            val delay = (expireTime - creationTime).seconds - 5.minutes
+                            logger.info { "Scheduled refresh login session in ${delay.toHumanReadableString()}." }
+                            delay(delay)
+                        }
+                        runCatching {
+                            doFastLogin()
+                            registerClientOnline()
+                        }.onFailure {
+                            logger.warning("Failed to refresh login session.", it)
+                        }
+                    }
+                }
+                launch {
+                    while (isActive) {
+                        bot.client.wLoginSigInfo.sKey.run {
+                            val delay = (expireTime - creationTime).seconds - 5.minutes
+                            logger.info { "Scheduled key refresh in ${delay.toHumanReadableString()}." }
+                            delay(delay)
+                        }
+                        runCatching {
+                            refreshKeys()
+                        }.onFailure {
+                            logger.error("Failed to refresh key.", it)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private val fastLoginOrSendPacketLock = Mutex()
+
+    private suspend fun doFastLogin(): Boolean {
+        fastLoginOrSendPacketLock.withLock {
+            val login10 = WtLogin10(bot.client).sendAndExpect(ignoreLock = true)
+            return login10 is WtLogin.Login.LoginPacketResponse.Success
+        }
+    }
+
+    private suspend fun doSlowLogin(host: String, port: Int, cause: Throwable?, step: Int) {
+
         fun LoginSolver?.notnull(): LoginSolver {
             checkNotNull(this) {
                 "No LoginSolver found. Please provide by BotConfiguration.loginSolver. " +
@@ -263,24 +353,6 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
             }
         }
 
-        // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
-        registerClientOnline()
-        startHeartbeatJobOrKill()
-
-        launch {
-            while (isActive) {
-                bot.client.wLoginSigInfo.sKey.run {
-                    val delay = (expireTime - creationTime).seconds - 5.minutes
-                    logger.info { "Scheduled key refresh in ${delay.toHumanReadableString()}." }
-                    delay(delay)
-                }
-                runCatching {
-                    refreshKeys()
-                }.onFailure {
-                    logger.error("Failed to refresh key.", it)
-                }
-            }
-        }
     }
 
     suspend fun refreshKeys() {
@@ -429,6 +501,17 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
         logger.info { "Syncing friend message history: Success." }
     }
 
+    private suspend fun doStatHeartbeat(): Throwable? {
+        return retryCatching(2) {
+            StatSvc.SimpleGet(bot.client)
+                .sendAndExpect<StatSvc.SimpleGet.Response>(
+                    timeoutMillis = bot.configuration.heartbeatTimeoutMillis,
+                    retry = 2
+                )
+            return null
+        }.exceptionOrNull()
+    }
+
     private suspend fun doHeartBeat(): Throwable? {
         return retryCatching(2) {
             Heartbeat.Alive(bot.client)
@@ -675,16 +758,27 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
 
     suspend inline fun <E : Packet> OutgoingPacketWithRespType<E>.sendAndExpect(
         timeoutMillis: Long = 5000,
-        retry: Int = 2
+        retry: Int = 2,
+        ignoreLock: Boolean = false,
     ): E {
-        return (this as OutgoingPacket).sendAndExpect(timeoutMillis, retry)
+        return (this as OutgoingPacket).sendAndExpect(timeoutMillis, retry, ignoreLock)
     }
 
     /**
      * 发送一个包, 挂起协程直到接收到指定的返回包或超时
      */
     @Suppress("UNCHECKED_CAST")
-    suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 5000, retry: Int = 2): E {
+    suspend fun <E : Packet> OutgoingPacket.sendAndExpect(
+        timeoutMillis: Long = 5000,
+        retry: Int = 2,
+        ignoreLock: Boolean = false
+    ): E {
+        return if (!ignoreLock) fastLoginOrSendPacketLock.withLock {
+            sendAndExpectImpl(timeoutMillis, retry)
+        } else sendAndExpectImpl(timeoutMillis, retry)
+    }
+
+    private suspend fun <E : Packet> OutgoingPacket.sendAndExpectImpl(timeoutMillis: Long, retry: Int): E {
         require(timeoutMillis > 100) { "timeoutMillis must > 100" }
         require(retry in 0..10) { "retry must in 0..10" }
 
diff --git a/mirai-core/src/commonMain/kotlin/network/keys.kt b/mirai-core/src/commonMain/kotlin/network/keys.kt
index 76159b262..636b591b4 100644
--- a/mirai-core/src/commonMain/kotlin/network/keys.kt
+++ b/mirai-core/src/commonMain/kotlin/network/keys.kt
@@ -13,6 +13,7 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.Input
 import kotlinx.io.core.readBytes
 import kotlinx.io.core.readUShort
+import kotlinx.serialization.Serializable
 import net.mamoe.mirai.internal.network.getRandomByteArray
 import net.mamoe.mirai.internal.network.protocol.packet.PacketLogger
 import net.mamoe.mirai.internal.utils.crypto.TEA
@@ -111,8 +112,19 @@ internal class WLoginSigInfo(
     // val pt4Token: ByteArray,
     var wtSessionTicket: WtSessionTicket,
     var wtSessionTicketKey: ByteArray,
-    var deviceToken: ByteArray
+    var deviceToken: ByteArray,
+    var encryptedDownloadSession: EncryptedDownloadSession? = null
 ) {
+
+    //图片加密下载
+    //是否加密从bigdatachannel处得知
+    @Serializable
+    internal class EncryptedDownloadSession(
+        val appId: Long,//1600000226L
+        val stKey: ByteArray,
+        val stSig: ByteArray
+    )
+
     override fun toString(): String {
         return "WLoginSigInfo(uin=$uin, encryptA1=${encryptA1?.toUHexString()}, noPicSig=${noPicSig?.toUHexString()}, simpleInfo=$simpleInfo, appPri=$appPri, a2ExpiryTime=$a2ExpiryTime, loginBitmap=$loginBitmap, tgt=${tgt.toUHexString()}, a2CreationTime=$a2CreationTime, tgtKey=${tgtKey.toUHexString()}, userStSig=$userStSig, userStKey=${userStKey.toUHexString()}, userStWebSig=$userStWebSig, userA5=$userA5, userA8=$userA8, lsKey=$lsKey, sKey=$sKey, userSig64=$userSig64, openId=${openId.toUHexString()}, openKey=$openKey, vKey=$vKey, accessToken=$accessToken, d2=$d2, d2Key=${d2Key.toUHexString()}, sid=$sid, aqSig=$aqSig, psKey=$psKeyMap, superKey=${superKey.toUHexString()}, payToken=${payToken.toUHexString()}, pf=${pf.toUHexString()}, pfKey=${pfKey.toUHexString()}, da2=${da2.toUHexString()}, wtSessionTicket=$wtSessionTicket, wtSessionTicketKey=${wtSessionTicketKey.toUHexString()}, deviceToken=${deviceToken.toUHexString()})"
     }
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
index ad328e122..bd7d46538 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/PacketFactory.kt
@@ -127,6 +127,7 @@ internal object KnownPacketFactories {
         WtLogin.ExchangeEmp,
         StatSvc.Register,
         StatSvc.GetOnlineStatus,
+        StatSvc.SimpleGet,
         StatSvc.GetDevLoginInfo,
         MessageSvcPbGetMsg,
         MessageSvcPushForceOffline,
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt
index ae8fb0b87..d2d9bd1a7 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/Tlv.kt
@@ -222,6 +222,16 @@ internal fun BytePacketBuilder.t100(
     } shouldEqualsTo 22
 }
 
+internal fun BytePacketBuilder.t10a(
+    tgt: ByteArray,
+) {
+    writeShort(0x10a)
+    writeShortLVPacket {
+        writeFully(tgt)
+    }
+}
+
+
 internal fun BytePacketBuilder.t107(
     picType: Int,
     capType: Int = 0,
@@ -326,6 +336,15 @@ internal fun BytePacketBuilder.t142(
     }
 }
 
+internal fun BytePacketBuilder.t143(
+    d2: ByteArray
+) {
+    writeShort(0x143)
+    writeShortLVPacket {
+        writeFully(d2)
+    }
+}
+
 internal fun BytePacketBuilder.t112(
     nonNumberUin: ByteArray
 ) {
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
index 52cdd4c80..f7dc045c5 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/ConfigPushSvc.kt
@@ -143,7 +143,7 @@ internal class ConfigPushSvc {
                     serverListPush.mobileSSOServerList
                 }
 
-                bot.logger.info { "Server list: ${pushServerList.joinToString()}." }
+                bot.network.logger.info { "Server list: ${pushServerList.joinToString()}." }
 
                 if (pushServerList.isNotEmpty()) {
                     bot.serverList.clear()
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
index 1a9d29d56..626dd1ccf 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/StatSvc.kt
@@ -95,6 +95,29 @@ internal class StatSvc {
         }
     }
 
+    internal object SimpleGet : OutgoingPacketFactory<SimpleGet.Response>("StatSvc.SimpleGet") {
+        internal object Response : Packet {
+            override fun toString(): String = "Response(SimpleGet.Response)"
+        }
+
+        operator fun invoke(
+            client: QQAndroidClient
+        ): OutgoingPacket = buildLoginOutgoingPacket(
+            client,
+            bodyType = 1,
+            extraData = client.wLoginSigInfo.d2.data,
+            key = client.wLoginSigInfo.d2Key
+        ) {
+            writeSsoPacket(client, client.subAppId, commandName, sequenceId = it) {
+
+            }
+        }
+
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
+            return Response
+        }
+    }
+
     internal object Register : OutgoingPacketFactory<Register.Response>("StatSvc.register") {
 
         internal class Response(
@@ -106,7 +129,7 @@ internal class StatSvc {
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
             val packet = readUniPacket(SvcRespRegister.serializer())
             packet.iHelloInterval.let {
-                bot.configuration.heartbeatPeriodMillis = it.times(1000).toLong()
+                bot.configuration.statHeartbeatPeriodMillis = it.times(1000).toLong()
             }
 
             return Response(packet)
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt
index b5513c622..e9519ed6e 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/WtLogin.kt
@@ -101,6 +101,7 @@ internal class WtLogin {
             }
 
             data class Error(
+                val code: Int,
                 val title: String,
                 val message: String,
                 val errorInfo: String
@@ -137,7 +138,7 @@ internal class WtLogin {
 
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacketResponse {
 
-            discardExact(2) // subCommand
+            val subCommand = readUShort().toInt() // subCommand
             // println("subCommand=$subCommand")
             val type = readUByte()
             // println("type=$type")
@@ -162,13 +163,13 @@ internal class WtLogin {
 //            }.readBytes().md5()
             //   }
             return when (type.toInt()) {
-                0 -> onLoginSuccess(tlvMap, bot)
+                0 -> onLoginSuccess(subCommand, tlvMap, bot)
                 2 -> onSolveLoginCaptcha(tlvMap, bot)
                 160, 239 /*-96*/ -> onUnsafeDeviceLogin(tlvMap)
                 204 /*-52*/ -> onDevLockLogin(tlvMap, bot)
                 // 1, 15 -> onErrorMessage(tlvMap) ?: error("Cannot find error message")
                 else -> {
-                    onErrorMessage(tlvMap)
+                    onErrorMessage(type.toInt(), tlvMap)
                         ?: error("Cannot find error message, unknown login result type: $type, TLVMap = ${tlvMap._miraiContentToString()}")
                 }
             }
@@ -229,7 +230,7 @@ internal class WtLogin {
             error("UNKNOWN CAPTCHA, tlvMap=" + tlvMap._miraiContentToString())
         }
 
-        fun onLoginSuccess(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Success {
+        fun onLoginSuccess(subCommand: Int, tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Success {
             val client = bot.client
             //println("TLV KEYS: " + tlvMap.keys.joinToString { it.contentToString() })
 
@@ -237,7 +238,13 @@ internal class WtLogin {
             //  tlvMap[0x305]?.let { println("TLV 0x305=${it.toUHexString()}") }
             tlvMap[0x161]?.let { client.analysisTlv161(it) }
             tlvMap[0x119]?.let { t119Data ->
-                TEA.decrypt(t119Data, client.tgtgtKey).read {
+                TEA.decrypt(
+                    t119Data, if (subCommand == 11) {
+                        client.wLoginSigInfo.d2Key.md5()
+                    } else {
+                        client.tgtgtKey
+                    }
+                ).read {
                     discardExact(2) // always discarded.  00 1C
                     // 00 1C
                     // 01 08 00 10 A1 73 76 98 64 E0 38 C6 C8 18 73 FA D3 85 DA D6 01 6A 00 30 1D 99 4A 28 7E B3 B8 AC 74 B9 C4 BB 6D BB 41 72 F7 5C 9F 0F 79 8A 82 4F 1F 69 34 6D 10 D6 BB E8 A3 4A 2B 5D F1 C7 05 3C F8 72 EF CF 67 E4 3C 94 01 06 00 78 B4 ED 9F 44 ED 10 18 A8 85 0A 8A 85 79 45 47 7F 25 AA EE 2C 53 83 80 0A B3 B0 47 3E 95 51 A4 AE 3E CA A0 1D B4 91 F7 BB 2E 94 76 A8 C8 97 02 C4 5B 15 02 B7 03 9A FC C2 58 6D 17 92 46 AE EB 2F 6F 65 B8 69 6C D6 9D AC 18 6F 07 53 AC FE FA BC BD CE 57 13 10 2D 5A C6 50 AA C2 AE 18 D4 FD CD F2 E0 D1 25 29 56 21 35 8F 01 9D D6 69 44 8F 06 D0 23 26 D3 0E E6 E6 B7 01 0C 00 10 73 32 61 4E 2C 72 35 58 68 28 47 3E 2B 6E 52 62 01 0A 00 48 A4 DA 48 FB B4 8D DA 7B 86 D7 A7 FE 01 1B 70 6F 54 F8 55 38 B0 AD 1B 0C 0B B9 F6 94 24 F8 9E 30 32 22 99 0C 22 CD 44 B8 B0 8A A8 65 E1 B8 F0 49 EF E1 23 D7 0D A3 F1 BB 52 B7 4B AF BD 50 EA BF 15 02 78 2B 8B 10 FB 15 01 0D 00 10 29 75 38 72 21 5D 3F 24 37 46 67 79 2B 65 6D 34 01 14 00 60 00 01 5E 19 65 8C 00 58 93 DD 4D 2C 2D 01 44 99 62 B8 7A EF 04 C5 71 0B F1 BE 4C F4 21 F2 97 B0 14 67 0E 14 9F D8 A2 0B 93 40 90 80 F3 59 7A 69 45 D7 D4 53 4C 08 3A 56 1D C9 95 36 2C 7C 5E EE 36 47 5F AE 26 72 76 FD FD 69 E6 0C 2D 3A E8 CF D4 8D 76 C9 17 C3 E3 CD 21 AB 04 6B 70 C5 EC EC 01 0E 00 10 56 48 3E 29 3A 5A 21 74 55 6A 2C 72 58 73 79 71 01 03 00 30 9B A6 5D 85 5C 40 7C 28 E7 05 A9 25 CA F5 FC C0 51 40 85 F3 2F D2 37 F9 09 A6 E6 56 7F 7A 2E 7D 9F B9 1C 00 65 55 D2 A9 60 03 77 AB 6A F5 3F CE 01 33 00 30 F4 3A A7 08 E2 04 FA C8 9D 54 49 DE 63 EA F0 A5 1C C4 03 57 51 B6 AE 0B 55 41 F8 AB 22 F1 DC A3 B0 73 08 55 14 02 BF FF 55 87 42 4C 23 70 91 6A 01 34 00 10 61 C7 02 3F 1D BE A6 27 2F 24 D4 92 95 68 71 EF 05 28 00 1A 7B 22 51 49 4D 5F 69 6E 76 69 74 61 74 69 6F 6E 5F 62 69 74 22 3A 22 31 22 7D 03 22 00 10 CE 1E 2E DC 69 24 4F 9B FF 2F 52 D8 8F 69 DD 40 01 1D 00 76 5F 5E 10 E2 34 36 79 27 23 53 4D 65 6B 6A 33 6D 7D 4E 3C 5F 00 60 00 01 5E 19 65 8C 00 58 67 00 9C 02 E4 BC DB A3 93 98 A1 ED 4C 91 08 6F 0C 06 E0 12 6A DC 14 5B 4D 20 7C 82 83 AE 94 53 A2 4A A0 35 FF 59 9D F3 EF 82 42 61 67 2A 31 E7 87 7E 74 E7 A3 E7 5C A8 3C 87 CF 40 6A 9F E5 F7 20 4E 56 C6 4F 1C 98 3A 8B A9 4F 1D 10 35 C2 3B A1 08 7A 89 0B 25 0C 63 01 1F 00 0A 00 01 51 80 00 00 03 84 00 00 01 38 00 0E 00 00 00 01 01 0A 00 27 8D 00 00 00 00 00 01 1A 00 13 02 5B 06 01 0E 73 74 65 61 6D 63 68 69 6E 61 2E 66 75 6E 05 22 00 14 00 00 00 00 76 E4 B8 DD AB 53 02 9F 5E 19 65 8C 20 02 ED BD 05 37 00 17 01 01 00 00 00 00 76 E4 B8 DD 04 AB 53 02 9F 5E 19 65 8C 20 02 ED BD 01 20 00 0A 4D 39 50 57 50 6E 4C 31 65 4F 01 6D 00 2C 31 7A 50 7A 63 72 70 4D 30 43 6E 31 37 4C 32 32 6E 77 2D 36 7A 4E 71 48 48 59 41 35 48 71 77 41 37 6D 76 4F 63 2D 4A 56 77 47 51 5F 05 12 03 5D 00 0E 00 0A 74 65 6E 70 61 79 2E 63 6F 6D 00 2C 6E 4A 72 55 55 74 63 2A 34 7A 32 76 31 66 6A 75 77 6F 6A 65 73 72 76 4F 68 70 66 45 76 4A 75 55 4B 6D 34 43 2D 76 74 38 4D 77 38 5F 00 00 00 11 6F 70 65 6E 6D 6F 62 69 6C 65 2E 71 71 2E 63 6F 6D 00 2C 78 59 35 65 62 4D 74 48 44 6D 30 53 6F 68 56 71 68 33 43 79 79 34 6F 63 65 4A 46 6A 51 58 65 68 30 44 61 75 55 30 6C 78 65 52 6B 5F 00 00 00 0B 64 6F 63 73 2E 71 71 2E 63 6F 6D 00 2C 64 6A 62 79 47 57 45 4F 34 58 34 6A 36 4A 73 48 45 65 6B 73 69 74 72 78 79 62 57 69 77 49 68 46 45 70 72 4A 59 4F 2D 6B 36 47 6F 5F 00 00 00 0E 63 6F 6E 6E 65 63 74 2E 71 71 2E 63 6F 6D 00 2C 64 4C 31 41 79 32 41 31 74 33 58 36 58 58 2A 74 33 64 4E 70 2A 31 61 2D 50 7A 65 57 67 48 70 2D 65 47 78 6B 59 74 71 62 69 6C 55 5F 00 00 00 0C 71 7A 6F 6E 65 2E 71 71 2E 63 6F 6D 00 2C 75 6A 55 5A 4F 6A 4F 48 52 61 75 6B 32 55 50 38 77 33 34 68 36 69 46 38 2A 77 4E 50 35 2D 66 54 75 37 67 39 56 67 44 57 2A 6B 6F 5F 00 00 00 0A 76 69 70 2E 71 71 2E 63 6F 6D 00 2C 37 47 31 44 6F 54 2D 4D 57 50 63 2D 62 43 46 68 63 62 32 56 38 6E 77 4A 75 41 51 63 54 39 77 45 49 62 57 43 4A 4B 44 4D 6C 6D 34 5F 00 00 00 0A 71 75 6E 2E 71 71 2E 63 6F 6D 00 2C 7A 73 70 5A 56 43 59 45 7A 35 2A 4F 6B 4E 68 6E 74 79 61 69 6E 6F 68 4D 32 6B 41 6C 2A 74 31 63 7A 48 57 77 30 41 6A 4B 50 4B 6B 5F 00 00 00 0B 67 61 6D 65 2E 71 71 2E 63 6F 6D 00 2C 32 6F 2D 51 53 36 65 43 70 37 6A 43 4E 34 6A 74 6E 47 4F 4B 33 67 73 32 63 4A 6F 56 71 58 65 44 48 61 55 39 65 34 2D 32 34 64 30 5F 00 00 00 0C 71 71 77 65 62 2E 71 71 2E 63 6F 6D 00 2C 63 54 4D 79 64 51 43 35 50 74 43 45 51 72 6F 33 53 54 41 66 7A 56 2D 44 76 46 56 35 58 6D 56 6B 49 31 68 4C 55 48 4E 65 76 56 38 5F 00 00 00 0D 6F 66 66 69 63 65 2E 71 71 2E 63 6F 6D 00 2C 6F 73 72 54 36 32 69 37 66 76 6D 49 50 64 6F 58 4B 48 74 38 58 52 59 56 77 72 7A 6E 69 31 58 7A 57 4C 77 2A 71 36 33 44 74 73 6F 5F 00 00 00 09 74 69 2E 71 71 2E 63 6F 6D 00 2C 41 61 77 4D 78 4D 32 79 58 51 47 75 72 75 55 6C 66 53 58 79 5A 57 48 53 78 52 57 58 50 74 6B 6B 4F 78 6F 66 4A 59 47 6C 71 68 34 5F 00 00 00 0B 6D 61 69 6C 2E 71 71 2E 63 6F 6D 00 2C 67 72 57 68 58 77 34 4C 6E 4B 49 4F 67 63 78 45 71 70 33 61 45 67 37 38 46 7A 77 4E 6D 4B 48 56 6E 6F 50 4C 4F 32 6D 57 6D 6E 38 5F 00 00 00 09 71 7A 6F 6E 65 2E 63 6F 6D 00 2C 72 61 47 79 51 35 54 72 4D 55 7A 6E 74 31 4E 52 44 2D 50 72 74 72 41 55 43 35 6A 61 2D 49 47 2D 73 77 4C 6D 49 51 51 41 44 4C 41 5F 00 00 00 0A 6D 6D 61 2E 71 71 2E 63 6F 6D 00 2C 39 73 2D 4F 51 30 67 76 39 42 6A 37 58 71 52 49 4E 30 35 46 32 64 4D 47 67 47 43 58 57 4A 62 68 63 30 38 63 7A 4B 52 76 6B 78 6B 5F 00 00 03 05 00 10 77 75 6E 54 5F 7E 66 7A 72 40 3C 6E 35 50 53 46 01 43 00 40 3A AE 30 87 81 3D EE BA 31 9C EA 9D 0D D4 73 B1 81 12 E0 94 71 73 7A B0 47 3D 09 47 E5 1B E1 E2 06 1A CB A4 E3 71 9E A6 EA 2A 73 5C C8 D3 B1 2A B1 C7 DA 04 A6 6D 12 26 DF 6B 8B EC C7 12 F8 E1 01 18 00 05 00 00 00 01 00 01 63 00 10 67 6B 60 23 24 6A 55 39 4E 58 24 5E 39 2B 7A 69 01 38 00 5E 00 00 00 09 01 06 00 27 8D 00 00 00 00 00 01 0A 00 24 EA 00 00 00 00 00 01 1C 00 1A 5E 00 00 00 00 00 01 02 00 01 51 80 00 00 00 00 01 03 00 00 1C 20 00 00 00 00 01 20 00 01 51 80 00 00 00 00 01 36 00 1B AF 80 00 00 00 00 01 43 00 1B AF 80 00 00 00 00 01 64 00 1B AF 80 00 00 00 00 01 30 00 0E 00 00 5E 19 65 8C 9F 02 53 AB 00 00 00 00
@@ -265,7 +272,13 @@ internal class WtLogin {
 
                     tlvMap119[0x118]?.let { client.mainDisplayName = it }
                     tlvMap119[0x108]?.let { client.ksid = it }
-
+                    tlvMap119[0x11a]?.read {
+                        val faceId = readShort().toInt()
+                        val age = readByte().toInt()
+                        val gender = readByte().toInt()
+                        val nickLength = readByte().toInt()
+                        bot.nick = readString(nickLength)
+                    }
                     var openId: ByteArray? = null
                     var openKey: ByteArray? = null
                     tlvMap119[0x125]?.read {
@@ -296,6 +309,7 @@ internal class WtLogin {
                             }.getOrElse { ByteReadPacket(byteArrayOf()) }
                         )
                     }
+
                     tlvMap119[0x167]?.let {
                         val imgType = byteArrayOf(readByte())
                         val imgFormat = byteArrayOf(readByte())
@@ -325,6 +339,21 @@ internal class WtLogin {
                     val creationTime = currentTimeSeconds()
                     val expireTime = creationTime + 21600
 
+                    val changeTokenTimeMap = tlvMap119[0x138]?.read {
+                        val tlvMap138 = mutableMapOf<Int, Long>()
+                        val count = readInt()
+                        repeat(count) {
+                            val key = readShort().toInt()
+                            val value = readInt().toLong()
+                            tlvMap138[key] = value
+                        }
+                        tlvMap138
+                    } ?: emptyMap()
+
+                    if (SHOW_TLV_MAP_ON_LOGIN_SUCCESS) {
+                        changeTokenTimeMap._miraiContentToString().soutv("tokenChangeTime")
+                    }
+
                     val outPSKeyMap: PSKeyMap?
                     val outPt4TokenMap: Pt4TokenMap?
                     if (tlvMap119[0x512] != null) {
@@ -342,28 +371,60 @@ internal class WtLogin {
                         outPt4TokenMap = null
                     }
 
-                    var a1: ByteArray? = tlvMap119.getOrFail(0x106)
-                    var noPicSig: ByteArray? = tlvMap119[0x16a]
-                    tlvMap119[0x531]?.let {
-                        analysisTlv0x531(it) { arg1, arg2 ->
-                            a1 = arg1
-                            noPicSig = arg2
-                        }
-                    }
-
                     if (client.wLoginSigInfoInitialized) {
                         client.wLoginSigInfo.apply {
-                            userStWebSig = UserStWebSig(tlvMap119.getOrEmpty(0x103), creationTime, expireTime)
-                            userStKey = tlvMap119.getOrEmpty(0x10e)
-                            userStSig = UserStSig((tlvMap119.getOrEmpty(0x114)), creationTime)
-                            appPri = tlvMap119[0x11f]?.let { it.read { discardExact(4); readUInt().toLong() } }
-                                ?: 4294967295L
-                            sKey = SKey(tlvMap119.getOrEmpty(0x120), creationTime, expireTime)
-                            wtSessionTicket = WtSessionTicket(tlvMap119.getOrEmpty(0x133), creationTime)
-                            wtSessionTicketKey = tlvMap119.getOrEmpty(0x134)
-                            deviceToken = tlvMap119.getOrEmpty(0x322)
+                            superKey = tlvMap119.getOrDefault(0x16d, superKey)
+                            d2 = D2(
+                                tlvMap119.getOrDefault(0x143, d2.data),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x143, 1728000L)
+                            )
+                            d2Key = tlvMap119.getOrDefault(0x305, d2Key)
+                            tgt = tlvMap119.getOrDefault(0x10a, tgt)
+                            tgtKey = tlvMap119.getOrDefault(0x10d, tgtKey)
+                            a2ExpiryTime = creationTime + changeTokenTimeMap.getOrDefault(0x10a, 2160000L)
+                            userStWebSig = UserStWebSig(
+                                tlvMap119.getOrDefault(0x103, userStWebSig.data),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x103, 6000L)
+                            )
+                            userStKey = tlvMap119.getOrDefault(0x10e, userStKey)
+                            userStSig = UserStSig((tlvMap119.getOrDefault(0x114, userStSig.data)), creationTime)
+                            appPri = tlvMap119[0x11f]?.let {
+                                it.read {
+                                    //change interval (int time)
+                                    discardExact(4)
+                                    readUInt().toLong()
+                                }
+                            }
+                                ?: appPri
+                            sKey = SKey(
+                                tlvMap119.getOrEmpty(0x120),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x120, 86400L)
+                            )
+                            wtSessionTicket = WtSessionTicket(
+                                tlvMap119.getOrDefault(
+                                    0x133,
+                                    client.wLoginSigInfo.wtSessionTicket.data
+                                ), creationTime
+                            )
+
+                            wtSessionTicketKey = tlvMap119.getOrDefault(0x134, client.wLoginSigInfo.wtSessionTicketKey)
+                            deviceToken = tlvMap119.getOrDefault(0x322, deviceToken)
+                            encryptedDownloadSession = tlvMap119[0x11d]?.let {
+                                client.analysisTlv11d(it)
+                            } ?: encryptedDownloadSession
                         }
                     } else {
+                        var a1: ByteArray? = tlvMap119.getOrFail(0x106)
+                        var noPicSig: ByteArray? = tlvMap119[0x16a]
+                        tlvMap119[0x531]?.let {
+                            analysisTlv0x531(it) { arg1, arg2 ->
+                                a1 = arg1
+                                noPicSig = arg2
+                            }
+                        }
                         client.wLoginSigInfo = WLoginSigInfo(
                             uin = client.uin,
                             encryptA1 = a1,
@@ -375,28 +436,65 @@ internal class WtLogin {
                                 imgUrl = client.reserveUinInfo?.imgUrl ?: byteArrayOf(),
                                 mainDisplayName = tlvMap119[0x118] ?: error("Cannot find tlv 0x118")
                             ), // defaults {}, from asyncContext._G
-                            appPri = tlvMap119[0x11f]?.let { it.read { discardExact(4); readUInt().toLong() } }
+                            appPri = tlvMap119[0x11f]?.let {
+                                it.read {
+                                    //change interval (int time)
+                                    discardExact(4)
+                                    readUInt().toLong()
+                                }
+                            }
                                 ?: 4294967295L, // defaults {}, from asyncContext._G
-                            a2ExpiryTime = expireTime, // or from asyncContext._t403.get_body_data()
+                            a2ExpiryTime = creationTime + changeTokenTimeMap.getOrDefault(
+                                0x10a,
+                                2160000L
+                            ), // or from asyncContext._t403.get_body_data()
                             loginBitmap = 0,
-                            tgt = tlvMap119.getOrEmpty(0x10a),
+                            tgt = tlvMap119.getOrFail(0x10a),
                             a2CreationTime = creationTime,
                             tgtKey = tlvMap119.getOrEmpty(0x10d), // from asyncContext._login_bitmap
                             userStSig = UserStSig((tlvMap119.getOrEmpty(0x114)), creationTime),
                             userStKey = tlvMap119.getOrEmpty(0x10e),
-                            userStWebSig = UserStWebSig(tlvMap119.getOrEmpty(0x103), creationTime, expireTime),
+                            userStWebSig = UserStWebSig(
+                                tlvMap119.getOrEmpty(0x103),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x103, 6000L)
+                            ),
                             userA5 = UserA5(tlvMap119.getOrEmpty(0x10b), creationTime),
-                            userA8 = UserA8(tlvMap119.getOrEmpty(0x102), creationTime, expireTime),
-                            lsKey = LSKey(tlvMap119.getOrEmpty(0x11c), creationTime, expireTime),
-                            sKey = SKey(tlvMap119.getOrEmpty(0x120), creationTime, expireTime),
+                            userA8 = UserA8(
+                                tlvMap119.getOrEmpty(0x102),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x102, 72000L)
+                            ),
+                            lsKey = LSKey(
+                                tlvMap119.getOrEmpty(0x11c),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x11c, 1641600L)
+                            ),
+                            sKey = SKey(
+                                tlvMap119.getOrEmpty(0x120),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x120, 86400L)
+                            ),
                             userSig64 = UserSig64(tlvMap119.getOrEmpty(0x121), creationTime),
                             openId = openId.orEmpty(),
                             openKey = OpenKey(openKey.orEmpty(), creationTime),
-                            vKey = VKey(tlvMap119.getOrEmpty(0x136), creationTime, expireTime),
+                            vKey = VKey(
+                                tlvMap119.getOrEmpty(0x136),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x136, 1728000L)
+                            ),
                             accessToken = AccessToken(tlvMap119.getOrEmpty(0x136), creationTime),
-                            d2 = D2(tlvMap119.getOrEmpty(0x143), creationTime, expireTime),
+                            d2 = D2(
+                                tlvMap119.getOrFail(0x143),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x143, 1728000L)
+                            ),
                             d2Key = tlvMap119.getOrEmpty(0x305),
-                            sid = Sid(tlvMap119.getOrEmpty(0x164), creationTime, expireTime),
+                            sid = Sid(
+                                tlvMap119.getOrEmpty(0x164),
+                                creationTime,
+                                creationTime + changeTokenTimeMap.getOrDefault(0x164, 1728000L)
+                            ),
                             aqSig = AqSig(tlvMap119.getOrEmpty(0x171), creationTime),
                             psKeyMap = outPSKeyMap.orEmpty().toMutableMap(),
                             pt4TokenMap = outPt4TokenMap.orEmpty().toMutableMap(),
@@ -407,7 +505,10 @@ internal class WtLogin {
                             da2 = tlvMap119.getOrEmpty(0x203),
                             wtSessionTicket = WtSessionTicket(tlvMap119.getOrEmpty(0x133), creationTime),
                             wtSessionTicketKey = tlvMap119.getOrEmpty(0x134),
-                            deviceToken = tlvMap119.getOrEmpty(0x322)
+                            deviceToken = tlvMap119.getOrEmpty(0x322),
+                            encryptedDownloadSession = tlvMap119[0x11d]?.let {
+                                client.analysisTlv11d(it)
+                            }
                         )
                     }
                     //bot.network.logger.error(client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString())
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt
new file mode 100644
index 000000000..215c41879
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLogin10.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019-2021 Mamoe Technologies and contributors.
+ *
+ *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin
+
+import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.protocol.packet.*
+import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
+import net.mamoe.mirai.internal.utils.GuidSource
+import net.mamoe.mirai.internal.utils.MacOrAndroidIdChangeFlag
+import net.mamoe.mirai.internal.utils.guidFlag
+import net.mamoe.mirai.utils.generateDeviceInfoData
+import net.mamoe.mirai.utils.md5
+import net.mamoe.mirai.utils.toReadPacket
+
+internal object WtLogin10 : WtLoginExt {
+
+    const val appId: Long = 16L
+    operator fun invoke(
+        client: QQAndroidClient,
+    ) = WtLogin.ExchangeEmp.buildLoginOutgoingPacket(client, bodyType = 2, key = ByteArray(16)) { sequenceId ->
+        writeSsoPacket(
+            client,
+            client.subAppId,
+            WtLogin.ExchangeEmp.commandName,
+            extraData = client.wLoginSigInfo.tgt.toReadPacket(),
+            sequenceId = sequenceId
+        ) {
+            writeOicqRequestPacket(
+                client,
+                EncryptMethodECDH(client.ecdh),
+                0x0810
+            ) {
+                writeShort(11) // subCommand
+                writeShort(17)
+                t100(appId, 100, client.appClientVersion, client.ssoVersion, client.mainSigMap)
+                t10a(client.wLoginSigInfo.tgt)
+                t116(client.miscBitMap, client.subSigMap)
+                t108(client.ksid)
+                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(0)),
+                    buildModel = client.device.model,
+                    guid = client.device.guid,
+                    buildBrand = client.device.brand,
+                    tgtgtKey = client.wLoginSigInfo.d2Key.md5()
+                )
+                //t112(client.account.phoneNumber.encodeToByteArray())
+                t143(client.wLoginSigInfo.d2.data)
+                t142(client.apkId)
+                t154(sequenceId)
+                t18(appId, uin = client.uin)
+                t141(client.device.simInfo, client.networkType, client.device.apn)
+                t8(2052)
+                //t511()
+                t147(appId, client.apkVersionName, client.apkSignatureMd5)
+                t177(client.buildTime, client.sdkVersion)
+                t187(client.device.macAddress)
+                t188(client.device.androidId)
+                t194(client.device.imsiMd5)
+                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"
+                    )
+                )
+                //t544()
+
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt
index 6aeefefb1..4dd40f643 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/login/wtlogin/WtLoginExt.kt
@@ -12,6 +12,7 @@ package net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin
 import kotlinx.io.core.*
 import net.mamoe.mirai.internal.network.LoginExtraData
 import net.mamoe.mirai.internal.network.QQAndroidClient
+import net.mamoe.mirai.internal.network.WLoginSigInfo
 import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.network.protocol.packet.Tlv
 import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
@@ -40,14 +41,14 @@ internal inline fun WtLoginExt.analysisTlv0x531(
 
 internal interface WtLoginExt { // so as not to register to global extension
 
-    fun onErrorMessage(tlvMap: TlvMap): WtLogin.Login.LoginPacketResponse.Error? {
+    fun onErrorMessage(type: Int, tlvMap: TlvMap): WtLogin.Login.LoginPacketResponse.Error? {
         return tlvMap[0x149]?.read {
             discardExact(2) //type
             val title: String = readUShortLVString()
             val content: String = readUShortLVString()
             val otherInfo: String = readUShortLVString()
 
-            WtLogin.Login.LoginPacketResponse.Error(title, content, otherInfo)
+            WtLogin.Login.LoginPacketResponse.Error(type, title, content, otherInfo)
         } ?: tlvMap[0x146]?.read {
             discardExact(2) // ver
             discardExact(2)  // code
@@ -56,7 +57,7 @@ internal interface WtLoginExt { // so as not to register to global extension
             val message = readUShortLVString()
             val errorInfo = readUShortLVString()
 
-            WtLogin.Login.LoginPacketResponse.Error(title, message, errorInfo)
+            WtLogin.Login.LoginPacketResponse.Error(type, title, message, errorInfo)
         }
     }
 
@@ -116,6 +117,23 @@ internal interface WtLoginExt { // so as not to register to global extension
         }
     }
 
+    /**
+     * Encrypt sig and key for pic downloading
+     */
+    fun QQAndroidClient.analysisTlv11d(t11d: ByteArray): WLoginSigInfo.EncryptedDownloadSession = t11d.read {
+        val appid = readInt().toLong().and(4294967295L)
+        val stKey = ByteArray(16)
+        readAvailable(stKey)
+        val stSigLength = readUShort().toInt()
+        val stSig = ByteArray(stSigLength)
+        readAvailable(stSig)
+        WLoginSigInfo.EncryptedDownloadSession(
+            appid,
+            stKey,
+            stSig
+        )
+    }
+
     /**
      * pwd flag
      */