Files
wechat_ipad_pro/clientsdk/protocol.go
2026-02-17 13:06:23 +08:00

807 lines
28 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package clientsdk
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"hash/crc32"
"strconv"
"strings"
"time"
"xiawan/wx/clientsdk/android"
clientsdk "xiawan/wx/clientsdk/hybrid"
"github.com/lunny/log"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/clientsdk/ccdata"
"xiawan/wx/clientsdk/proxynet"
"xiawan/wx/protobuf/wechat"
"golang.org/x/net/proxy"
"github.com/golang/protobuf/proto"
)
// NewUserInfo 新建一个UserInfo
func NewUserInfo(uuid string, proxyInfo *proxynet.WXProxyInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.UserInfo {
var WifiInfo = createWifiInfo()
//随机生成 deviceID
var userInfo = baseinfo.UserInfo{
UUID: uuid,
Uin: 0,
WxId: "",
Session: []byte{},
SessionKey: baseutils.RandomStringByLength(16),
ShortHost: "szshort.weixin.qq.com",
LongHost: "szlong.weixin.qq.com",
ClientVersion: ClientVersion,
SyncKey: []byte{},
BalanceVersion: 1589560770,
DeviceInfo: createDeviceInfo(WifiInfo, ClientVersion, dbUserInfo),
DeviceInfoA16: createDeviceInfoA16(),
WifiInfo: WifiInfo,
ProxyInfo: proxyInfo,
// 默认登录版本号 135
LoginRsaVer: baseinfo.DefaultLoginRsaVer,
DeviceCreateTime: time.Now(), // 新设备注册时间
}
return &userInfo
}
func NewUserInfo_Mac(uuid string, proxyInfo *proxynet.WXProxyInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.UserInfo {
var WifiInfo = createWifiInfo()
//随机生成 deviceID
var userInfo = baseinfo.UserInfo{
UUID: uuid,
Uin: 0,
WxId: "",
Session: []byte{},
SessionKey: baseutils.RandomStringByLength(16),
ShortHost: "szshort.weixin.qq.com",
LongHost: "szlong.weixin.qq.com",
ClientVersion: ClientVersion,
SyncKey: []byte{},
BalanceVersion: 1589560770,
DeviceInfo: createDeviceInfoMac(WifiInfo, ClientVersion, dbUserInfo),
DeviceInfoA16: createDeviceInfoA16(),
WifiInfo: WifiInfo,
ProxyInfo: proxyInfo,
// 默认登录版本号 135
LoginRsaVer: baseinfo.DefaultLoginRsaVer,
DeviceCreateTime: time.Now(), // 新设备注册时间
}
return &userInfo
}
// 新建Wifi信息
func createWifiInfo() *baseinfo.WifiInfo {
retWifiInfo := &baseinfo.WifiInfo{}
retWifiInfo.Name = "Chinanet-" + string(baseutils.RandomString(4, 7))
retWifiInfo.WifiBssID = baseutils.RandomBSSID()
return retWifiInfo
}
// 生成A16设备信息
func createDeviceInfoA16() *baseinfo.AndroidDeviceInfo {
deviceInfo := &baseinfo.AndroidDeviceInfo{}
deviceInfo.BuildBoard = "bullhead"
return deviceInfo
}
// CreateDeviceInfo 生成新的设备信息 ipad
func createDeviceInfo(wifiInfo *baseinfo.WifiInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.DeviceInfo {
IPadDeviceName := baseinfo.IPadDeviceName
IPadModel := baseinfo.IPadModel
IPadOsVersion := baseinfo.IPadOsVersion
DeviceTypeIos := baseinfo.DeviceTypeIos
CoreCount := uint32(2)
Imei := baseutils.RandomSmallHexString(32)
tmpDeviceID := baseutils.HexStringToBytes(Imei)
tmpDeviceID[0] = 0x49
if dbUserInfo != nil && dbUserInfo.DeviceInfo != nil {
IPadDeviceName = dbUserInfo.DeviceInfo.DeviceName
IPadModel = dbUserInfo.DeviceInfo.IphoneVer
IPadOsVersion = dbUserInfo.DeviceInfo.OsTypeNumber
DeviceTypeIos = dbUserInfo.DeviceInfo.OsType
CoreCount = dbUserInfo.DeviceInfo.CoreCount
Imei = dbUserInfo.DeviceInfo.Imei
tmpDeviceID = dbUserInfo.DeviceInfo.DeviceID
}
deviceInfo := &baseinfo.DeviceInfo{}
deviceInfo.Imei = Imei
deviceInfo.DeviceID = tmpDeviceID
deviceInfo.DeviceName = IPadDeviceName //iPad Air 3 对应 iPad11,4 || iPad11,3
deviceInfo.TimeZone = "8.00"
deviceInfo.Language = "zh_CN"
deviceInfo.DeviceBrand = "Apple"
deviceInfo.RealCountry = "CN"
deviceInfo.IphoneVer = IPadModel
deviceInfo.BundleID = "com.tencent.xin"
// deviceInfo.OsTypeNumber = "15.0.0"
deviceInfo.OsTypeNumber = IPadOsVersion // "15.7.9"
deviceInfo.OsType = DeviceTypeIos // "iPad iPadOS" + deviceInfo.OsTypeNumber
deviceInfo.CoreCount = CoreCount // 2 核
deviceInfo.AdSource = baseutils.RandomUUID()
deviceInfo.UUIDOne = baseutils.RandomUUID()
deviceInfo.UUIDTwo = baseutils.RandomUUID()
// 运营商名
deviceInfo.CarrierName = "(null)"
// deviceInfo.CarrierName = "中国电信"
deviceInfo.SoftTypeXML = CreateSoftInfoXML(deviceInfo, wifiInfo)
// ClientCheckDataXML
deviceInfo.ClientCheckDataXML = ccdata.CreateClientCheckDataXML(deviceInfo, ClientVersion)
return deviceInfo
}
// CreateDeviceInfo 生成新的设备信息 mac
func createDeviceInfoMac(wifiInfo *baseinfo.WifiInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *baseinfo.DeviceInfo {
IPadDeviceName := baseinfo.MacDeviceName
IPadModel := baseinfo.MacModel
IPadOsVersion := baseinfo.MacOsVersion
DeviceTypeIos := baseinfo.MacDeviceType
CoreCount := uint32(2)
Imei := baseutils.RandomSmallHexString(32)
tmpDeviceID := baseutils.HexStringToBytes(Imei)
tmpDeviceID[0] = 0x49
if dbUserInfo != nil {
IPadDeviceName = dbUserInfo.DeviceInfo.DeviceName
IPadModel = dbUserInfo.DeviceInfo.IphoneVer
IPadOsVersion = dbUserInfo.DeviceInfo.OsTypeNumber
DeviceTypeIos = dbUserInfo.DeviceInfo.OsType
CoreCount = dbUserInfo.DeviceInfo.CoreCount
Imei = dbUserInfo.DeviceInfo.Imei
tmpDeviceID = dbUserInfo.DeviceInfo.DeviceID
}
deviceInfo := &baseinfo.DeviceInfo{}
deviceInfo.Imei = Imei
deviceInfo.DeviceID = tmpDeviceID
deviceInfo.DeviceName = IPadDeviceName //iPad Air 3 对应 iPad11,4 || iPad11,3
deviceInfo.TimeZone = "8.00"
deviceInfo.Language = "zh_CN"
deviceInfo.DeviceBrand = "Apple"
deviceInfo.RealCountry = "CN"
deviceInfo.IphoneVer = IPadModel
deviceInfo.BundleID = "com.tencent.xin"
// deviceInfo.OsTypeNumber = "15.0.0"
deviceInfo.OsTypeNumber = IPadOsVersion // "15.7.9"
deviceInfo.OsType = DeviceTypeIos // "iPad iPadOS" + deviceInfo.OsTypeNumber
deviceInfo.CoreCount = CoreCount // 2 核
deviceInfo.AdSource = baseutils.RandomUUID()
deviceInfo.UUIDOne = baseutils.RandomUUID()
deviceInfo.UUIDTwo = baseutils.RandomUUID()
// 运营商名
deviceInfo.CarrierName = "(null)"
// deviceInfo.CarrierName = "中国电信"
deviceInfo.SoftTypeXML = CreateSoftInfoXML(deviceInfo, wifiInfo)
// ClientCheckDataXML
deviceInfo.ClientCheckDataXML = ccdata.CreateClientCheckDataXML(deviceInfo, ClientVersion)
return deviceInfo
}
// CreateSoftInfoXML CreateSoftInfoXML
func CreateSoftInfoXML(deviceInfo *baseinfo.DeviceInfo, wifiInfo *baseinfo.WifiInfo) string {
var retString string
retString = retString + "<softtype><lctmoc>0</lctmoc><level>0</level><k1>0</k1>"
retString = retString + "<k3>" + deviceInfo.OsTypeNumber + "</k3>"
retString = retString + "<k9>" + deviceInfo.DeviceName + "</k9>"
retString = retString + "<k10>" + strconv.Itoa(int(deviceInfo.CoreCount)) + "</k10>"
retString = retString + "<k19>" + deviceInfo.UUIDOne + "</k19>"
retString = retString + "<k20>" + deviceInfo.UUIDTwo + "</k20>"
// retString = retString + "<k21>" + wifiInfo.Name + "</k21>"
retString = retString + "<k22>" + deviceInfo.CarrierName + "</k22>"
// retString = retString + "<k22>" + deviceInfo.CarrierName + "</k22>"
retString = retString + "<k24>" + baseutils.BuildRandomMac() + "</k24>"
retString = retString + "<k33>微信</k33>"
// <k47>: 网络类型 1-wifi
retString = retString + "<k47>1</k47>"
// <k50>: 是否越狱 0-非越狱 1-越狱
retString = retString + "<k50>0</k50>"
retString = retString + "<k51>" + deviceInfo.BundleID + "</k51>"
retString = retString + "<k54>" + deviceInfo.IphoneVer + "</k54>"
// <k61>: 设备UUID是新的设备还是老的设备
retString = retString + "<k61>" + strconv.Itoa(1) + "</k61>"
retString = retString + "</softtype>"
return retString
}
// GetEncryptUserInfo 获取加密信息
func GetEncryptUserInfo(userInfo *baseinfo.UserInfo) string {
if userInfo.WifiInfo == nil {
userInfo.WifiInfo = createWifiInfo()
}
tmpString := "wifissid=" + userInfo.WifiInfo.Name
tmpString = tmpString + "&wifibssid=" + userInfo.WifiInfo.WifiBssID
timeStamp := strconv.Itoa(int(time.Now().UnixNano() / 1000))
tmpString = tmpString + "&ssid_timestamp=" + timeStamp
srcBytes := []byte(tmpString)
srcBytes = append(srcBytes, 0)
userInfo.GenHBKey()
encData := baseutils.AesEncryptECB(srcBytes, userInfo.HBAesKey)
return base64.StdEncoding.EncodeToString(encData)
}
// GetDialer 获取代理
func GetDialer(userInfo *baseinfo.UserInfo) proxy.Dialer {
if userInfo.Dialer != nil {
return userInfo.Dialer
}
if userInfo.ProxyInfo == nil {
return nil
}
return userInfo.ProxyInfo.GetDialer()
}
// Paser62Data 解析62数据
func Parse62Data(data62 string) (string, error) {
retList := strings.Split(strings.ToUpper(data62), "6E756C6C5F1020")
if len(retList) < 2 {
return "", errors.New("InitLoginDataInfo err: loginDataInfo.Data Split 6E756C6C5F1020 error")
}
// 截取64位数据
data64Str := retList[1][0:64]
// 设置Imei
return string(baseutils.HexStringToBytes(data64Str)), nil
}
// CreatePackHead 创建包头
func CreatePackHead(userInfo *baseinfo.UserInfo, compressType byte, urlID uint32, srcData []byte, encodeData []byte, zipLen uint32, encodeType byte, encodeVersion uint32) *baseinfo.PackHeader {
retHeader := &baseinfo.PackHeader{}
// Signature
retHeader.Signature = 0xbf
retHeader.CompressType = compressType
retHeader.EncodeType = encodeType << 4
retHeader.ServerVersion = userInfo.ClientVersion
if !(retHeader.ServerVersion > 0) {
retHeader.ServerVersion = baseinfo.ClientVersion
}
retHeader.Uin = userInfo.Uin
retHeader.Session = userInfo.Session
retHeader.URLID = urlID
retHeader.SrcLen = uint32(len(srcData))
retHeader.ZipLen = zipLen
retHeader.EncodeVersion = encodeVersion
retHeader.HeadDeviceType = baseinfo.MMHeadDeviceTypeIpadUniversal
retHeader.CheckSum = 0x00
// 如果有压缩则计算Sum值
if retHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
retHeader.CheckSum = CalcHeadCheckSum(userInfo.Uin, userInfo.CheckSumKey, srcData)
}
// test
/*if retHeader.URLID == 213 {
retHeader.HeadDeviceType = 0x00
}*/
retHeader.RunState = baseinfo.MMAppRunStateNormal
// 修改 rqt 版本
// 旧 rqtx
// retHeader.RqtCode = SignRqtBufByAutoChosenKey(baseutils.Md5ValueByte(encodeData, false))
// rqtx 加密
// retHeader.RqtCode = baseutils.CalcMsgCrcForString_807(baseutils.Md5ValueByte(encodeData, false))
// 新 rqtx
retHeader.RqtCode = android.CalcMsgCrcForData_7019(encodeData)
retHeader.EndFlag = 0x00
retHeader.Data = encodeData
return retHeader
}
// PackHeaderSerialize 序列化PackHeader
func PackHeaderSerialize(packHeader *baseinfo.PackHeader, needCookie bool) []byte {
retBytes := make([]byte, 0)
retBytes = append(retBytes, packHeader.Signature)
retBytes = append(retBytes, 0)
encodeType := packHeader.EncodeType
if needCookie {
packHeader.EncodeType = packHeader.EncodeType + 0xf
}
retBytes = append(retBytes, packHeader.EncodeType)
retBytes = append(retBytes, baseutils.Int32ToBytes(packHeader.ServerVersion)[0:]...)
retBytes = append(retBytes, baseutils.Int32ToBytes(packHeader.Uin)[0:]...)
if needCookie {
retBytes = append(retBytes, packHeader.Session[0:]...)
}
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.URLID)[0:]...)
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.SrcLen)[0:]...)
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.ZipLen)[0:]...)
// hybrid
if encodeType>>4 == 12 {
retBytes = append(retBytes, []byte{byte(packHeader.HybridKeyVer)}...)
}
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.EncodeVersion)[0:]...)
retBytes = append(retBytes, packHeader.HeadDeviceType)
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.CheckSum)[0:]...)
retBytes = append(retBytes, packHeader.RunState)
retBytes = append(retBytes, baseutils.EncodeVByte32(packHeader.RqtCode)[0:]...)
retBytes = append(retBytes, packHeader.EndFlag)
headLen := byte(len(retBytes))
retBytes[1] = packHeader.CompressType + headLen<<2
//fmt.Println(hex.EncodeToString(retBytes))
retBytes = append(retBytes, packHeader.Data[0:]...)
return retBytes
}
// Pack 打包加密数据
func Pack(userInfo *baseinfo.UserInfo, src []byte, urlID uint32, encodeType byte) []byte {
retData := make([]byte, 0)
if encodeType == 7 || encodeType == 17 {
//加密类型7
encodeData := src
if encodeType == 7 {
encodeData = baseutils.NoCompressRsaByVer(src, userInfo.GetLoginRsaVer())
}
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), 7, userInfo.GetLoginRsaVer())
retData = PackHeaderSerialize(packHeader, false)
} else if encodeType == 5 {
zipBytes := baseutils.CompressByteArray(src)
encodeData := baseutils.AesEncrypt(zipBytes, userInfo.SessionKey)
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeCompressed, urlID, src, encodeData, uint32(len(zipBytes)), encodeType, 0)
retData = PackHeaderSerialize(packHeader, true)
} else if encodeType == 9 {
// 加密类型9
encodeData := src
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), encodeType, userInfo.GetLoginRsaVer())
retData = PackHeaderSerialize(packHeader, true)
} else if encodeType == 1 {
// 加密类型1
encodeData := baseutils.NoCompressRsaByVer(src, userInfo.GetLoginRsaVer())
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), encodeType, userInfo.GetLoginRsaVer())
retData = PackHeaderSerialize(packHeader, true)
} else if encodeType == 12 {
secKeyMgr := NewSecLoginKeyMgrByVer(146)
reqData := src
//加密
encrypt, epKey, token, ecdhpairkey, err := clientsdk.HybridEncrypt(reqData, secKeyMgr.WeChatPubKey)
if err != nil {
log.Error("加密 error", err.Error())
}
ecdhPacket := &wechat.EcdhPacket{
Type: proto.Uint32(1),
Key: &wechat.BufferT{
ILen: proto.Uint32(415),
Buffer: ecdhpairkey.PubKey,
},
Token: token,
Url: proto.String(""),
ProtobufData: encrypt,
}
secKeyMgr.PubKey = ecdhpairkey.PubKey
secKeyMgr.PriKey = ecdhpairkey.PriKey
secKeyMgr.SourceData = reqData
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, epKey[24:]...)
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, reqData...)
ecdhDataPacket, err := proto.Marshal(ecdhPacket)
if err != nil {
log.Error("ecdhDataPacket error", err.Error())
}
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, ecdhDataPacket, ecdhDataPacket, uint32(len(ecdhDataPacket)), encodeType, uint32(0x4e))
//设置Hybrid 加密密钥版本
packHeader.HybridKeyVer = secKeyMgr.WeChatPubKeyVersion
//开始组头
retData := PackHeaderSerialize(packHeader, false)
//fmt.Println(hex.EncodeToString(retData))
/*resp, err := mmtls.MMHTTPPostData(userInfo.MMInfo, "/cgi-bin/micromsg-bin/secautoauth", retData)
if err != nil {
log.Error("mmtls error", err.Error())
}*/
/*packHeader, err = DecodePackHeader(resp, nil)
if err != nil {
log.Error("ecdhDataPacket error", err.Error())
}
packHeader.Data, err = clientsdk.HybridEcdhDecrypt(packHeader.Data, secKeyMgr.PriKey, secKeyMgr.PubKey, secKeyMgr.FinalSha256)
if err != nil {
log.Error("HybridEcdhDecrypt error", err.Error())
}
return packHeader, err*/
return retData
}
return retData
}
func PackNoCompressAES(userInfo *baseinfo.UserInfo, src []byte, urlID uint32) []byte {
encodeData := baseutils.AesEncrypt(src, userInfo.SessionKey)
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, src, encodeData, uint32(len(src)), 5, 0)
return PackHeaderSerialize(packHeader, true)
}
// Pack 打包加密数据
func Pack12(userInfo *baseinfo.UserInfo, src []byte, urlID uint32, encodeType byte) ([]byte, *SecLoginKeyMgr) {
retData := make([]byte, 0)
secKeyMgr := NewSecLoginKeyMgrByVer(146)
reqData := src
//加密
encrypt, epKey, token, ecdhpairkey, err := clientsdk.HybridEncrypt(reqData, secKeyMgr.WeChatPubKey)
if err != nil {
log.Error("加密 error", err.Error())
}
ecdhPacket := &wechat.EcdhPacket{
Type: proto.Uint32(1),
Key: &wechat.BufferT{
ILen: proto.Uint32(415),
Buffer: ecdhpairkey.PubKey,
},
Token: token,
Url: proto.String(""),
ProtobufData: encrypt,
}
secKeyMgr.PubKey = ecdhpairkey.PubKey
secKeyMgr.PriKey = ecdhpairkey.PriKey
secKeyMgr.SourceData = reqData
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, epKey[24:]...)
secKeyMgr.FinalSha256 = append(secKeyMgr.FinalSha256, reqData...)
ecdhDataPacket, err := proto.Marshal(ecdhPacket)
if err != nil {
log.Error("ecdhDataPacket error", err.Error())
}
packHeader := CreatePackHead(userInfo, baseinfo.MMPackDataTypeUnCompressed, urlID, ecdhDataPacket, ecdhDataPacket, uint32(len(ecdhDataPacket)), encodeType, uint32(0x4e))
//设置Hybrid 加密密钥版本
packHeader.HybridKeyVer = secKeyMgr.WeChatPubKeyVersion
//开始组头
retData = PackHeaderSerialize(packHeader, false)
//fmt.Println(hex.EncodeToString(retData))
/*resp, err := mmtls.MMHTTPPostData(userInfo.MMInfo, "/cgi-bin/micromsg-bin/secautoauth", retData)
if err != nil {
log.Error("mmtls error", err.Error())
}*/
/*packHeader, err = DecodePackHeader(resp, nil)
if err != nil {
log.Error("ecdhDataPacket error", err.Error())
}
packHeader.Data, err = clientsdk.HybridEcdhDecrypt(packHeader.Data, secKeyMgr.PriKey, secKeyMgr.PubKey, secKeyMgr.FinalSha256)
if err != nil {
log.Error("HybridEcdhDecrypt error", err.Error())
}
return packHeader, err*/
return retData, secKeyMgr
}
// DecodePackHeader DecodePackHeader
func DecodePackHeader(respData []byte, reqData []byte) (*baseinfo.PackHeader, error) {
packHeader := &baseinfo.PackHeader{}
packHeader.ReqData = reqData
packHeader.RetCode = 0
if len(respData) <= 32 {
packHeader.RetCode = GetRespErrorCode(respData)
return packHeader, errors.New("DecodePackHeader err: len(respData) <= 32")
}
current := 0
packHeader.Signature = respData[current]
current++
packHeader.HeadLength = (respData[current]) >> 2
packHeader.CompressType = (respData[current]) & 3
current++
packHeader.EncodeType = respData[current] >> 4
sessionLen := int(respData[current] & 0x0f)
current++
packHeader.ServerVersion = baseutils.BytesToInt32(respData[current : current+4])
current = current + 4
packHeader.Uin = baseutils.BytesToInt32(respData[current : current+4])
current = current + 4
if sessionLen > 0 {
packHeader.Session = respData[current : current+sessionLen]
current = current + sessionLen
}
retLen := uint32(0)
packHeader.URLID, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.SrcLen, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.ZipLen, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.EncodeVersion, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.HeadDeviceType = respData[current]
current = current + 1
packHeader.CheckSum, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.RunState = respData[current]
current = current + 1
packHeader.RqtCode, retLen = baseutils.DecodeVByte32(respData, uint32(current))
current = current + int(retLen)
packHeader.EndFlag = respData[current]
current = current + 1
// // 后面还有一个字节-- 可能是7.10新版本增加的一个字节,待后面分析
// current = current + 1
// if current != int(packHeader.HeadLength) {
// return nil, errors.New("DecodePackHeader failed current != int(packHeader.HeadLength")
// }
packHeader.Data = respData[packHeader.HeadLength:]
return packHeader, nil
}
// ParseResponseData 解析相应数据
func ParseResponseData(userInfo *baseinfo.UserInfo, packHeader *baseinfo.PackHeader, response proto.Message) error {
// 判断包体长度是否大于0
if len(packHeader.Data) <= 0 {
log.Error("ParseResponseData err: len(packHeader.Data) <= 0")
return errors.New("ParseResponseData err: len(packHeader.Data) <= 0")
}
var decptBody []byte
var err error
if packHeader.EncodeType == 12 {
decptBody = packHeader.Data
} else if packHeader.EncodeType == 5 {
// 解密
decptBody, err = baseutils.AesDecrypt(packHeader.Data, userInfo.SessionKey)
if err != nil {
return err
}
// fmt.Println(hex.EncodeToString(decptBody))
// 判断是否有压缩
if packHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
if decptBody != nil {
// fmt.Println(hex.EncodeToString(decptBody))
decptBody, err = baseutils.UnzipByteArray(decptBody)
if err != nil {
log.Error("ParseResponseData err:", err.Error(), packHeader.URLID)
// 打印解密后的数据前100字节用于调试
if len(decptBody) > 0 {
debugLen := 100
if len(decptBody) < debugLen {
debugLen = len(decptBody)
}
log.Error("Decrypted data (first bytes):", hex.EncodeToString(decptBody[:debugLen]))
}
return err
}
} else {
return errors.New("decptBody err: len(decptBody) == nil")
}
}
} else {
// 解密
decptBody, err = baseutils.AesDecrypt(packHeader.Data, userInfo.SessionKey)
// fmt.Println(hex.EncodeToString(decptBody))
if err != nil {
//log.Error("ParseResponseData err:", err.Error())
return err
}
// 判断是否有压缩
if packHeader.CompressType == baseinfo.MMPackDataTypeCompressed {
if decptBody != nil {
decptBody, err = baseutils.UnzipByteArray(decptBody)
if err != nil {
//fmt.Println(hex.EncodeToString(packHeader.Data))
log.Error("ParseResponseData err:", err.Error(), packHeader.URLID)
// 打印解密后的数据前100字节用于调试
if len(decptBody) > 0 {
debugLen := 100
if len(decptBody) < debugLen {
debugLen = len(decptBody)
}
log.Error("Decrypted data (first bytes):", hex.EncodeToString(decptBody[:debugLen]))
}
return err
}
} else {
return errors.New("decptBody err: len(decptBody) == nil")
}
}
}
// 更新UserInfo
if len(packHeader.Session) > 6 {
userInfo.Session = packHeader.Session
}
if packHeader.Uin != 0 {
userInfo.Uin = packHeader.Uin
}
// fmt.Println(hex.EncodeToString(decptBody))
// 解包ProtoBuf
err = proto.Unmarshal(decptBody, response)
if err != nil {
log.Error("ParseResponseData err:", err.Error())
return err
}
return nil
}
// GetBaseRequest 获取baserequest
func GetBaseRequest(userInfo *baseinfo.UserInfo) *wechat.BaseRequest {
ret := &wechat.BaseRequest{}
ret.SessionKey = []byte(userInfo.SessionKey)
ret.Uin = &userInfo.Uin
if !strings.HasPrefix(userInfo.LoginDataInfo.LoginData, "A") && userInfo.DeviceInfo != nil {
ret.DeviceId = userInfo.DeviceInfo.DeviceID
ret.OsType = &userInfo.DeviceInfo.OsType
ret.Scene = proto.Uint32(0)
ret.ClientVersion = &userInfo.ClientVersion
if !(int(*ret.ClientVersion) > 0) {
ret.ClientVersion = &baseinfo.ClientVersion
}
} else {
ret.ClientVersion = &baseinfo.AndroidClientVersion
ret.OsType = &baseinfo.AndroidPadDeviceType
ret.DeviceId = userInfo.DeviceInfoA16.DeviceId
ret.Scene = proto.Uint32(1)
}
return ret
}
// CalcCheckCode 计算校验码
// wxId : 微信ID
// currentTime : 时间
// return uint32 计算出来的校验码
func CalcCheckCode(wxID string, currentTime time.Time) uint32 {
var tmpTime = currentTime.Format("051504010206")
if len(wxID) <= 0 {
tmpTime = tmpTime + "fffffff"
}
if len(wxID) > 0 {
wxIDMd5 := baseutils.Md5Value(wxID)
tmpTime = tmpTime + baseutils.StringCut(wxIDMd5, 0, 7)
}
misSecond := currentTime.UnixNano() / 1000000
var modValue = uint32(misSecond % 65535)
var modValue2 = int(misSecond%7 + 100)
modHexString := string(baseutils.UInt32To16Bytes(modValue))
mod2String := strconv.Itoa(modValue2)
tmpTime = tmpTime + modHexString + mod2String
return baseutils.HashCode(tmpTime)
}
// WithSeqidCalcCheckCode 根据seqid计算
func WithSeqidCalcCheckCode(wxID string, seqid int64) uint32 {
currentTime := time.Unix(0, seqid)
var tmpTime = currentTime.Format("051504010206")
if len(wxID) <= 0 {
tmpTime = tmpTime + "fffffff"
}
if len(wxID) > 0 {
wxIDMd5 := baseutils.Md5Value(wxID)
tmpTime = tmpTime + baseutils.StringCut(wxIDMd5, 0, 7)
}
misSecond := currentTime.UnixNano() / 1000000
var modValue = uint32(misSecond % 65535)
var modValue2 = int(misSecond%7 + 100)
modHexString := string(baseutils.UInt32To16Bytes(modValue))
mod2String := strconv.Itoa(modValue2)
tmpTime = tmpTime + modHexString + mod2String
return baseutils.HashCode(tmpTime)
}
// GetErrStrByErrCode GetErrStrByErrCode
func GetErrStrByErrCode(errCode int32) string {
if errCode == -2 {
return "error: args not whole or args type error"
}
if errCode == -13 {
return "error: session timeout"
}
if errCode == -102 {
return "error: cert expired"
}
if errCode == -306 {
return "error: ecdh failed rollback"
}
if errCode == -3001 || errCode == -3003 {
return "error: need get dns"
}
if errCode == -3002 {
return "error: MM_ERR_IDCDISASTER"
}
return "unknow"
}
// GetRespErrorCode 当response 小于32个字节时调用这个接口获取响应的错误码
func GetRespErrorCode(data []byte) int32 {
tmpData := make([]byte, 0)
tmpData = append(tmpData, data[2:6]...)
tmpRet := binary.BigEndian.Uint32(tmpData)
return int32(tmpRet)
}
// RqtKey 计算RQT用到到Key
var RqtKey = []byte{0x6a, 0x66, 0x4d, 0x5d, 0x53, 0x7c, 0x25, 0x3f, 0x73, 0x6e, 0x48, 0x27, 0x3a, 0x29, 0x5e, 0x4f}
// SignRqtBufByAutoChosenKey 计算RQT值
func SignRqtBufByAutoChosenKey(md5Value string) uint32 {
// tmpRqtKeyOne
rqtLen := len(RqtKey)
totalLength := 48 + rqtLen
blockOne := make([]byte, totalLength)
for index := 0; index < totalLength; index++ {
blockOne[index] = 0
if index < rqtLen {
blockOne[index] = RqtKey[index]
}
blockOne[index] = blockOne[index] ^ 0x36
}
// tmpRqtKeyTwo
blockTwo := make([]byte, totalLength)
for index := 0; index < totalLength; index++ {
blockTwo[index] = 0
if index < rqtLen {
blockTwo[index] = RqtKey[index]
}
blockTwo[index] = blockTwo[index] ^ 0x5c
}
// 计算Hash值
tmpData := append(blockOne, []byte(md5Value)[0:]...)
shaValue := baseutils.Sha1(tmpData)
tmpData = append(blockTwo, shaValue[0:]...)
shaValue = baseutils.Sha1(tmpData)
// 计算key1key2, key3
key1 := 0
key2 := 0
key3 := 0
tmpLen := len(shaValue) - 2
for index := 0; index < tmpLen; index++ {
tmpValue1 := shaValue[index] & 0xff
tmpValue2 := shaValue[index+1] & 0xff
tmpValue3 := shaValue[index+2] & 0xff
key1 = key1*0x83 + int(tmpValue1)
key2 = key2*0x83 + int(tmpValue2)
key3 = key3*0x83 + int(tmpValue3)
}
// 计算RQT值
key1 = key1 & 0x7f
key2 = (key2 << 8) & 0x7f00
key3 = (key3 << 16) & 0x7f0000
retValue := key1 | key3 | key2
retValue = retValue | 0x21000000
return uint32(retValue)
}
// CalcHeadCheckSum 计算HeadCheckSum值
func CalcHeadCheckSum(uin uint32, checkSumKey []byte, srcData []byte) uint32 {
uinBytes := baseutils.Int32ToBytes(uin)
tmpBytes := append(uinBytes, checkSumKey[0:]...)
md5Value := baseutils.Md5Value16(tmpBytes)
dataLen := uint32(len(srcData))
dataLenBytes := baseutils.Int32ToBytes(dataLen)
tmpBytes = append(dataLenBytes, checkSumKey[0:]...)
tmpBytes = append(tmpBytes, md5Value[0:]...)
md5Value = baseutils.Md5Value16(tmpBytes)
tmpBytes = append([]byte{}, md5Value[0:]...)
// 计算返回
/*tmpSum := baseutils.Adler32(1, tmpBytes)
return baseutils.Adler32(tmpSum, srcData)*/
return crc32.ChecksumIEEE(tmpBytes)
}
// TenPaySignDes3 支付相关的加密算法
func TenPaySignDes3(srcData string, encKey string) (string, error) {
srcMD5Bytes := []byte(baseutils.Md5ValueByte([]byte(srcData), true))
keyMD5Bytes := baseutils.Md5ValueByte([]byte(encKey), true)
desKey := baseutils.HexStringToBytes(keyMD5Bytes)
encBytes := make([]byte, 0)
for index := 0; index < 4; index++ {
currentOffset := index * 8
tmpSrcData := srcMD5Bytes[currentOffset : currentOffset+8]
encData, err := baseutils.Encrypt3DES(tmpSrcData, desKey)
if err != nil {
return "", err
}
encBytes = append(encBytes, encData...)
}
return baseutils.BytesToHexString(encBytes, true), nil
}