diff --git a/binary/jce/structs.go b/binary/jce/structs.go index 77905475..30e648e7 100644 --- a/binary/jce/structs.go +++ b/binary/jce/structs.go @@ -101,6 +101,30 @@ type ( ServiceType int32 `jceId:"4"` } + SvcReqGetDevLoginInfo struct { + IJceStruct + Guid []byte `jceId:"0"` + AppName string `jceId:"1"` + LoginType int64 `jceId:"2"` + Timestamp int64 `jceId:"3"` + NextItemIndex int64 `jceId:"4"` + RequireMax int64 `jceId:"5"` + GetDevListType int64 `jceId:"6"` // 1: getLoginDevList 2: getRecentLoginDevList 4: getAuthLoginDevList + } + + SvcDevLoginInfo struct { + AppId int64 + Guid []byte + LoginTime int64 + LoginPlatform int64 + LoginLocation string + DeviceName string + DeviceTypeInfo string + TerType int64 + ProductType int64 + CanBeKicked int64 + } + DelMsgInfo struct { IJceStruct FromUin int64 `jceId:"0"` @@ -473,6 +497,20 @@ func (pkt *PushMessageInfo) ReadFrom(r *JceReader) { pkt.FromName = r.ReadString(17) } +func (pkt *SvcDevLoginInfo) ReadFrom(r *JceReader) { + pkt.AppId = r.ReadInt64(0) + pkt.Guid = []byte{} + r.ReadSlice(&pkt.Guid, 1) + pkt.LoginTime = r.ReadInt64(2) + pkt.LoginPlatform = r.ReadInt64(3) + pkt.LoginLocation = r.ReadString(4) + pkt.DeviceName = r.ReadString(5) + pkt.DeviceTypeInfo = r.ReadString(6) + pkt.TerType = r.ReadInt64(8) + pkt.ProductType = r.ReadInt64(9) + pkt.CanBeKicked = r.ReadInt64(10) +} + func (pkt *SvcRespPushMsg) ToBytes() []byte { w := NewJceWriter() w.WriteJceStructRaw(pkt) @@ -484,3 +522,9 @@ func (pkt *ModifyGroupCardRequest) ToBytes() []byte { w.WriteJceStructRaw(pkt) return w.Bytes() } + +func (pkt *SvcReqGetDevLoginInfo) ToBytes() []byte { + w := NewJceWriter() + w.WriteJceStructRaw(pkt) + return w.Bytes() +} diff --git a/client/builders.go b/client/builders.go index 7bad83b0..b72c75a6 100644 --- a/client/builders.go +++ b/client/builders.go @@ -116,6 +116,7 @@ func (c *QQClient) buildCaptchaPacket(result string, sign []byte) (uint16, []byt req := packets.BuildOicqRequestPacket(c.Uin, 0x810, crypto.ECDH, c.RandomKey, func(w *binary.Writer) { w.WriteUInt16(2) // sub command w.WriteUInt16(4) + w.Write(tlv.T2(result, sign)) w.Write(tlv.T8(2052)) w.Write(tlv.T104(c.t104)) @@ -196,6 +197,29 @@ func (c *QQClient) buildConfPushRespPacket(t int32, pktSeq int64, jceBuf []byte) return seq, packet } +// StatSvc.GetDevLoginInfo +func (c *QQClient) buildDeviceListRequestPacket() (uint16, []byte) { + seq := c.nextSeq() + req := &jce.SvcReqGetDevLoginInfo{ + Guid: SystemDeviceInfo.Guid, + LoginType: 1, + AppName: "com.tencent.mobileqq", + RequireMax: 20, + GetDevListType: 2, + } + buf := &jce.RequestDataVersion3{Map: map[string][]byte{"SvcReqGetDevLoginInfo": packRequestDataV3(req.ToBytes())}} + pkt := &jce.RequestPacket{ + IVersion: 3, + SServantName: "StatSvc", + SFuncName: "SvcReqGetDevLoginInfo", + SBuffer: buf.ToBytes(), + Context: make(map[string]string), + Status: make(map[string]string), + } + packet := packets.BuildUniPacket(c.Uin, seq, "StatSvc.GetDevLoginInfo", 1, c.OutGoingPacketSessionId, []byte{}, c.sigInfo.d2Key, pkt.ToBytes()) + return seq, packet +} + // friendlist.getFriendGroupList func (c *QQClient) buildFriendGroupListRequestPacket(friendStartIndex, friendListCount, groupStartIndex, groupListCount int16) (uint16, []byte) { seq := c.nextSeq() diff --git a/client/client.go b/client/client.go index d29e5de9..4f98c393 100644 --- a/client/client.go +++ b/client/client.go @@ -89,6 +89,8 @@ type loginSigInfo struct { tgt []byte tgtKey []byte + srmToken []byte // study room manager | 0x16a + t133 []byte userStKey []byte userStWebSig []byte sKey []byte @@ -121,6 +123,7 @@ func NewClientMd5(uin int64, passwordMd5 [16]byte) *QQClient { "wtlogin.login": decodeLoginResponse, // 登录操作包 "StatSvc.register": decodeClientRegisterResponse, // 客户端注册包 "StatSvc.ReqMSFOffline": decodeMSFOfflinePacket, // 强制离线 + "StatSvc.GetDevLoginInfo": decodeDevListResponse, // 设备列表请求包 "MessageSvc.PushNotify": decodeSvcNotify, // 好友消息通知包 "OnlinePush.PbPushGroupMsg": decodeGroupMessagePacket, // 群消息通知包 "OnlinePush.ReqPush": decodeOnlinePushReqPacket, // 群组相关事件包 diff --git a/client/decoders.go b/client/decoders.go index 3458c177..5d7df156 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -332,6 +332,18 @@ func decodeSvcNotify(c *QQClient, _ uint16, _ []byte) (interface{}, error) { return nil, err } +func decodeDevListResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { + request := &jce.RequestPacket{} + request.ReadFrom(jce.NewJceReader(payload)) + data := &jce.RequestDataVersion2{} + data.ReadFrom(jce.NewJceReader(request.SBuffer)) + rsp := jce.NewJceReader(data.Map["SvcRspGetDevLoginInfo"]["QQService.SvcRspGetDevLoginInfo"][1:]) + d := []jce.SvcDevLoginInfo{} + ret := rsp.ReadInt64(3) + rsp.ReadSlice(&d, 5) + return ret, nil +} + func decodeSummaryCardResponse(c *QQClient, _ uint16, payload []byte) (interface{}, error) { request := &jce.RequestPacket{} request.ReadFrom(jce.NewJceReader(payload)) diff --git a/client/tlv_decoders.go b/client/tlv_decoders.go index 1671af56..dea1858f 100644 --- a/client/tlv_decoders.go +++ b/client/tlv_decoders.go @@ -81,6 +81,8 @@ func (c *QQClient) decodeT119(data []byte) { c.sigInfo = &loginSigInfo{ loginBitmap: 0, + srmToken: m[0x16a], + t133: m[0x133], tgt: m[0x10a], tgtKey: m[0x10d], userStKey: m[0x10e], diff --git a/protocol/crypto/crypto.go b/protocol/crypto/crypto.go index 335198eb..c3d17086 100644 --- a/protocol/crypto/crypto.go +++ b/protocol/crypto/crypto.go @@ -12,6 +12,10 @@ type EncryptECDH struct { PublicKey []byte } +type EncryptSession struct { + T133 []byte +} + var ECDH = &EncryptECDH{} var tenKeyX = new(big.Int).SetBytes([]byte{ // pubkey[1:24] @@ -56,3 +60,22 @@ func (e *EncryptECDH) DoEncrypt(d, k []byte) []byte { func (e *EncryptECDH) Id() byte { return 7 } + +func NewEncryptSession(t133 []byte) *EncryptSession { + return &EncryptSession{T133: t133} +} + +func (e *EncryptSession) DoEncrypt(d, k []byte) []byte { + return binary.NewWriterF(func(w *binary.Writer) { + w.WriteByte(0x01) + w.WriteByte(0x03) + w.Write(k) + w.WriteUInt16(258) + w.WriteUInt16(0) + w.EncryptAndWrite(k, d) + }) +} + +func (e *EncryptSession) Id() byte { + return 69 +} diff --git a/protocol/crypto/ecdh.go b/protocol/crypto/ecdh.go deleted file mode 100644 index 5871506e..00000000 --- a/protocol/crypto/ecdh.go +++ /dev/null @@ -1 +0,0 @@ -package crypto diff --git a/protocol/tlv/t108.go b/protocol/tlv/t108.go new file mode 100644 index 00000000..dbf1679f --- /dev/null +++ b/protocol/tlv/t108.go @@ -0,0 +1,10 @@ +package tlv + +import "github.com/Mrs4s/MiraiGo/binary" + +func T108(arr []byte) []byte { + return binary.NewWriterF(func(w *binary.Writer) { + w.WriteUInt16(0x108) + w.WriteTlv(arr) + }) +} diff --git a/protocol/tlv/t10a.go b/protocol/tlv/t10a.go new file mode 100644 index 00000000..482adb01 --- /dev/null +++ b/protocol/tlv/t10a.go @@ -0,0 +1,10 @@ +package tlv + +import "github.com/Mrs4s/MiraiGo/binary" + +func T10A(arr []byte) []byte { + return binary.NewWriterF(func(w *binary.Writer) { + w.WriteUInt16(0x10A) + w.WriteTlv(arr) + }) +} diff --git a/protocol/tlv/t143.go b/protocol/tlv/t143.go new file mode 100644 index 00000000..8ce9b624 --- /dev/null +++ b/protocol/tlv/t143.go @@ -0,0 +1,10 @@ +package tlv + +import "github.com/Mrs4s/MiraiGo/binary" + +func T143(arr []byte) []byte { + return binary.NewWriterF(func(w *binary.Writer) { + w.WriteUInt16(0x143) + w.WriteTlv(arr) + }) +} diff --git a/protocol/tlv/t16a.go b/protocol/tlv/t16a.go new file mode 100644 index 00000000..27a23690 --- /dev/null +++ b/protocol/tlv/t16a.go @@ -0,0 +1,10 @@ +package tlv + +import "github.com/Mrs4s/MiraiGo/binary" + +func T16A(arr []byte) []byte { + return binary.NewWriterF(func(w *binary.Writer) { + w.WriteUInt16(0x16A) + w.WriteTlv(arr) + }) +}