package ccdata import ( "errors" "hash/crc32" "strconv" "time" "xiawan/wx/clientsdk/baseinfo" "xiawan/wx/clientsdk/baseutils" "xiawan/wx/protobuf/wechat" "github.com/gogo/protobuf/proto" "github.com/lunny/log" ) // saeInfo ClientCheckData加密信息 var saeInfo *wechat.SaeInfo func init() { initSaeInfo() } func initSaeInfo() { saeBytes, err := baseutils.ReadFile("assets/sae.dat") if err != nil { baseutils.PrintLog("initSaeInfo err: " + err.Error()) return } saeInfo = &wechat.SaeInfo{} unmarshalErr := proto.Unmarshal(saeBytes, saeInfo) if unmarshalErr != nil { log.Info(unmarshalErr) } } // GetSaeInfo GetSaeInfo func GetSaeInfo() *wechat.SaeInfo { return saeInfo } // CircleShift CircleShift func CircleShift(data []byte, offset uint32, pos uint32) []byte { retData := []byte{} retData = append(retData, data[0:]...) if pos == 1 { retData[offset+0] = data[offset+1] retData[offset+1] = data[offset+2] retData[offset+2] = data[offset+3] retData[offset+3] = data[offset+0] } if pos == 2 { retData[offset+0] = data[offset+2] retData[offset+2] = data[offset+0] retData[offset+1] = data[offset+3] retData[offset+3] = data[offset+1] } if pos == 3 { retData[offset+0] = data[offset+3] retData[offset+1] = data[offset+0] retData[offset+2] = data[offset+1] retData[offset+3] = data[offset+2] } return retData } // ShiftRows ShiftRows func ShiftRows(data []byte) []byte { retData := CircleShift(data, 4, 1) retData = CircleShift(retData, 8, 2) retData = CircleShift(retData, 12, 3) return retData } // GetSecTable GetSecTable func GetSecTable(secTable []byte, encryptRecordData []byte, secTableKey []byte, keyOffset int) []byte { // fmt.Println("keyOffset = ", keyOffset) tmpTableKeyOffset := 0 for index := 0; index < 4; index++ { for secIndex := 0; secIndex < 4; secIndex++ { tmpOffset := index + secIndex*4 tmpCount := 0 recordIndex := 4*index + secIndex for threeIndex := 0; threeIndex < 64; threeIndex += 16 { tmpValue := 4 * int(encryptRecordData[recordIndex]) tmpByte := secTableKey[keyOffset+tmpTableKeyOffset+tmpCount+tmpValue] secTable[tmpOffset+threeIndex] = tmpByte tmpCount++ } tmpTableKeyOffset += 1024 } } return secTable } // GetSecValue GetSecValue func GetSecValue(encryptRecordData []byte, secTable []byte, secTableValue []byte, valueOffset int) []byte { // fmt.Println(secTable) secTableValueOffset := valueOffset for index := 0; index < 4; index++ { for secIndex := 0; secIndex < 4; secIndex++ { tmpValue := secTable[16*index+4*secIndex+3] tmpPtrOffset := 16*index + 4*secIndex + 2 outBufferOffset := 4*index + secIndex for threeIndex := 0; threeIndex < 3; threeIndex++ { // 第一部分 tmpHigh4Value := (secTable[tmpPtrOffset] & 0xF0) | (tmpValue&0xF0)>>4 tmpValue12 := threeIndex * 0x100 tmpValue14 := byte(secTableValue[secTableValueOffset+int(tmpHigh4Value&0x7F)+0x200-tmpValue12]) if tmpHigh4Value&0x80 == 0 { tmpValue14 = tmpValue14 & 0x0F } else { tmpValue14 = tmpValue14 >> 4 } // 第二部分 tmpLow4Value := byte(tmpValue&0x0F | 16*secTable[tmpPtrOffset]) tmpValue16 := byte(secTableValue[secTableValueOffset+int(tmpLow4Value&0x7F)+0x280-tmpValue12]) if tmpLow4Value&0x80 == 0 { tmpValue16 = tmpValue16 & 0x0F } else { tmpValue16 = tmpValue16 >> 4 } // 第三部分 tmpValue = byte((tmpValue14 << 4) | tmpValue16) tmpPtrOffset = tmpPtrOffset - 1 encryptRecordData[outBufferOffset] = tmpValue } secTableValueOffset = secTableValueOffset + 0x300 } } return encryptRecordData } // GetSecValueFinal GetSecValueFinal func GetSecValueFinal(encryptRecordData []byte, saeTableFinal []byte) []byte { for index := 0; index < 4; index++ { for secIndex := 0; secIndex < 4; secIndex++ { recordIndex := index*4 + secIndex recordValue := int(encryptRecordData[recordIndex]) tmpOffset := index*0x400 + secIndex*0x100 tmpValue := saeTableFinal[tmpOffset+recordValue] encryptRecordData[recordIndex] = tmpValue } } return encryptRecordData } // EncodeZipData 加密ClientCheckData压缩后的数据 func EncodeZipData(data []byte, encodeType int) ([]byte, error) { retBytes := []byte{} tmpEncodeData := data saeInfo := GetSaeInfo() dataLen := len(data) if saeInfo == nil || dataLen <= 0 { return retBytes, errors.New("EncodeZipData err: saeInfo == nil || dataLen <= 0") } if encodeType != 0x3060 && encodeType != 0x4095 { return retBytes, errors.New("EncodeZipData err: encodeType != 0x3060 && encodeType != 0x4095") } // 先按16字节补齐 lessLen := 16 - dataLen&0xF if lessLen < 16 { for index := 0; index < lessLen; index++ { tmpEncodeData = append(tmpEncodeData, byte(lessLen)) } } // IV ivData := saeInfo.GetIv() lessEncodeLength := len(tmpEncodeData) secTable := make([]byte, 64) // 每次加密16字节 count := lessEncodeLength / 16 for index := 0; index < count; index++ { tmpOffset := index * 16 outEncodeBuffer := make([]byte, 16) encryptRecordBuffer := make([]byte, 16) // 先跟IV异或 for secIndex := 0; secIndex < 16; secIndex++ { outEncodeBuffer[secIndex] = tmpEncodeData[tmpOffset+secIndex] ^ ivData[secIndex] } // 第一次换算 for secIndex := 0; secIndex < 4; secIndex++ { for threeIndex := 0; threeIndex < 4; threeIndex++ { encryptRecordBuffer[secIndex*4+threeIndex] = outEncodeBuffer[4*threeIndex+secIndex] } } // 行移位 encryptRecordBuffer = ShiftRows(encryptRecordBuffer) // 下一步 for secIndex := 0; secIndex < 9; secIndex++ { // 获取SecTable if (encodeType & 0x20) == 0x20 { secTable = GetSecTable(secTable, encryptRecordBuffer, saeInfo.GetTableKey(), secIndex*0x4000) } // 获取SecValue if (encodeType & 0x40) == 0x40 { encryptRecordBuffer = GetSecValue(encryptRecordBuffer, secTable, saeInfo.GetTableValue(), secIndex*0x3000) } encryptRecordBuffer = ShiftRows(encryptRecordBuffer) } // 获取最后的SecValue if (encodeType & 0x1000) == 0x1000 { encryptRecordBuffer = GetSecValueFinal(encryptRecordBuffer, saeInfo.GetUnknowValue18()) ivData = outEncodeBuffer for secIndex := 0; secIndex < 4; secIndex++ { for threeIndex := 0; threeIndex < 4; threeIndex++ { outEncodeBuffer[secIndex+4*threeIndex] = encryptRecordBuffer[secIndex*4+threeIndex] } } } // 保存第Index次加密后的16字节数据 retBytes = append(retBytes, outEncodeBuffer[0:]...) } return retBytes, nil } // GetClientCheckDataInfo GetClientCheckDataInfo func GetClientCheckDataInfo(deviceInfo *baseinfo.DeviceInfo, ClientVersion uint32) *baseinfo.ClientCheckDataInfo { if !(int(ClientVersion) > 0) { ClientVersion = baseinfo.ClientVersion } wechatUUID := baseutils.RandomUUID() retInfo := &baseinfo.ClientCheckDataInfo{} retInfo.FileSafeAPI = "yes" retInfo.DylibSafeAPI = "yes" retInfo.OSVersion = deviceInfo.OsTypeNumber retInfo.Model = deviceInfo.DeviceName retInfo.CoreCount = deviceInfo.CoreCount retInfo.VendorID = baseutils.RandomUUID() retInfo.ADId = deviceInfo.AdSource retInfo.NetType = 1 retInfo.IsJaiBreak = 0 retInfo.BundleID = deviceInfo.BundleID retInfo.Device = deviceInfo.IphoneVer retInfo.DisplayName = "微信" retInfo.Version = ClientVersion retInfo.PListVersion = ClientVersion retInfo.USBState = 2 retInfo.HasSIMCard = 2 retInfo.LanguageNum = deviceInfo.Language retInfo.LocalCountry = deviceInfo.RealCountry retInfo.IsInCalling = 2 retInfo.WechatUUID = "/var/mobile/Containers/Data/Application/" + baseutils.RandomUUID() + "/Documents" retInfo.APPState = 0 retInfo.IllegalFileList = "" retInfo.EncryptStatusOfMachO = 1 retInfo.Md5OfMachOHeader = baseinfo.Md5OfMachOHeader // DirUUID dirUUID := baseutils.RandomUUID() retInfo.DylibInfoList = make([]*baseinfo.DylibInfo, 0) // WeChat wechatDylibInfo := &baseinfo.DylibInfo{} wechatDylibInfo.S = "/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/WeChat" wechatDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, wechatDylibInfo) // andromeda andromedaDylibInfo := &baseinfo.DylibInfo{} andromedaDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/andromeda.framework/andromeda" andromedaDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, andromedaDylibInfo) // mars marsDylibInfo := &baseinfo.DylibInfo{} marsDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/mars.framework/mars" marsDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, marsDylibInfo) // marsbridgenetwork marsbridgenetworkDylibInfo := &baseinfo.DylibInfo{} marsbridgenetworkDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/marsbridgenetworkDylibInfo.framework/marsbridgenetworkDylibInfo" marsbridgenetworkDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, marsbridgenetworkDylibInfo) // matrixreport matrixreportDylibInfo := &baseinfo.DylibInfo{} matrixreportDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/matrixreport.framework/matrixreport" matrixreportDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, matrixreportDylibInfo) // OpenSSL openSSLDylibInfo := &baseinfo.DylibInfo{} openSSLDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/OpenSSL.framework/OpenSSL" openSSLDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, openSSLDylibInfo) // ProtobufLite protobufLiteDylibInfo := &baseinfo.DylibInfo{} protobufLiteDylibInfo.S = "/private/var/containers/Bundle/Application/" + dirUUID + "/WeChat.app/Frameworks/ProtobufLite.framework/ProtobufLite" protobufLiteDylibInfo.U = wechatUUID retInfo.DylibInfoList = append(retInfo.DylibInfoList, protobufLiteDylibInfo) return retInfo } // CreateClientCheckDataXML 创建ClientCheckDataXML func CreateClientCheckDataXML(deviceInfo *baseinfo.DeviceInfo, ClientVersion uint32) string { clientCheckDataInfo := GetClientCheckDataInfo(deviceInfo, ClientVersion) retString := "" retString = retString + "" + clientCheckDataInfo.FileSafeAPI + "" retString = retString + "" + clientCheckDataInfo.DylibSafeAPI + "" retString = retString + "" + clientCheckDataInfo.OSVersion + "" retString = retString + "" + clientCheckDataInfo.Model + "
" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.CoreCount)) + "" retString = retString + "" + clientCheckDataInfo.VendorID + "" retString = retString + "" + clientCheckDataInfo.ADId + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.NetType)) + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.IsJaiBreak)) + "" retString = retString + "" + clientCheckDataInfo.BundleID + "" retString = retString + "" + clientCheckDataInfo.Device + "" retString = retString + "" + clientCheckDataInfo.DisplayName + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.Version)) + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.PListVersion)) + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.USBState)) + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.HasSIMCard)) + "" retString = retString + "" + clientCheckDataInfo.LanguageNum + "" retString = retString + "" + clientCheckDataInfo.LocalCountry + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.IsInCalling)) + "" retString = retString + "" + clientCheckDataInfo.WechatUUID + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.APPState)) + "" retString = retString + "" + clientCheckDataInfo.IllegalFileList + "" retString = retString + "" + strconv.Itoa(int(clientCheckDataInfo.EncryptStatusOfMachO)) + "" retString = retString + "" + clientCheckDataInfo.Md5OfMachOHeader + "" retString = retString + "" count := len(clientCheckDataInfo.DylibInfoList) for index := 0; index < count; index++ { dylibInfo := clientCheckDataInfo.DylibInfoList[index] retString = retString + "" retString = retString + "" retString = retString + dylibInfo.S retString = retString + "" retString = retString + "" retString = retString + dylibInfo.U retString = retString + "" retString = retString + "" } retString = retString + "" retString = retString + "
" return retString } // CreateClientCheckData 生成ClientCheckData func CreateClientCheckData(clientCheckDataXML string) ([]byte, error) { finalXML := clientCheckDataXML crc32Value := crc32.ChecksumIEEE([]byte(finalXML)) currentTime := int(time.Now().UnixNano() / 1000000000) finalXML = finalXML + "" + strconv.Itoa(int(crc32Value)) + "" finalXML = finalXML + "" + strconv.Itoa(currentTime) + "" // 压缩 zipData := baseutils.CompressByteArray([]byte(finalXML)) retData, err := EncodeZipData(zipData, 0x3060) if err != nil { return []byte{}, err } return retData, nil }