Files
wechat_ipad_pro/clientsdk/protocol.go

807 lines
28 KiB
Go
Raw Normal View History

2026-02-17 13:06:23 +08:00
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
}