You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python如何解析Minecraft基岩版登录包Chain与Skin数据

问题分析

你现有代码仅完成了登录包前5字节的解析(1字节包ID + 4字节协议版本),未适配基岩版协议的变长编码规则,因此无法提取后续的Chain data与Skin data字段。
基岩版Login包在协议版本字段之后的固定结构顺序如下:

  • payload总长度:无符号VarInt类型,标记后续所有登录载荷的总字节数,一般用于包完整性校验
  • Chain data长度:无符号VarInt类型,标记Chain数据的字节长度
  • Chain data内容:UTF-8编码的JSON字符串,内容为Xbox Live认证链
  • Skin data长度:无符号VarInt类型,标记Skin数据的字节长度
  • Skin data内容:UTF-8编码的JWT字符串,包含玩家用户名、皮肤、客户端信息等数据

其中VarInt是基岩版协议通用的变长整数编码,每个字节最高位标记是否存在后续字节,低7位存储实际数值,无法用固定长度的struct模块直接解析。

实现代码

1. 扩展Packet基类,添加通用解析方法

首先修改packet/packet.py,增加读取偏移指针和VarInt、变长字符串的通用解析方法,后续所有包解析都可以复用:

class Packet(object):
    def __init__(self, original_bytes: bytes):
        self.original_bytes = original_bytes
        self.id = original_bytes[0:1]
        self.data = original_bytes[1:]
        # 读取偏移指针,初始位置指向包ID后第一个字节
        self.offset = 0

    def read_unsigned_varint(self) -> int:
        """读取无符号VarInt,读取完成后自动移动偏移指针"""
        result = 0
        bit_offset = 0
        while True:
            if self.offset >= len(self.data):
                raise ValueError("Packet truncated when reading VarInt")
            current_byte = self.data[self.offset]
            self.offset += 1
            result |= (current_byte & 0x7F) << bit_offset
            if not (current_byte & 0x80):
                break
            bit_offset += 7
            if bit_offset >= 35:
                raise ValueError("VarInt exceeds maximum allowed length")
        return result

    def read_string(self) -> str:
        """读取变长字符串(VarInt长度前缀 + UTF-8内容),读取完成后自动移动偏移指针"""
        str_length = self.read_unsigned_varint()
        content = self.data[self.offset : self.offset + str_length]
        self.offset += str_length
        return content.decode("utf-8")


class IncorrectPacketID(Exception):
    pass

2. 完善Login_Packet解析逻辑

修改packet/login.py,修正原有协议版本解析的字节序问题,补充Chain data和Skin data的解析逻辑:

from packet import *
import struct


class Login_Packet(Packet):
    """客户端发送的登录包"""
    def __init__(self, original_bytes: bytes):
        super().__init__(original_bytes)
        if self.id != b'\x01':
            raise IncorrectPacketID(f"Expected packet ID 0x01, got {self.id.hex()}")
        
        # 解析固定字段
        self.protocol_version = self._parse_protocol_version()
        # 读取并跳过载荷总长度字段
        self.read_unsigned_varint()
        self.chain_data = self.read_string()
        self.skin_data = self.read_string()

    def _parse_protocol_version(self) -> int:
        # 协议版本为4字节大端有符号整数
        version = struct.unpack(">i", self.data[self.offset : self.offset + 4])[0]
        self.offset += 4
        return version

    def get_protocol_version(self) -> int:
        return self.protocol_version

    def get_chain_data(self) -> str:
        return self.chain_data

    def get_skin_data(self) -> str:
        return self.skin_data
注意事项
  • 你当前提供的测试字节串是不完整的登录包,实际客户端发送的登录包长度远大于该示例,测试时请使用完整抓包数据,否则会触发包截断错误。
  • 解析得到的Chain data是JSON格式,可直接用json.loads加载,其中chain字段为三段JWT认证令牌;Skin data是单个JWT令牌,base64解码中段载荷即可获取皮肤、玩家ID等信息。
  • 后续解析其他基岩版协议包时,可直接复用Packet基类的VarInt、字符串读取方法,按照协议文档补充其他类型(如小端整数、浮点数、有符号VarInt)的读取逻辑即可。

内容的提问来源于stack exchange,提问作者UCYT5040

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 16:57:20