diff --git a/.github/workflows/test_and_lint.yml b/.github/workflows/test_and_lint.yml index 6a0f8d16..2720847c 100644 --- a/.github/workflows/test_and_lint.yml +++ b/.github/workflows/test_and_lint.yml @@ -19,7 +19,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: '1.19' + go-version: '1.20' cache: false - run: go get - run: go generate ./... @@ -34,7 +34,7 @@ jobs: uses: actions/setup-go@v5 with: cache: false - go-version: '1.19' + go-version: '1.20' - run: go get - run: go generate ./... - name: Go vet diff --git a/.gitignore b/.gitignore index 8b01fd6b..5041f303 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,6 @@ fabric.properties # Go workspace file go.work +# Running stub +sig.bin +qrcode.png diff --git a/client/client.go b/client/client.go index 4bb549eb..f92e6fff 100644 --- a/client/client.go +++ b/client/client.go @@ -12,6 +12,7 @@ import ( "github.com/LagrangeDev/LagrangeGo/packets/tlv" + "github.com/LagrangeDev/LagrangeGo/utils/binary" binary2 "github.com/LagrangeDev/LagrangeGo/utils/binary" "github.com/LagrangeDev/LagrangeGo/utils" @@ -81,11 +82,11 @@ func (c *QQClient) Login(password, qrcodePath string) (bool, error) { } func (c *QQClient) FecthQrcode() ([]byte, string, error) { - body := utils.NewPacketBuilder(nil). + body := binary2.NewBuilder(nil). WriteU16(0). WriteU64(0). WriteU8(0). - WriteTlv([][]byte{ + WritePacketTlv( tlv.T16(c.appInfo.AppID, c.appInfo.SubAppID, utils.MustParseHexStr(c.deviceInfo.Guid), c.appInfo.PTVersion, c.appInfo.PackageName), tlv.T1b(), @@ -94,7 +95,7 @@ func (c *QQClient) FecthQrcode() ([]byte, string, error) { tlv.T35(c.appInfo.PTOSVersion), tlv.T66(c.appInfo.PTOSVersion), tlv.Td1(c.appInfo.OS, c.deviceInfo.DeviceName), - }).WriteU8(3).Pack(-1) + ).WriteU8(3).Pack(binary.PackTypeNone) packet := wtlogin.BuildCode2dPacket(c.Uin, 0x31, c.appInfo, body) response, err := c.SendUniPacketAndAwait("wtlogin.trans_emp", packet) @@ -114,7 +115,7 @@ func (c *QQClient) FecthQrcode() ([]byte, string, error) { // 这样是不对的,调试后发现应该丢一个字节,然后读下一个字节才是数据的大小 // string(binary2.NewReader(tlvs[209]).ReadBytesWithLength("u16", true)) urlreader.ReadU8() - return tlvs[0x17], string(urlreader.ReadBytesWithLength("u8", false)), nil + return tlvs[0x17], utils.B2S(urlreader.ReadBytesWithLength("u8", false)), nil } return nil, "", fmt.Errorf("err qr retcode %d", retCode) @@ -126,12 +127,12 @@ func (c *QQClient) GetQrcodeResult() (qrcodeState.State, error) { return -1, errors.New("no qrsig found, execute fetch_qrcode first") } - body := utils.NewPacketBuilder(nil). - WriteBytes(c.sig.Qrsig, "u16", false). + body := binary2.NewBuilder(nil). + WritePacketBytes(c.sig.Qrsig, "u16", false). WriteU64(0). WriteU32(0). WriteU8(0). - WriteU8(0x83).Pack(-1) + WriteU8(0x83).Pack(binary.PackTypeNone) response, err := c.SendUniPacketAndAwait("wtlogin.trans_emp", wtlogin.BuildCode2dPacket(0, 0x12, c.appInfo, body)) @@ -172,7 +173,7 @@ func (c *QQClient) KeyExchange() { } func (c *QQClient) PasswordLogin(password string) (loginState.State, error) { - md5Password := utils.MD5Digest([]byte(password)) + md5Password := utils.MD5Digest(utils.S2B(password)) cr := tlv.T106( c.appInfo.AppID, @@ -226,25 +227,25 @@ func (c *QQClient) QrcodeLogin(refreshInterval int) (bool, error) { app := c.appInfo device := c.deviceInfo - body := utils.NewPacketBuilder(nil). + body := binary2.NewBuilder(nil). WriteU16(0x09). - WriteTlv([][]byte{ - utils.NewPacketBuilder(nil).WriteBytes(c.t106, "", true).Pack(0x106), + WritePacketTlv( + binary2.NewBuilder(nil).WritePacketBytes(c.t106, "", true).Pack(0x106), tlv.T144(c.sig.Tgtgt, app, device), tlv.T116(app.SubSigmap), tlv.T142(app.PackageName, 0), tlv.T145(utils.MustParseHexStr(device.Guid)), tlv.T18(0, app.AppClientVersion, int(c.Uin), 0, 5, 0), - tlv.T141([]byte("Unknown"), make([]byte, 0)), + tlv.T141([]byte("Unknown"), nil), tlv.T177(app.WTLoginSDK, 0), tlv.T191(0), tlv.T100(5, app.AppID, app.SubAppID, 8001, app.MainSigmap, 0), tlv.T107(1, 0x0d, 0, 1), - tlv.T318(make([]byte, 0)), - utils.NewPacketBuilder(nil).WriteBytes(c.t16a, "", true).Pack(0x16a), + tlv.T318(nil), + binary2.NewBuilder(nil).WritePacketBytes(c.t16a, "", true).Pack(0x16a), tlv.T166(5), tlv.T521(0x13, "basicim"), - }).Pack(-1) + ).Pack(binary.PackTypeNone) response, err := c.SendUniPacketAndAwait( "wtlogin.login", diff --git a/client/listener.go b/client/listener.go index 73662750..a185410a 100644 --- a/client/listener.go +++ b/client/listener.go @@ -10,6 +10,7 @@ import ( msgConverter "github.com/LagrangeDev/LagrangeGo/message" "github.com/LagrangeDev/LagrangeGo/packets/pb/message" "github.com/LagrangeDev/LagrangeGo/packets/wtlogin" + "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/binary" ) @@ -63,7 +64,7 @@ func decodeOlPushServicePacket(c *QQClient, pkt *wtlogin.SSOPacket) (any, error) if err != nil { return nil, err } - pb.Operator = []byte(Operator.OperatorField1.OperatorUid) + pb.Operator = utils.S2B(Operator.OperatorField1.OperatorUid) } return eventConverter.ParseMemberDecreaseEvent(&pb), nil case 84: // group request join notice diff --git a/event/group.go b/event/group.go index cbc16095..28249253 100644 --- a/event/group.go +++ b/event/group.go @@ -2,6 +2,7 @@ package event import ( "github.com/LagrangeDev/LagrangeGo/packets/pb/message" + "github.com/LagrangeDev/LagrangeGo/utils" ) type ( @@ -96,7 +97,7 @@ func ParseMemberIncreaseEvent(event *message.GroupChange) *GroupMemberIncrease { GroupUin: event.GroupUin, }, MemberUid: event.MemberUid, - InvitorUid: string(event.Operator), + InvitorUid: utils.B2S(event.Operator), JoinType: event.IncreaseType, } } @@ -107,7 +108,7 @@ func ParseMemberDecreaseEvent(event *message.GroupChange) *GroupMemberDecrease { GroupUin: event.GroupUin, }, MemberUid: event.MemberUid, - OperatorUid: string(event.Operator), + OperatorUid: utils.B2S(event.Operator), ExitType: event.DecreaseType, } } diff --git a/go.mod b/go.mod index 4b4f965d..19f8b114 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/LagrangeDev/LagrangeGo -go 1.19 +go 1.20 require ( github.com/RomiChan/protobuf v0.1.1-0.20230204044148-2ed269a2e54d diff --git a/info/device.go b/info/device.go index f8d3d2b7..21311adf 100644 --- a/info/device.go +++ b/info/device.go @@ -18,8 +18,8 @@ type DeviceInfo struct { func NewDeviceInfo(uin int) *DeviceInfo { return &DeviceInfo{ - Guid: fmt.Sprintf("%X", utils.MD5Digest([]byte(strconv.Itoa(uin)))), - DeviceName: fmt.Sprintf("Lagrange-%X", utils.MD5Digest([]byte(strconv.Itoa(uin)))[0:4]), + Guid: fmt.Sprintf("%X", utils.MD5Digest(utils.S2B(strconv.Itoa(uin)))), + DeviceName: fmt.Sprintf("Lagrange-%X", utils.MD5Digest(utils.S2B(strconv.Itoa(uin)))[0:4]), SystemKernel: fmt.Sprintf("%s %s", platform.GetSystem(), platform.GetVersion()), KernelVersion: platform.GetVersion(), } diff --git a/info/serialize.go b/info/serialize.go index 74e7eb95..928a4c62 100644 --- a/info/serialize.go +++ b/info/serialize.go @@ -27,7 +27,7 @@ func Encode(sig *SigInfo) []byte { return binary.NewBuilder(nil). WriteBytes(dataHash, true). WriteBytes(buffer.Bytes(), true). - Pack(-1) + Pack(binary.PackTypeNone) } func Decode(buf []byte, verify bool) *SigInfo { @@ -35,7 +35,7 @@ func Decode(buf []byte, verify bool) *SigInfo { dataHash := reader.ReadBytesWithLength("u16", false) data := reader.ReadBytesWithLength("u16", false) - if verify && string(dataHash) != string(utils.MD5Digest(data)) { + if verify && !bytes.Equal(dataHash, utils.MD5Digest(data)) { panic("Data hash does not match") } buffer := bytes.NewBuffer(data) diff --git a/info/sig.go b/info/sig.go index bb0f7693..30ea213d 100644 --- a/info/sig.go +++ b/info/sig.go @@ -23,18 +23,7 @@ type SigInfo struct { func NewSigInfo(seq int) *SigInfo { return &SigInfo{ - Uid: "", - Sequence: seq, - Tgtgt: make([]byte, 0), - Tgt: make([]byte, 0), - D2: make([]byte, 0), - D2Key: make([]byte, 16), - Qrsig: make([]byte, 0), - ExchangeKey: make([]byte, 0), - KeySig: make([]byte, 0), - Cookies: "", - UnusualSig: make([]byte, 0), - TempPwd: make([]byte, 0), - CaptchaInfo: [3]string{"", "", ""}, + Sequence: seq, + D2Key: make([]byte, 16), } } diff --git a/main.go b/main.go index 81f749c1..997aee2d 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,11 @@ package main import ( "fmt" - "github.com/LagrangeDev/LagrangeGo/message" "os" "github.com/LagrangeDev/LagrangeGo/client" "github.com/LagrangeDev/LagrangeGo/info" + "github.com/LagrangeDev/LagrangeGo/message" ) func main() { @@ -23,7 +23,7 @@ func main() { qqclient.GroupMessageEvent.Subscribe(func(client *client.QQClient, event *message.GroupMessage) { if event.ToString() == "114514" { - img, _ := os.ReadFile("/Users/wenxuanlin/Desktop/2373259535.png") + img, _ := os.ReadFile("./testgroup.png") _, err := client.SendGroupMessage(event.GroupCode, []message.IMessageElement{&message.GroupImageElement{Stream: img}}) if err != nil { return @@ -32,7 +32,7 @@ func main() { }) qqclient.PrivateMessageEvent.Subscribe(func(client *client.QQClient, event *message.PrivateMessage) { - img, _ := os.ReadFile("/Users/wenxuanlin/Desktop/2373259535.png") + img, _ := os.ReadFile("testprivate.png") _, err := client.SendPrivateMessage(event.Sender.Uin, []message.IMessageElement{&message.FriendImageElement{Stream: img}}) if err != nil { return diff --git a/message/message.go b/message/message.go index 8c41b267..758fc332 100644 --- a/message/message.go +++ b/message/message.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/LagrangeDev/LagrangeGo/packets/pb/message" + "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/binary" "github.com/LagrangeDev/LagrangeGo/utils/proto" ) @@ -195,7 +196,7 @@ func parseMessageElements(msg []*message.Elem) []IMessageElement { return []IMessageElement{ &ShortVideoElement{ Name: elem.VideoFile.FileName, - Uuid: []byte(elem.VideoFile.FileUuid), + Uuid: utils.S2B(elem.VideoFile.FileUuid), Size: elem.VideoFile.FileSize, ThumbSize: elem.VideoFile.ThumbFileSize, Md5: elem.VideoFile.FileMd5, diff --git a/packets/tlv/common.go b/packets/tlv/common.go index fe1b1664..263ef9a1 100644 --- a/packets/tlv/common.go +++ b/packets/tlv/common.go @@ -5,12 +5,13 @@ import ( "github.com/LagrangeDev/LagrangeGo/info" "github.com/LagrangeDev/LagrangeGo/utils" + "github.com/LagrangeDev/LagrangeGo/utils/binary" "github.com/LagrangeDev/LagrangeGo/utils/crypto" ) // T18 默认参数 pingVersion, unknown = 0, ssoVersion = 5 func T18(appID, appClientVersion, uin, pingVersion, ssoVersion, unknown int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU16(uint16(pingVersion)). WriteU32(uint32(ssoVersion)). WriteU32(uint32(appID)). @@ -22,7 +23,7 @@ func T18(appID, appClientVersion, uin, pingVersion, ssoVersion, unknown int) []b // T100 dbBufVer 默认为 0 func T100(ssoVersion, appID, subAppID, appClientVersion, sigmap, dbBufVer int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU16(uint16(dbBufVer)). WriteU32(uint32(ssoVersion)). WriteU32(uint32(appID)). @@ -36,9 +37,9 @@ func T100(ssoVersion, appID, subAppID, appClientVersion, sigmap, dbBufVer int) [ func T106(appId, appClientVersion, uin int, guid string, passwordMd5, tgtgtKey, ip []byte, savePassword bool) []byte { // password_md5 + bytes(4) + write_u32(uin).pack() key := utils.MD5Digest(append(passwordMd5, append(make([]byte, 4), - utils.NewPacketBuilder(nil).WriteU32(uint32(uin)).Pack(-1)...)...)) + binary.NewBuilder(nil).WriteU32(uint32(uin)).Pack(binary.PackTypeNone)...)...)) - body := utils.NewPacketBuilder(nil). + body := binary.NewBuilder(nil). WriteStruct(uint16(4), // tgtgt version utils.RandU32(), uint32(0), // sso_version, depreciated @@ -46,26 +47,26 @@ func T106(appId, appClientVersion, uin int, guid string, passwordMd5, tgtgtKey, uint32(appClientVersion), uint64(uin)). WriteU32(uint32(utils.TimeStamp())). - WriteBytes(ip, "", true). + WritePacketBytes(ip, "", true). WriteBool(savePassword). - WriteBytes(passwordMd5, "", true). - WriteBytes(tgtgtKey, "", true). + WritePacketBytes(passwordMd5, "", true). + WritePacketBytes(tgtgtKey, "", true). WriteU32(0). WriteBool(true). - WriteBytes(utils.MustParseHexStr(guid), "", true). + WritePacketBytes(utils.MustParseHexStr(guid), "", true). WriteU32(0). WriteU32(1). - WriteString(strconv.Itoa(uin), "u16", false). - Pack(-1) + WritePacketString(strconv.Itoa(uin), "u16", false). + Pack(binary.PackTypeNone) - return utils.NewPacketBuilder(nil). - WriteBytes(crypto.NewTeaCipher(key).Encrypt(body), "u32", true). + return binary.NewBuilder(nil). + WritePacketBytes(crypto.NewTeaCipher(key).Encrypt(body), "u32", true). Pack(0x106) } // T107 默认参数为 1, 0x0d, 0, 1 func T107(picType, capType, picSize, retType int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU16(uint16(picType)). WriteU8(uint8(capType)). WriteU16(uint16(picSize)). @@ -74,7 +75,7 @@ func T107(picType, capType, picSize, retType int) []byte { } func T116(subSigmap int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU8(0). WriteU32(12058620). // unknown? WriteU32(uint32(subSigmap)). @@ -83,110 +84,110 @@ func T116(subSigmap int) []byte { } func T124() []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(make([]byte, 12), "", true). + return binary.NewBuilder(nil). + WritePacketBytes(make([]byte, 12), "", true). Pack(0x124) } func T128(appInfoOS string, deviceGuid []byte) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU16(0). WriteU8(0). WriteU8(1). WriteU8(0). WriteU32(0). - WriteString(appInfoOS, "u16", false). - WriteBytes(deviceGuid, "u16", false). - WriteString("", "u16", false). + WritePacketString(appInfoOS, "u16", false). + WritePacketBytes(deviceGuid, "u16", false). + WritePacketString("", "u16", false). Pack(0x128) } // T141 默认参数 apn = []byte{0} func T141(simInfo, apn []byte) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(simInfo, "u32", false). - WriteBytes(apn, "u32", false). + return binary.NewBuilder(nil). + WritePacketBytes(simInfo, "u32", false). + WritePacketBytes(apn, "u32", false). Pack(0x141) } // T142 默认参数 version = 0 注意apkID长度要过32 func T142(apkID string, version int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU16(uint16(version)). - // WriteString(apkID[:32], "u16", false). + // WritePacketString(apkID[:32], "u16", false). // apkID长度没有32,不动了 - WriteString(apkID, "u16", false). + WritePacketString(apkID, "u16", false). Pack(0x142) } func T144(tgtgtKey []byte, appInfo *info.AppInfo, device *info.DeviceInfo) []byte { - return utils.NewPacketBuilder(tgtgtKey). - WriteTlv([][]byte{ + return binary.NewBuilder(tgtgtKey). + WritePacketTlv( T16e(device.DeviceName), T147(appInfo.AppID, appInfo.PTVersion, appInfo.PackageName), T128(appInfo.OS, utils.MustParseHexStr(device.Guid)), T124(), - }).Pack(0x144) + ).Pack(0x144) } func T145(guid []byte) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(guid, "", true). + return binary.NewBuilder(nil). + WritePacketBytes(guid, "", true). Pack(0x145) } func T147(appId int, ptVersion string, packageName string) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU32(uint32(appId)). - WriteString(ptVersion, "u16", false). - WriteString(packageName, "u16", false). + WritePacketString(ptVersion, "u16", false). + WritePacketString(packageName, "u16", false). Pack(0x147) } func T166(imageType int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteI8(int8(imageType)). Pack(0x166) } func T16a(noPicSig []byte) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(noPicSig, "", true). + return binary.NewBuilder(nil). + WritePacketBytes(noPicSig, "", true). Pack(0x16a) } func T16e(deviceName string) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes([]byte(deviceName), "", true). + return binary.NewBuilder(nil). + WritePacketBytes(utils.S2B(deviceName), "", true). Pack(0x16e) } // T177 默认参数 buildTime=0 func T177(sdkVersion string, buildTime int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteStruct(uint8(1), uint32(buildTime)). - WriteString(sdkVersion, "u16", false). + WritePacketString(sdkVersion, "u16", false). Pack(0x177) } // T191 默认参数 canWebVerify=0 func T191(canWebVerify int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU8(uint8(canWebVerify)). Pack(0x191) } // T318 默认参数 tgtQr = []byte{0} func T318(tgtQr []byte) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(tgtQr, "", true). + return binary.NewBuilder(nil). + WritePacketBytes(tgtQr, "", true). Pack(0x318) } // T521 默认参数 0x13, "basicim" func T521(productType int, productDesc string) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU32(uint32(productType)). - WriteString(productDesc, "u16", false). + WritePacketString(productDesc, "u16", false). Pack(0x521) } diff --git a/packets/tlv/qrcode.go b/packets/tlv/qrcode.go index b1193368..aedfce50 100644 --- a/packets/tlv/qrcode.go +++ b/packets/tlv/qrcode.go @@ -1,36 +1,36 @@ package tlv import ( - "github.com/LagrangeDev/LagrangeGo/utils" + "github.com/LagrangeDev/LagrangeGo/utils/binary" "github.com/LagrangeDev/LagrangeGo/utils/proto" ) func T11(unusualSign []byte) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(unusualSign, "", true). + return binary.NewBuilder(nil). + WritePacketBytes(unusualSign, "", true). Pack(0x11) } func T16(appid, subAppid int, guid []byte, ptVersion, packageName string) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU32(0). WriteU32(uint32(appid)). WriteU32(uint32(subAppid)). - WriteBytes(guid, "", true). - WriteString(packageName, "u16", false). - WriteString(ptVersion, "u16", false). - WriteString(packageName, "u16", false). + WritePacketBytes(guid, "", true). + WritePacketString(packageName, "u16", false). + WritePacketString(ptVersion, "u16", false). + WritePacketString(packageName, "u16", false). Pack(0x16) } func T1b() []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteStruct(uint32(0), uint32(0), uint32(3), uint32(4), uint32(72), uint32(2), uint32(2), uint16(0)). Pack(0x1B) } func T1d(miscBitmap int) []byte { - return utils.NewPacketBuilder(nil). + return binary.NewBuilder(nil). WriteU8(1). WriteU32(uint32(miscBitmap)). WriteU32(0). @@ -39,20 +39,20 @@ func T1d(miscBitmap int) []byte { } func T33(guid []byte) []byte { - return utils.NewPacketBuilder(nil).WriteBytes(guid, "", true).Pack(0x33) + return binary.NewBuilder(nil).WritePacketBytes(guid, "", true).Pack(0x33) } func T35(PtOSVersion int) []byte { - return utils.NewPacketBuilder(nil).WriteU32(uint32(PtOSVersion)).Pack(0x35) + return binary.NewBuilder(nil).WriteU32(uint32(PtOSVersion)).Pack(0x35) } func T66(PtOSVersion int) []byte { - return utils.NewPacketBuilder(nil).WriteU32(uint32(PtOSVersion)).Pack(0x66) + return binary.NewBuilder(nil).WriteU32(uint32(PtOSVersion)).Pack(0x66) } func Td1(AppOS, DeviceName string) []byte { - return utils.NewPacketBuilder(nil). - WriteBytes(proto.DynamicMessage{ + return binary.NewBuilder(nil). + WritePacketBytes(proto.DynamicMessage{ 1: proto.DynamicMessage{ 1: AppOS, 2: DeviceName, diff --git a/packets/wtlogin/exchange.go b/packets/wtlogin/exchange.go index 8f9a034b..9fcfb979 100644 --- a/packets/wtlogin/exchange.go +++ b/packets/wtlogin/exchange.go @@ -30,7 +30,7 @@ func BuildKexExchangeRequest(uin uint32, guid string) []byte { WriteBytes(encl, false). WriteU32(0). WriteU32(uint32(utils.TimeStamp())). - Pack(-1) + Pack(binary.PackTypeNone) p2Hash := utils.SHA256Digest(p2) encP2Hash := crypto.AesGCMEncrypt(p2Hash, encKey) diff --git a/packets/wtlogin/oicq.go b/packets/wtlogin/oicq.go index 67638472..b22f7dcc 100644 --- a/packets/wtlogin/oicq.go +++ b/packets/wtlogin/oicq.go @@ -25,23 +25,23 @@ func BuildCode2dPacket(uin uint32, cmdID int, appInfo *info.AppInfo, body []byte uin, "wtlogin.trans_emp", appInfo, - utils.NewPacketBuilder(nil). + binary.NewBuilder(nil). WriteU8(0). WriteU16(uint16(len(body))+53). WriteU32(uint32(appInfo.AppID)). WriteU32(0x72). - WriteBytes(make([]byte, 3), "", true). + WritePacketBytes(make([]byte, 3), "", true). WriteU32(uint32(utils.TimeStamp())). WriteU8(2). WriteU16(uint16(len(body)+49)). WriteU16(uint16(cmdID)). - WriteBytes(make([]byte, 21), "", true). + WritePacketBytes(make([]byte, 21), "", true). WriteU8(3). WriteU32(50). - WriteBytes(make([]byte, 14), "", true). + WritePacketBytes(make([]byte, 14), "", true). WriteU32(uint32(appInfo.AppID)). - WriteBytes(body, "", true). - Pack(-1), + WritePacketBytes(body, "", true). + Pack(binary.PackTypeNone), ) } @@ -55,7 +55,7 @@ func BuildLoginPacket(uin uint32, cmd string, appinfo *info.AppInfo, body []byte _cmd = 2066 } - frameBody := utils.NewPacketBuilder(nil). + frameBody := binary.NewBuilder(nil). WriteU16(8001). WriteU16(_cmd). WriteU16(0). @@ -69,19 +69,19 @@ func BuildLoginPacket(uin uint32, cmd string, appinfo *info.AppInfo, body []byte WriteU32(0). WriteU8(1). WriteU8(1). - WriteBytes(make([]byte, 16), "", true). + WritePacketBytes(make([]byte, 16), "", true). WriteU16(0x102). WriteU16(uint16(len(ecdh.ECDH["secp192k1"].GetPublicKey()))). - WriteBytes(ecdh.ECDH["secp192k1"].GetPublicKey(), "", true). - WriteBytes(encBody, "", true). + WritePacketBytes(ecdh.ECDH["secp192k1"].GetPublicKey(), "", true). + WritePacketBytes(encBody, "", true). WriteU8(3). - Pack(-1) + Pack(binary.PackTypeNone) - frame := utils.NewPacketBuilder(nil). + frame := binary.NewBuilder(nil). WriteU8(2). WriteU16(uint16(len(frameBody))+3). // + 2 + 1 - WriteBytes(frameBody, "", true). - Pack(-1) + WritePacketBytes(frameBody, "", true). + Pack(binary.PackTypeNone) return frame } @@ -104,24 +104,24 @@ func BuildUniPacket(uin, seq int, cmd string, sign map[string]string, } } - ssoHeader := utils.NewPacketBuilder(nil). + ssoHeader := binary.NewBuilder(nil). WriteU32(uint32(seq)). WriteU32(uint32(appInfo.SubAppID)). - WriteU32(2052). // locate id - WriteBytes(append([]byte{0x02}, make([]byte, 11)...), "", true). //020000000000000000000000 - WriteBytes(sigInfo.Tgt, "u32", true). - WriteString(cmd, "u32", true). - WriteBytes(make([]byte, 0), "u32", true). - WriteBytes(utils.MustParseHexStr(deviceInfo.Guid), "u32", true). - WriteBytes(make([]byte, 0), "u32", true). - WriteString(appInfo.CurrentVersion, "u16", true). - WriteBytes(head.Encode(), "u32", true). - Pack(-1) - - ssoPacket := utils.NewPacketBuilder(nil). - WriteBytes(ssoHeader, "u32", true). - WriteBytes(body, "u32", true). - Pack(-1) + WriteU32(2052). // locate id + WritePacketBytes(append([]byte{0x02}, make([]byte, 11)...), "", true). //020000000000000000000000 + WritePacketBytes(sigInfo.Tgt, "u32", true). + WritePacketString(cmd, "u32", true). + WritePacketBytes(nil, "u32", true). + WritePacketBytes(utils.MustParseHexStr(deviceInfo.Guid), "u32", true). + WritePacketBytes(nil, "u32", true). + WritePacketString(appInfo.CurrentVersion, "u16", true). + WritePacketBytes(head.Encode(), "u32", true). + Pack(binary.PackTypeNone) + + ssoPacket := binary.NewBuilder(nil). + WritePacketBytes(ssoHeader, "u32", true). + WritePacketBytes(body, "u32", true). + Pack(binary.PackTypeNone) encrypted := crypto.NewTeaCipher(sigInfo.D2Key).Encrypt(ssoPacket) @@ -132,16 +132,16 @@ func BuildUniPacket(uin, seq int, cmd string, sign map[string]string, _s = 1 } - service := utils.NewPacketBuilder(nil). + service := binary.NewBuilder(nil). WriteU32(12). WriteU8(_s). - WriteBytes(sigInfo.D2, "u32", true). + WritePacketBytes(sigInfo.D2, "u32", true). WriteU8(0). - WriteString(strconv.Itoa(uin), "u32", true). - WriteBytes(encrypted, "", true). - Pack(-1) + WritePacketString(strconv.Itoa(uin), "u32", true). + WritePacketBytes(encrypted, "", true). + Pack(binary.PackTypeNone) - return utils.NewPacketBuilder(nil).WriteBytes(service, "u32", true).Pack(-1) + return binary.NewBuilder(nil).WritePacketBytes(service, "u32", true).Pack(binary.PackTypeNone) } func DecodeLoginResponse(buf []byte, sig *info.SigInfo) (bool, error) { diff --git a/packets/wtlogin/sso.go b/packets/wtlogin/sso.go index df38cafa..d2a67df0 100644 --- a/packets/wtlogin/sso.go +++ b/packets/wtlogin/sso.go @@ -56,7 +56,7 @@ func ParseSSOHeader(raw, d2Key []byte) (*SSOHeader, error) { var flag uint8 _ = binary.Read(buf, binary.BigEndian, &flag) buf.Next(1) - uin := string(ParseLv(buf)) + uin := utils.B2S(ParseLv(buf)) var dec []byte if flag == 0 { // no encrypted @@ -90,7 +90,7 @@ func ParseSSOFrame(buffer []byte, IsOicqBody bool) (*SSOPacket, error) { sessionID := reader.ReadBytesWithLength("u32", true) if retCode != 0 { - return NewSSOPacket(int(seq), int(retCode), extra, sessionID, "", make([]byte, 0)), nil + return NewSSOPacket(int(seq), int(retCode), extra, sessionID, "", nil), nil } compressType := reader.ReadU32() diff --git a/packets/wtlogin/statusService.go b/packets/wtlogin/statusService.go index 0daeeeb0..e3fbcf20 100644 --- a/packets/wtlogin/statusService.go +++ b/packets/wtlogin/statusService.go @@ -2,10 +2,11 @@ package wtlogin import ( "strings" - - "github.com/LagrangeDev/LagrangeGo/packets/pb/system" + "unicode" "github.com/LagrangeDev/LagrangeGo/info" + "github.com/LagrangeDev/LagrangeGo/packets/pb/system" + "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/proto" ) @@ -53,5 +54,9 @@ func ParseRegisterResponse(response []byte) bool { } func capitalize(s string) string { - return strings.ToUpper(string(s[0])) + strings.ToLower(s[1:]) + news := make([]byte, len(s)) + rs := []rune(s) + n := copy(news, string(unicode.ToUpper(rs[0]))) + copy(news[n:], strings.ToLower(s[n:])) + return utils.B2S(news) } diff --git a/utils/binary/builder.go b/utils/binary/builder.go index eb28180f..ac8f0c7e 100644 --- a/utils/binary/builder.go +++ b/utils/binary/builder.go @@ -5,9 +5,14 @@ import ( "encoding/binary" "math" + "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/crypto" ) +type PackType int + +const PackTypeNone PackType = -1 + type Builder struct { buffer []byte key crypto.TEA @@ -16,7 +21,7 @@ type Builder struct { func NewBuilder(key []byte) *Builder { return &Builder{ - buffer: make([]byte, 0), + buffer: make([]byte, 0, 64), key: crypto.NewTeaCipher(key), usetea: len(key) == 16, } @@ -48,13 +53,14 @@ func (b *Builder) pack(v any) *Builder { return b } -func (b *Builder) Pack(typ int64) []byte { - if typ != -1 { +func (b *Builder) Pack(typ PackType) []byte { + if typ != PackTypeNone { // 或许这里是tlv - buf := new(bytes.Buffer) - _ = binary.Write(buf, binary.BigEndian, typ) // type - _ = binary.Write(buf, binary.BigEndian, int64(len(b.Data()))) // length - return append(buf.Bytes(), b.Data()...) // type + length + value + buf := make([]byte, b.Len()+4) + binary.BigEndian.PutUint16(buf[0:2], uint16(typ)) // type + binary.BigEndian.PutUint16(buf[2:4], uint16(len(b.Data()))) // length + copy(buf[4:], b.Data()) // type + length + value + return buf } return b.Data() } @@ -69,10 +75,44 @@ func (b *Builder) WriteBool(v bool) *Builder { return b } -//func (b *Builder) WriteByte(v byte) *Builder { -// b.buffer = append(b.buffer, v) -// return b.pack(v) -//} +// WritePacketBytes default prefix = "", withPrefix = true +func (b *Builder) WritePacketBytes(v []byte, prefix string, withPrefix bool) *Builder { + if withPrefix { + switch prefix { + case "": + case "u8": + b.WriteU8(uint8(len(v) + 1)) + case "u16": + b.WriteU16(uint16(len(v) + 2)) + case "u32": + b.WriteU32(uint32(len(v) + 4)) + case "u64": + b.WriteU64(uint64(len(v) + 8)) + default: + panic("Invaild prefix") + } + } else { + switch prefix { + case "": + case "u8": + b.WriteU8(uint8(len(v))) + case "u16": + b.WriteU16(uint16(len(v))) + case "u32": + b.WriteU32(uint32(len(v))) + case "u64": + b.WriteU64(uint64(len(v))) + default: + panic("Invaild prefix") + } + } + b.append(v) + return b +} + +func (b *Builder) WritePacketString(s, prefix string, withPrefix bool) *Builder { + return b.WritePacketBytes(utils.S2B(s), prefix, withPrefix) +} func (b *Builder) WriteBytes(v []byte, withLength bool) *Builder { if withLength { @@ -83,11 +123,11 @@ func (b *Builder) WriteBytes(v []byte, withLength bool) *Builder { } func (b *Builder) WriteString(v string) *Builder { - return b.WriteBytes([]byte(v), true) + return b.WriteBytes(utils.S2B(v), true) } -func (b *Builder) WriteStruct(datas ...any) *Builder { - for _, data := range datas { +func (b *Builder) WriteStruct(data ...any) *Builder { + for _, data := range data { b.pack(data) } return b @@ -132,13 +172,25 @@ func (b *Builder) WriteI64(v int64) *Builder { func (b *Builder) WriteFloat(v float32) *Builder { return b.WriteU32(math.Float32bits(v)) } + func (b *Builder) WriteDouble(v float64) *Builder { return b.WriteU64(math.Float64bits(v)) } -func (b *Builder) WriteTlv(tlvs [][]byte) *Builder { + +/* +func (b *Builder) WriteTlv(tlvs ...[]byte) *Builder { b.WriteU16(uint16(len(tlvs))) for _, tlv := range tlvs { b.WriteBytes(tlv, false) } return b } +*/ + +func (b *Builder) WritePacketTlv(tlvs ...[]byte) *Builder { + b.WriteU16(uint16(len(tlvs))) + for _, tlv := range tlvs { + b.WritePacketBytes(tlv, "", true) + } + return b +} diff --git a/utils/binary/builder_test.go b/utils/binary/builder_test.go index b7d71204..7856574a 100644 --- a/utils/binary/builder_test.go +++ b/utils/binary/builder_test.go @@ -7,13 +7,13 @@ import ( func TestBuilder(t *testing.T) { r := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9} - data := NewBuilder(nil).WriteBytes(r, true).Pack(-1) + data := NewBuilder(nil).WriteBytes(r, true).Pack(PackTypeNone) fmt.Printf("%x\n", data) } func build() []byte { r := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9} - return NewBuilder(nil).WriteBytes(r, true).WriteBytes(r, true).Pack(-1) + return NewBuilder(nil).WriteBytes(r, true).WriteBytes(r, true).Pack(PackTypeNone) } func TestReader(t *testing.T) { diff --git a/utils/binary/reader.go b/utils/binary/reader.go index b30eb8f8..63f4cbc1 100644 --- a/utils/binary/reader.go +++ b/utils/binary/reader.go @@ -2,6 +2,8 @@ package binary import ( "encoding/binary" + + "github.com/LagrangeDev/LagrangeGo/utils" ) type Reader struct { @@ -52,7 +54,7 @@ func (r *Reader) ReadBytes(length int) (v []byte) { } func (r *Reader) ReadString(length int) string { - return string(r.ReadBytes(length)) + return utils.B2S(r.ReadBytes(length)) } func (r *Reader) ReadBytesWithLength(prefix string, withPerfix bool) (v []byte) { @@ -91,7 +93,7 @@ func (r *Reader) ReadBytesWithLength(prefix string, withPerfix bool) (v []byte) } func (r *Reader) ReadStringWithLength(prefix string, withPerfix bool) string { - return string(r.ReadBytesWithLength(prefix, withPerfix)) + return utils.B2S(r.ReadBytesWithLength(prefix, withPerfix)) } func (r *Reader) ReadTlv() (result map[int][]byte) { diff --git a/utils/crypto/tea_test.go b/utils/crypto/tea_test.go index e0c9c465..76d13c71 100644 --- a/utils/crypto/tea_test.go +++ b/utils/crypto/tea_test.go @@ -283,7 +283,7 @@ func xor(a, b []byte) []byte { //_ = binary.Read(readerb, binary.BigEndian, &b1) //_ = binary.Read(readerb, binary.BigEndian, &b2) - buf := make([]byte, 0) + buf := make([]byte, 0, 64) buf = binary.BigEndian.AppendUint32(buf, (a1^b1)&uint32(OP)) buf = binary.BigEndian.AppendUint32(buf, (a2^b2)&uint32(OP)) @@ -331,7 +331,7 @@ func teaCode(v, k []byte) []byte { v1 &= OP } - buf := make([]byte, 0) + buf := make([]byte, 0, 64) buf = binary.BigEndian.AppendUint32(buf, uint32(v0)) buf = binary.BigEndian.AppendUint32(buf, uint32(v1)) @@ -380,7 +380,7 @@ func teaDecipher(v, k []byte) []byte { sum &= OP } - buf := make([]byte, 0) + buf := make([]byte, 0, 64) buf = binary.BigEndian.AppendUint32(buf, uint32(v0)) buf = binary.BigEndian.AppendUint32(buf, uint32(v1)) @@ -391,7 +391,7 @@ func preprocess(data []byte) []byte { dataLen := len(data) // 保证取余出来是正数 filln := ((8-(dataLen+2))%8+8)%8 + 2 - fills := make([]byte, 0) + fills := make([]byte, 0, 64) for i := 0; i < filln; i++ { fills = append(fills, 220) } @@ -406,7 +406,7 @@ func encrypt(data, key []byte) []byte { data = preprocess(data) tr := make([]byte, 8) to := make([]byte, 8) - result := make([]byte, 0) + result := make([]byte, 0, 64) for i := 0; i < len(data); i += 8 { o := xor(data[i:i+8], tr) tr = xor(teaCode(o, key), to) diff --git a/utils/log.go b/utils/log.go index 49bfc04b..3479e5e6 100644 --- a/utils/log.go +++ b/utils/log.go @@ -62,7 +62,7 @@ func (f *ColoredFormatter) Format(entry *logrus.Entry) ([]byte, error) { timestamp, levelColor, strings.ToUpper(entry.Level.String()), colorReset, 7-len(entry.Level.String()), "", entry.Data["prefix"], entry.Message) } - return []byte(message), nil + return S2B(message), nil } func GetLogger(prefix string) *logrus.Entry { diff --git a/utils/packet.go b/utils/packet.go deleted file mode 100644 index e7cabc78..00000000 --- a/utils/packet.go +++ /dev/null @@ -1,169 +0,0 @@ -package utils - -import ( - "bytes" - "encoding/binary" - "math" - - "github.com/LagrangeDev/LagrangeGo/utils/crypto" -) - -type PacketBuilder struct { - buffer []byte - key crypto.TEA - usetea bool -} - -func NewPacketBuilder(key []byte) *PacketBuilder { - return &PacketBuilder{ - buffer: make([]byte, 0), - key: crypto.NewTeaCipher(key), - usetea: len(key) == 16, - } -} - -// WriteByte就是i8 - -// WriteBytes 重写 默认参数 prefix = "", withPerfix = true -func (b *PacketBuilder) WriteBytes(v []byte, prefix string, withPerfix bool) *PacketBuilder { - if withPerfix { - switch prefix { - case "": - case "u8": - b.WriteU8(uint8(len(v) + 1)) - case "u16": - b.WriteU16(uint16(len(v) + 2)) - case "u32": - b.WriteU32(uint32(len(v) + 4)) - case "u64": - b.WriteU64(uint64(len(v) + 8)) - default: - panic("Invaild prefix") - } - } else { - switch prefix { - case "": - case "u8": - b.WriteU8(uint8(len(v))) - case "u16": - b.WriteU16(uint16(len(v))) - case "u32": - b.WriteU32(uint32(len(v))) - case "u64": - b.WriteU64(uint64(len(v))) - default: - panic("Invaild prefix") - } - } - b.append(v) - return b -} - -func (b *PacketBuilder) WriteString(s, prefix string, withPerfix bool) *PacketBuilder { - return b.WriteBytes([]byte(s), prefix, withPerfix) - -} - -func (b *PacketBuilder) Len() int { - return len(b.buffer) -} - -func (b *PacketBuilder) append(v []byte) { - b.buffer = append(b.buffer, v...) -} - -func (b *PacketBuilder) Buffer() []byte { - return b.buffer -} - -func (b *PacketBuilder) Data() []byte { - if b.usetea { - return b.key.Encrypt(b.buffer) - } - return b.buffer -} - -func (b *PacketBuilder) pack(v any) *PacketBuilder { - buf := new(bytes.Buffer) - _ = binary.Write(buf, binary.BigEndian, v) - b.append(buf.Bytes()) - return b -} - -func (b *PacketBuilder) Pack(typ int) []byte { - if typ != -1 { - // 或许这里是tlv - buf := make([]byte, 0) - buf = binary.BigEndian.AppendUint16(buf, uint16(typ)) // type - buf = binary.BigEndian.AppendUint16(buf, uint16(len(b.Data()))) // length - return append(buf, b.Data()...) // type + length + value - } - return b.Data() -} - -func (b *PacketBuilder) WriteBool(v bool) *PacketBuilder { - if v { - b.buffer = append(b.buffer, 1) - } else { - b.buffer = append(b.buffer, 0) - } - - return b -} - -func (b *PacketBuilder) WriteStruct(datas ...any) *PacketBuilder { - for _, data := range datas { - b.pack(data) - } - return b -} - -func (b *PacketBuilder) WriteU8(v uint8) *PacketBuilder { - b.buffer = append(b.buffer, v) - return b -} - -func (b *PacketBuilder) WriteU16(v uint16) *PacketBuilder { - b.buffer = binary.BigEndian.AppendUint16(b.buffer, v) - return b -} - -func (b *PacketBuilder) WriteU32(v uint32) *PacketBuilder { - b.buffer = binary.BigEndian.AppendUint32(b.buffer, v) - return b -} - -func (b *PacketBuilder) WriteU64(v uint64) *PacketBuilder { - b.buffer = binary.BigEndian.AppendUint64(b.buffer, v) - return b -} - -func (b *PacketBuilder) WriteI8(v int8) *PacketBuilder { - return b.WriteU8(byte(v)) -} - -func (b *PacketBuilder) WriteI16(v int16) *PacketBuilder { - return b.WriteU16(uint16(v)) -} - -func (b *PacketBuilder) WriteI32(v int32) *PacketBuilder { - return b.WriteU32(uint32(v)) -} - -func (b *PacketBuilder) WriteI64(v int64) *PacketBuilder { - return b.WriteU64(uint64(v)) -} - -func (b *PacketBuilder) WriteFloat(v float32) *PacketBuilder { - return b.WriteU32(math.Float32bits(v)) -} -func (b *PacketBuilder) WriteDouble(v float64) *PacketBuilder { - return b.WriteU64(math.Float64bits(v)) -} -func (b *PacketBuilder) WriteTlv(tlvs [][]byte) *PacketBuilder { - b.WriteU16(uint16(len(tlvs))) - for _, tlv := range tlvs { - b.WriteBytes(tlv, "", true) - } - return b -} diff --git a/utils/string.go b/utils/string.go new file mode 100644 index 00000000..4ff28c98 --- /dev/null +++ b/utils/string.go @@ -0,0 +1,22 @@ +package utils + +// from https://github.com/Mrs4s/MiraiGo/blob/master/utils/string.go + +import "unsafe" + +// B2S converts byte slice to a string without memory allocation. +func B2S(b []byte) string { + size := len(b) + if size == 0 { + return "" + } + return unsafe.String(&b[0], size) +} + +// S2B converts string to a byte slice without memory allocation. +// +// Note it may break if string and/or slice header will change +// in the future go versions. +func S2B(s string) (b []byte) { + return unsafe.Slice(unsafe.StringData(s), len(s)) +}