mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 11:07:40 +08:00
implements qimei & fix t545
This commit is contained in:
parent
692fc0f6ea
commit
cdc207867e
@ -114,6 +114,11 @@ func (c *QQClient) buildLoginPacket() (uint16, []byte) {
|
|||||||
})
|
})
|
||||||
t.Append(tlv.T544Custom("810_9", salt, wrapper.DandelionEnergy))
|
t.Append(tlv.T544Custom("810_9", salt, wrapper.DandelionEnergy))
|
||||||
}
|
}
|
||||||
|
if c.Device().QImei36 != "" {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().QImei36)))
|
||||||
|
} else {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().IMEI)))
|
||||||
|
}
|
||||||
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
req := c.buildOicqRequestPacket(c.Uin, 0x0810, t)
|
||||||
r := network.Request{
|
r := network.Request{
|
||||||
Type: network.RequestTypeLogin,
|
Type: network.RequestTypeLogin,
|
||||||
@ -450,9 +455,13 @@ func (c *QQClient) buildRequestTgtgtNopicsigPacket() (uint16, []byte) {
|
|||||||
tlv.T516(),
|
tlv.T516(),
|
||||||
tlv.T521(0),
|
tlv.T521(0),
|
||||||
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
tlv.T525(tlv.T536([]byte{0x01, 0x00})),
|
||||||
tlv.T545([]byte(c.Device().IMEI)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if c.Device().QImei36 != "" {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().QImei36)))
|
||||||
|
} else {
|
||||||
|
t.Append(tlv.T545([]byte(c.Device().IMEI)))
|
||||||
|
}
|
||||||
m := oicq.Message{
|
m := oicq.Message{
|
||||||
Uin: uint32(c.Uin),
|
Uin: uint32(c.Uin),
|
||||||
Command: 0x810,
|
Command: 0x810,
|
||||||
|
@ -81,6 +81,7 @@ func GenRandomDevice() *DeviceInfo {
|
|||||||
hex.Encode(device.AndroidId, r)
|
hex.Encode(device.AndroidId, r)
|
||||||
device.GenNewGuid()
|
device.GenNewGuid()
|
||||||
device.GenNewTgtgtKey()
|
device.GenNewTgtgtKey()
|
||||||
|
device.RequestQImei()
|
||||||
return device
|
return device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ var (
|
|||||||
ApkId: "com.tencent.mobileqq",
|
ApkId: "com.tencent.mobileqq",
|
||||||
AppId: 537151682,
|
AppId: 537151682,
|
||||||
SubAppId: 537151682,
|
SubAppId: 537151682,
|
||||||
|
AppKey: "0S200MNJT807V3GE",
|
||||||
SortVersionName: "8.9.33.10335",
|
SortVersionName: "8.9.33.10335",
|
||||||
BuildTime: 1673599898,
|
BuildTime: 1673599898,
|
||||||
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
||||||
@ -43,6 +44,7 @@ var (
|
|||||||
ApkId: "com.tencent.mobileqq",
|
ApkId: "com.tencent.mobileqq",
|
||||||
AppId: 537151218,
|
AppId: 537151218,
|
||||||
SubAppId: 537151218,
|
SubAppId: 537151218,
|
||||||
|
AppKey: "0S200MNJT807V3GE",
|
||||||
SortVersionName: "8.9.33.10335",
|
SortVersionName: "8.9.33.10335",
|
||||||
BuildTime: 1673599898,
|
BuildTime: 1673599898,
|
||||||
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
ApkSign: []byte{0xA6, 0xB7, 0x45, 0xBF, 0x24, 0xA2, 0xC2, 0x77, 0x52, 0x77, 0x16, 0xF6, 0xF3, 0x6E, 0xB6, 0x8D},
|
||||||
@ -153,6 +155,7 @@ type AppVersion struct {
|
|||||||
SdkVersion string
|
SdkVersion string
|
||||||
AppId uint32
|
AppId uint32
|
||||||
SubAppId uint32
|
SubAppId uint32
|
||||||
|
AppKey string
|
||||||
BuildTime uint32
|
BuildTime uint32
|
||||||
SSOVersion uint32
|
SSOVersion uint32
|
||||||
MiscBitmap uint32
|
MiscBitmap uint32
|
||||||
@ -173,6 +176,7 @@ func (v *AppVersion) ReadJson(d []byte) error {
|
|||||||
v.ApkId = f.ApkId
|
v.ApkId = f.ApkId
|
||||||
v.AppId = f.AppId
|
v.AppId = f.AppId
|
||||||
v.SubAppId = f.SubAppId
|
v.SubAppId = f.SubAppId
|
||||||
|
v.AppKey = f.AppKey
|
||||||
v.SortVersionName = f.SortVersionName
|
v.SortVersionName = f.SortVersionName
|
||||||
v.BuildTime = f.BuildTime
|
v.BuildTime = f.BuildTime
|
||||||
v.ApkSign, _ = hex.DecodeString(f.ApkSign)
|
v.ApkSign, _ = hex.DecodeString(f.ApkSign)
|
||||||
@ -236,6 +240,7 @@ type appVersionFile struct {
|
|||||||
ApkId string `json:"apk_id"`
|
ApkId string `json:"apk_id"`
|
||||||
AppId uint32 `json:"app_id"`
|
AppId uint32 `json:"app_id"`
|
||||||
SubAppId uint32 `json:"sub_app_id"`
|
SubAppId uint32 `json:"sub_app_id"`
|
||||||
|
AppKey string `json:"app_key"`
|
||||||
SortVersionName string `json:"sort_version_name"`
|
SortVersionName string `json:"sort_version_name"`
|
||||||
BuildTime uint32 `json:"build_time"`
|
BuildTime uint32 `json:"build_time"`
|
||||||
ApkSign string `json:"apk_sign"` // hex encoded
|
ApkSign string `json:"apk_sign"` // hex encoded
|
||||||
|
@ -45,6 +45,8 @@ type Device struct {
|
|||||||
VendorOSName []byte
|
VendorOSName []byte
|
||||||
Guid []byte
|
Guid []byte
|
||||||
TgtgtKey []byte
|
TgtgtKey []byte
|
||||||
|
QImei16 string
|
||||||
|
QImei36 string
|
||||||
Protocol ProtocolType
|
Protocol ProtocolType
|
||||||
Version *OSVersion
|
Version *OSVersion
|
||||||
}
|
}
|
||||||
@ -149,6 +151,7 @@ func (info *Device) ReadJson(d []byte) error {
|
|||||||
|
|
||||||
info.GenNewGuid()
|
info.GenNewGuid()
|
||||||
info.GenNewTgtgtKey()
|
info.GenNewTgtgtKey()
|
||||||
|
info.RequestQImei() // 应该可以缓存, 理论上同一设备每次请求都是一样的
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
192
client/internal/auth/qimei.go
Normal file
192
client/internal/auth/qimei.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Mrs4s/MiraiGo/utils"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
secret = "ZdJqM15EeO2zWc08"
|
||||||
|
rsaKey = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEIxgwoutfwoJxcGQeedgP7FG9
|
||||||
|
qaIuS0qzfR8gWkrkTZKM2iWHn2ajQpBRZjMSoSf6+KJGvar2ORhBfpDXyVtZCKpq
|
||||||
|
LQ+FLkpncClKVIrBwv6PHyUvuCb0rIarmgDnzkfQAqVufEtR64iazGDKatvJ9y6B
|
||||||
|
9NMbHddGSAUmRTCrHQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----`
|
||||||
|
)
|
||||||
|
|
||||||
|
func (info *Device) RequestQImei() {
|
||||||
|
if info.Protocol.Version().AppKey == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init params
|
||||||
|
payload, _ := json.Marshal(genRandomPayloadByDevice(info))
|
||||||
|
cryptKey := utils.RandomStringRange(16, "abcdef1234567890")
|
||||||
|
ts := time.Now().Unix() * 1000
|
||||||
|
nonce := utils.RandomStringRange(16, "abcdef1234567890")
|
||||||
|
|
||||||
|
// init rsa key and aes key
|
||||||
|
publicKey := initPublicKey()
|
||||||
|
encryptedAesKey, _ := rsa.EncryptPKCS1v15(rand.New(rand.NewSource(time.Now().UnixNano())), publicKey, []byte(cryptKey))
|
||||||
|
|
||||||
|
encryptedPayload := aesEncrypt(payload, []byte(cryptKey))
|
||||||
|
|
||||||
|
key := base64.StdEncoding.EncodeToString(encryptedAesKey)
|
||||||
|
params := base64.StdEncoding.EncodeToString(encryptedPayload)
|
||||||
|
|
||||||
|
postData, _ := json.Marshal(map[string]any{
|
||||||
|
"key": key,
|
||||||
|
"params": params,
|
||||||
|
"time": ts,
|
||||||
|
"nonce": nonce,
|
||||||
|
"sign": sign(key, params, fmt.Sprint(ts), nonce),
|
||||||
|
"extra": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
resp, _ := utils.HttpPostBytesWithCookie("https://snowflake.qq.com/ola/android", postData, "", "application/json")
|
||||||
|
if gjson.GetBytes(resp, "code").Int() != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
encryptedResponse, _ := base64.StdEncoding.DecodeString(gjson.GetBytes(resp, "data").String())
|
||||||
|
decryptedResponse := aesDecrypt(encryptedResponse, []byte(cryptKey))
|
||||||
|
info.QImei16 = gjson.GetBytes(decryptedResponse, "q16").String()
|
||||||
|
info.QImei36 = gjson.GetBytes(decryptedResponse, "q36").String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initPublicKey() *rsa.PublicKey {
|
||||||
|
blockPub, _ := pem.Decode([]byte(rsaKey))
|
||||||
|
pub, _ := x509.ParsePKIXPublicKey(blockPub.Bytes)
|
||||||
|
return pub.(*rsa.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sign(key, params, ts, nonce string) string {
|
||||||
|
h := md5.Sum([]byte(key + params + ts + nonce + secret))
|
||||||
|
return hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesEncrypt(src []byte, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
ecb := cipher.NewCBCEncrypter(block, key)
|
||||||
|
content := src
|
||||||
|
content = pkcs5Padding(content, block.BlockSize())
|
||||||
|
crypted := make([]byte, len(content))
|
||||||
|
ecb.CryptBlocks(crypted, content)
|
||||||
|
return crypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesDecrypt(crypt []byte, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
ecb := cipher.NewCBCDecrypter(block, key)
|
||||||
|
decrypted := make([]byte, len(crypt))
|
||||||
|
ecb.CryptBlocks(decrypted, crypt)
|
||||||
|
return pkcs5Trimming(decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pkcs5Trimming(encrypt []byte) []byte {
|
||||||
|
padding := encrypt[len(encrypt)-1]
|
||||||
|
return encrypt[:len(encrypt)-int(padding)]
|
||||||
|
}
|
||||||
|
|
||||||
|
func genRandomPayloadByDevice(info *Device) map[string]any {
|
||||||
|
now := time.Now()
|
||||||
|
seed := int64(0x6F4)
|
||||||
|
for _, b := range info.Guid {
|
||||||
|
seed += int64(b)
|
||||||
|
}
|
||||||
|
fixedRand := rand.New(rand.NewSource(seed))
|
||||||
|
years := now.Year()
|
||||||
|
month := now.Month()
|
||||||
|
if month == 1 {
|
||||||
|
years--
|
||||||
|
month = 12
|
||||||
|
} else {
|
||||||
|
month--
|
||||||
|
}
|
||||||
|
reserved := map[string]string{
|
||||||
|
"harmony": "0",
|
||||||
|
"clone": "0",
|
||||||
|
"containe": "",
|
||||||
|
"oz": "UhYmelwouA+V2nPWbOvLTgN2/m8jwGB+yUB5v9tysQg=",
|
||||||
|
"oo": "Xecjt+9S1+f8Pz2VLSxgpw==",
|
||||||
|
"kelong": "0",
|
||||||
|
"uptimes": time.Date(years, month, fixedRand.Intn(27)+1, fixedRand.Intn(60), fixedRand.Intn(60), fixedRand.Intn(60), fixedRand.Intn(1e9), now.Location()).Format("2006-01-02 15:04:05"),
|
||||||
|
"multiUser": "0",
|
||||||
|
"bod": string(info.Board),
|
||||||
|
"brd": string(info.Brand),
|
||||||
|
"dv": string(info.Device),
|
||||||
|
"firstLevel": "",
|
||||||
|
"manufact": string(info.Brand),
|
||||||
|
"name": string(info.Model),
|
||||||
|
"host": "se.infra",
|
||||||
|
"kernel": string(info.ProcVersion),
|
||||||
|
}
|
||||||
|
reservedBytes, _ := json.Marshal(reserved)
|
||||||
|
deviceType := "Phone"
|
||||||
|
if info.Protocol == AndroidPad {
|
||||||
|
deviceType = "Pad"
|
||||||
|
}
|
||||||
|
beaconId := ""
|
||||||
|
timeMonth := time.Now().Format("2006-01-") + "01"
|
||||||
|
rand1 := fixedRand.Intn(899999) + 100000
|
||||||
|
rand2 := fixedRand.Intn(899999999) + 100000000
|
||||||
|
for i := 1; i <= 40; i++ {
|
||||||
|
switch i {
|
||||||
|
case 1, 2, 13, 14, 17, 18, 21, 22, 25, 26, 29, 30, 33, 34, 37, 38:
|
||||||
|
beaconId += fmt.Sprintf("k%v:%v%v.%v", i, timeMonth, rand1, rand2)
|
||||||
|
case 3:
|
||||||
|
beaconId += "k3:0000000000000000"
|
||||||
|
case 4:
|
||||||
|
beaconId += "k4:" + utils.RandomStringRange(16, "123456789abcdef")
|
||||||
|
default:
|
||||||
|
beaconId += fmt.Sprintf("k%v:%v", i, fixedRand.Intn(10000))
|
||||||
|
}
|
||||||
|
beaconId += ";"
|
||||||
|
}
|
||||||
|
return map[string]any{
|
||||||
|
"androidId": string(info.AndroidId),
|
||||||
|
"platformId": 1,
|
||||||
|
"appKey": info.Protocol.Version().AppKey,
|
||||||
|
"appVersion": info.Protocol.Version().SortVersionName,
|
||||||
|
"beaconIdSrc": beaconId,
|
||||||
|
"brand": string(info.Brand),
|
||||||
|
"channelId": "2017",
|
||||||
|
"cid": "",
|
||||||
|
"imei": info.IMEI,
|
||||||
|
"imsi": "",
|
||||||
|
"mac": "",
|
||||||
|
"model": string(info.Model),
|
||||||
|
"networkType": "unknown",
|
||||||
|
"oaid": "",
|
||||||
|
"osVersion": "Android " + string(info.Version.Release) + ",level " + fmt.Sprint(info.Version.SDK),
|
||||||
|
"qimei": "",
|
||||||
|
"qimei36": "",
|
||||||
|
"sdkVersion": "1.2.13.6",
|
||||||
|
"audit": "",
|
||||||
|
"userId": "{}",
|
||||||
|
"packageId": info.Protocol.Version().ApkId,
|
||||||
|
"deviceType": deviceType,
|
||||||
|
"sdkName": "",
|
||||||
|
"reserved": string(reservedBytes),
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,9 @@ package tlv
|
|||||||
|
|
||||||
import "github.com/Mrs4s/MiraiGo/binary"
|
import "github.com/Mrs4s/MiraiGo/binary"
|
||||||
|
|
||||||
func T545(imei []byte) []byte {
|
func T545(qimei []byte) []byte {
|
||||||
return binary.NewWriterF(func(w *binary.Writer) {
|
return binary.NewWriterF(func(w *binary.Writer) {
|
||||||
w.WriteUInt16(0x545)
|
w.WriteUInt16(0x545)
|
||||||
w.WriteBytesShort(imei)
|
w.WriteBytesShort(qimei)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user