Impl send rich text message

This commit is contained in:
Changhua 2023-12-05 23:37:57 +08:00
parent a75be1f161
commit cf2c038256
10 changed files with 232 additions and 56 deletions

View File

@ -18,6 +18,7 @@ enum Functions {
FUNC_SEND_FILE = 0x22;
FUNC_SEND_XML = 0x23;
FUNC_SEND_EMOTION = 0x24;
FUNC_SEND_RICH_TXT = 0x25;
FUNC_ENABLE_RECV_TXT = 0x30;
FUNC_DISABLE_RECV_TXT = 0x40;
FUNC_EXEC_DB_QUERY = 0x50;
@ -51,6 +52,7 @@ message Request
bool flag = 13;
AttachMsg att = 14;
AudioMsg am = 15;
RichText rt = 16;
}
}
@ -195,3 +197,14 @@ message AudioMsg
uint64 id = 1; // id
string dir = 2; //
}
message RichText
{
string name = 1; //
string account = 2; // id
string title = 3; //
string digest = 4; //
string url = 5; //
string thumburl = 6; //
string receiver = 7; //
}

View File

@ -31,7 +31,9 @@ WxCalls_t wxCalls = {
/* call1, call2, call3, call4, call5, call6*/
{ 0x76F010, 0x792700, 0xBC0370, 0x80F110, 0x82BB40, 0x756E30},
/* call1, call2, call3, call4, call5*/
{0x76F010, 0x792700, 0xBC0370, 0xBB5F70, 0x756E30}
{0x76F010, 0x792700, 0xBC0370, 0xBB5F70, 0x756E30},
/* call1, call2, call3, call4, call5*/
{0x76E630, 0x76AE20, 0xF59E40, 0xB73000, 0x76E350}
};
int LoadCalls(const wchar_t *version, WxCalls_t *calls)

View File

@ -334,6 +334,33 @@ bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len)
return true;
}
bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_SEND_RICH_TXT;
rsp.which_msg = Response_status_tag;
rsp.msg.status = 0;
RichText_t rtt;
rtt.account = string(rt.account ? rt.account : "");
rtt.digest = string(rt.digest ? rt.digest : "");
rtt.name = string(rt.name ? rt.name : "");
rtt.receiver = string(rt.receiver ? rt.receiver : "");
rtt.thumburl = string(rt.thumburl ? rt.thumburl : "");
rtt.title = string(rt.title ? rt.title : "");
rtt.url = string(rt.url ? rt.url : "");
rsp.msg.status = SendRichTextMessage(rtt);
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
static void PushMessage()
{
static nng_socket msg_sock;
@ -726,6 +753,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_send_txt(req.msg.txt, out, out_len);
break;
}
case Functions_FUNC_SEND_RICH_TXT: {
LOG_DEBUG("[Functions_FUNC_SEND_RICH_TXT]");
ret = func_send_rich_txt(req.msg.rt, out, out_len);
break;
}
case Functions_FUNC_SEND_IMG: {
LOG_DEBUG("[Functions_FUNC_SEND_IMG]");
ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len);

View File

@ -171,6 +171,7 @@ void SendFileMessage(string wxid, string path)
popad;
}
}
void SendXmlMessage(string receiver, string xml, string path, int type)
{
if (g_WeChatWinDllAddr == 0) {
@ -294,3 +295,72 @@ void SendEmotionMessage(string wxid, string path)
popad;
}
}
int SendRichTextMessage(RichText_t &rt)
{
int status = -1;
char buff[0x238] = { 0 };
DWORD rtCall3 = g_WeChatWinDllAddr + g_WxCalls.rt.call3;
DWORD rtCall2 = g_WeChatWinDllAddr + g_WxCalls.rt.call2;
DWORD rtCall1 = g_WeChatWinDllAddr + g_WxCalls.rt.call1;
DWORD rtCall5 = g_WeChatWinDllAddr + g_WxCalls.rt.call5;
DWORD rtCall4 = g_WeChatWinDllAddr + g_WxCalls.rt.call4;
__asm {
pushad;
pushfd;
lea ecx,buff;
call rtCall1;
popfd;
popad;
}
wstring receiver = String2Wstring(rt.receiver);
wstring title = String2Wstring(rt.title);
wstring url = String2Wstring(rt.url);
wstring thumburl = String2Wstring(rt.thumburl);
wstring account = String2Wstring(rt.account);
wstring name = String2Wstring(rt.name);
wstring digest = String2Wstring(rt.digest);
WxString wxReceiver(receiver);
WxString wxTitle(title);
WxString wxUrl(url);
WxString wxThumburl(thumburl);
WxString wxAccount(account);
WxString wxName(name);
WxString wxDigest(digest);
memcpy(&buff[0x4], &wxTitle, sizeof(wxTitle));
memcpy(&buff[0x2C], &wxUrl, sizeof(wxUrl));
memcpy(&buff[0x6C], &wxThumburl, sizeof(wxThumburl));
memcpy(&buff[0x94], &wxDigest, sizeof(wxDigest));
memcpy(&buff[0x1A0], &wxAccount, sizeof(wxAccount));
memcpy(&buff[0x1B4], &wxName, sizeof(wxName));
__asm {
pushad;
pushfd;
call rtCall2;
lea ecx, buff;
push ecx;
sub esp, 0x14;
mov edi, eax;
mov ecx, esp;
lea ebx, wxReceiver;
push ebx;
call rtCall3;
mov ecx, edi;
call rtCall4;
mov status, eax;
add ebx, 0x14;
lea ecx, buff;
push 0x0;
call rtCall5;
popfd;
popad;
}
return status;
}

View File

@ -4,8 +4,19 @@
using namespace std;
typedef struct {
string name;
string account;
string title;
string digest;
string url;
string thumburl;
string receiver;
} RichText_t;
void SendTextMessage(string wxid, string msg, string atWxids);
void SendImageMessage(string wxid, string path);
void SendFileMessage(string wxid, string path);
void SendXmlMessage(string receiver, string xml, string path, int type);
void SendEmotionMessage(string wxid, string path);
int SendRichTextMessage(RichText_t &rt);

Binary file not shown.

View File

@ -51,7 +51,7 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 39,0,6,0
FILEVERSION 39,0,8,0
PRODUCTVERSION 3,9,2,23
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
@ -69,7 +69,7 @@ BEGIN
BEGIN
VALUE "CompanyName", "WeChatFerry"
VALUE "FileDescription", "WeChatFerry"
VALUE "FileVersion", "39.0.6.0"
VALUE "FileVersion", "39.0.8.0"
VALUE "InternalName", "spy.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "spy.dll"

View File

@ -120,6 +120,14 @@ typedef struct RevokeMsg {
DWORD call5;
} RevokeMsg_t;
typedef struct CallRichText {
DWORD call1;
DWORD call2;
DWORD call3;
DWORD call4;
DWORD call5;
} CallRichText_t;
typedef struct WxCalls {
DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息
@ -138,6 +146,7 @@ typedef struct WxCalls {
Pyq_t pyq; // 接收朋友圈消息
DlAttach_t da; // 下载资源(图片、文件、视频)
RevokeMsg_t rm; // 撤回消息
CallRichText_t rt; // 消息卡片
} WxCalls_t;
struct WxString {

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
__version__ = "39.0.7.1"
__version__ = "39.0.8.0"
import atexit
import base64
@ -415,6 +415,43 @@ class Wcf():
rsp = self._send_request(req)
return rsp.status
def send_rich_text(
self, name: str, account: str, title: str, digest: str, url: str, thumburl: str, receiver: str) -> int:
"""发送富文本消息
卡片样式
|-------------------------------------|
|title, 最长两行
|(长标题, 标题短的话这行没有)
|digest, 最多三行会占位 |--------|
|digest, 最多三行会占位 |thumburl|
|digest, 最多三行会占位 |--------|
|(account logo) name
|-------------------------------------|
Args:
name (str): 左下显示的名字
account (str): 填公众号 id 可以显示对应的头像gh_ 开头的
title (str): 标题最多两行
digest (str): 摘要三行
url (str): 点击后跳转的链接
thumburl (str): 缩略图的链接
receiver (str): 接收人, wxid 或者 roomid
Returns:
int: 0 为成功其他失败
"""
req = wcf_pb2.Request()
req.func = wcf_pb2.FUNC_SEND_RICH_TXT # FUNC_SEND_RICH_TXT
req.rt.name = name
req.rt.account = account
req.rt.title = title
req.rt.digest = digest
req.rt.url = url
req.rt.thumburl = thumburl
req.rt.receiver = receiver
rsp = self._send_request(req)
return rsp.status
def get_msg(self, block=True) -> WxMsg:
"""从消息队列中获取消息

File diff suppressed because one or more lines are too long