From 2af5ad0253f9001607312c80b0aa83772e50dc05 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 1 Mar 2023 04:03:53 +0800 Subject: [PATCH] Impl SendXmlMessage --- python/demo.py | 6 +++ python/wcferry/client.py | 16 ++++++- rpc/proto/wcf.proto | 10 ++++ spy/load_calls.cpp | 5 +- spy/rpc_server.cpp | 36 +++++++++++++- spy/send_msg.cpp | 100 +++++++++++++++++++++++++++++++++++---- spy/send_msg.h | 1 + spy/spy_types.h | 9 ++++ 8 files changed, 167 insertions(+), 16 deletions(-) diff --git a/python/demo.py b/python/demo.py index aac393b..2fd8e42 100644 --- a/python/demo.py +++ b/python/demo.py @@ -3,6 +3,7 @@ import logging from threading import Thread +from time import sleep from wcferry import Wcf @@ -26,6 +27,7 @@ def main(): wcf = Wcf(debug=True) # 默认连接本地服务 # wcf = Wcf("tcp://127.0.0.1:10086") # 连接远端服务 + sleep(5) # 等微信加载好,以免信息显示异常 LOG.info(f"已经登录: {True if wcf.is_login() else False}") LOG.info(f"wxid: {wcf.get_self_wxid()}") @@ -58,6 +60,10 @@ def main(): # ret = wcf.add_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...") # LOG.info(f"add_chatroom_members: {ret}") + xml = '叮当药房,24小时服务,28分钟送药到家!叮当快药首家承诺范围内28分钟送药到家!叮当快药核心区域内7*24小时全天候服务,送药上门!叮当快药官网为您提供快捷便利,正品低价,安全放心的购药、送药服务体验。view330https://mp.weixin.qq.com/mp/waerrpage?appid=wxc2edadc87077fa2a&type=upgrade&upgradetype=3#wechat_redirect7f6f49d301ebf47100199b8a4fcf4de4gh_c2b88a38c424@app叮当快药 药店送药到家夜间买药0jpgda0e08f5c7259d03da150d5e7ca6d9503057020100044b30490201000204e4c0232702032f4ef20204a6bace6f02046401f62d042430326337303430352d333734332d343362652d623335322d6233333566623266376334620204012400030201000405004c5376000db26456caf243fbd4efb99058a01d660db26456caf243fbd4efb99058a01d66161558100100pages/index/index.htmlgh_c2b88a38c424@appwxc2edadc87077fa2a1972http://wx.qlogo.cn/mmhead/Q3auHgzwzM4727n0NQ0ZIPQPlfp15m1WLsnrXbo1kLhFGcolgLyc0A/9601_wxc2edadc87077fa2a_29177e9a9b918cb9e75964f80bb8f32e_1677849476_0wxid_eob5qfcrv4zd2201' + ret = wcf.send_xml("filehelper", xml, 0x21) + LOG.info(f"send_xml: {ret}") + # 一直运行 wcf.keep_running() diff --git a/python/wcferry/client.py b/python/wcferry/client.py index a15bd2a..c82d3a2 100644 --- a/python/wcferry/client.py +++ b/python/wcferry/client.py @@ -227,6 +227,18 @@ class Wcf(): rsp = self._send_request(req) return rsp.status + def send_xml(self, receiver: str, xml: str, type: int, path: str = None) -> int: + """发送文件""" + req = wcf_pb2.Request() + req.func = wcf_pb2.FUNC_SEND_XML # FUNC_SEND_XML + req.xml.receiver = receiver + req.xml.content = xml + req.xml.type = type + if path: + req.xml.path = path + rsp = self._send_request(req) + return rsp.status + def get_msg(self, block=True) -> WxMsg: return self.msgQ.get(block, timeout=1) @@ -351,8 +363,8 @@ class Wcf(): friends = [] for cnt in self.get_contacts(): if (cnt.wxid.endswith("@chatroom") # 群聊 - or cnt.wxid.startswith("gh_") # 公众号 - or cnt.wxid in not_friends.keys() # 其他杂号 + or cnt.wxid.startswith("gh_") # 公众号 + or cnt.wxid in not_friends.keys() # 其他杂号 ): continue friends.append(cnt) diff --git a/rpc/proto/wcf.proto b/rpc/proto/wcf.proto index b68bb61..8204025 100644 --- a/rpc/proto/wcf.proto +++ b/rpc/proto/wcf.proto @@ -31,6 +31,7 @@ enum Functions { FUNC_SEND_TXT = 0x20; FUNC_SEND_IMG = 0x21; FUNC_SEND_FILE = 0x22; + FUNC_SEND_XML = 0x23; FUNC_ENABLE_RECV_TXT = 0x30; FUNC_DISABLE_RECV_TXT = 0x40; FUNC_EXEC_DB_QUERY = 0x50; @@ -50,6 +51,7 @@ message Request DbQuery query = 6; Verification v = 7; AddMembers m = 8; + XmlMsg xml = 9; } } @@ -96,6 +98,14 @@ message PathMsg string receiver = 2; // 消息接收人 } +message XmlMsg +{ + string receiver = 1; // 消息接收人 + string content = 2; // xml 内容 + string path = 3; // 图片路径 + int32 type = 4; // 消息类型 +} + message MsgTypes { map types = 1; } message RpcContact diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 5efe9a5..529c237 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -11,8 +11,9 @@ WxCalls_t wxCalls = { /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content */ { 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 }, - { 0xBD780, 0x771980, 0x521640 }, // Send Image Message - { 0xC3B70, 0x771980, 0x3ED8C0 }, // Send File Message + { 0xBD780, 0x771980, 0x521640 }, // Send Image Message + { 0xC3B70, 0x771980, 0x3ED8C0 }, // Send File Message + { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml message /* Get Contacts: Base, head, wxId, Code, Name, Gender, Country, Province, City*/ { 0x23668F4, 0x4C, 0x30, 0x44, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 }, diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index b8c1c1a..a4dc2a4 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -234,6 +234,33 @@ bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) return true; } +bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_XML; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((xml.content == NULL) || (xml.receiver == NULL)) { + rsp.msg.status = -1; + } else { + string receiver(xml.receiver); + string content(xml.content); + string path(xml.path ? xml.path : ""); + uint32_t type = (uint32_t)xml.type; + SendXmlMessage(receiver, content, path, type); + } + + 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; @@ -417,7 +444,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len return false; } - LOG_DEBUG("Func: {}", (uint8_t)req.func); + LOG_DEBUG("Func: {:#x} Data: {}", (uint8_t)req.func, in_len); switch (req.func) { case Functions_FUNC_IS_LOGIN: { LOG_DEBUG("[Functions_FUNC_IS_LOGIN]"); @@ -464,6 +491,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); break; } + case Functions_FUNC_SEND_XML: { + LOG_DEBUG("[Functions_FUNC_SEND_XML]"); + ret = func_send_xml(req.msg.xml, out, out_len); + break; + } case Functions_FUNC_ENABLE_RECV_TXT: { LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]"); ret = func_enable_recv_txt(out, out_len); @@ -527,7 +559,7 @@ static int RunServer() break; } - LOG_BUFFER(in, in_len); + // LOG_BUFFER(in, in_len); if (dispatcher(in, in_len, gBuffer, &out_len)) { LOG_DEBUG("Send data length {}", out_len); // LOG_BUFFER(gBuffer, out_len); diff --git a/spy/send_msg.cpp b/spy/send_msg.cpp index 95319a5..08b2849 100644 --- a/spy/send_msg.cpp +++ b/spy/send_msg.cpp @@ -9,12 +9,13 @@ extern HANDLE g_hEvent; extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; +extern string GetSelfWxid(); // Defined in spy.cpp void SendTextMessage(string wxid, string msg, string atWxids) { char buffer[0x3B0] = { 0 }; - WxString_t txtMsg = { 0 }; - WxString_t txtWxid = { 0 }; + WxString_t wxMsg = { 0 }; + WxString_t wxWxid = { 0 }; // 发送消息Call地址 = 微信基址 + 偏移 DWORD sendCallAddress = g_WeChatWinDllAddr + g_WxCalls.sendTextMsg; @@ -22,13 +23,13 @@ void SendTextMessage(string wxid, string msg, string atWxids) wstring wsWxid = String2Wstring(wxid); wstring wsMsg = String2Wstring(msg); - txtMsg.text = (wchar_t *)wsMsg.c_str(); - txtMsg.size = wsMsg.size(); - txtMsg.capacity = wsMsg.capacity(); + wxMsg.text = (wchar_t *)wsMsg.c_str(); + wxMsg.size = wsMsg.size(); + wxMsg.capacity = wsMsg.capacity(); - txtWxid.text = (wchar_t *)wsWxid.c_str(); - txtWxid.size = wsWxid.size(); - txtWxid.capacity = wsWxid.capacity(); + wxWxid.text = (wchar_t *)wsWxid.c_str(); + wxWxid.size = wsWxid.size(); + wxWxid.capacity = wsWxid.capacity(); vector vTxtAtWxids; if (!atWxids.empty()) { @@ -51,9 +52,9 @@ void SendTextMessage(string wxid, string msg, string atWxids) lea eax, vTxtAtWxids; push 0x01; push eax; - lea edi, txtMsg; + lea edi, wxMsg; push edi; - lea edx, txtWxid; + lea edx, wxWxid; lea ecx, buffer; call sendCallAddress; add esp, 0xC; @@ -173,3 +174,82 @@ void SendFileMessage(string wxid, string path) popad; } } + +void SendXmlMessage(string receiver, string xml, string path, int type) +{ + if (g_WeChatWinDllAddr == 0) { + return; + } + + // 发送消息Call地址 = 微信基址 + 偏移 + DWORD sendXmlCall1 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call1; + DWORD sendXmlCall2 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call2; + DWORD sendXmlCall3 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call3; + DWORD sendXmlCall4 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call4; + DWORD sendXmlParam = g_WeChatWinDllAddr + g_WxCalls.sendXml.param; + + char buffer[0xFF0] = { 0 }; + char nullBuf[0x1C] = { 0 }; + WxString_t wxReceiver = { 0 }; + WxString_t wxXml = { 0 }; + WxString_t wxPath = { 0 }; + WxString_t wxNull = { 0 }; + WxString_t wxSender = { 0 }; + + wstring wsSender = String2Wstring(GetSelfWxid()); + wstring wsReceiver = String2Wstring(receiver); + wstring wsXml = String2Wstring(xml); + + wxReceiver.text = (wchar_t *)wsReceiver.c_str(); + wxReceiver.size = wsReceiver.size(); + wxReceiver.capacity = wsReceiver.capacity(); + + wxXml.text = (wchar_t *)wsXml.c_str(); + wxXml.size = wsXml.size(); + wxXml.capacity = wsXml.capacity(); + + wxSender.text = (wchar_t *)wsSender.c_str(); + wxSender.size = wsSender.size(); + wxSender.capacity = wsSender.capacity(); + + if (!path.empty()) { + wstring wsPath = String2Wstring(path); + wxPath.text = (wchar_t *)wsPath.c_str(); + wxPath.size = wsPath.size(); + wxPath.capacity = wsPath.capacity(); + } + + DWORD sendtype = type; + __asm { + pushad; + pushfd; + lea ecx, buffer; + call sendXmlCall1; + mov eax, [sendtype]; + push eax; + lea eax, nullBuf; + lea edx, wxSender; + push eax; + lea eax, wxPath; + push eax; + lea eax, wxXml; + push eax; + lea edi, wxReceiver; + push edi; + lea ecx, buffer; + call sendXmlCall2; + add esp, 0x14; + lea eax, wxNull; + push eax; + lea ecx, buffer; + call sendXmlCall3; + mov dl, 0x0; + lea ecx, buffer; + push sendXmlParam; + push sendXmlParam; + call sendXmlCall4; + add esp, 0x8; + popfd; + popad; + } +} diff --git a/spy/send_msg.h b/spy/send_msg.h index 9abac22..6706e10 100644 --- a/spy/send_msg.h +++ b/spy/send_msg.h @@ -7,3 +7,4 @@ using namespace std; 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); diff --git a/spy/spy_types.h b/spy/spy_types.h index 0330dc3..162180a 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -59,6 +59,14 @@ typedef struct RoomMember { DWORD call3; } RoomMember_t; +typedef struct Xml { + DWORD call1; + DWORD call2; + DWORD call3; + DWORD call4; + DWORD param; +} Xml_t; + typedef struct WxCalls { DWORD login; // 登录状态 UserInfoCall_t ui; // 用户信息 @@ -66,6 +74,7 @@ typedef struct WxCalls { RecvMsg_t recvMsg; // 接收消息 Sendfile_t sendImg; // 发送图片 Sendfile_t sendFile; // 发送文件 + Xml_t sendXml; // 发送XML Contact_t contact; // 获取联系人 Sql_t sql; // 执行 SQL NewFriend_t anf; // 通过好友申请