Protobuf协议解析与微信数据结构设计
Protobuf协议解析与微信数据结构设计
免责声明
本文所分析的源代码均来自互联网公开渠道的技术研究和学习资料。本文的内容仅供安全研究、技术学习和学术分析目的使用,旨在帮助读者理解现代即时通讯协议的数据结构设计思路。
重要提示:
合法合规:任何使用本文所涉及技术的行为,必须严格遵守所在地的法律法规,不得用于任何非法目的。
知识产权:微信及其相关技术、商标、著作权均归腾讯公司所有。本文仅进行技术层面的分析,不构成对任何知识产权的侵犯。
安全责任:读者应自行承担使用本文内容所产生的一切责任和后果。作者不对任何因不当使用本文内容而导致的法律责任、安全问题或经济损失负责。
学习目的:本文的技术分析旨在促进网络安全知识的普及和技术交流,帮助安全研究人员提升防护能力,而非用于攻击或其他恶意用途。
请在继续阅读前确认您已理解并同意以上条款。
前言
Protocol Buffers(Protobuf)是Google开发的一种语言无关、平台无关、可扩展的序列化数据结构协议。微信采用Protobuf作为主要的数据交换格式,配合自定义的数据包封装机制,实现了高效、紧凑的网络传输。本文将深入分析wechatdll807项目中的Protobuf协议定义和数据封装机制。
一、Protobuf基础结构
微信使用Protobuf 2版本(syntax=“proto2”),定义了大量的消息类型。让我们先看一些基础结构:
1.1 基础响应结构
message BaseResponse { optional int32 ret = 1; optional SKBuiltinString_t errMsg = 2; } message SKBuiltinString_t { optional string string = 1; }BaseResponse是几乎所有响应消息都包含的基础结构,用于返回操作结果和错误信息。
1.2 二进制数据容器
message SKBuiltinBuffer_t { optional uint32 iLen = 1; optional bytes buffer = 2; }SKBuiltinBuffer_t是一个通用的二进制数据容器,包含数据长度和数据内容。
1.3 字符串容器变体
message SKBuiltinString_S { optional uint32 iLen = 1; optional string buffer = 2; } message SKBuiltinBuffer_K { optional uint32 iLen = 1; optional string buffer = 2; }微信定义了多个类似但字段名不同的字符串容器,可能用于不同的业务场景。
二、ECDH密钥交换结构
message ECDHKey { optional int32 nid = 1; optional SKBuiltinBuffer_t key = 2; }ECDHKey用于椭圆曲线密钥交换,包含曲线类型标识(nid)和公钥数据。
三、认证响应结构
3.1 认证分区响应
message AuthSectResp { optional uint32 uin = 1; optional ECDHKey svrPubEcdhkey = 2; optional SKBuiltinBuffer_t sessionKey = 3; optional SKBuiltinBuffer_t autoAuthKey = 4; optional uint32 wtloginRspBuffFlag = 5; optional SKBuiltinBuffer_t wtloginRspBuff = 6; optional WTLoginImgRespInfo wtloginImgRespInfo = 7; optional WxVerifyCodeRespInfo wxVerifyCodeRespInfo = 8; optional SKBuiltinBuffer_t cliDbencryptKey = 9; optional SKBuiltinBuffer_t cliDbencryptInfo = 10; optional string authKey = 11; optional SKBuiltinBuffer_t a2Key = 12; optional string applyBetaUrl = 14; optional ShowStyleKey showStyle = 15; optional string authTicket = 16; optional uint32 newVersion = 17; optional uint32 updateFlag = 18; optional uint32 authResultFlag = 19; optional string fsurl = 20; optional uint32 mmtlsControlBitFlag = 21; optional uint32 serverTime = 22; optional SKBuiltinBuffer_t clientSessionKey = 23; optional SKBuiltinBuffer_t serverSessionKey = 24; optional uint32 ecdhControlFlag = 25; }AuthSectResp是认证响应的核心结构,包含:
- 用户标识(uin)
- 服务器ECDH公钥
- 会话密钥(sessionKey)
- 自动认证密钥(autoAuthKey)
- 客户端/服务器会话密钥
- 各种控制标志
3.2 账户分区响应
message AcctSectResp { optional string userName = 1; optional string nickName = 2; optional uint32 bindUin = 3; optional string bindEmail = 4; optional string bindMobile = 5; optional string alias = 6; optional uint32 status = 8; optional uint32 pluginFlag = 9; optional uint32 regType = 10; optional string deviceInfoXml = 11; optional uint32 safeDevice = 12; optional string officialUserName = 13; optional string officialNickName = 14; optional uint32 pushMailStatus = 15; optional string fsurl = 16; }AcctSectResp包含用户账户信息,如用户名、昵称、绑定信息等。
四、网络配置结构
4.1 主机信息
message RealHostInfo { optional string host = 1; optional string redirect = 2; } message HostList { optional uint32 count = 1; repeated RealHostInfo list = 2; }4.2 网络控制参数
message NetworkControl { optional string portList = 1; optional string timeoutList = 2; optional uint32 minNoopInterval = 3; optional uint32 maxNoopInterval = 4; optional int32 typingInterval = 5; optional int32 noopIntervalTime = 7; }4.3 IP地址列表
message IPInfo { optional string ip = 3; optional string host = 4; } message BuiltinIPList { optional uint32 longConnectIpcount = 1; optional uint32 shortConnectIpcount = 2; repeated IPInfo longConnectIplist = 3; repeated IPInfo shortConnectIplist = 4; optional uint32 seq = 5; }五、登录相关结构
5.1 基础请求结构
message BaseRequest { optional bytes sessionKey = 1; optional uint32 uin = 2; optional bytes deviceId = 3; optional int32 clientVersion = 4; optional bytes deviceType = 5; optional uint32 scene = 6; }BaseRequest是几乎所有请求消息都包含的基础结构,包含会话密钥、用户标识、设备信息等。
5.2 获取登录二维码请求
message GetLoginQRCodeRequest { optional BaseRequest baseRequest = 1; optional SKBuiltinBuffer_t randomEncryKey = 2; optional uint32 opcode = 3; optional string deviceName = 4; optional string userName = 5; optional uint32 extDevLoginType = 6; optional string hardwareExtra = 7; optional string softType = 8; optional SKBuiltinBuffer_t msgContextPubKey = 9; }5.3 获取登录二维码响应
message GetLoginQRCodeResponse { optional BaseResponse baseResponse = 1; optional SKBuiltinBuffer_t qrcode = 2; optional string uuid = 3; optional uint32 checkTime = 4; optional SKBuiltinBuffer_t notifyKey = 5; optional uint32 expiredTime = 6; }六、数据打包机制分析
微信在Protobuf序列化后,还会进行一层自定义的数据包封装。让我们分析Pack.go中的实现:
6.1 iOS版本打包
func(h*Client)HybridEcdhPackIosEn(Cgi,Uinuint32,Cookies,Data,loginecdhkey[]byte)[]byte{header:=new(bytes.Buffer)header.Write([]byte{0xbf})// 魔数header.Write([]byte{0x02})// 加密模式encryptdata:=h.encryptoIOS(Data)cookielen:=len(Cookies)header.Write([]byte{byte((12<<4)+cookielen)})binary.Write(header,binary.BigEndian,int32(h.Version))ifUin!=0{binary.Write(header,binary.BigEndian,int32(Uin))}else{header.Write([]byte{0x00,