github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/client/internal/auth/qimei.go (about)

     1  package auth
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"crypto/md5"
     8  	crand "crypto/rand"
     9  	"crypto/rsa"
    10  	"crypto/x509"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"encoding/json"
    14  	"encoding/pem"
    15  	"fmt"
    16  	"math/rand"
    17  	"time"
    18  
    19  	"github.com/Mrs4s/MiraiGo/utils"
    20  	"github.com/tidwall/gjson"
    21  )
    22  
    23  const (
    24  	secret = "ZdJqM15EeO2zWc08"
    25  	rsaKey = `-----BEGIN PUBLIC KEY-----
    26  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEIxgwoutfwoJxcGQeedgP7FG9
    27  qaIuS0qzfR8gWkrkTZKM2iWHn2ajQpBRZjMSoSf6+KJGvar2ORhBfpDXyVtZCKpq
    28  LQ+FLkpncClKVIrBwv6PHyUvuCb0rIarmgDnzkfQAqVufEtR64iazGDKatvJ9y6B
    29  9NMbHddGSAUmRTCrHQIDAQAB
    30  -----END PUBLIC KEY-----`
    31  )
    32  
    33  func (info *Device) RequestQImei() {
    34  	if info.Protocol.Version().AppKey == "" {
    35  		return
    36  	}
    37  
    38  	// init params
    39  	payload, _ := json.Marshal(genRandomPayloadByDevice(info))
    40  	cryptKey := utils.RandomStringRange(16, "abcdef1234567890")
    41  	ts := time.Now().Unix() * 1000
    42  	nonce := utils.RandomStringRange(16, "abcdef1234567890")
    43  
    44  	// init rsa key and aes key
    45  	publicKey := initPublicKey()
    46  	encryptedAesKey, _ := rsa.EncryptPKCS1v15(crand.Reader, publicKey, []byte(cryptKey))
    47  
    48  	encryptedPayload := aesEncrypt(payload, []byte(cryptKey))
    49  
    50  	key := base64.StdEncoding.EncodeToString(encryptedAesKey)
    51  	params := base64.StdEncoding.EncodeToString(encryptedPayload)
    52  
    53  	postData, _ := json.Marshal(map[string]any{
    54  		"key":    key,
    55  		"params": params,
    56  		"time":   ts,
    57  		"nonce":  nonce,
    58  		"sign":   sign(key, params, fmt.Sprint(ts), nonce),
    59  		"extra":  "",
    60  	})
    61  
    62  	resp, _ := utils.HttpPostBytesWithCookie("https://snowflake.qq.com/ola/android", postData, "", "application/json")
    63  	if gjson.GetBytes(resp, "code").Int() != 0 {
    64  		return
    65  	}
    66  	encryptedResponse, _ := base64.StdEncoding.DecodeString(gjson.GetBytes(resp, "data").String())
    67  	if len(encryptedResponse) == 0 {
    68  		return
    69  	}
    70  	decryptedResponse := aesDecrypt(encryptedResponse, []byte(cryptKey))
    71  	info.QImei16 = gjson.GetBytes(decryptedResponse, "q16").String()
    72  	info.QImei36 = gjson.GetBytes(decryptedResponse, "q36").String()
    73  }
    74  
    75  func initPublicKey() *rsa.PublicKey {
    76  	blockPub, _ := pem.Decode([]byte(rsaKey))
    77  	pub, _ := x509.ParsePKIXPublicKey(blockPub.Bytes)
    78  	return pub.(*rsa.PublicKey)
    79  }
    80  
    81  func sign(key, params, ts, nonce string) string {
    82  	h := md5.Sum([]byte(key + params + ts + nonce + secret))
    83  	return hex.EncodeToString(h[:])
    84  }
    85  
    86  func aesEncrypt(src []byte, key []byte) []byte {
    87  	block, _ := aes.NewCipher(key)
    88  	ecb := cipher.NewCBCEncrypter(block, key)
    89  	content := src
    90  	content = pkcs5Padding(content, block.BlockSize())
    91  	crypted := make([]byte, len(content))
    92  	ecb.CryptBlocks(crypted, content)
    93  	return crypted
    94  }
    95  
    96  func aesDecrypt(crypt []byte, key []byte) []byte {
    97  	block, _ := aes.NewCipher(key)
    98  	ecb := cipher.NewCBCDecrypter(block, key)
    99  	decrypted := make([]byte, len(crypt))
   100  	ecb.CryptBlocks(decrypted, crypt)
   101  	return pkcs5Trimming(decrypted)
   102  }
   103  
   104  func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
   105  	padding := blockSize - len(ciphertext)%blockSize
   106  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
   107  	return append(ciphertext, padtext...)
   108  }
   109  
   110  func pkcs5Trimming(encrypt []byte) []byte {
   111  	padding := encrypt[len(encrypt)-1]
   112  	return encrypt[:len(encrypt)-int(padding)]
   113  }
   114  
   115  func genRandomPayloadByDevice(info *Device) map[string]any {
   116  	now := time.Now()
   117  	seed := int64(0x6F4)
   118  	for _, b := range info.Guid {
   119  		seed += int64(b)
   120  	}
   121  	fixedRand := rand.New(rand.NewSource(seed))
   122  
   123  	reserved := map[string]string{
   124  		"harmony":    "0",
   125  		"clone":      "0",
   126  		"containe":   "",
   127  		"oz":         "UhYmelwouA+V2nPWbOvLTgN2/m8jwGB+yUB5v9tysQg=",
   128  		"oo":         "Xecjt+9S1+f8Pz2VLSxgpw==",
   129  		"kelong":     "0",
   130  		"uptimes":    time.Unix(now.Unix()-fixedRand.Int63n(14400), 0).Format(time.DateTime),
   131  		"multiUser":  "0",
   132  		"bod":        string(info.Board),
   133  		"brd":        string(info.Brand),
   134  		"dv":         string(info.Device),
   135  		"firstLevel": "",
   136  		"manufact":   string(info.Brand),
   137  		"name":       string(info.Model),
   138  		"host":       "se.infra",
   139  		"kernel":     string(info.ProcVersion),
   140  	}
   141  	reservedBytes, _ := json.Marshal(reserved)
   142  	deviceType := "Phone"
   143  	if info.Protocol == AndroidPad {
   144  		deviceType = "Pad"
   145  	}
   146  	beaconId := ""
   147  	timeMonth := time.Now().Format("2006-01-") + "01"
   148  	rand1 := fixedRand.Intn(899999) + 100000
   149  	rand2 := fixedRand.Intn(899999999) + 100000000
   150  	for i := 1; i <= 40; i++ {
   151  		switch i {
   152  		case 1, 2, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30, 33, 34, 37, 38:
   153  			beaconId += fmt.Sprintf("k%v:%v%v.%v", i, timeMonth, rand1, rand2)
   154  		case 3:
   155  			beaconId += "k3:0000000000000000"
   156  		case 4:
   157  			beaconId += "k4:" + utils.RandomStringRange(16, "123456789abcdef")
   158  		default:
   159  			beaconId += fmt.Sprintf("k%v:%v", i, fixedRand.Intn(10000))
   160  		}
   161  		beaconId += ";"
   162  	}
   163  	return map[string]any{
   164  		"androidId":   string(info.AndroidId),
   165  		"platformId":  1,
   166  		"appKey":      info.Protocol.Version().AppKey,
   167  		"appVersion":  info.Protocol.Version().SortVersionName,
   168  		"beaconIdSrc": beaconId,
   169  		"brand":       string(info.Brand),
   170  		"channelId":   "2017",
   171  		"cid":         "",
   172  		"imei":        info.IMEI,
   173  		"imsi":        "",
   174  		"mac":         "",
   175  		"model":       string(info.Model),
   176  		"networkType": "unknown",
   177  		"oaid":        "",
   178  		"osVersion":   "Android " + string(info.Version.Release) + ",level " + fmt.Sprint(info.Version.SDK),
   179  		"qimei":       "",
   180  		"qimei36":     "",
   181  		"sdkVersion":  "1.2.13.6",
   182  		"audit":       "",
   183  		"userId":      "{}",
   184  		"packageId":   info.Protocol.Version().ApkId,
   185  		"deviceType":  deviceType,
   186  		"sdkName":     "",
   187  		"reserved":    string(reservedBytes),
   188  	}
   189  }