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 + "000" retString = retString + "" + deviceInfo.OsTypeNumber + "" retString = retString + "" + deviceInfo.DeviceName + "" retString = retString + "" + strconv.Itoa(int(deviceInfo.CoreCount)) + "" retString = retString + "" + deviceInfo.UUIDOne + "" retString = retString + "" + deviceInfo.UUIDTwo + "" // retString = retString + "" + wifiInfo.Name + "" retString = retString + "" + deviceInfo.CarrierName + "" // retString = retString + "" + deviceInfo.CarrierName + "" retString = retString + "" + baseutils.BuildRandomMac() + "" retString = retString + "微信" // : 网络类型 1-wifi retString = retString + "1" // : 是否越狱 0-非越狱 1-越狱 retString = retString + "0" retString = retString + "" + deviceInfo.BundleID + "" retString = retString + "" + deviceInfo.IphoneVer + "" // : 设备UUID是新的设备,还是老的设备 retString = retString + "" + strconv.Itoa(1) + "" retString = retString + "" 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) // 计算key1,key2, 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 }