mirror of
https://github.com/yincongcyincong/wechat_chatter.git
synced 2026-07-15 10:26:52 +08:00
update protobuf
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
mathrand "math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto"
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// BuildImgMsgProto 构建发送图片消息的protobuf并返回hex编码的字符串
|
||||
func BuildImgMsgProto(sender, targetId, cdnKey, aesKey, md5Key string) (string, error) {
|
||||
// 生成16字节随机client_proof (模拟JS的generateBytes(16))
|
||||
clientProof := make([]byte, 16)
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
for i := range clientProof {
|
||||
clientProof[i] = chars[int(randBytes[i])%len(chars)]
|
||||
}
|
||||
|
||||
// 生成5字节varint范围的msgId (2^28 ~ 2^35-1)
|
||||
msgId := mathrand.Int63n(1<<35-1<<28) + (1 << 28)
|
||||
|
||||
// header.unknown4 的值: 从 [0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01] 解码
|
||||
// = -228321745 (signed int64)
|
||||
const headerUnknown4 int64 = -228321745
|
||||
|
||||
// client_msg_id: targetId_timestamp_160_xwechat_3
|
||||
timestamp := time.Now().Unix()
|
||||
clientMsgId := targetId + "_" + strconv.FormatInt(timestamp, 10) + "_160_xwechat_3"
|
||||
|
||||
// xml内容
|
||||
xmlContent := []byte("<msgsource><alnode><fr>1</fr></alnode></msgsource>")
|
||||
|
||||
msg := &wxproto.WxSendImgMsg{
|
||||
Header: &wxproto.ImgMsgHeader{
|
||||
Flag: []byte{0x00},
|
||||
MsgId: msgId,
|
||||
ClientProof: clientProof,
|
||||
Unknown4: headerUnknown4,
|
||||
SysInfo: []byte("UnifiedPCMac 26 arm64"),
|
||||
Unknown6: 304,
|
||||
},
|
||||
ClientMsgId: &wxproto.WxString{Value: clientMsgId},
|
||||
Sender: &wxproto.WxString{Value: sender},
|
||||
Receiver: &wxproto.WxString{Value: targetId},
|
||||
Unknown5: 1524,
|
||||
// MsgType: 0, // proto3不会序列化0值,需要手动追加
|
||||
Unknown7: 1524,
|
||||
// Unknown8: 手动追加 [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
|
||||
Unknown9: 3,
|
||||
Xml: xmlContent,
|
||||
Unknown11: 1,
|
||||
Unknown12: 2,
|
||||
// Unknown13: 0, // 需要手动追加
|
||||
CdnKey: []byte(cdnKey),
|
||||
CdnKey2: []byte(cdnKey),
|
||||
AesKey: []byte(aesKey),
|
||||
Unknown18: 1,
|
||||
Unknown19: 2559,
|
||||
Unknown20: 2559,
|
||||
CdnKey3: []byte(cdnKey),
|
||||
Unknown22: 1524,
|
||||
Unknown23: 104,
|
||||
Unknown24: 58,
|
||||
AesKey2: []byte(aesKey),
|
||||
Md5Key: []byte(md5Key),
|
||||
Unknown28: 779219929,
|
||||
// Unknown30: 0, // 需要手动追加
|
||||
// Unknown36: 0, // 需要手动追加
|
||||
// Unknown41: 0, // 需要手动追加
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal img proto failed: %w", err)
|
||||
}
|
||||
|
||||
// 手动追加proto3不会序列化的0值字段
|
||||
// field 6 (msg_type=0): tag=0x30, value=0x00
|
||||
data = appendZeroVarintField(data, 6)
|
||||
// field 8 (ImgMsgExtra with field1=0, field2=""): [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
|
||||
data = append(data, 0x42, 0x04, 0x08, 0x00, 0x12, 0x00)
|
||||
// field 13 (unknown13=0): tag=0x68, value=0x00
|
||||
data = appendZeroVarintField(data, 13)
|
||||
// field 30 (unknown30=0): tag=[0xF0, 0x01], value=0x00
|
||||
data = appendZeroVarintField(data, 30)
|
||||
// field 36 (unknown36=0): tag=[0xA0, 0x02], value=0x00
|
||||
data = appendZeroVarintField(data, 36)
|
||||
// field 41 (unknown41=0): tag=[0xC8, 0x02], value=0x00
|
||||
data = appendZeroVarintField(data, 41)
|
||||
|
||||
// 追加尾部的 \x00 字节
|
||||
data = append(data, 0x00)
|
||||
|
||||
return hex.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
// appendZeroVarintField 追加一个值为0的varint字段
|
||||
func appendZeroVarintField(data []byte, fieldNum protowire.Number) []byte {
|
||||
data = protowire.AppendTag(data, fieldNum, protowire.VarintType)
|
||||
data = protowire.AppendVarint(data, 0)
|
||||
return data
|
||||
}
|
||||
+5
-3
@@ -22,6 +22,7 @@ var (
|
||||
|
||||
userID2NicknameMap sync.Map
|
||||
userID2FileMsgMap sync.Map
|
||||
videoDurationMap sync.Map // targetId -> int32(duration seconds)
|
||||
)
|
||||
|
||||
type WechatMessage struct {
|
||||
@@ -57,9 +58,10 @@ type SendMsg struct {
|
||||
FilePath string
|
||||
FileType int
|
||||
|
||||
CdnKey string
|
||||
Md5Key string
|
||||
VideoId string
|
||||
CdnKey string
|
||||
Md5Key string
|
||||
VideoId string
|
||||
Duration int32
|
||||
}
|
||||
|
||||
// SendRequest 请求结构体
|
||||
|
||||
@@ -0,0 +1,536 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v3.5.1
|
||||
// source: proto/wxproto/img_msg.proto
|
||||
|
||||
package wxproto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// 发送图片消息的protobuf结构
|
||||
type WxSendImgMsg struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Header *ImgMsgHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
|
||||
ClientMsgId *WxString `protobuf:"bytes,2,opt,name=client_msg_id,json=clientMsgId,proto3" json:"client_msg_id,omitempty"`
|
||||
Sender *WxString `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"`
|
||||
Receiver *WxString `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"`
|
||||
Unknown5 int32 `protobuf:"varint,5,opt,name=unknown5,proto3" json:"unknown5,omitempty"`
|
||||
MsgType int32 `protobuf:"varint,6,opt,name=msg_type,json=msgType,proto3" json:"msg_type,omitempty"`
|
||||
Unknown7 int32 `protobuf:"varint,7,opt,name=unknown7,proto3" json:"unknown7,omitempty"`
|
||||
Unknown8 *ImgMsgExtra `protobuf:"bytes,8,opt,name=unknown8,proto3" json:"unknown8,omitempty"`
|
||||
Unknown9 int32 `protobuf:"varint,9,opt,name=unknown9,proto3" json:"unknown9,omitempty"`
|
||||
Xml []byte `protobuf:"bytes,10,opt,name=xml,proto3" json:"xml,omitempty"`
|
||||
Unknown11 int32 `protobuf:"varint,11,opt,name=unknown11,proto3" json:"unknown11,omitempty"`
|
||||
Unknown12 int32 `protobuf:"varint,12,opt,name=unknown12,proto3" json:"unknown12,omitempty"`
|
||||
Unknown13 int32 `protobuf:"varint,13,opt,name=unknown13,proto3" json:"unknown13,omitempty"`
|
||||
// field 14 skipped
|
||||
CdnKey []byte `protobuf:"bytes,15,opt,name=cdn_key,json=cdnKey,proto3" json:"cdn_key,omitempty"`
|
||||
CdnKey2 []byte `protobuf:"bytes,16,opt,name=cdn_key2,json=cdnKey2,proto3" json:"cdn_key2,omitempty"`
|
||||
AesKey []byte `protobuf:"bytes,17,opt,name=aes_key,json=aesKey,proto3" json:"aes_key,omitempty"`
|
||||
Unknown18 int32 `protobuf:"varint,18,opt,name=unknown18,proto3" json:"unknown18,omitempty"`
|
||||
Unknown19 int32 `protobuf:"varint,19,opt,name=unknown19,proto3" json:"unknown19,omitempty"`
|
||||
Unknown20 int32 `protobuf:"varint,20,opt,name=unknown20,proto3" json:"unknown20,omitempty"`
|
||||
CdnKey3 []byte `protobuf:"bytes,21,opt,name=cdn_key3,json=cdnKey3,proto3" json:"cdn_key3,omitempty"`
|
||||
Unknown22 int32 `protobuf:"varint,22,opt,name=unknown22,proto3" json:"unknown22,omitempty"`
|
||||
Unknown23 int32 `protobuf:"varint,23,opt,name=unknown23,proto3" json:"unknown23,omitempty"`
|
||||
Unknown24 int32 `protobuf:"varint,24,opt,name=unknown24,proto3" json:"unknown24,omitempty"`
|
||||
AesKey2 []byte `protobuf:"bytes,25,opt,name=aes_key2,json=aesKey2,proto3" json:"aes_key2,omitempty"`
|
||||
// field 26 skipped
|
||||
Md5Key []byte `protobuf:"bytes,27,opt,name=md5_key,json=md5Key,proto3" json:"md5_key,omitempty"`
|
||||
Unknown28 int64 `protobuf:"varint,28,opt,name=unknown28,proto3" json:"unknown28,omitempty"`
|
||||
// field 29 skipped
|
||||
Unknown30 int32 `protobuf:"varint,30,opt,name=unknown30,proto3" json:"unknown30,omitempty"`
|
||||
// fields 31-35 skipped
|
||||
Unknown36 int32 `protobuf:"varint,36,opt,name=unknown36,proto3" json:"unknown36,omitempty"`
|
||||
// fields 37-40 skipped
|
||||
Unknown41 int32 `protobuf:"varint,41,opt,name=unknown41,proto3" json:"unknown41,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) Reset() {
|
||||
*x = WxSendImgMsg{}
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WxSendImgMsg) ProtoMessage() {}
|
||||
|
||||
func (x *WxSendImgMsg) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WxSendImgMsg.ProtoReflect.Descriptor instead.
|
||||
func (*WxSendImgMsg) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetHeader() *ImgMsgHeader {
|
||||
if x != nil {
|
||||
return x.Header
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetClientMsgId() *WxString {
|
||||
if x != nil {
|
||||
return x.ClientMsgId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetSender() *WxString {
|
||||
if x != nil {
|
||||
return x.Sender
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetReceiver() *WxString {
|
||||
if x != nil {
|
||||
return x.Receiver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown5() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown5
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetMsgType() int32 {
|
||||
if x != nil {
|
||||
return x.MsgType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown7() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown7
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown8() *ImgMsgExtra {
|
||||
if x != nil {
|
||||
return x.Unknown8
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown9() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown9
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetXml() []byte {
|
||||
if x != nil {
|
||||
return x.Xml
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown11() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown11
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown12() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown12
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown13() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown13
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetCdnKey() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetCdnKey2() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetAesKey() []byte {
|
||||
if x != nil {
|
||||
return x.AesKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown18() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown18
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown19() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown19
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown20() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown20
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetCdnKey3() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey3
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown22() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown22
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown23() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown23
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown24() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown24
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetAesKey2() []byte {
|
||||
if x != nil {
|
||||
return x.AesKey2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetMd5Key() []byte {
|
||||
if x != nil {
|
||||
return x.Md5Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown28() int64 {
|
||||
if x != nil {
|
||||
return x.Unknown28
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown30() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown30
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown36() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown36
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendImgMsg) GetUnknown41() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown41
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ImgMsgHeader struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Flag []byte `protobuf:"bytes,1,opt,name=flag,proto3" json:"flag,omitempty"`
|
||||
MsgId int64 `protobuf:"varint,2,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
|
||||
ClientProof []byte `protobuf:"bytes,3,opt,name=client_proof,json=clientProof,proto3" json:"client_proof,omitempty"`
|
||||
Unknown4 int64 `protobuf:"varint,4,opt,name=unknown4,proto3" json:"unknown4,omitempty"`
|
||||
SysInfo []byte `protobuf:"bytes,5,opt,name=sys_info,json=sysInfo,proto3" json:"sys_info,omitempty"`
|
||||
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) Reset() {
|
||||
*x = ImgMsgHeader{}
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ImgMsgHeader) ProtoMessage() {}
|
||||
|
||||
func (x *ImgMsgHeader) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ImgMsgHeader.ProtoReflect.Descriptor instead.
|
||||
func (*ImgMsgHeader) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetFlag() []byte {
|
||||
if x != nil {
|
||||
return x.Flag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetMsgId() int64 {
|
||||
if x != nil {
|
||||
return x.MsgId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetClientProof() []byte {
|
||||
if x != nil {
|
||||
return x.ClientProof
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetUnknown4() int64 {
|
||||
if x != nil {
|
||||
return x.Unknown4
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetSysInfo() []byte {
|
||||
if x != nil {
|
||||
return x.SysInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ImgMsgHeader) GetUnknown6() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ImgMsgExtra struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
|
||||
Field2 []byte `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ImgMsgExtra) Reset() {
|
||||
*x = ImgMsgExtra{}
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ImgMsgExtra) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ImgMsgExtra) ProtoMessage() {}
|
||||
|
||||
func (x *ImgMsgExtra) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_img_msg_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ImgMsgExtra.ProtoReflect.Descriptor instead.
|
||||
func (*ImgMsgExtra) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ImgMsgExtra) GetField1() int32 {
|
||||
if x != nil {
|
||||
return x.Field1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ImgMsgExtra) GetField2() []byte {
|
||||
if x != nil {
|
||||
return x.Field2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proto_wxproto_img_msg_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_proto_wxproto_img_msg_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1bproto/wxproto/img_msg.proto\x12\awxproto\x1a\x1aproto/wxproto/wx_msg.proto\"\xa3\a\n" +
|
||||
"\fWxSendImgMsg\x12-\n" +
|
||||
"\x06header\x18\x01 \x01(\v2\x15.wxproto.ImgMsgHeaderR\x06header\x125\n" +
|
||||
"\rclient_msg_id\x18\x02 \x01(\v2\x11.wxproto.WxStringR\vclientMsgId\x12)\n" +
|
||||
"\x06sender\x18\x03 \x01(\v2\x11.wxproto.WxStringR\x06sender\x12-\n" +
|
||||
"\breceiver\x18\x04 \x01(\v2\x11.wxproto.WxStringR\breceiver\x12\x1a\n" +
|
||||
"\bunknown5\x18\x05 \x01(\x05R\bunknown5\x12\x19\n" +
|
||||
"\bmsg_type\x18\x06 \x01(\x05R\amsgType\x12\x1a\n" +
|
||||
"\bunknown7\x18\a \x01(\x05R\bunknown7\x120\n" +
|
||||
"\bunknown8\x18\b \x01(\v2\x14.wxproto.ImgMsgExtraR\bunknown8\x12\x1a\n" +
|
||||
"\bunknown9\x18\t \x01(\x05R\bunknown9\x12\x10\n" +
|
||||
"\x03xml\x18\n" +
|
||||
" \x01(\fR\x03xml\x12\x1c\n" +
|
||||
"\tunknown11\x18\v \x01(\x05R\tunknown11\x12\x1c\n" +
|
||||
"\tunknown12\x18\f \x01(\x05R\tunknown12\x12\x1c\n" +
|
||||
"\tunknown13\x18\r \x01(\x05R\tunknown13\x12\x17\n" +
|
||||
"\acdn_key\x18\x0f \x01(\fR\x06cdnKey\x12\x19\n" +
|
||||
"\bcdn_key2\x18\x10 \x01(\fR\acdnKey2\x12\x17\n" +
|
||||
"\aaes_key\x18\x11 \x01(\fR\x06aesKey\x12\x1c\n" +
|
||||
"\tunknown18\x18\x12 \x01(\x05R\tunknown18\x12\x1c\n" +
|
||||
"\tunknown19\x18\x13 \x01(\x05R\tunknown19\x12\x1c\n" +
|
||||
"\tunknown20\x18\x14 \x01(\x05R\tunknown20\x12\x19\n" +
|
||||
"\bcdn_key3\x18\x15 \x01(\fR\acdnKey3\x12\x1c\n" +
|
||||
"\tunknown22\x18\x16 \x01(\x05R\tunknown22\x12\x1c\n" +
|
||||
"\tunknown23\x18\x17 \x01(\x05R\tunknown23\x12\x1c\n" +
|
||||
"\tunknown24\x18\x18 \x01(\x05R\tunknown24\x12\x19\n" +
|
||||
"\baes_key2\x18\x19 \x01(\fR\aaesKey2\x12\x17\n" +
|
||||
"\amd5_key\x18\x1b \x01(\fR\x06md5Key\x12\x1c\n" +
|
||||
"\tunknown28\x18\x1c \x01(\x03R\tunknown28\x12\x1c\n" +
|
||||
"\tunknown30\x18\x1e \x01(\x05R\tunknown30\x12\x1c\n" +
|
||||
"\tunknown36\x18$ \x01(\x05R\tunknown36\x12\x1c\n" +
|
||||
"\tunknown41\x18) \x01(\x05R\tunknown41\"\xaf\x01\n" +
|
||||
"\fImgMsgHeader\x12\x12\n" +
|
||||
"\x04flag\x18\x01 \x01(\fR\x04flag\x12\x15\n" +
|
||||
"\x06msg_id\x18\x02 \x01(\x03R\x05msgId\x12!\n" +
|
||||
"\fclient_proof\x18\x03 \x01(\fR\vclientProof\x12\x1a\n" +
|
||||
"\bunknown4\x18\x04 \x01(\x03R\bunknown4\x12\x19\n" +
|
||||
"\bsys_info\x18\x05 \x01(\fR\asysInfo\x12\x1a\n" +
|
||||
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\"=\n" +
|
||||
"\vImgMsgExtra\x12\x16\n" +
|
||||
"\x06field1\x18\x01 \x01(\x05R\x06field1\x12\x16\n" +
|
||||
"\x06field2\x18\x02 \x01(\fR\x06field2B>Z<github.com/yincongcyincong/weixin-macos/onebot/proto/wxprotob\x06proto3"
|
||||
|
||||
var (
|
||||
file_proto_wxproto_img_msg_proto_rawDescOnce sync.Once
|
||||
file_proto_wxproto_img_msg_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_proto_wxproto_img_msg_proto_rawDescGZIP() []byte {
|
||||
file_proto_wxproto_img_msg_proto_rawDescOnce.Do(func() {
|
||||
file_proto_wxproto_img_msg_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_wxproto_img_msg_proto_rawDesc), len(file_proto_wxproto_img_msg_proto_rawDesc)))
|
||||
})
|
||||
return file_proto_wxproto_img_msg_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_wxproto_img_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_proto_wxproto_img_msg_proto_goTypes = []any{
|
||||
(*WxSendImgMsg)(nil), // 0: wxproto.WxSendImgMsg
|
||||
(*ImgMsgHeader)(nil), // 1: wxproto.ImgMsgHeader
|
||||
(*ImgMsgExtra)(nil), // 2: wxproto.ImgMsgExtra
|
||||
(*WxString)(nil), // 3: wxproto.WxString
|
||||
}
|
||||
var file_proto_wxproto_img_msg_proto_depIdxs = []int32{
|
||||
1, // 0: wxproto.WxSendImgMsg.header:type_name -> wxproto.ImgMsgHeader
|
||||
3, // 1: wxproto.WxSendImgMsg.client_msg_id:type_name -> wxproto.WxString
|
||||
3, // 2: wxproto.WxSendImgMsg.sender:type_name -> wxproto.WxString
|
||||
3, // 3: wxproto.WxSendImgMsg.receiver:type_name -> wxproto.WxString
|
||||
2, // 4: wxproto.WxSendImgMsg.unknown8:type_name -> wxproto.ImgMsgExtra
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_wxproto_img_msg_proto_init() }
|
||||
func file_proto_wxproto_img_msg_proto_init() {
|
||||
if File_proto_wxproto_img_msg_proto != nil {
|
||||
return
|
||||
}
|
||||
file_proto_wxproto_wx_msg_proto_init()
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wxproto_img_msg_proto_rawDesc), len(file_proto_wxproto_img_msg_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_proto_wxproto_img_msg_proto_goTypes,
|
||||
DependencyIndexes: file_proto_wxproto_img_msg_proto_depIdxs,
|
||||
MessageInfos: file_proto_wxproto_img_msg_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proto_wxproto_img_msg_proto = out.File
|
||||
file_proto_wxproto_img_msg_proto_goTypes = nil
|
||||
file_proto_wxproto_img_msg_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package wxproto;
|
||||
|
||||
option go_package = "github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto";
|
||||
|
||||
import "proto/wxproto/wx_msg.proto";
|
||||
|
||||
// 发送图片消息的protobuf结构
|
||||
message WxSendImgMsg {
|
||||
ImgMsgHeader header = 1;
|
||||
WxString client_msg_id = 2;
|
||||
WxString sender = 3;
|
||||
WxString receiver = 4;
|
||||
int32 unknown5 = 5;
|
||||
int32 msg_type = 6;
|
||||
int32 unknown7 = 7;
|
||||
ImgMsgExtra unknown8 = 8;
|
||||
int32 unknown9 = 9;
|
||||
bytes xml = 10;
|
||||
int32 unknown11 = 11;
|
||||
int32 unknown12 = 12;
|
||||
int32 unknown13 = 13;
|
||||
// field 14 skipped
|
||||
bytes cdn_key = 15;
|
||||
bytes cdn_key2 = 16;
|
||||
bytes aes_key = 17;
|
||||
int32 unknown18 = 18;
|
||||
int32 unknown19 = 19;
|
||||
int32 unknown20 = 20;
|
||||
bytes cdn_key3 = 21;
|
||||
int32 unknown22 = 22;
|
||||
int32 unknown23 = 23;
|
||||
int32 unknown24 = 24;
|
||||
bytes aes_key2 = 25;
|
||||
// field 26 skipped
|
||||
bytes md5_key = 27;
|
||||
int64 unknown28 = 28;
|
||||
// field 29 skipped
|
||||
int32 unknown30 = 30;
|
||||
// fields 31-35 skipped
|
||||
int32 unknown36 = 36;
|
||||
// fields 37-40 skipped
|
||||
int32 unknown41 = 41;
|
||||
}
|
||||
|
||||
message ImgMsgHeader {
|
||||
bytes flag = 1;
|
||||
int64 msg_id = 2;
|
||||
bytes client_proof = 3;
|
||||
int64 unknown4 = 4;
|
||||
bytes sys_info = 5;
|
||||
int32 unknown6 = 6;
|
||||
}
|
||||
|
||||
message ImgMsgExtra {
|
||||
int32 field1 = 1;
|
||||
bytes field2 = 2;
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v3.5.1
|
||||
// source: proto/wxproto/video_msg.proto
|
||||
|
||||
package wxproto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// 发送视频消息的protobuf结构
|
||||
type WxSendVideoMsg struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Header *VideoMsgHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
|
||||
ClientMsgId []byte `protobuf:"bytes,2,opt,name=client_msg_id,json=clientMsgId,proto3" json:"client_msg_id,omitempty"`
|
||||
Sender []byte `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"`
|
||||
Receiver []byte `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"`
|
||||
Unknown5 int32 `protobuf:"varint,5,opt,name=unknown5,proto3" json:"unknown5,omitempty"`
|
||||
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
|
||||
Unknown7 *VideoMsgExtra `protobuf:"bytes,7,opt,name=unknown7,proto3" json:"unknown7,omitempty"`
|
||||
Unknown8 int32 `protobuf:"varint,8,opt,name=unknown8,proto3" json:"unknown8,omitempty"`
|
||||
Unknown9 int32 `protobuf:"varint,9,opt,name=unknown9,proto3" json:"unknown9,omitempty"`
|
||||
Unknown10 *VideoMsgExtra `protobuf:"bytes,10,opt,name=unknown10,proto3" json:"unknown10,omitempty"`
|
||||
Duration int32 `protobuf:"varint,11,opt,name=duration,proto3" json:"duration,omitempty"`
|
||||
Unknown12 int32 `protobuf:"varint,12,opt,name=unknown12,proto3" json:"unknown12,omitempty"`
|
||||
Unknown13 int32 `protobuf:"varint,13,opt,name=unknown13,proto3" json:"unknown13,omitempty"`
|
||||
Unknown14 int32 `protobuf:"varint,14,opt,name=unknown14,proto3" json:"unknown14,omitempty"`
|
||||
Xml []byte `protobuf:"bytes,15,opt,name=xml,proto3" json:"xml,omitempty"`
|
||||
CdnKey []byte `protobuf:"bytes,16,opt,name=cdn_key,json=cdnKey,proto3" json:"cdn_key,omitempty"`
|
||||
AesKey []byte `protobuf:"bytes,17,opt,name=aes_key,json=aesKey,proto3" json:"aes_key,omitempty"`
|
||||
Unknown18 int32 `protobuf:"varint,18,opt,name=unknown18,proto3" json:"unknown18,omitempty"`
|
||||
CdnKey2 []byte `protobuf:"bytes,19,opt,name=cdn_key2,json=cdnKey2,proto3" json:"cdn_key2,omitempty"`
|
||||
Unknown20 int32 `protobuf:"varint,20,opt,name=unknown20,proto3" json:"unknown20,omitempty"`
|
||||
Unknown21 int32 `protobuf:"varint,21,opt,name=unknown21,proto3" json:"unknown21,omitempty"`
|
||||
Unknown22 int32 `protobuf:"varint,22,opt,name=unknown22,proto3" json:"unknown22,omitempty"`
|
||||
AesKey2 []byte `protobuf:"bytes,23,opt,name=aes_key2,json=aesKey2,proto3" json:"aes_key2,omitempty"`
|
||||
// fields 24-25 skipped
|
||||
Md5Key []byte `protobuf:"bytes,26,opt,name=md5_key,json=md5Key,proto3" json:"md5_key,omitempty"`
|
||||
// fields 27-36 skipped
|
||||
VideoId []byte `protobuf:"bytes,37,opt,name=video_id,json=videoId,proto3" json:"video_id,omitempty"`
|
||||
Unknown38 int32 `protobuf:"varint,38,opt,name=unknown38,proto3" json:"unknown38,omitempty"`
|
||||
// fields 39-47 skipped
|
||||
Md5Key2 []byte `protobuf:"bytes,48,opt,name=md5_key2,json=md5Key2,proto3" json:"md5_key2,omitempty"`
|
||||
CdnKey3 []byte `protobuf:"bytes,49,opt,name=cdn_key3,json=cdnKey3,proto3" json:"cdn_key3,omitempty"`
|
||||
AesKey3 []byte `protobuf:"bytes,50,opt,name=aes_key3,json=aesKey3,proto3" json:"aes_key3,omitempty"`
|
||||
Unknown51 int32 `protobuf:"varint,51,opt,name=unknown51,proto3" json:"unknown51,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) Reset() {
|
||||
*x = WxSendVideoMsg{}
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WxSendVideoMsg) ProtoMessage() {}
|
||||
|
||||
func (x *WxSendVideoMsg) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WxSendVideoMsg.ProtoReflect.Descriptor instead.
|
||||
func (*WxSendVideoMsg) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetHeader() *VideoMsgHeader {
|
||||
if x != nil {
|
||||
return x.Header
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetClientMsgId() []byte {
|
||||
if x != nil {
|
||||
return x.ClientMsgId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetSender() []byte {
|
||||
if x != nil {
|
||||
return x.Sender
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetReceiver() []byte {
|
||||
if x != nil {
|
||||
return x.Receiver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown5() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown5
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown6() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown7() *VideoMsgExtra {
|
||||
if x != nil {
|
||||
return x.Unknown7
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown8() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown8
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown9() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown9
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown10() *VideoMsgExtra {
|
||||
if x != nil {
|
||||
return x.Unknown10
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetDuration() int32 {
|
||||
if x != nil {
|
||||
return x.Duration
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown12() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown12
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown13() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown13
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown14() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown14
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetXml() []byte {
|
||||
if x != nil {
|
||||
return x.Xml
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetCdnKey() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetAesKey() []byte {
|
||||
if x != nil {
|
||||
return x.AesKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown18() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown18
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetCdnKey2() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown20() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown20
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown21() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown21
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown22() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown22
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetAesKey2() []byte {
|
||||
if x != nil {
|
||||
return x.AesKey2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetMd5Key() []byte {
|
||||
if x != nil {
|
||||
return x.Md5Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetVideoId() []byte {
|
||||
if x != nil {
|
||||
return x.VideoId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown38() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown38
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetMd5Key2() []byte {
|
||||
if x != nil {
|
||||
return x.Md5Key2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetCdnKey3() []byte {
|
||||
if x != nil {
|
||||
return x.CdnKey3
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetAesKey3() []byte {
|
||||
if x != nil {
|
||||
return x.AesKey3
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *WxSendVideoMsg) GetUnknown51() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown51
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type VideoMsgHeader struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Flag []byte `protobuf:"bytes,1,opt,name=flag,proto3" json:"flag,omitempty"`
|
||||
MsgId int64 `protobuf:"varint,2,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
|
||||
ClientProof []byte `protobuf:"bytes,3,opt,name=client_proof,json=clientProof,proto3" json:"client_proof,omitempty"`
|
||||
Unknown4 int64 `protobuf:"varint,4,opt,name=unknown4,proto3" json:"unknown4,omitempty"`
|
||||
SysInfo []byte `protobuf:"bytes,5,opt,name=sys_info,json=sysInfo,proto3" json:"sys_info,omitempty"`
|
||||
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) Reset() {
|
||||
*x = VideoMsgHeader{}
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*VideoMsgHeader) ProtoMessage() {}
|
||||
|
||||
func (x *VideoMsgHeader) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use VideoMsgHeader.ProtoReflect.Descriptor instead.
|
||||
func (*VideoMsgHeader) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetFlag() []byte {
|
||||
if x != nil {
|
||||
return x.Flag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetMsgId() int64 {
|
||||
if x != nil {
|
||||
return x.MsgId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetClientProof() []byte {
|
||||
if x != nil {
|
||||
return x.ClientProof
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetUnknown4() int64 {
|
||||
if x != nil {
|
||||
return x.Unknown4
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetSysInfo() []byte {
|
||||
if x != nil {
|
||||
return x.SysInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *VideoMsgHeader) GetUnknown6() int32 {
|
||||
if x != nil {
|
||||
return x.Unknown6
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type VideoMsgExtra struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
|
||||
Field2 []byte `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *VideoMsgExtra) Reset() {
|
||||
*x = VideoMsgExtra{}
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *VideoMsgExtra) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*VideoMsgExtra) ProtoMessage() {}
|
||||
|
||||
func (x *VideoMsgExtra) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wxproto_video_msg_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use VideoMsgExtra.ProtoReflect.Descriptor instead.
|
||||
func (*VideoMsgExtra) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *VideoMsgExtra) GetField1() int32 {
|
||||
if x != nil {
|
||||
return x.Field1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *VideoMsgExtra) GetField2() []byte {
|
||||
if x != nil {
|
||||
return x.Field2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proto_wxproto_video_msg_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_proto_wxproto_video_msg_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1dproto/wxproto/video_msg.proto\x12\awxproto\"\x9c\a\n" +
|
||||
"\x0eWxSendVideoMsg\x12/\n" +
|
||||
"\x06header\x18\x01 \x01(\v2\x17.wxproto.VideoMsgHeaderR\x06header\x12\"\n" +
|
||||
"\rclient_msg_id\x18\x02 \x01(\fR\vclientMsgId\x12\x16\n" +
|
||||
"\x06sender\x18\x03 \x01(\fR\x06sender\x12\x1a\n" +
|
||||
"\breceiver\x18\x04 \x01(\fR\breceiver\x12\x1a\n" +
|
||||
"\bunknown5\x18\x05 \x01(\x05R\bunknown5\x12\x1a\n" +
|
||||
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\x122\n" +
|
||||
"\bunknown7\x18\a \x01(\v2\x16.wxproto.VideoMsgExtraR\bunknown7\x12\x1a\n" +
|
||||
"\bunknown8\x18\b \x01(\x05R\bunknown8\x12\x1a\n" +
|
||||
"\bunknown9\x18\t \x01(\x05R\bunknown9\x124\n" +
|
||||
"\tunknown10\x18\n" +
|
||||
" \x01(\v2\x16.wxproto.VideoMsgExtraR\tunknown10\x12\x1a\n" +
|
||||
"\bduration\x18\v \x01(\x05R\bduration\x12\x1c\n" +
|
||||
"\tunknown12\x18\f \x01(\x05R\tunknown12\x12\x1c\n" +
|
||||
"\tunknown13\x18\r \x01(\x05R\tunknown13\x12\x1c\n" +
|
||||
"\tunknown14\x18\x0e \x01(\x05R\tunknown14\x12\x10\n" +
|
||||
"\x03xml\x18\x0f \x01(\fR\x03xml\x12\x17\n" +
|
||||
"\acdn_key\x18\x10 \x01(\fR\x06cdnKey\x12\x17\n" +
|
||||
"\aaes_key\x18\x11 \x01(\fR\x06aesKey\x12\x1c\n" +
|
||||
"\tunknown18\x18\x12 \x01(\x05R\tunknown18\x12\x19\n" +
|
||||
"\bcdn_key2\x18\x13 \x01(\fR\acdnKey2\x12\x1c\n" +
|
||||
"\tunknown20\x18\x14 \x01(\x05R\tunknown20\x12\x1c\n" +
|
||||
"\tunknown21\x18\x15 \x01(\x05R\tunknown21\x12\x1c\n" +
|
||||
"\tunknown22\x18\x16 \x01(\x05R\tunknown22\x12\x19\n" +
|
||||
"\baes_key2\x18\x17 \x01(\fR\aaesKey2\x12\x17\n" +
|
||||
"\amd5_key\x18\x1a \x01(\fR\x06md5Key\x12\x19\n" +
|
||||
"\bvideo_id\x18% \x01(\fR\avideoId\x12\x1c\n" +
|
||||
"\tunknown38\x18& \x01(\x05R\tunknown38\x12\x19\n" +
|
||||
"\bmd5_key2\x180 \x01(\fR\amd5Key2\x12\x19\n" +
|
||||
"\bcdn_key3\x181 \x01(\fR\acdnKey3\x12\x19\n" +
|
||||
"\baes_key3\x182 \x01(\fR\aaesKey3\x12\x1c\n" +
|
||||
"\tunknown51\x183 \x01(\x05R\tunknown51\"\xb1\x01\n" +
|
||||
"\x0eVideoMsgHeader\x12\x12\n" +
|
||||
"\x04flag\x18\x01 \x01(\fR\x04flag\x12\x15\n" +
|
||||
"\x06msg_id\x18\x02 \x01(\x03R\x05msgId\x12!\n" +
|
||||
"\fclient_proof\x18\x03 \x01(\fR\vclientProof\x12\x1a\n" +
|
||||
"\bunknown4\x18\x04 \x01(\x03R\bunknown4\x12\x19\n" +
|
||||
"\bsys_info\x18\x05 \x01(\fR\asysInfo\x12\x1a\n" +
|
||||
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\"?\n" +
|
||||
"\rVideoMsgExtra\x12\x16\n" +
|
||||
"\x06field1\x18\x01 \x01(\x05R\x06field1\x12\x16\n" +
|
||||
"\x06field2\x18\x02 \x01(\fR\x06field2B>Z<github.com/yincongcyincong/weixin-macos/onebot/proto/wxprotob\x06proto3"
|
||||
|
||||
var (
|
||||
file_proto_wxproto_video_msg_proto_rawDescOnce sync.Once
|
||||
file_proto_wxproto_video_msg_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_proto_wxproto_video_msg_proto_rawDescGZIP() []byte {
|
||||
file_proto_wxproto_video_msg_proto_rawDescOnce.Do(func() {
|
||||
file_proto_wxproto_video_msg_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_wxproto_video_msg_proto_rawDesc), len(file_proto_wxproto_video_msg_proto_rawDesc)))
|
||||
})
|
||||
return file_proto_wxproto_video_msg_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_wxproto_video_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_proto_wxproto_video_msg_proto_goTypes = []any{
|
||||
(*WxSendVideoMsg)(nil), // 0: wxproto.WxSendVideoMsg
|
||||
(*VideoMsgHeader)(nil), // 1: wxproto.VideoMsgHeader
|
||||
(*VideoMsgExtra)(nil), // 2: wxproto.VideoMsgExtra
|
||||
}
|
||||
var file_proto_wxproto_video_msg_proto_depIdxs = []int32{
|
||||
1, // 0: wxproto.WxSendVideoMsg.header:type_name -> wxproto.VideoMsgHeader
|
||||
2, // 1: wxproto.WxSendVideoMsg.unknown7:type_name -> wxproto.VideoMsgExtra
|
||||
2, // 2: wxproto.WxSendVideoMsg.unknown10:type_name -> wxproto.VideoMsgExtra
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_wxproto_video_msg_proto_init() }
|
||||
func file_proto_wxproto_video_msg_proto_init() {
|
||||
if File_proto_wxproto_video_msg_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wxproto_video_msg_proto_rawDesc), len(file_proto_wxproto_video_msg_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_proto_wxproto_video_msg_proto_goTypes,
|
||||
DependencyIndexes: file_proto_wxproto_video_msg_proto_depIdxs,
|
||||
MessageInfos: file_proto_wxproto_video_msg_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proto_wxproto_video_msg_proto = out.File
|
||||
file_proto_wxproto_video_msg_proto_goTypes = nil
|
||||
file_proto_wxproto_video_msg_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package wxproto;
|
||||
|
||||
option go_package = "github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto";
|
||||
|
||||
// 发送视频消息的protobuf结构
|
||||
message WxSendVideoMsg {
|
||||
VideoMsgHeader header = 1;
|
||||
bytes client_msg_id = 2;
|
||||
bytes sender = 3;
|
||||
bytes receiver = 4;
|
||||
int32 unknown5 = 5;
|
||||
int32 unknown6 = 6;
|
||||
VideoMsgExtra unknown7 = 7;
|
||||
int32 unknown8 = 8;
|
||||
int32 unknown9 = 9;
|
||||
VideoMsgExtra unknown10 = 10;
|
||||
int32 duration = 11;
|
||||
int32 unknown12 = 12;
|
||||
int32 unknown13 = 13;
|
||||
int32 unknown14 = 14;
|
||||
bytes xml = 15;
|
||||
bytes cdn_key = 16;
|
||||
bytes aes_key = 17;
|
||||
int32 unknown18 = 18;
|
||||
bytes cdn_key2 = 19;
|
||||
int32 unknown20 = 20;
|
||||
int32 unknown21 = 21;
|
||||
int32 unknown22 = 22;
|
||||
bytes aes_key2 = 23;
|
||||
// fields 24-25 skipped
|
||||
bytes md5_key = 26;
|
||||
// fields 27-36 skipped
|
||||
bytes video_id = 37;
|
||||
int32 unknown38 = 38;
|
||||
// fields 39-47 skipped
|
||||
bytes md5_key2 = 48;
|
||||
bytes cdn_key3 = 49;
|
||||
bytes aes_key3 = 50;
|
||||
int32 unknown51 = 51;
|
||||
}
|
||||
|
||||
message VideoMsgHeader {
|
||||
bytes flag = 1;
|
||||
int64 msg_id = 2;
|
||||
bytes client_proof = 3;
|
||||
int64 unknown4 = 4;
|
||||
bytes sys_info = 5;
|
||||
int32 unknown6 = 6;
|
||||
}
|
||||
|
||||
message VideoMsgExtra {
|
||||
int32 field1 = 1;
|
||||
bytes field2 = 2;
|
||||
}
|
||||
+18
-280
@@ -14,63 +14,6 @@ function hexToByteArray(hexStr) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function toVarint(n) {
|
||||
let res = [];
|
||||
while (n >= 128) {
|
||||
res.push((n & 0x7F) | 0x80); // 取后7位,最高位置1
|
||||
n = n >> 7; // 右移7位
|
||||
}
|
||||
res.push(n); // 最后一位最高位为0
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
function stringToHexArray(str) {
|
||||
var utf8Str = unescape(encodeURIComponent(str));
|
||||
var arr = [];
|
||||
for (var i = 0; i < utf8Str.length; i++) {
|
||||
arr.push(utf8Str.charCodeAt(i)); // 获取字符的 ASCII 码 (即十六进制值)
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
function generateRandom5ByteVarint() {
|
||||
let res = [];
|
||||
|
||||
// 前 4 个字节:最高位(bit 7)必须是 1,低 7 位随机
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let random7Bit = Math.floor(Math.random() * 128);
|
||||
res.push(random7Bit | 0x80); // 强制设置最高位为 1
|
||||
}
|
||||
|
||||
// 第 5 个字节:最高位必须是 0,为了确保不变成 4 字节,低 7 位不能全为 0
|
||||
let lastByte = Math.floor(Math.random() * 127) + 1;
|
||||
res.push(lastByte & 0x7F); // 确保最高位为 0
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
|
||||
function getVarintTimestampBytes() {
|
||||
let ts = Math.floor(Date.now() / 1000);
|
||||
let encodedBytes = [];
|
||||
let tempTs = ts >>> 0; // 强制转为 32位 无符号整数
|
||||
|
||||
while (true) {
|
||||
let byte = tempTs & 0x7F;
|
||||
tempTs >>>= 7;
|
||||
if (tempTs !== 0) {
|
||||
encodedBytes.push(byte | 0x80);
|
||||
} else {
|
||||
encodedBytes.push(byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return encodedBytes;
|
||||
}
|
||||
|
||||
function patchString(addr, plainStr) {
|
||||
const bytes = [];
|
||||
for (let i = 0; i < plainStr.length; i++) {
|
||||
@@ -90,19 +33,6 @@ function generateAESKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
function generateBytes(n) {
|
||||
// 生成随机字符串
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
|
||||
return stringToHexArray(result);
|
||||
}
|
||||
|
||||
// -------------------------基础函数分区-------------------------
|
||||
|
||||
// -------------------------全局变量分区-------------------------
|
||||
@@ -206,18 +136,12 @@ var senderGlobal = "wxid_"
|
||||
var lastSendTime = 0;
|
||||
var atUserGlobal = "";
|
||||
|
||||
// 图片/视频发送cdn信息全局变量 (从Go直接传入)
|
||||
var imgCdnKeyGlobal = "";
|
||||
var imgAesKeyGlobal = "";
|
||||
var imgMd5KeyGlobal = "";
|
||||
var videoCdnKeyGlobal = "";
|
||||
var videoAesKeyGlobal = "";
|
||||
var videoMd5KeyGlobal = "";
|
||||
var videoIdGlobal = "";
|
||||
// 文本消息protobuf全局变量 (从Go直接传入hex编码)
|
||||
var textProtoHexGlobal = "";
|
||||
|
||||
const fileCp = generateBytes(16)
|
||||
// 图片消息protobuf全局变量 (从Go直接传入hex编码)
|
||||
var imgProtoHexGlobal = "";
|
||||
// 视频消息protobuf全局变量 (从Go直接传入hex编码)
|
||||
var videoProtoHexGlobal = "";
|
||||
|
||||
// -------------------------全局变量分区-------------------------
|
||||
|
||||
@@ -532,7 +456,7 @@ function setupSendImgMessageDynamic() {
|
||||
uploadAesKeyAddr = Memory.alloc(256);
|
||||
ImagePathAddr1 = Memory.alloc(256);
|
||||
uploadImageX1 = Memory.alloc(1024);
|
||||
imgProtoX1PayloadAddr = Memory.alloc(1024);
|
||||
imgProtoX1PayloadAddr = Memory.alloc(2048);
|
||||
|
||||
// 图片数据写入
|
||||
patchString(imgCgiAddr, "/cgi-bin/micromsg-bin/uploadmsgimg");
|
||||
@@ -688,7 +612,7 @@ function patchVideoProtoBuf() {
|
||||
|
||||
setImmediate(patchVideoProtoBuf);
|
||||
|
||||
function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key) {
|
||||
function triggerSendImgMessage(taskId, sender, receiver, protoHex) {
|
||||
if (!taskId || !receiver || !sender) {
|
||||
console.error("[!] taskId or receiver or sender is empty!");
|
||||
return "fail";
|
||||
@@ -699,10 +623,8 @@ function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key)
|
||||
return "fail";
|
||||
}
|
||||
|
||||
// 保存cdn信息供attachProto使用
|
||||
imgCdnKeyGlobal = cdnKey;
|
||||
imgAesKeyGlobal = aesKey;
|
||||
imgMd5KeyGlobal = md5Key;
|
||||
// 保存protobuf hex供attachProto使用
|
||||
imgProtoHexGlobal = protoHex;
|
||||
|
||||
// 获取当前时间戳 (秒)
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
@@ -787,7 +709,7 @@ function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key)
|
||||
}
|
||||
}
|
||||
|
||||
function triggerSendVideoMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key, videoId) {
|
||||
function triggerSendVideoMessage(taskId, sender, receiver, protoHex) {
|
||||
if (!taskId || !receiver || !sender) {
|
||||
console.error("[!] taskId or receiver or sender is empty!");
|
||||
return "fail";
|
||||
@@ -798,11 +720,8 @@ function triggerSendVideoMessage(taskId, sender, receiver, cdnKey, aesKey, md5Ke
|
||||
return "fail";
|
||||
}
|
||||
|
||||
// 保存cdn信息供attachProto使用
|
||||
videoCdnKeyGlobal = cdnKey;
|
||||
videoAesKeyGlobal = aesKey;
|
||||
videoMd5KeyGlobal = md5Key;
|
||||
videoIdGlobal = videoId;
|
||||
// 保存protobuf hex供attachProto使用
|
||||
videoProtoHexGlobal = protoHex;
|
||||
|
||||
// 获取当前时间戳 (秒)
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
@@ -898,104 +817,16 @@ function attachProto() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用从Go传入的全局cdn信息
|
||||
let cdnKey = imgCdnKeyGlobal;
|
||||
let aesKey = imgAesKeyGlobal;
|
||||
let md5Key = imgMd5KeyGlobal;
|
||||
let targetId = receiverGlobal;
|
||||
|
||||
if (!cdnKey || !aesKey || !md5Key) {
|
||||
console.error("[!] 无法获取图片上传信息")
|
||||
return
|
||||
if (!imgProtoHexGlobal || imgProtoHexGlobal.length === 0) {
|
||||
console.error("[!] imgProtoHexGlobal 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
const type = [0x0A, 0x40, 0x0A, 0x01, 0x00]
|
||||
const msgId = [0x10].concat(generateRandom5ByteVarint())
|
||||
const cpHeader = [0x1A, 0x10]
|
||||
|
||||
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
|
||||
const sysHeader = [0x2A, 0x15]
|
||||
// UnifiedPCMac 26 arm64
|
||||
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x30]
|
||||
|
||||
// 45872025384@chatroom_176787000_60_xwechat_1 只需要改这个时间戳就能重复发送
|
||||
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
|
||||
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
|
||||
.concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x33]);
|
||||
|
||||
// 0xb0, 0x02 是长度,需要看一下什么的长度
|
||||
const msgIdHeader = [0xb0, 0x02, 0x12, receiverMsgId.length + 2, 0x0A, receiverMsgId.length]
|
||||
|
||||
const senderHeader = [0x1A, senderGlobal.length + 2, 0x0A, senderGlobal.length];
|
||||
// wxid_xxxx 或者 chatroom
|
||||
const sender = stringToHexArray(senderGlobal);
|
||||
const receiverHeader = [0x22, targetId.length + 2, 0x0A, targetId.length]
|
||||
// wxid_xxxx
|
||||
const receiver = stringToHexArray(targetId)
|
||||
const randomId1 = [0x28, 0xF4, 0x0B]
|
||||
const type1 = [0x30, 0x00]
|
||||
const randomId2 = [0x38, 0xF4, 0x0B]
|
||||
const randomId3 = [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
|
||||
const randomId4 = [0x48, 0x03]
|
||||
const htmlHeader = [0x52, 0x32];
|
||||
|
||||
const html = [0x3C,
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x30 msgsour
|
||||
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
|
||||
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
|
||||
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
|
||||
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
|
||||
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x58 msgsour
|
||||
0x63, 0x65, 0x3E // 0x60 ce>
|
||||
];
|
||||
|
||||
const cdnHeader = [0x58, 0x01, 0x60, 0x02, 0x68, 0x00, 0x7A, 0xB2, 0x01]
|
||||
// 3057 开头的cdn key
|
||||
const cdn = stringToHexArray(cdnKey);
|
||||
|
||||
const cdn2Header = [0x82, 0x01, 0xB2, 0x01]
|
||||
const cdn2 = stringToHexArray(cdnKey)
|
||||
|
||||
const aesKeyHeader = [0x8A, 0x01, 0x20]
|
||||
const aesKeyBytes = stringToHexArray(aesKey)
|
||||
|
||||
const randomId5 = [0x90, 0x01, 0x01, 0x98, 0x01, 0xFF, // 0x2C8
|
||||
0x13, 0xA0, 0x01, 0xFF, 0x13]
|
||||
|
||||
const cdn3Header = [0xAA, 0x01, 0xB2, 0x01]
|
||||
const cdn3 = stringToHexArray(cdnKey)
|
||||
|
||||
const randomId6 = [0xB0, 0x01, 0xF4, 0x0B]
|
||||
const randomId7 = [0xB8, 0x01, 0x68]
|
||||
const randomId8 = [0xC0, 0x01, 0x3A]
|
||||
const aesKey1Header = [0xCA, 0x01, 0x20]
|
||||
const aesKey1 = stringToHexArray(aesKey)
|
||||
const md5Header = [0xDA, 0x01, 0x20]
|
||||
const me5Key = stringToHexArray(md5Key)
|
||||
|
||||
const randomId9 = [0xE0, 0x01, 0xd9, 0xe7, 0xc7, 0xF3, 0x02]
|
||||
|
||||
var left0 = [
|
||||
0xF0, 0x01, 0x00, 0xA0, 0x02, 0x00, // 0x3E0
|
||||
0xC8, 0x02, 0x00, 0x00 // 0x3E8
|
||||
]
|
||||
|
||||
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
|
||||
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
|
||||
cdnHeader, cdn, cdn2Header, cdn2, aesKeyHeader, aesKeyBytes, randomId5, cdn3Header, cdn3, randomId6, randomId7, randomId8,
|
||||
aesKey1Header, aesKey1, md5Header, me5Key, randomId9, left0)
|
||||
|
||||
const finalPayload = hexToByteArray(imgProtoHexGlobal);
|
||||
imgProtoX1PayloadAddr.writeByteArray(finalPayload);
|
||||
|
||||
this.context.x1 = imgProtoX1PayloadAddr;
|
||||
this.context.x2 = ptr(finalPayload.length);
|
||||
|
||||
// console.log("[+] 图片 寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(imgProtoX1PayloadAddr, {
|
||||
// offset: 0,
|
||||
// length: 256,
|
||||
// header: true,
|
||||
// ansi: true
|
||||
// }));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1007,109 +838,16 @@ function attachProto() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用从Go传入的全局cdn信息
|
||||
let cdnKey = videoCdnKeyGlobal;
|
||||
let aesKey = videoAesKeyGlobal;
|
||||
let md5Key = videoMd5KeyGlobal;
|
||||
let videoId = videoIdGlobal;
|
||||
let targetId = receiverGlobal;
|
||||
|
||||
if (!cdnKey || !aesKey || !md5Key) {
|
||||
console.error("[!] 无法获取视频上传信息");
|
||||
if (!videoProtoHexGlobal || videoProtoHexGlobal.length === 0) {
|
||||
console.error("[!] videoProtoHexGlobal 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
const type = [0x0A, 0x3f, 0x0A, 0x01, 0x00]
|
||||
const msgId = [0x10].concat(generateRandom5ByteVarint())
|
||||
const cpHeader = [0x1A, 0x10]
|
||||
|
||||
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
|
||||
const sysHeader = [0x2A, 0x15]
|
||||
// UnifiedPCMac 26 arm64
|
||||
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34]
|
||||
|
||||
// 注意:这里 sender 和 receiver 互换了
|
||||
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
|
||||
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
|
||||
.concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x31]);
|
||||
|
||||
// 0x81, 0x01 是 tag,0x12, 0x2b 是长度=43
|
||||
const msgIdHeader = [0x30, 0x76, 0x12, receiverMsgId.length]
|
||||
|
||||
const senderHeader = [0x1A, senderGlobal.length];
|
||||
// sender 和 receiver 互换了,sender 是 wxid_ldftuhe36izg19
|
||||
const sender = stringToHexArray(senderGlobal);
|
||||
const receiverHeader = [0x22, targetId.length]
|
||||
// receiver 是 wxid_7wd1ece99f7i21
|
||||
const receiver = stringToHexArray(targetId)
|
||||
|
||||
const randomId1 = [0x28, 0xac, 0x73, 0x30, 0xac, 0x73, 0x3a, 0x04, 0x08, 0x00, 0x12, 0x00]
|
||||
const type1 = [0x40, 0xe8, 0xf2, 0x6f]
|
||||
const randomId2 = [0x48, 0xe8, 0xf2, 0x6f]
|
||||
const randomId3 = [0x52, 0x04, 0x08, 0x00, 0x12, 0x00]
|
||||
const randomId4 = [0x58, 0x0d, 0x60, 0x01, 0x68, 0x02, 0x70, 0x00]
|
||||
const htmlHeader = [0x7a, 0x3c];
|
||||
|
||||
const html = [0x3C, 0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65,
|
||||
0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72,
|
||||
0x3E, 0x31, 0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x63, 0x66, 0x3E, 0x33,
|
||||
0x3C, 0x2F, 0x63, 0x66, 0x3E, 0x3C, 0x2F, 0x61, 0x6C, 0x6E, 0x6F, 0x64,
|
||||
0x65, 0x3E, 0x3C, 0x2F, 0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, 0x63,
|
||||
0x65, 0x3E]
|
||||
|
||||
const cdnHeader = [0x82, 0x01, ...toVarint(cdnKey.length)]
|
||||
// 3057 开头的cdn key
|
||||
const cdn = stringToHexArray(cdnKey);
|
||||
|
||||
const aesKeyHeader = [0x8A, 0x01, 0x20]
|
||||
const aesKeyBytes = stringToHexArray(aesKey)
|
||||
|
||||
const randomId5 = [0x90, 0x01, 0x01, 0x9A, 0x01, ...toVarint(cdnKey.length)]
|
||||
|
||||
const cdn2 = stringToHexArray(cdnKey)
|
||||
|
||||
const randomId6 = [0xA0, 0x01, 0xAC, 0x73, 0xA8, 0x01, 0xE8, 0x02, 0xB0, 0x01, 0xCB, 0x01]
|
||||
|
||||
const aesKey1Header = [0xBA, 0x01, 0x20]
|
||||
const aesKey1 = stringToHexArray(aesKey)
|
||||
const md5Header = [0xd2, 0x01, 0x20]
|
||||
const md5KeyBytes = stringToHexArray(md5Key)
|
||||
|
||||
const md5Header1 = [0xAA, 0x02, 0x20]
|
||||
const md5Key1 = stringToHexArray(videoId)
|
||||
|
||||
const randomId7 = [0xB0, 0x02, 0x00]
|
||||
|
||||
const md5Key2Header = [0x82, 0x03, 0x20]
|
||||
const md5Key2 = stringToHexArray(md5Key)
|
||||
|
||||
const cdn3Header = [0x8A, 0x03, ...toVarint(cdnKey.length)]
|
||||
const cdn3 = stringToHexArray(cdnKey)
|
||||
|
||||
const randomId8 = [0x92, 0x03, 0x20]
|
||||
|
||||
const md5Key3 = stringToHexArray(aesKey)
|
||||
|
||||
var left0 = [
|
||||
0x98, 0x03, 0xe8, 0xf2, 0x6f
|
||||
]
|
||||
|
||||
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
|
||||
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
|
||||
cdnHeader, cdn, aesKeyHeader, aesKeyBytes, randomId5, cdn2, randomId6, aesKey1Header, aesKey1, md5Header, md5KeyBytes, md5Header1,
|
||||
md5Key1, randomId7, md5Key2Header, md5Key2, cdn3Header, cdn3, randomId8, md5Key3, left0)
|
||||
|
||||
const finalPayload = hexToByteArray(videoProtoHexGlobal);
|
||||
videoProtoX1PayloadAddr.writeByteArray(finalPayload);
|
||||
|
||||
this.context.x1 = videoProtoX1PayloadAddr;
|
||||
this.context.x2 = ptr(finalPayload.length);
|
||||
|
||||
// console.log("[+] 视频寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(videoProtoX1PayloadAddr, {
|
||||
// offset: 0,
|
||||
// length: finalPayload.length,
|
||||
// header: true,
|
||||
// ansi: true
|
||||
// }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -61,6 +61,29 @@ func SaveBase64Image(base64Data string) (string, string, error) {
|
||||
return targetPath, md5Str, nil
|
||||
}
|
||||
|
||||
// GetVideoDuration 使用ffprobe获取视频时长(秒)
|
||||
func GetVideoDuration(filePath string) (int32, error) {
|
||||
cmd := exec.Command("ffprobe",
|
||||
"-v", "error",
|
||||
"-show_entries", "format=duration",
|
||||
"-of", "default=noprint_wrappers=1:nokey=1",
|
||||
filePath,
|
||||
)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
if err := cmd.Run(); err != nil {
|
||||
return 0, fmt.Errorf("ffprobe error: %v", err)
|
||||
}
|
||||
|
||||
durationStr := strings.TrimSpace(out.String())
|
||||
durationFloat, err := strconv.ParseFloat(durationStr, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("parse duration failed: %v", err)
|
||||
}
|
||||
|
||||
return int32(durationFloat), nil
|
||||
}
|
||||
|
||||
func GetFileMD5(filePath string) (string, error) {
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
mathrand "math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// BuildVideoMsgProto 构建发送视频消息的protobuf并返回hex编码的字符串
|
||||
func BuildVideoMsgProto(sender, targetId, cdnKey, aesKey, md5Key, videoId string, duration int32) (string, error) {
|
||||
// 生成16字节随机client_proof
|
||||
clientProof := make([]byte, 16)
|
||||
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
randBytes := make([]byte, 16)
|
||||
rand.Read(randBytes)
|
||||
for i := range clientProof {
|
||||
clientProof[i] = chars[int(randBytes[i])%len(chars)]
|
||||
}
|
||||
|
||||
// 生成5字节varint范围的msgId (2^28 ~ 2^35-1)
|
||||
msgId := mathrand.Int63n(1<<35-1<<28) + (1 << 28)
|
||||
|
||||
// header.unknown4: 同图片proto
|
||||
const headerUnknown4 int64 = -228321745
|
||||
|
||||
// client_msg_id: targetId_timestamp_160_xwechat_1
|
||||
timestamp := time.Now().Unix()
|
||||
clientMsgId := targetId + "_" + strconv.FormatInt(timestamp, 10) + "_160_xwechat_1"
|
||||
|
||||
// xml内容 (视频多了<cf>3</cf>)
|
||||
xmlContent := []byte("<msgsource><alnode><fr>1</fr><cf>3</cf></alnode></msgsource>")
|
||||
|
||||
msg := &wxproto.WxSendVideoMsg{
|
||||
Header: &wxproto.VideoMsgHeader{
|
||||
Flag: []byte{0x00},
|
||||
MsgId: msgId,
|
||||
ClientProof: clientProof,
|
||||
Unknown4: headerUnknown4,
|
||||
SysInfo: []byte("UnifiedPCMac 26 arm64"),
|
||||
Unknown6: 118,
|
||||
},
|
||||
ClientMsgId: []byte(clientMsgId),
|
||||
Sender: []byte(sender),
|
||||
Receiver: []byte(targetId),
|
||||
Unknown5: 14764,
|
||||
Unknown6: 14764,
|
||||
Unknown7: &wxproto.VideoMsgExtra{
|
||||
Field1: 0,
|
||||
Field2: []byte{},
|
||||
},
|
||||
Unknown8: 1833320,
|
||||
Unknown9: 1833320,
|
||||
Unknown10: &wxproto.VideoMsgExtra{
|
||||
Field1: 0,
|
||||
Field2: []byte{},
|
||||
},
|
||||
Duration: duration,
|
||||
Unknown12: 1,
|
||||
Unknown13: 2,
|
||||
// Unknown14: 0, // 需要手动追加
|
||||
Xml: xmlContent,
|
||||
CdnKey: []byte(cdnKey),
|
||||
AesKey: []byte(aesKey),
|
||||
Unknown18: 1,
|
||||
CdnKey2: []byte(cdnKey),
|
||||
Unknown20: 14764,
|
||||
Unknown21: 360,
|
||||
Unknown22: 203,
|
||||
AesKey2: []byte(aesKey),
|
||||
Md5Key: []byte(md5Key),
|
||||
VideoId: []byte(videoId),
|
||||
// Unknown38: 0, // 需要手动追加
|
||||
Md5Key2: []byte(md5Key),
|
||||
CdnKey3: []byte(cdnKey),
|
||||
AesKey3: []byte(aesKey),
|
||||
Unknown51: 1833320,
|
||||
}
|
||||
|
||||
data, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal video proto failed: %w", err)
|
||||
}
|
||||
|
||||
// 手动追加proto3不会序列化的0值字段
|
||||
// field 14 (unknown14=0)
|
||||
data = appendZeroVarintField(data, 14)
|
||||
// field 38 (unknown38=0)
|
||||
data = appendZeroVarintField(data, 38)
|
||||
|
||||
return hex.EncodeToString(data), nil
|
||||
}
|
||||
+28
-6
@@ -78,7 +78,12 @@ func SendWechatMsg(m *SendMsg) {
|
||||
return
|
||||
}
|
||||
case "send_image":
|
||||
result := fridaScript.ExportsCall("triggerSendImgMessage", currTaskId, myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key)
|
||||
protoHex, err := BuildImgMsgProto(myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key)
|
||||
if err != nil {
|
||||
Error("构建图片protobuf失败", "err", err)
|
||||
return
|
||||
}
|
||||
result := fridaScript.ExportsCall("triggerSendImgMessage", currTaskId, myWechatId, targetId, protoHex)
|
||||
Info("📩 发送图片任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId)
|
||||
if result != "1" {
|
||||
Error("上传图片失败", "task_id", currTaskId, "target_id", targetId, "result", result)
|
||||
@@ -90,18 +95,35 @@ func SendWechatMsg(m *SendMsg) {
|
||||
Error("保存图片失败", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 获取视频时长
|
||||
duration, err := GetVideoDuration(targetPath)
|
||||
if err != nil {
|
||||
Error("获取视频时长失败", "err", err)
|
||||
} else {
|
||||
videoDurationMap.Store(targetId, duration)
|
||||
}
|
||||
|
||||
result := fridaScript.ExportsCall("triggerUploadVideo", targetId, md5Str, targetPath)
|
||||
Info("📩 上传视频任务执行结果", "result", result, "target_id", targetId, "md5", md5Str, "path", targetPath)
|
||||
Info("📩 上传视频任务执行结果", "result", result, "target_id", targetId, "md5", md5Str, "path", targetPath, "duration", duration)
|
||||
if result != "0" {
|
||||
Error("上传视频失败", "target_id", targetId, "md5", md5Str, "result", result)
|
||||
return
|
||||
}
|
||||
case "send_video":
|
||||
result := fridaScript.ExportsCall("triggerSendVideoMessage", currTaskId, myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key, m.VideoId)
|
||||
Info("📩 发送视频任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId)
|
||||
var duration int32
|
||||
if d, ok := videoDurationMap.LoadAndDelete(targetId); ok {
|
||||
duration = d.(int32)
|
||||
}
|
||||
protoHex, err := BuildVideoMsgProto(myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key, m.VideoId, duration)
|
||||
if err != nil {
|
||||
Error("构建视频protobuf失败", "err", err)
|
||||
return
|
||||
}
|
||||
result := fridaScript.ExportsCall("triggerSendVideoMessage", currTaskId, myWechatId, targetId, protoHex)
|
||||
Info("📩 发送视频任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId, "duration", duration)
|
||||
if result != "1" {
|
||||
Error("上传图片失败", "task_id", currTaskId, "target_id", targetId, "result", result)
|
||||
Error("发送视频失败", "task_id", currTaskId, "target_id", targetId, "result", result)
|
||||
return
|
||||
}
|
||||
case "download":
|
||||
|
||||
Reference in New Issue
Block a user