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 a32d966ef..fb5de7b0b 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
@@ -82,9 +82,14 @@ internal class MemberImpl(
             "Permission Denied when trying to edit group card for $this"
         }
         if (group.botPermission != MemberPermission.MEMBER && new != old) {
+
             launch {
                 bot.network.run {
-
+                    TroopManagement.EditGroupNametag(
+                        bot.client,
+                        this@MemberImpl,
+                        new
+                    ).sendWithoutExpect()
                 }
             }
         }
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt
index 9b5f13501..693d7d7c8 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt
@@ -90,7 +90,10 @@ fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrategy<T>): T
 /**
  * load
  */
-fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrategy<T>, length: Int = this.remaining.toInt()): T {
+fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(
+    serializer: DeserializationStrategy<T>,
+    length: Int = this.remaining.toInt()
+): T {
     return ProtoBufWithNullableSupport.load(serializer, this.readBytes(length))
 }
 
@@ -98,11 +101,20 @@ fun <T : ProtoBuf> ByteReadPacket.readProtoBuf(serializer: DeserializationStrate
  * 构造 [RequestPacket] 的 [RequestPacket.sBuffer]
  */
 fun <T : JceStruct> jceRequestSBuffer(name: String, serializer: SerializationStrategy<T>, jceStruct: T): ByteArray {
+    return jceRequestSBuffer(name, serializer, jceStruct, JceCharset.GBK)
+}
+
+fun <T : JceStruct> jceRequestSBuffer(
+    name: String,
+    serializer: SerializationStrategy<T>,
+    jceStruct: T,
+    charset: JceCharset
+): ByteArray {
     return RequestDataVersion3(
         mapOf(
             name to JCE_STRUCT_HEAD_OF_TAG_0 + jceStruct.toByteArray(serializer) + JCE_STRUCT_TAIL_OF_TAG_0
         )
-    ).toByteArray(RequestDataVersion3.serializer())
+    ).toByteArray(RequestDataVersion3.serializer(), charset)
 }
 
 private val JCE_STRUCT_HEAD_OF_TAG_0 = byteArrayOf(0x0A)
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
index 0e3529024..34d627b08 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/FriendList.kt
@@ -4,6 +4,25 @@ import kotlinx.serialization.SerialId
 import kotlinx.serialization.Serializable
 import net.mamoe.mirai.qqandroid.io.JceStruct
 
+@Serializable
+internal class ModifyGroupCardReq(
+    @SerialId(0) val dwZero: Long,
+    @SerialId(1) val dwGroupCode: Long,
+    @SerialId(2) val dwNewSeq: Long,
+    @SerialId(3) val vecUinInfo: List<stUinInfo>
+) : JceStruct
+
+@Serializable
+internal class stUinInfo(
+    @SerialId(0) val dwuin: Long,
+    @SerialId(1) val dwFlag: Long,
+    @SerialId(2) val sName: String = "",
+    @SerialId(3) val gender: Byte,
+    @SerialId(4) val sPhone: String = "",
+    @SerialId(5) val sEmail: String = "",
+    @SerialId(6) val sRemark: String = ""
+) : JceStruct
+
 @Serializable
 internal class GetFriendListReq(
     @SerialId(0) val reqtype: Int? = null,
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 8b147523d..0916806cd 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
@@ -128,7 +128,8 @@ internal object KnownPacketFactories {
         TroopManagement.EditSpecialTitle,
         TroopManagement.Mute,
         TroopManagement.GroupOperation,
-        TroopManagement.GetGroupOperationInfo
+        TroopManagement.GetGroupOperationInfo,
+        TroopManagement.EditGroupNametag
     )
 
     object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
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 b77313acc..16f05b3c3 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
@@ -1,16 +1,18 @@
 package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
 
-import kotlinx.io.core.ByteReadPacket
-import kotlinx.io.core.buildPacket
-import kotlinx.io.core.readBytes
-import kotlinx.io.core.toByteArray
+import kotlinx.io.charsets.Charset
+import kotlinx.io.charsets.encode
+import kotlinx.io.core.*
+import kotlinx.serialization.toUtf8Bytes
 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
-import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
-import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
+import net.mamoe.mirai.qqandroid.io.serialization.*
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetTroopListReqV2Simplify
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo
 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
@@ -20,6 +22,8 @@ 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.utils.daysToSeconds
+import net.mamoe.mirai.utils.io.encodeToGBKString
+import net.mamoe.mirai.utils.io.encodeToString
 
 internal object TroopManagement {
 
@@ -316,6 +320,57 @@ internal object TroopManagement {
         }
     }
 
+    internal object EditGroupNametag :
+        OutgoingPacketFactory<EditGroupNametag.Response>("friendlist.ModifyGroupCardReq") {
+        object Response : Packet
+
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): EditGroupNametag.Response {
+            return Response
+        }
+
+        operator fun invoke(
+            client: QQAndroidClient,
+            member: Member,
+            newName: String
+        ): OutgoingPacket {
+            return buildOutgoingUniPacket(client) {
+                writeJceStruct(
+                    RequestPacket.serializer(),
+                    RequestPacket(
+                        sFuncName = "ModifyGroupCardReq",
+                        sServantName = "mqq.IMService.FriendListServiceServantObj",
+                        iVersion = 3,
+                        cPacketType = 0x00,
+                        iMessageType = 0x00000,
+                        iRequestId = client.nextRequestPacketRequestId(),
+                        sBuffer = jceRequestSBuffer(
+                            "MGCREQ",
+                            ModifyGroupCardReq.serializer(),
+                            ModifyGroupCardReq(
+                                dwZero = 0L,
+                                dwGroupCode = member.group.id,
+                                dwNewSeq = 0L,
+                                vecUinInfo = listOf(
+                                    stUinInfo(
+                                        gender = 0,
+                                        dwuin = member.id,
+                                        dwFlag = 31,
+                                        sName = newName.toUtf8Bytes().encodeToGBKString(),
+                                        sPhone = "",
+                                        sEmail = "",
+                                        sRemark = ""
+                                    )
+                                )
+                            ),
+                            JceCharset.GBK
+                        )
+                    )
+                )
+            }
+        }
+
+    }
+
     /*
     internal object Recall: OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login"){
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): LoginPacket.LoginPacketResponse {
diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
index 41d6ddcea..e304fccfd 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt
@@ -2,6 +2,7 @@
 
 package net.mamoe.mirai.utils.io
 
+import kotlinx.io.charsets.Charset
 import kotlinx.io.core.ByteReadPacket
 import kotlinx.io.core.String
 import kotlinx.io.core.use
@@ -81,7 +82,11 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In
 @Suppress("NOTHING_TO_INLINE")
 inline fun ByteArray.encodeToString(): String = String(this)
 
-fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) = ByteReadPacket(this, offset = offset, length = length)
+fun ByteArray.encodeToGBKString(): String = String(this, 0, this.size, Charset.forName("GBK"))
+
+
+fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) =
+    ByteReadPacket(this, offset = offset, length = length)
 
 @UseExperimental(ExperimentalContracts::class)
 inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R {