From a4131cdc07392a772b9bc9ac6a5d1c5a97985c81 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Sun, 8 Nov 2020 20:23:53 +0800 Subject: [PATCH 01/14] fix packet dropped. --- client/client.go | 2 +- protocol/packets/global.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/client.go b/client/client.go index 1c4c1674..fb8c09ca 100644 --- a/client/client.go +++ b/client/client.go @@ -1053,7 +1053,7 @@ func (c *QQClient) netLoop() { pkt, err := packets.ParseIncomingPacket(data, c.sigInfo.d2Key) if err != nil { c.Error("parse incoming packet error: %v", err) - if err == packets.ErrSessionExpired { + if err == packets.ErrSessionExpired || err == packets.ErrPacketDropped { break } errCount++ diff --git a/protocol/packets/global.go b/protocol/packets/global.go index cccdc0fb..167314fa 100644 --- a/protocol/packets/global.go +++ b/protocol/packets/global.go @@ -11,6 +11,7 @@ var ErrUnknownFlag = errors.New("unknown flag") var ErrInvalidPayload = errors.New("invalid payload") var ErrDecryptFailed = errors.New("decrypt failed") var ErrSessionExpired = errors.New("session expired") +var ErrPacketDropped = errors.New("packet dropped") type ISendingPacket interface { CommandId() uint16 @@ -121,7 +122,7 @@ func ParseIncomingPacket(payload, d2key []byte) (*IncomingPacket, error) { func parseSsoFrame(payload []byte, flag2 byte) (*IncomingPacket, error) { reader := binary.NewReader(payload) if reader.ReadInt32()-4 > int32(reader.Len()) { - return nil, errors.New("dropped") + return nil, ErrPacketDropped } seqId := reader.ReadInt32() retCode := reader.ReadInt32() From 1fbac975a752cab35b54ca90c21059862f4bd4c1 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Tue, 10 Nov 2020 18:22:36 +0800 Subject: [PATCH 02/14] fix heartbeat. --- client/client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/client.go b/client/client.go index 1c4c1674..f09677b6 100644 --- a/client/client.go +++ b/client/client.go @@ -1124,6 +1124,7 @@ func (c *QQClient) doHeartbeat() { _ = c.Conn.Close() } time.AfterFunc(30*time.Second, c.doHeartbeat) + return } c.heartbeatEnabled = false } From a8986651e7c3b0ddb8a5293b605dbcfc866c8f9d Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Tue, 10 Nov 2020 23:14:01 +0800 Subject: [PATCH 03/14] feature: group file delete. --- client/client.go | 3 ++- client/group_file.go | 48 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/client/client.go b/client/client.go index 1c4c1674..963631a0 100644 --- a/client/client.go +++ b/client/client.go @@ -151,7 +151,8 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { "ProfileService.Pb.ReqSystemMsgNew.Friend": decodeSystemMsgFriendPacket, "MultiMsg.ApplyUp": decodeMultiApplyUpResponse, "MultiMsg.ApplyDown": decodeMultiApplyDownResponse, - "OidbSvc.0x6d6_2": decodeOIDB6d6Response, + "OidbSvc.0x6d6_2": decodeOIDB6d62Response, + "OidbSvc.0x6d6_3": decodeOIDB6d63Response, "OidbSvc.0x6d8_1": decodeOIDB6d81Response, "OidbSvc.0x88d_0": decodeGroupInfoResponse, "OidbSvc.0xe07_0": decodeImageOcrResponse, diff --git a/client/group_file.go b/client/group_file.go index 68155f58..fe873408 100644 --- a/client/group_file.go +++ b/client/group_file.go @@ -142,6 +142,16 @@ func (fs *GroupFileSystem) GetDownloadUrl(file *GroupFile) string { return fs.client.GetGroupFileUrl(file.GroupCode, file.FileId, file.BusId) } +// DeleteFile 删除群文件,需要管理权限. +// 返回错误, 空为删除成功 +func (fs *GroupFileSystem) DeleteFile(parentFolderId, fileId string, busId int32) string { + i, err := fs.client.sendAndWait(fs.client.buildGroupFileDeleteReqPacket(fs.GroupCode, parentFolderId, fileId, busId)) + if err != nil { + return err.Error() + } + return i.(string) +} + // OidbSvc.0x6d8_1 func (c *QQClient) buildGroupFileListRequestPacket(groupCode int64, folderId string, startIndex uint32) (uint16, []byte) { seq := c.nextSeq() @@ -229,6 +239,27 @@ func (c *QQClient) buildGroupFileDownloadReqPacket(groupCode int64, fileId strin return seq, packet } +func (c *QQClient) buildGroupFileDeleteReqPacket(groupCode int64, parentFolderId, fileId string, busId int32) (uint16, []byte) { + seq := c.nextSeq() + body := &oidb.D6D6ReqBody{DeleteFileReq: &oidb.DeleteFileReqBody{ + GroupCode: groupCode, + AppId: 3, + BusId: busId, + ParentFolderId: parentFolderId, + FileId: fileId, + }} + b, _ := proto.Marshal(body) + req := &oidb.OIDBSSOPkg{ + Command: 1750, + ServiceType: 3, + Bodybuffer: b, + ClientVersion: "android 8.4.8", + } + payload, _ := proto.Marshal(req) + packet := packets.BuildUniPacket(c.Uin, seq, "OidbSvc.0x6d6_3", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload) + return seq, packet +} + func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, error) { pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D8RspBody{} @@ -242,7 +273,7 @@ func decodeOIDB6d81Response(c *QQClient, _ uint16, payload []byte) (interface{}, } // OidbSvc.0x6d6_2 -func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { +func decodeOIDB6d62Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { pkg := oidb.OIDBSSOPkg{} rsp := oidb.D6D6RspBody{} if err := proto.Unmarshal(payload, &pkg); err != nil { @@ -258,3 +289,18 @@ func decodeOIDB6d6Response(_ *QQClient, _ uint16, payload []byte) (interface{}, url := hex.EncodeToString(rsp.DownloadFileRsp.DownloadUrl) return fmt.Sprintf("http://%s/ftn_handler/%s/", ip, url), nil } + +func decodeOIDB6d63Response(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { + pkg := oidb.OIDBSSOPkg{} + rsp := oidb.D6D6RspBody{} + if err := proto.Unmarshal(payload, &pkg); err != nil { + return nil, err + } + if err := proto.Unmarshal(pkg.Bodybuffer, &rsp); err != nil { + return nil, err + } + if rsp.DeleteFileRsp == nil { + return "", nil + } + return rsp.DeleteFileRsp.ClientWording, nil +} From a54d978fa9bea80c673945d86599ed4e9f29e86e Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Wed, 11 Nov 2020 22:05:26 +0800 Subject: [PATCH 04/14] fix private image upload error. --- client/client.go | 17 +++++++++++------ client/entities.go | 1 + 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/client/client.go b/client/client.go index bb2603a5..689c4425 100644 --- a/client/client.go +++ b/client/client.go @@ -641,18 +641,20 @@ func (c *QQClient) UploadPrivateImage(target int64, img []byte) (*message.Friend func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*message.FriendImageElement, error) { count++ h := md5.Sum(img) - e, err := c.QueryFriendImage(target, h[:], int32(len(img))) - if err != nil { + e, err := c.QueryFriendImage(target, h[:], img, int32(len(img))) + if err == ErrNotExists { // use group highway upload and query again for image id. if _, err = c.UploadGroupImage(target, img); err != nil { return nil, err } - // safe if count >= 5 { - return nil, errors.New("upload failed") + return e, nil } return c.uploadPrivateImage(target, img, count) } + if err != nil { + return nil, err + } return e, nil } @@ -689,7 +691,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New("image not exists") } -func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) { +func (c *QQClient) QueryFriendImage(target int64, hash, img []byte, size int32) (*message.FriendImageElement, error) { i, err := c.sendAndWait(c.buildOffPicUpPacket(target, hash, size)) if err != nil { return nil, err @@ -699,7 +701,10 @@ func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*mes return nil, errors.New(rsp.Message) } if !rsp.IsExists { - return nil, errors.New("image not exists") + return &message.FriendImageElement{ + ImageId: rsp.ResourceId, + Md5: hash, + }, ErrNotExists } return &message.FriendImageElement{ ImageId: rsp.ResourceId, diff --git a/client/entities.go b/client/entities.go index 172c6e83..d46743e1 100644 --- a/client/entities.go +++ b/client/entities.go @@ -11,6 +11,7 @@ import ( var ( ErrAlreadyOnline = errors.New("already online") ErrMemberNotFound = errors.New("member not found") + ErrNotExists = errors.New("not exists") ) type ( From 8b59d083ebeb64a387fc58f35144e95741dcc744 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Wed, 11 Nov 2020 22:10:37 +0800 Subject: [PATCH 05/14] fix param. --- client/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/client.go b/client/client.go index 689c4425..bf1e980f 100644 --- a/client/client.go +++ b/client/client.go @@ -641,7 +641,7 @@ func (c *QQClient) UploadPrivateImage(target int64, img []byte) (*message.Friend func (c *QQClient) uploadPrivateImage(target int64, img []byte, count int) (*message.FriendImageElement, error) { count++ h := md5.Sum(img) - e, err := c.QueryFriendImage(target, h[:], img, int32(len(img))) + e, err := c.QueryFriendImage(target, h[:], int32(len(img))) if err == ErrNotExists { // use group highway upload and query again for image id. if _, err = c.UploadGroupImage(target, img); err != nil { @@ -691,7 +691,7 @@ func (c *QQClient) QueryGroupImage(groupCode int64, hash []byte, size int32) (*m return nil, errors.New("image not exists") } -func (c *QQClient) QueryFriendImage(target int64, hash, img []byte, size int32) (*message.FriendImageElement, error) { +func (c *QQClient) QueryFriendImage(target int64, hash []byte, size int32) (*message.FriendImageElement, error) { i, err := c.sendAndWait(c.buildOffPicUpPacket(target, hash, size)) if err != nil { return nil, err From c41a3dbb0f4a7f2c976012c0561dba5d62ce9dcf Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Thu, 12 Nov 2020 20:51:00 +0800 Subject: [PATCH 06/14] fix connection. --- client/client.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/client/client.go b/client/client.go index d5e6d25d..9d15af8a 100644 --- a/client/client.go +++ b/client/client.go @@ -208,8 +208,7 @@ func (c *QQClient) Login() (*LoginResponse, error) { return nil, err } go c.netLoop() - seq, packet := c.buildLoginPacket() - rsp, err := c.sendAndWait(seq, packet) + rsp, err := c.sendAndWait(c.buildLoginPacket()) if err != nil { c.Disconnect() return nil, err @@ -226,6 +225,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er seq, packet := c.buildCaptchaPacket(result, sign) rsp, err := c.sendAndWait(seq, packet) if err != nil { + c.Disconnect() return nil, err } l := rsp.(LoginResponse) @@ -238,6 +238,7 @@ func (c *QQClient) SubmitCaptcha(result string, sign []byte) (*LoginResponse, er func (c *QQClient) SubmitSMS(code string) (*LoginResponse, error) { rsp, err := c.sendAndWait(c.buildSMSCodeSubmitPacket(code)) if err != nil { + c.Disconnect() return nil, err } l := rsp.(LoginResponse) @@ -1027,6 +1028,9 @@ func (c *QQClient) sendAndWait(seq uint16, pkt []byte) (interface{}, error) { } func (c *QQClient) netLoop() { + if c.NetLooping { + return + } c.NetLooping = true reader := binary.NewNetworkReader(c.Conn) retry := 0 @@ -1126,11 +1130,12 @@ func (c *QQClient) doHeartbeat() { sso := packets.BuildSsoPacket(seq, c.version.AppId, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid) packet := packets.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{}) _, err := c.sendAndWait(seq, packet) - if err != nil { - _ = c.Conn.Close() + if err == nil { + time.AfterFunc(30*time.Second, c.doHeartbeat) + return } - time.AfterFunc(30*time.Second, c.doHeartbeat) - return + c.lastLostMsg = "Heartbeat failed" + c.Disconnect() } c.heartbeatEnabled = false } From 58e7c82fd2ddbeb2344e788bd196dc6780686004 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Thu, 12 Nov 2020 23:01:30 +0800 Subject: [PATCH 07/14] feature: sso addr control. --- client/decoders.go | 14 +++++++++++--- client/events.go | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/client/decoders.go b/client/decoders.go index 525375c4..e427ef78 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -165,7 +165,7 @@ func decodeLoginResponse(c *QQClient, _ uint16, payload []byte) (interface{}, er } // StatSvc.register -func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interface{}, error) { +func decodeClientRegisterResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) data := &jce.RequestDataVersion2{} @@ -173,6 +173,9 @@ func decodeClientRegisterResponse(_ *QQClient, _ uint16, payload []byte) (interf svcRsp := &jce.SvcRespRegister{} svcRsp.ReadFrom(jce.NewJceReader(data.Map["SvcRespRegister"]["QQService.SvcRespRegister"][1:])) if svcRsp.Result != "" || svcRsp.Status != 11 { + if svcRsp.Result != "" { + c.Error("reg error: %v", svcRsp.Result) + } return nil, errors.New("reg failed") } return nil, nil @@ -221,12 +224,17 @@ func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, er Port: int(s.Port), }) } - c.SetCustomServer(adds) + f := true for _, e := range c.eventHandlers.serverUpdatedHandlers { cover(func() { - e(c, &ServerUpdatedEvent{Servers: servers}) + if !e(c, &ServerUpdatedEvent{Servers: servers}) { + f = false + } }) } + if !f { + c.SetCustomServer(adds) + } return nil, nil } } diff --git a/client/events.go b/client/events.go index 6f286e51..83a23c0d 100644 --- a/client/events.go +++ b/client/events.go @@ -25,7 +25,7 @@ type eventHandlers struct { newFriendHandlers []func(*QQClient, *NewFriendEvent) disconnectHandlers []func(*QQClient, *ClientDisconnectedEvent) logHandlers []func(*QQClient, *LogEvent) - serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) + serverUpdatedHandlers []func(*QQClient, *ServerUpdatedEvent) bool notifyHandlers []func(*QQClient, IGroupNotifyEvent) offlineFileHandlers []func(*QQClient, *OfflineFileEvent) groupMessageReceiptHandlers sync.Map @@ -107,7 +107,7 @@ func (c *QQClient) OnDisconnected(f func(*QQClient, *ClientDisconnectedEvent)) { c.eventHandlers.disconnectHandlers = append(c.eventHandlers.disconnectHandlers, f) } -func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent)) { +func (c *QQClient) OnServerUpdated(f func(*QQClient, *ServerUpdatedEvent) bool) { c.eventHandlers.serverUpdatedHandlers = append(c.eventHandlers.serverUpdatedHandlers, f) } From d36eb9abe7649e423259e8017550ce08c7bd8986 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 15:48:09 +0800 Subject: [PATCH 08/14] fix flag error. --- client/decoders.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/decoders.go b/client/decoders.go index e427ef78..1b1e89a2 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -232,7 +232,7 @@ func decodePushReqPacket(c *QQClient, _ uint16, payload []byte) (interface{}, er } }) } - if !f { + if f { c.SetCustomServer(adds) } return nil, nil From 9012263efea29c176332a1bb5d897b88fd229649 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 15:55:15 +0800 Subject: [PATCH 09/14] heartbeat failed message. --- client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/client.go b/client/client.go index 9d15af8a..f152c486 100644 --- a/client/client.go +++ b/client/client.go @@ -1134,7 +1134,7 @@ func (c *QQClient) doHeartbeat() { time.AfterFunc(30*time.Second, c.doHeartbeat) return } - c.lastLostMsg = "Heartbeat failed" + c.lastLostMsg = "Heartbeat failed: " + err.Error() c.Disconnect() } c.heartbeatEnabled = false From 13560ec838fdae9d7879f7017112bf1dcbf1f434 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 16:08:22 +0800 Subject: [PATCH 10/14] reg failed message. --- client/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/client.go b/client/client.go index f152c486..f14e9bf8 100644 --- a/client/client.go +++ b/client/client.go @@ -1044,10 +1044,10 @@ func (c *QQClient) netLoop() { break } reader = binary.NewNetworkReader(c.Conn) - if c.registerClient() != nil { + if e := c.registerClient(); e != nil { c.Disconnect() - c.lastLostMsg = "register client failed." - c.Error("reconnect failed: register client failed.") + c.lastLostMsg = "register client failed: " + e.Error() + c.Error("reconnect failed: " + e.Error()) break } } From b6a695d43d8e379c89c5b0e8852004122650d706 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 16:16:13 +0800 Subject: [PATCH 11/14] fix heartbeat loop. --- client/client.go | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/client/client.go b/client/client.go index f14e9bf8..e2fc7c00 100644 --- a/client/client.go +++ b/client/client.go @@ -253,7 +253,7 @@ func (c *QQClient) init() { _ = c.registerClient() c.groupSysMsgCache, _ = c.GetGroupSystemMessages() if !c.heartbeatEnabled { - c.startHeartbeat() + go c.doHeartbeat() } } @@ -1041,6 +1041,7 @@ func (c *QQClient) netLoop() { c.Error("connection dropped by server: %v", err) err = c.connect() if err != nil { + c.Error("connect server error: %v", err) break } reader = binary.NewNetworkReader(c.Conn) @@ -1119,23 +1120,19 @@ func (c *QQClient) netLoop() { c.dispatchDisconnectEvent(&ClientDisconnectedEvent{Message: c.lastLostMsg}) } -func (c *QQClient) startHeartbeat() { - c.heartbeatEnabled = true - time.AfterFunc(30*time.Second, c.doHeartbeat) -} - func (c *QQClient) doHeartbeat() { - if c.Online { + c.heartbeatEnabled = true + for c.Online { seq := c.nextSeq() sso := packets.BuildSsoPacket(seq, c.version.AppId, "Heartbeat.Alive", SystemDeviceInfo.IMEI, []byte{}, c.OutGoingPacketSessionId, []byte{}, c.ksid) packet := packets.BuildLoginPacket(c.Uin, 0, []byte{}, sso, []byte{}) _, err := c.sendAndWait(seq, packet) - if err == nil { - time.AfterFunc(30*time.Second, c.doHeartbeat) - return + if err != nil { + c.lastLostMsg = "Heartbeat failed: " + err.Error() + c.Disconnect() + break } - c.lastLostMsg = "Heartbeat failed: " + err.Error() - c.Disconnect() + time.Sleep(time.Second * 30) } c.heartbeatEnabled = false } From b17cee2e6dce02d8e64d1e7b296ae47da718e267 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 16:36:15 +0800 Subject: [PATCH 12/14] more host addr. --- client/client.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/client/client.go b/client/client.go index e2fc7c00..a75110a1 100644 --- a/client/client.go +++ b/client/client.go @@ -188,11 +188,14 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { } adds, err := net.LookupIP("msfwifi.3g.qq.com") // host servers if err == nil && len(adds) > 0 { - addr := &net.TCPAddr{ - IP: adds[0], - Port: 8080, + var hostAddrs []*net.TCPAddr + for _, addr := range adds { + hostAddrs = append(hostAddrs, &net.TCPAddr{ + IP: addr, + Port: 8080, + }) } - cli.servers = append([]*net.TCPAddr{addr}, cli.servers...) + cli.servers = append(hostAddrs, cli.servers...) } rand.Read(cli.RandomKey) return cli 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 13/14] 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, From c1739dba15c95d3f913dc8c84024c63fdbd4d146 Mon Sep 17 00:00:00 2001 From: Mrs4s <1844812067@qq.com> Date: Fri, 13 Nov 2020 19:38:25 +0800 Subject: [PATCH 14/14] feature ipad protocol & fix error image panic. --- client/entities.go | 2 +- client/global.go | 10 +++++----- client/notify.go | 2 +- message/message.go | 3 +++ 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/client/entities.go b/client/entities.go index d46743e1..ce2e6447 100644 --- a/client/entities.go +++ b/client/entities.go @@ -252,7 +252,7 @@ const ( Member AndroidPhone ClientProtocol = 1 - AndroidPad ClientProtocol = 2 + IPad ClientProtocol = 2 AndroidWatch ClientProtocol = 3 ) diff --git a/client/global.go b/client/global.go index 62e8c60b..c8870c59 100644 --- a/client/global.go +++ b/client/global.go @@ -106,7 +106,7 @@ var SystemDeviceInfo = &DeviceInfo{ IMEI: "468356291846738", AndroidId: []byte("MIRAI.123456.001"), APN: []byte("wifi"), - Protocol: AndroidPad, + Protocol: IPad, Version: &Version{ Incremental: []byte("5891938"), Release: []byte("10"), @@ -171,10 +171,10 @@ func genVersionInfo(p ClientProtocol) *versionInfo { SubSigmap: 0x10400, MainSigMap: 34869472, } - case AndroidPad: // Dumped from qq-hd v5.8.9 + case IPad: return &versionInfo{ ApkId: "com.tencent.minihd.qq", - AppId: 537065549, + AppId: 537065739, SortVersionName: "5.8.9", BuildTime: 1595836208, ApkSign: []byte{170, 57, 120, 244, 31, 217, 111, 249, 145, 74, 102, 158, 24, 100, 116, 199}, @@ -201,7 +201,7 @@ func (info *DeviceInfo) ToJson() []byte { IMEI: info.IMEI, Protocol: func() int { switch info.Protocol { - case AndroidPad: + case IPad: return 0 case AndroidPhone: return 1 @@ -238,7 +238,7 @@ func (info *DeviceInfo) ReadJson(d []byte) error { case 2: info.Protocol = AndroidWatch default: - info.Protocol = AndroidPad + info.Protocol = IPad } SystemDeviceInfo.GenNewGuid() SystemDeviceInfo.GenNewTgtgtKey() diff --git a/client/notify.go b/client/notify.go index bfa90359..c52c9206 100644 --- a/client/notify.go +++ b/client/notify.go @@ -33,7 +33,7 @@ type ( // grayTipProcessor 提取出来专门用于处理群内 notify tips func (c *QQClient) grayTipProcessor(groupId int64, tipInfo *notify.GeneralGrayTipInfo) { switch tipInfo.TemplId { - case 10043, 1136: // 戳一戳 + case 10043, 1136, 1132: // 戳一戳 var sender int64 = 0 receiver := c.Uin for _, templ := range tipInfo.MsgTemplParam { diff --git a/message/message.go b/message/message.go index 00392a9a..f21bbd6f 100644 --- a/message/message.go +++ b/message/message.go @@ -432,6 +432,9 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement { } } if elem.CustomFace != nil { + if len(elem.CustomFace.Md5) == 0 { + continue + } res = append(res, &ImageElement{ Filename: elem.CustomFace.FilePath, Size: elem.CustomFace.Size,