From b51d8b417c0c7b726a03e6a3c8cf6d97a5696abe Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 18:46:55 +0800 Subject: [PATCH] feature sso addr fetch. --- binary/jce/structs.go | 6 +++++ binary/jce/writer.go | 23 ++++++++++++------- client/builders.go | 14 ++++++------ client/client.go | 4 ++++ client/global.go | 53 ++++++++++++++++++++++++++++++++++++++++++- client/group_info.go | 4 ++-- 6 files changed, 86 insertions(+), 18 deletions(-) diff --git a/binary/jce/structs.go b/binary/jce/structs.go index db98d38d..d0483654 100644 --- a/binary/jce/structs.go +++ b/binary/jce/structs.go @@ -430,6 +430,12 @@ func (pkt *RequestDataVersion3) ReadFrom(r *JceReader) { }) } +func (pkt *RequestDataVersion2) ToBytes() []byte { + w := NewJceWriter() + w.WriteJceStructRaw(pkt) + return w.Bytes() +} + func (pkt *RequestDataVersion2) ReadFrom(r *JceReader) { pkt.Map = make(map[string]map[string][]byte) r.ReadMapF(0, func(k interface{}, v interface{}) { diff --git a/binary/jce/writer.go b/binary/jce/writer.go index 94f9647c..a4ba3350 100644 --- a/binary/jce/writer.go +++ b/binary/jce/writer.go @@ -26,13 +26,14 @@ func (w *JceWriter) writeHead(t byte, tag int) { } } -func (w *JceWriter) WriteByte(b byte, tag int) { +func (w *JceWriter) WriteByte(b byte, tag int) *JceWriter { if b == 0 { w.writeHead(12, tag) } else { w.writeHead(0, tag) w.buf.WriteByte(b) } + return w } func (w *JceWriter) WriteBool(b bool, tag int) { @@ -52,22 +53,23 @@ func (w *JceWriter) WriteInt16(n int16, tag int) { _ = goBinary.Write(w.buf, goBinary.BigEndian, n) } -func (w *JceWriter) WriteInt32(n int32, tag int) { +func (w *JceWriter) WriteInt32(n int32, tag int) *JceWriter { if n >= -32768 && n <= 32767 { // ? if ((n >= 32768) && (n <= 32767)) w.WriteInt16(int16(n), tag) - return + return w } w.writeHead(2, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, n) + return w } -func (w *JceWriter) WriteInt64(n int64, tag int) { +func (w *JceWriter) WriteInt64(n int64, tag int) *JceWriter { if n >= -2147483648 && n <= 2147483647 { - w.WriteInt32(int32(n), tag) - return + return w.WriteInt32(int32(n), tag) } w.writeHead(3, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, n) + return w } func (w *JceWriter) WriteFloat32(n float32, tag int) { @@ -80,17 +82,18 @@ func (w *JceWriter) WriteFloat64(n float64, tag int) { _ = goBinary.Write(w.buf, goBinary.BigEndian, n) } -func (w *JceWriter) WriteString(s string, tag int) { +func (w *JceWriter) WriteString(s string, tag int) *JceWriter { by := []byte(s) if len(by) > 255 { w.writeHead(7, tag) _ = goBinary.Write(w.buf, goBinary.BigEndian, len(by)) w.buf.Write(by) - return + return w } w.writeHead(6, tag) w.buf.WriteByte(byte(len(by))) w.buf.Write(by) + return w } func (w *JceWriter) WriteBytes(l []byte, tag int) { @@ -167,6 +170,10 @@ func (w *JceWriter) WriteObject(i interface{}, tag int) { return } if t.Kind() == reflect.Slice { + if b, ok := i.([]byte); ok { + w.WriteBytes(b, tag) + return + } w.WriteSlice(i, tag) return } diff --git a/client/builders.go b/client/builders.go index fd5e19c7..d1a564cf 100644 --- a/client/builders.go +++ b/client/builders.go @@ -274,7 +274,7 @@ func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte) req.WriteInt64(pktSeq, 2) req.WriteBytes(jceBuf, 3) buf := &jce.RequestDataVersion3{ - Map: map[string][]byte{"PushResp": packRequestDataV3(req.Bytes())}, + Map: map[string][]byte{"PushResp": packUniRequestData(req.Bytes())}, } pkt := &jce.RequestPacket{ IVersion: 3, @@ -298,7 +298,7 @@ func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) { RequireMax: 20, GetDevListType: 2, } - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packRequestDataV3(req.ToBytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packUniRequestData(req.ToBytes())}} pkt := &jce.RequestPacket{ IVersion: 3, SServantName: "StatSvc", @@ -353,7 +353,7 @@ func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendLis SnsTypeList: []int64{13580, 13581, 13582}, } buf := &jce.RequestDataVersion3{ - Map: map[string][]byte{"FL": packRequestDataV3(req.ToBytes())}, + Map: map[string][]byte{"FL": packUniRequestData(req.ToBytes())}, } pkt := &jce.RequestPacket{ IVersion: 3, @@ -386,8 +386,8 @@ func (c *QQClient) buildSummaryCardRequestPacket(target int64) (uint16, []byte) head := jce.NewJceWriter() head.WriteInt32(2, 0) buf := &jce.RequestDataVersion3{Map: map[string][]byte{ - "ReqHead": packRequestDataV3(head.Bytes()), - "ReqSummaryCard": packRequestDataV3(req.ToBytes()), + "ReqHead": packUniRequestData(head.Bytes()), + "ReqSummaryCard": packUniRequestData(req.ToBytes()), }} pkt := &jce.RequestPacket{ IVersion: 3, @@ -869,7 +869,7 @@ func (c *QQClient) buildEditGroupTagPacket(groupCode, memberUin int64, newTag st }, }, } - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packRequestDataV3(req.ToBytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"MGCREQ": packUniRequestData(req.ToBytes())}} pkt := &jce.RequestPacket{ IVersion: 3, IRequestId: c.nextPacketSeq(), @@ -1051,7 +1051,7 @@ func (c *QQClient) buildQuitGroupPacket(groupCode int64) (uint16, []byte) { w.WriteUInt32(uint32(c.Uin)) w.WriteUInt32(uint32(groupCode)) }), 2) - buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packRequestDataV3(jw.Bytes())}} + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"GroupMngReq": packUniRequestData(jw.Bytes())}} pkt := &jce.RequestPacket{ IVersion: 3, IRequestId: c.nextPacketSeq(), diff --git a/client/client.go b/client/client.go index a75110a1..763fe518 100644 --- a/client/client.go +++ b/client/client.go @@ -197,6 +197,10 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { } cli.servers = append(hostAddrs, cli.servers...) } + sso, err := getSSOAddress() + if err == nil && len(sso) > 0 { + cli.servers = append(sso, cli.servers...) + } rand.Read(cli.RandomKey) return cli } diff --git a/client/global.go b/client/global.go index 468ee308..62e8c60b 100644 --- a/client/global.go +++ b/client/global.go @@ -2,9 +2,11 @@ package client import ( "crypto/md5" + "encoding/hex" "encoding/json" "fmt" "github.com/Mrs4s/MiraiGo/binary" + "github.com/Mrs4s/MiraiGo/binary/jce" devinfo "github.com/Mrs4s/MiraiGo/client/pb" "github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/oidb" @@ -12,7 +14,9 @@ import ( "github.com/Mrs4s/MiraiGo/utils" "google.golang.org/protobuf/proto" "math/rand" + "net" "sort" + "strings" ) type DeviceInfo struct { @@ -272,6 +276,53 @@ func (info *DeviceInfo) GenDeviceInfoData() []byte { return data } +func getSSOAddress() ([]*net.TCPAddr, error) { + protocol := genVersionInfo(SystemDeviceInfo.Protocol) + key, _ := hex.DecodeString("F0441F5FF42DA58FDCF7949ABA62D411") + payload := jce.NewJceWriter(). // see ServerConfig.d + WriteInt64(0, 1).WriteInt64(0, 2).WriteByte(1, 3). + WriteString("00000", 4).WriteInt32(100, 5). + WriteInt32(int32(protocol.AppId), 6).WriteString(SystemDeviceInfo.IMEI, 7). + WriteInt64(0, 8).WriteInt64(0, 9).WriteInt64(0, 10). + WriteInt64(0, 11).WriteByte(0, 12).WriteInt64(0, 13).WriteByte(1, 14).Bytes() + buf := &jce.RequestDataVersion2{ + Map: map[string]map[string][]byte{"HttpServerListReq": {"ConfigHttp.HttpServerListReq": packUniRequestData(payload)}}, + } + pkt := &jce.RequestPacket{ + IVersion: 2, + SServantName: "ConfigHttp", + SFuncName: "HttpServerListReq", + SBuffer: buf.ToBytes(), + } + tea := binary.NewTeaCipher(key) + rsp, err := utils.HttpPostBytes("https://configsvr.msf.3g.qq.com/configsvr/serverlist.jsp", tea.Encrypt(binary.NewWriterF(func(w *binary.Writer) { + w.WriteIntLvPacket(0, func(w *binary.Writer) { + w.Write(pkt.ToBytes()) + }) + }))) + if err != nil { + return nil, err + } + rspPkt := &jce.RequestPacket{} + data := &jce.RequestDataVersion2{} + rspPkt.ReadFrom(jce.NewJceReader(tea.Decrypt(rsp)[4:])) + data.ReadFrom(jce.NewJceReader(rspPkt.SBuffer)) + reader := jce.NewJceReader(data.Map["HttpServerListRes"]["ConfigHttp.HttpServerListRes"][1:]) + servers := []jce.SsoServerInfo{} + reader.ReadSlice(&servers, 2) + var adds []*net.TCPAddr + for _, s := range servers { + if strings.Contains(s.Server, "com") { + continue + } + adds = append(adds, &net.TCPAddr{ + IP: net.ParseIP(s.Server), + Port: int(s.Port), + }) + } + return adds, nil +} + func (c *QQClient) parsePrivateMessage(msg *msg.Message) *message.PrivateMessage { friend := c.FindFriend(msg.Head.FromUin) var sender *message.Sender @@ -459,7 +510,7 @@ func (b *groupMessageBuilder) build() *msg.Message { return base } -func packRequestDataV3(data []byte) (r []byte) { +func packUniRequestData(data []byte) (r []byte) { r = append([]byte{0x0A}, data...) r = append(r, 0x0B) return diff --git a/client/group_info.go b/client/group_info.go index bd790921..baa57f8b 100644 --- a/client/group_info.go +++ b/client/group_info.go @@ -77,8 +77,8 @@ func (c *QQClient) buildGroupSearchPacket(keyword string) (uint16, []byte) { head := jce.NewJceWriter() head.WriteInt32(2, 0) buf := &jce.RequestDataVersion3{Map: map[string][]byte{ - "ReqHead": packRequestDataV3(head.Bytes()), - "ReqSearch": packRequestDataV3(req.ToBytes()), + "ReqHead": packUniRequestData(head.Bytes()), + "ReqSearch": packUniRequestData(req.ToBytes()), }} pkt := &jce.RequestPacket{ IVersion: 3,