diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
index db5604f6a..a32d966ef 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt
@@ -67,7 +67,8 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin
 
 internal class MemberImpl(
     qq: QQImpl,
-    override var groupCard: String,
+    initGroupCard: String,
+    initSpecialTitle: String,
     group: GroupImpl,
     override val coroutineContext: CoroutineContext,
     override val permission: MemberPermission
@@ -75,6 +76,37 @@ internal class MemberImpl(
     override val group: GroupImpl by group.unsafeWeakRef()
     val qq: QQImpl by qq.unsafeWeakRef()
 
+
+    override var groupCard: String by Delegates.observable(initGroupCard) { _, old, new ->
+        check(group.botPermission != MemberPermission.MEMBER) {
+            "Permission Denied when trying to edit group card for $this"
+        }
+        if (group.botPermission != MemberPermission.MEMBER && new != old) {
+            launch {
+                bot.network.run {
+
+                }
+            }
+        }
+    }
+
+    override var specialTitle: String by Delegates.observable(initSpecialTitle) { _, old, new ->
+        check(group.botPermission == MemberPermission.OWNER) {
+            "Permission Denied when trying to edit special title for $this, need to be OWNER"
+        }
+        if (new != old) {
+            launch {
+                bot.network.run {
+                    TroopManagement.EditSpecialTitle(
+                        bot.client,
+                        this@MemberImpl,
+                        new
+                    ).sendWithoutExpect()
+                }
+            }
+        }
+    }
+
     override val bot: QQAndroidBot get() = qq.bot
 
     override suspend fun mute(durationSeconds: Int): Boolean {
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
index 5650d5404..690b5a5f8 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
@@ -190,32 +190,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                         initAnonymousChat = groupInfoResponse.allowAnonymousChat,
                         members = contactList
                     )
-                group.owner =
-                    MemberImpl(
-                        qq = bot.QQ(it.dwGroupOwnerUin) as QQImpl,
-                        groupCard = "",//unknown now
-                        group = group,
-                        coroutineContext = group.coroutineContext,
-                        permission = MemberPermission.OWNER
-                    )
-                if (it.dwGroupOwnerUin == bot.uin) {
-                    group.botPermission = MemberPermission.OWNER
-                }
                 toGet[group] = contactList
                 bot.groups.delegate.addLast(group)
-            }
-            coroutineScope {
-                toGet.forEach {
-                    launch {
-                        try {
-                            getTroopMemberList(it.key, it.value, it.key.owner.id)
-                            groupInfo[it.key.id] = it.value.size
-                        } catch (e: Exception) {
-                            groupInfo[it.key.id] = -1
-                            bot.logger.info("群${it.key.uin}的列表拉取失败, 将采用动态加入")
-                        }
+                launch {
+                    try {
+                        getTroopMemberList(group, contactList, it.dwGroupOwnerUin)
+                        groupInfo[it.groupCode] = contactList.size
+                    } catch (e: Exception) {
+                        groupInfo[it.groupCode] = -1
+                        bot.logger.info("群${it.groupCode}的列表拉取失败, 将采用动态加入")
+                        println(e.message)
+                        println(e.logStacktrace())
                     }
-                    //delay(200)
                 }
             }
             bot.logger.info("群组列表与群成员加载完成, 共 ${troopData.groups.size}个")
@@ -257,12 +243,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
     }
 
-    suspend fun getGroupInfo(uin: Long) {
-        val data = TroopManagement.GetGroupOperationInfo(
-            client = bot.client,
-            groupCode = uin
-        ).sendAndExpect<TroopManagement.GetGroupOperationInfo.Response>(timeoutMillis = 3000)
-    }
 
     suspend fun getTroopMemberList(group: GroupImpl, list: ContactList<Member>, owner: Long): ContactList<Member> {
         bot.logger.info("开始获取群[${group.uin}]成员列表")
@@ -276,29 +256,29 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                 nextUin = nextUin
             ).sendAndExpect<FriendList.GetTroopMemberList.Response>(timeoutMillis = 3000)
             data.members.forEach {
-                if (it.memberUin != bot.uin) {
-                    list.delegate.addLast(
-                        MemberImpl(
-                            qq = bot.QQ(it.memberUin) as QQImpl,
-                            groupCard = it.autoRemark ?: it.nick,
-                            group = group,
-                            coroutineContext = group.coroutineContext,
-                            permission = when {
-                                it.memberUin == owner -> MemberPermission.OWNER
-                                it.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
-                                else -> MemberPermission.MEMBER
-                            }
-                        )
-                    )
-                } else {
-                    group.owner.groupCard = it.autoRemark ?: it.nick
-                    if (it.dwFlag == 1L) {
-                        group.botPermission = MemberPermission.ADMINISTRATOR
+                val member = MemberImpl(
+                    qq = bot.QQ(it.memberUin) as QQImpl,
+                    initGroupCard = it.autoRemark ?: it.nick,
+                    initSpecialTitle = it.sSpecialTitle ?: "",
+                    group = group,
+                    coroutineContext = group.coroutineContext,
+                    permission = when {
+                        it.memberUin == owner -> MemberPermission.OWNER
+                        it.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
+                        else -> MemberPermission.MEMBER
                     }
+                )
+                if (member.permission == MemberPermission.OWNER) {
+                    group.owner = member
                 }
+                if (it.memberUin != bot.uin) {
+                    list.delegate.addLast(member)
+                } else {
+                    group.botPermission = member.permission
+                }
+                size += data.members.size
+                nextUin = data.nextUin
             }
-            size += data.members.size
-            nextUin = data.nextUin
             if (nextUin == 0L) {
                 break
             }
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
index a8b39c438..0cdc81bf4 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/OIDB.kt
@@ -5,6 +5,78 @@ import kotlinx.serialization.Serializable
 import net.mamoe.mirai.qqandroid.io.ProtoBuf
 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 
+@Serializable
+class Oidb0x8fc : ProtoBuf {
+    @Serializable
+    class CardNameElem(
+        @SerialId(1) val enumCardType: Int /* enum */ = 1,
+        @SerialId(2) val value: ByteArray = EMPTY_BYTE_ARRAY
+    ) : ProtoBuf
+
+    @Serializable
+    class CommCardNameBuf(
+        @SerialId(1) val richCardName: List<Oidb0x8fc.RichCardNameElem>? = null
+    ) : ProtoBuf
+
+    @Serializable
+    class ReqBody(
+        @SerialId(1) val groupCode: Long = 0L,
+        @SerialId(2) val showFlag: Int = 0,
+        @SerialId(3) val memLevelInfo: List<Oidb0x8fc.MemberInfo>? = null,
+        @SerialId(4) val levelName: List<Oidb0x8fc.LevelName>? = null,
+        @SerialId(5) val updateTime: Int = 0,
+        @SerialId(6) val officeMode: Int = 0,
+        @SerialId(7) val groupOpenAppid: Int = 0,
+        @SerialId(8) val msgClientInfo: Oidb0x8fc.ClientInfo? = null,
+        @SerialId(9) val authKey: ByteArray = EMPTY_BYTE_ARRAY
+    ) : ProtoBuf
+
+    @Serializable
+    class MemberInfo(
+        @SerialId(1) val uin: Long = 0L,
+        @SerialId(2) val point: Int = 0,
+        @SerialId(3) val activeDay: Int = 0,
+        @SerialId(4) val level: Int = 0,
+        @SerialId(5) val specialTitle: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(6) val specialTitleExpireTime: Int = 0,
+        @SerialId(7) val uinName: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(8) val memberCardName: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(9) val phone: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(10) val email: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(11) val remark: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(12) val gender: Int = 0,
+        @SerialId(13) val job: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(14) val tribeLevel: Int = 0,
+        @SerialId(15) val tribePoint: Int = 0,
+        @SerialId(16) val richCardName: List<Oidb0x8fc.CardNameElem>? = null,
+        @SerialId(17) val commRichCardName: ByteArray = EMPTY_BYTE_ARRAY
+    ) : ProtoBuf
+
+    @Serializable
+    class RichCardNameElem(
+        @SerialId(1) val ctrl: ByteArray = EMPTY_BYTE_ARRAY,
+        @SerialId(2) val text: ByteArray = EMPTY_BYTE_ARRAY
+    ) : ProtoBuf
+
+    @Serializable
+    class RspBody(
+        @SerialId(1) val groupCode: Long = 0L,
+        @SerialId(2) val errInfo: String = ""
+    ) : ProtoBuf
+
+    @Serializable
+    class ClientInfo(
+        @SerialId(1) val implat: Int = 0,
+        @SerialId(2) val ingClientver: String = ""
+    ) : ProtoBuf
+
+    @Serializable
+    class LevelName(
+        @SerialId(1) val level: Int = 0,
+        @SerialId(2) val name: String = ""
+    ) : ProtoBuf
+}
+
 @Serializable
 class Oidb0x88d : ProtoBuf {
     @Serializable
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
index 6fb982654..8b147523d 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
@@ -125,7 +125,7 @@ internal object KnownPacketFactories {
         ImgStore.GroupPicUp,
         ImageUpPacket,
         LongConn.OffPicDown,
-        TroopManagement.EditNametag,
+        TroopManagement.EditSpecialTitle,
         TroopManagement.Mute,
         TroopManagement.GroupOperation,
         TroopManagement.GetGroupOperationInfo
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
index ae0db6fd6..de1a30cdf 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/TroopManagement.kt
@@ -4,6 +4,7 @@ import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.buildPacket
 import kotlinx.io.core.readBytes
 import kotlinx.io.core.toByteArray
+import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.data.Packet
 import net.mamoe.mirai.qqandroid.QQAndroidBot
 import net.mamoe.mirai.qqandroid.io.serialization.loadAs
@@ -12,12 +13,12 @@ import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x88d
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x89a
+import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Oidb0x8fc
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.OidbSso
 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
-import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
 import net.mamoe.mirai.utils.daysToSeconds
 
 internal object TroopManagement {
@@ -272,9 +273,38 @@ internal object TroopManagement {
     }
 
 
-    internal object EditNametag : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("OidbSvc.0x8fc_2") {
-        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacket.LoginPacketResponse {
-            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    internal object EditSpecialTitle : OutgoingPacketFactory<EditSpecialTitle.Response>("OidbSvc.0x8fc_2") {
+        object Response : Packet
+
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
+            return Response
+        }
+
+        operator fun invoke(
+            client: QQAndroidClient,
+            member: Member,
+            newName: String
+        ): OutgoingPacket {
+            return buildOutgoingUniPacket(client) {
+                writeProtoBuf(
+                    OidbSso.OIDBSSOPkg.serializer(),
+                    OidbSso.OIDBSSOPkg(
+                        command = 2300,
+                        serviceType = 2,
+                        bodybuffer = Oidb0x8fc.ReqBody(
+                            groupCode = member.group.id,
+                            memLevelInfo = listOf(
+                                Oidb0x8fc.MemberInfo(
+                                    uin = member.id,
+                                    uinName = newName.toByteArray(),
+                                    specialTitle = newName.toByteArray(),
+                                    specialTitleExpireTime = -1
+                                )
+                            )
+                        ).toByteArray(Oidb0x8fc.ReqBody.serializer())
+                    )
+                )
+            }
         }
     }
 
diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
index 2a576e6d4..7bd8383fc 100644
--- a/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
+++ b/mirai-core-qqandroid/src/jvmTest/kotlin/test/ProtoBufDataClassGenerator.kt
@@ -6,7 +6,7 @@ import java.io.File
 
 fun main() {
     println(
-        File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/""")
+        File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/oidb/cmd0x8fc/""")
             .generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n")
     )
 }
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
index b8a7e3f86..614c93899 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
@@ -22,10 +22,23 @@ interface Member : QQ, Contact {
     val permission: MemberPermission
 
     /**
-     * 群名片 (如果有) 或个人昵称. 动态更新.
+     * ====以下字段会在更新后异步更新到服务器====
+     */
+
+    /**
+     * 群名片
      */
     var groupCard: String
 
+    /**
+     * 群头衔
+     */
+    var specialTitle: String
+
+    /**
+     * ====以上字段会在更新后异步更新到服务器====
+     */
+
     /**
      * 禁言
      *