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_FILE = 0x22;
FUNC_SEND_XML = 0x23; FUNC_SEND_XML = 0x23;
FUNC_SEND_EMOTION = 0x24; FUNC_SEND_EMOTION = 0x24;
FUNC_SEND_RICH_TXT = 0x25;
FUNC_ENABLE_RECV_TXT = 0x30; FUNC_ENABLE_RECV_TXT = 0x30;
FUNC_DISABLE_RECV_TXT = 0x40; FUNC_DISABLE_RECV_TXT = 0x40;
FUNC_EXEC_DB_QUERY = 0x50; FUNC_EXEC_DB_QUERY = 0x50;
@ -51,6 +52,7 @@ message Request
bool flag = 13; bool flag = 13;
AttachMsg att = 14; AttachMsg att = 14;
AudioMsg am = 15; AudioMsg am = 15;
RichText rt = 16;
} }
} }
@ -195,3 +197,14 @@ message AudioMsg
uint64 id = 1; // id uint64 id = 1; // id
string dir = 2; // 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*/ /* call1, call2, call3, call4, call5, call6*/
{ 0x76F010, 0x792700, 0xBC0370, 0x80F110, 0x82BB40, 0x756E30}, { 0x76F010, 0x792700, 0xBC0370, 0x80F110, 0x82BB40, 0x756E30},
/* call1, call2, call3, call4, call5*/ /* 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) 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; 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 void PushMessage()
{ {
static nng_socket msg_sock; 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); ret = func_send_txt(req.msg.txt, out, out_len);
break; 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: { case Functions_FUNC_SEND_IMG: {
LOG_DEBUG("[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); 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; popad;
} }
} }
void SendXmlMessage(string receiver, string xml, string path, int type) void SendXmlMessage(string receiver, string xml, string path, int type)
{ {
if (g_WeChatWinDllAddr == 0) { if (g_WeChatWinDllAddr == 0) {
@ -294,3 +295,72 @@ void SendEmotionMessage(string wxid, string path)
popad; 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; 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 SendTextMessage(string wxid, string msg, string atWxids);
void SendImageMessage(string wxid, string path); void SendImageMessage(string wxid, string path);
void SendFileMessage(string wxid, string path); void SendFileMessage(string wxid, string path);
void SendXmlMessage(string receiver, string xml, string path, int type); void SendXmlMessage(string receiver, string xml, string path, int type);
void SendEmotionMessage(string wxid, string path); 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 VS_VERSION_INFO VERSIONINFO
FILEVERSION 39,0,6,0 FILEVERSION 39,0,8,0
PRODUCTVERSION 3,9,2,23 PRODUCTVERSION 3,9,2,23
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
@ -69,7 +69,7 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "WeChatFerry" VALUE "CompanyName", "WeChatFerry"
VALUE "FileDescription", "WeChatFerry" VALUE "FileDescription", "WeChatFerry"
VALUE "FileVersion", "39.0.6.0" VALUE "FileVersion", "39.0.8.0"
VALUE "InternalName", "spy.dll" VALUE "InternalName", "spy.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "spy.dll" VALUE "OriginalFilename", "spy.dll"

View File

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

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = "39.0.7.1" __version__ = "39.0.8.0"
import atexit import atexit
import base64 import base64
@ -415,6 +415,43 @@ class Wcf():
rsp = self._send_request(req) rsp = self._send_request(req)
return rsp.status 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: def get_msg(self, block=True) -> WxMsg:
"""从消息队列中获取消息 """从消息队列中获取消息

File diff suppressed because one or more lines are too long