From 554d62efcf617290e0142eff3b6930f2b1e0de7d Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 28 Jan 2025 20:31:51 +0800 Subject: [PATCH 01/41] Refactor: replace C-style code with modern C++ idioms --- WeChatFerry/spy/receive_msg.cpp | 443 ++++++++++++-------------------- WeChatFerry/spy/receive_msg.h | 69 ++++- 2 files changed, 227 insertions(+), 285 deletions(-) diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index e283ce0..4aa92e3 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -1,23 +1,15 @@ -#pragma execution_character_set("utf-8") - -#include "MinHook.h" -#include "framework.h" + #include #include #include +#include "framework.h" + #include "log.hpp" #include "receive_msg.h" #include "user_info.h" #include "util.h" -// Defined in rpc_server.cpp -extern bool gIsLogging, gIsListening, gIsListeningPyq; -extern mutex gMutex; -extern condition_variable gCV; -extern queue gMsgQueue; - -// Defined in spy.cpp extern QWORD g_WeChatWinDllAddr; #define OS_RECV_MSG_ID 0x30 @@ -41,62 +33,10 @@ extern QWORD g_WeChatWinDllAddr; #define OS_PYQ_MSG_CALL 0x2E42C90 #define OS_WXLOG 0x2613D20 -typedef QWORD (*RecvMsg_t)(QWORD, QWORD); -typedef QWORD (*WxLog_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*RecvPyq_t)(QWORD, QWORD, QWORD); - -static RecvMsg_t funcRecvMsg = nullptr; -static RecvMsg_t realRecvMsg = nullptr; -static WxLog_t funcWxLog = nullptr; -static WxLog_t realWxLog = nullptr; -static RecvPyq_t funcRecvPyq = nullptr; -static RecvPyq_t realRecvPyq = nullptr; -static bool isMH_Initialized = false; - -MsgTypes_t GetMsgTypes() +QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) { - const MsgTypes_t m = { - { 0x00, "朋友圈消息" }, - { 0x01, "文字" }, - { 0x03, "图片" }, - { 0x22, "语音" }, - { 0x25, "好友确认" }, - { 0x28, "POSSIBLEFRIEND_MSG" }, - { 0x2A, "名片" }, - { 0x2B, "视频" }, - { 0x2F, "石头剪刀布 | 表情图片" }, - { 0x30, "位置" }, - { 0x31, "共享实时位置、文件、转账、链接" }, - { 0x32, "VOIPMSG" }, - { 0x33, "微信初始化" }, - { 0x34, "VOIPNOTIFY" }, - { 0x35, "VOIPINVITE" }, - { 0x3E, "小视频" }, - { 0x42, "微信红包" }, - { 0x270F, "SYSNOTICE" }, - { 0x2710, "红包、系统消息" }, - { 0x2712, "撤回消息" }, - { 0x100031, "搜狗表情" }, - { 0x1000031, "链接" }, - { 0x1A000031, "微信红包" }, - { 0x20010031, "红包封面" }, - { 0x2D000031, "视频号视频" }, - { 0x2E000031, "视频号名片" }, - { 0x31000031, "引用消息" }, - { 0x37000031, "拍一拍" }, - { 0x3A000031, "视频号直播" }, - { 0x3A100031, "商品链接" }, - { 0x3A200031, "视频号直播" }, - { 0x3E000031, "音乐链接" }, - { 0x41000031, "文件" }, - }; - - return m; -} - -static QWORD DispatchMsg(QWORD arg1, QWORD arg2) -{ - WxMsg_t wxMsg = { 0 }; + auto &handler = getInstance(); + WxMsg_t wxMsg = {}; try { wxMsg.id = GET_QWORD(arg2 + OS_RECV_MSG_ID); wxMsg.type = GET_DWORD(arg2 + OS_RECV_MSG_TYPE); @@ -105,66 +45,45 @@ static QWORD DispatchMsg(QWORD arg1, QWORD arg2) wxMsg.content = GetStringByWstrAddr(arg2 + OS_RECV_MSG_CONTENT); wxMsg.sign = GetStringByWstrAddr(arg2 + OS_RECV_MSG_SIGN); wxMsg.xml = GetStringByWstrAddr(arg2 + OS_RECV_MSG_XML); + wxMsg.roomid = GetStringByWstrAddr(arg2 + OS_RECV_MSG_ROOMID); - string roomid = GetStringByWstrAddr(arg2 + OS_RECV_MSG_ROOMID); - wxMsg.roomid = roomid; - if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom + if (wxMsg.roomid.find("@chatroom") != std::string::npos) { wxMsg.is_group = true; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID); - } + wxMsg.sender = wxMsg.is_self ? GetSelfWxid() : GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID); } else { wxMsg.is_group = false; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = roomid; - } - } - - wxMsg.thumb = GetStringByWstrAddr(arg2 + OS_RECV_MSG_THUMB); - if (!wxMsg.thumb.empty()) { - wxMsg.thumb = GetHomePath() + wxMsg.thumb; - replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/'); - } - - wxMsg.extra = GetStringByWstrAddr(arg2 + OS_RECV_MSG_EXTRA); - if (!wxMsg.extra.empty()) { - wxMsg.extra = GetHomePath() + wxMsg.extra; - replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/'); + wxMsg.sender = wxMsg.is_self ? GetSelfWxid() : wxMsg.roomid; } } catch (const std::exception &e) { LOG_ERROR(GB2312ToUtf8(e.what())); - } catch (...) { - LOG_ERROR("Unknow exception."); } { - unique_lock lock(gMutex); - gMsgQueue.push(wxMsg); // 推送到队列 + std::unique_lock lock(handler.mutex_); + handler.msgQueue_.push(wxMsg); } - gCV.notify_all(); // 通知各方消息就绪 - return realRecvMsg(arg1, arg2); + handler.cv_.notify_all(); + return handler.realRecvMsg(arg1, arg2); } -static QWORD PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, QWORD a9, - QWORD a10, QWORD a11, QWORD a12) +QWORD MessageHandler::PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, + QWORD a9, QWORD a10, QWORD a11, QWORD a12) { - QWORD p = realWxLog(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); + auto &handler = getInstance(); + + QWORD p = handler.realWxLog(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); if (p == 0 || p == 1) { return p; } LOG_INFO("【WX】\n{}", GB2312ToUtf8((char *)p)); - return p; } -static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) +void MessageHandler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) { + auto &handler = getInstance(); QWORD startAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_START); QWORD endAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_END); @@ -175,7 +94,7 @@ static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) while (startAddr < endAddr) { WxMsg_t wxMsg; - wxMsg.type = 0x00; // 朋友圈消息 + wxMsg.type = 0x00; wxMsg.is_self = false; wxMsg.is_group = false; wxMsg.id = GET_QWORD(startAddr); @@ -185,194 +104,162 @@ static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) wxMsg.content = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_CONTENT); { - unique_lock lock(gMutex); - gMsgQueue.push(wxMsg); // 推送到队列 + std::unique_lock lock(handler.mutex_); + handler.msgQueue_.push(wxMsg); } - gCV.notify_all(); // 通知各方消息就绪 - + handler.cv_.notify_all(); startAddr += 0x1618; } } -static MH_STATUS InitializeHook() +MessageHandler &MessageHandler::getInstance() { - if (isMH_Initialized) { - return MH_OK; + static MessageHandler instance; + return instance; +} + +MessageHandler::MessageHandler() +{ + isLogging = false; + isListeningMsg = false; + isListeningPyq = false; +} + +MessageHandler::~MessageHandler() +{ + DisableLog(); + UnListenMsg(); + UnListenPyq(); +} + +MsgTypes_t MessageHandler::GetMsgTypes() +{ + return { { 0x00, "朋友圈消息" }, + { 0x01, "文字" }, + { 0x03, "图片" }, + { 0x22, "语音" }, + { 0x25, "好友确认" }, + { 0x28, "POSSIBLEFRIEND_MSG" }, + { 0x2A, "名片" }, + { 0x2B, "视频" }, + { 0x2F, "石头剪刀布 | 表情图片" }, + { 0x30, "位置" }, + { 0x31, "共享实时位置、文件、转账、链接" }, + { 0x32, "VOIPMSG" }, + { 0x33, "微信初始化" }, + { 0x34, "VOIPNOTIFY" }, + { 0x35, "VOIPINVITE" }, + { 0x3E, "小视频" }, + { 0x42, "微信红包" }, + { 0x270F, "SYSNOTICE" }, + { 0x2710, "红包、系统消息" }, + { 0x2712, "撤回消息" }, + { 0x100031, "搜狗表情" }, + { 0x1000031, "链接" }, + { 0x1A000031, "微信红包" }, + { 0x20010031, "红包封面" }, + { 0x2D000031, "视频号视频" }, + { 0x2E000031, "视频号名片" }, + { 0x31000031, "引用消息" }, + { 0x37000031, "拍一拍" }, + { 0x3A000031, "视频号直播" }, + { 0x3A100031, "商品链接" }, + { 0x3A200031, "视频号直播" }, + { 0x3E000031, "音乐链接" }, + { 0x41000031, "文件" } }; +} + +std::optional MessageHandler::popMessage() +{ + std::lock_guard lock(mutex_); + if (msgQueue_.empty()) { + return std::nullopt; } + WxMsg_t msg = std::move(msgQueue_.front()); + msgQueue_.pop(); + return msg; +} + +int MessageHandler::EnableLog() +{ + if (isLogging) return 1; + + funcWxLog = reinterpret_cast(g_WeChatWinDllAddr + OS_WXLOG); + + if (InitializeHook() != MH_OK) return -1; + if (MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast(&realWxLog)) != MH_OK) return -1; + if (MH_EnableHook(funcWxLog) != MH_OK) return -1; + + isLogging = true; + return 0; +} + +int MessageHandler::DisableLog() +{ + if (!isLogging) return 1; + if (MH_DisableHook(funcWxLog) != MH_OK) return -1; + if (UninitializeHook() != MH_OK) return -1; + isLogging = false; + return 0; +} + +int MessageHandler::ListenMsg() +{ + if (isListeningMsg) return 1; + + funcRecvMsg = reinterpret_cast(g_WeChatWinDllAddr + OS_RECV_MSG_CALL); + if (InitializeHook() != MH_OK) return -1; + if (MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast(&realRecvMsg)) != MH_OK) return -1; + if (MH_EnableHook(funcRecvMsg) != MH_OK) return -1; + + isListeningMsg = true; + return 0; +} + +int MessageHandler::UnListenMsg() +{ + if (!isListeningMsg) return 1; + if (MH_DisableHook(funcRecvMsg) != MH_OK) return -1; + if (UninitializeHook() != MH_OK) return -1; + isListeningMsg = false; + return 0; +} + +int MessageHandler::ListenPyq() +{ + if (isListeningPyq) return 1; + + funcRecvPyq = reinterpret_cast(g_WeChatWinDllAddr + OS_PYQ_MSG_CALL); + if (InitializeHook() != MH_OK) return -1; + if (MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast(&realRecvPyq)) != MH_OK) return -1; + if (MH_EnableHook(funcRecvPyq) != MH_OK) return -1; + + isListeningPyq = true; + return 0; +} + +int MessageHandler::UnListenPyq() +{ + if (!isListeningPyq) return 1; + if (MH_DisableHook(funcRecvPyq) != MH_OK) return -1; + if (UninitializeHook() != MH_OK) return -1; + isListeningPyq = false; + return 0; +} + +MH_STATUS MessageHandler::InitializeHook() +{ + if (isMH_Initialized) return MH_OK; MH_STATUS status = MH_Initialize(); - if (status == MH_OK) { - isMH_Initialized = true; - } + if (status == MH_OK) isMH_Initialized = true; return status; } -static MH_STATUS UninitializeHook() +MH_STATUS MessageHandler::UninitializeHook() { - if (!isMH_Initialized) { - return MH_OK; - } - if (gIsLogging || gIsListening || gIsListeningPyq) { - return MH_OK; - } + if (!isMH_Initialized || isLogging || isListeningMsg || isListeningPyq) return MH_OK; MH_STATUS status = MH_Uninitialize(); - if (status == MH_OK) { - isMH_Initialized = false; - } + if (status == MH_OK) isMH_Initialized = false; return status; } - -void EnableLog() -{ - MH_STATUS status = MH_UNKNOWN; - if (gIsLogging) { - LOG_WARN("gIsLogging"); - return; - } - WxLog_t funcWxLog = (WxLog_t)(g_WeChatWinDllAddr + OS_WXLOG); - - status = InitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Initialize failed: {}", to_string(status)); - return; - } - - status = MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast(&realWxLog)); - if (status != MH_OK) { - LOG_ERROR("MH_CreateHook failed: {}", to_string(status)); - return; - } - - status = MH_EnableHook(funcWxLog); - if (status != MH_OK) { - LOG_ERROR("MH_EnableHook failed: {}", to_string(status)); - return; - } - gIsLogging = true; -} - -void DisableLog() -{ - MH_STATUS status = MH_UNKNOWN; - if (!gIsLogging) { - return; - } - - status = MH_DisableHook(funcWxLog); - if (status != MH_OK) { - LOG_ERROR("MH_DisableHook failed: {}", to_string(status)); - return; - } - - gIsLogging = false; - - status = UninitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); - return; - } -} - -void ListenMessage() -{ - MH_STATUS status = MH_UNKNOWN; - if (gIsListening) { - LOG_WARN("gIsListening"); - return; - } - funcRecvMsg = (RecvMsg_t)(g_WeChatWinDllAddr + OS_RECV_MSG_CALL); - - status = InitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Initialize failed: {}", to_string(status)); - return; - } - - status = MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast(&realRecvMsg)); - if (status != MH_OK) { - LOG_ERROR("MH_CreateHook failed: {}", to_string(status)); - return; - } - - status = MH_EnableHook(funcRecvMsg); - if (status != MH_OK) { - LOG_ERROR("MH_EnableHook failed: {}", to_string(status)); - return; - } - - gIsListening = true; -} - -void UnListenMessage() -{ - MH_STATUS status = MH_UNKNOWN; - if (!gIsListening) { - return; - } - - status = MH_DisableHook(funcRecvMsg); - if (status != MH_OK) { - LOG_ERROR("MH_DisableHook failed: {}", to_string(status)); - return; - } - - gIsListening = false; - - status = UninitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); - return; - } -} - -void ListenPyq() -{ - MH_STATUS status = MH_UNKNOWN; - if (gIsListeningPyq) { - LOG_WARN("gIsListeningPyq"); - return; - } - funcRecvPyq = (RecvPyq_t)(g_WeChatWinDllAddr + OS_PYQ_MSG_CALL); - - status = InitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Initialize failed: {}", to_string(status)); - return; - } - - status = MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast(&realRecvPyq)); - if (status != MH_OK) { - LOG_ERROR("MH_CreateHook failed: {}", to_string(status)); - return; - } - - status = MH_EnableHook(funcRecvPyq); - if (status != MH_OK) { - LOG_ERROR("MH_EnableHook failed: {}", to_string(status)); - return; - } - - gIsListeningPyq = true; -} - -void UnListenPyq() -{ - MH_STATUS status = MH_UNKNOWN; - if (!gIsListeningPyq) { - return; - } - - status = MH_DisableHook(funcRecvPyq); - if (status != MH_OK) { - LOG_ERROR("MH_DisableHook failed: {}", to_string(status)); - return; - } - - gIsListeningPyq = false; - - status = UninitializeHook(); - if (status != MH_OK) { - LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); - return; - } -} diff --git a/WeChatFerry/spy/receive_msg.h b/WeChatFerry/spy/receive_msg.h index 73d8759..0e2f314 100644 --- a/WeChatFerry/spy/receive_msg.h +++ b/WeChatFerry/spy/receive_msg.h @@ -1,11 +1,66 @@ #pragma once +#include +#include +#include +#include +#include +#include + +#include "MinHook.h" + #include "pb_types.h" -void EnableLog(); -void DisableLog(); -void ListenPyq(); -void UnListenPyq(); -void ListenMessage(); -void UnListenMessage(); -MsgTypes_t GetMsgTypes(); +class MessageHandler +{ +public: + static MessageHandler &getInstance(); + + // 0: 成功, -1: 失败, 1: 已经开启 + int EnableLog(); + int DisableLog(); + int ListenPyq(); + int UnListenPyq(); + int ListenMsg(); + int UnListenMsg(); + + MsgTypes_t GetMsgTypes(); + + bool isLoggingEnabled() const { return isLogging.load(); } + bool isMessageListening() const { return isListeningMsg.load(); } + bool isPyqListening() const { return isListeningPyq.load(); } + + std::optional popMessage(); + std::condition_variable &getConditionVariable() { return cv_; }; + std::mutex &getMutex() { return mutex_; }; + +private: + MessageHandler(); + ~MessageHandler(); + + mutable std::mutex mutex_; + std::condition_variable cv_; + std::queue msgQueue_; + + std::atomic isLogging { false }; + std::atomic isListeningMsg { false }; + std::atomic isListeningPyq { false }; + + using funcRecvMsg_t = QWORD (*)(QWORD, QWORD); + using funcWxLog_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); + using funcRecvPyq_t = QWORD (*)(QWORD, QWORD, QWORD); + + funcWxLog_t funcWxLog, realWxLog; + funcRecvMsg_t funcRecvMsg, realRecvMsg; + funcRecvPyq_t funcRecvPyq, realRecvPyq; + + bool isMH_Initialized { false }; + + MH_STATUS InitializeHook(); + MH_STATUS UninitializeHook(); + + static QWORD DispatchMsg(QWORD arg1, QWORD arg2); + static QWORD PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, QWORD a9, + QWORD a10, QWORD a11, QWORD a12); + static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3); +}; From 15267632a10e1e0d9c8a239cbdd900bf9dcce03b Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 29 Jan 2025 18:32:20 +0800 Subject: [PATCH 02/41] Refactor: replace C-style code with modern C++ idioms --- WeChatFerry/spy/funcs.cpp | 43 ++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index c12f9b5..56b1b8c 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -8,13 +8,13 @@ #include "exec_sql.h" #include "funcs.h" #include "log.hpp" +#include "receive_msg.h" #include "spy_types.h" #include "util.h" using namespace std; namespace fs = std::filesystem; -extern bool gIsListeningPyq; extern QWORD g_WeChatWinDllAddr; #define HEADER_PNG1 0x89 @@ -111,32 +111,25 @@ string DecryptImage(string src, string dir) string dst = ""; - try { - if (dir.empty()) { - dst = fs::path(src).replace_extension(ext).string(); - } else { - dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); - - // 判断dir文件夹是否存在,若不存在则创建(否则将无法创建出文件) - if (!fs::exists(dst)) {//判断该文件夹是否存在 - bool success = fs::create_directories(dst); //Windows创建文件夹 - if (!success) { //创建失败 - LOG_ERROR("Failed to mkdir:{}", dst); - return ""; - } + if (dir.empty()) { + dst = fs::path(src).replace_extension(ext).string(); + } else { + dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); + + // 判断dir文件夹是否存在,若不存在则创建(否则将无法创建出文件) + if (!fs::exists(dst)) { // 判断该文件夹是否存在 + bool success = fs::create_directories(dst); // Windows创建文件夹 + if (!success) { // 创建失败 + LOG_ERROR("Failed to mkdir:{}", dst); + return ""; } - - dst += fs::path(src).stem().string() + ext; } - replace(dst.begin(), dst.end(), '\\', '/'); - } catch (const std::exception &e) { - LOG_ERROR(GB2312ToUtf8(e.what())); - } catch (...) { - LOG_ERROR("Unknow exception."); - return ""; + dst += fs::path(src).stem().string() + ext; } + replace(dst.begin(), dst.end(), '\\', '/'); + ofstream out(dst.c_str(), ios::binary); if (!out.is_open()) { LOG_ERROR("Failed to write file {}", dst); @@ -178,7 +171,8 @@ static int GetNextPage(QWORD id) int RefreshPyq(QWORD id) { - if (!gIsListeningPyq) { + auto &msgHandler = MessageHandler::getInstance(); + if (!msgHandler.isPyqListening()) { LOG_ERROR("没有启动朋友圈消息接收,参考:enable_receiving_msg"); return -1; } @@ -319,7 +313,7 @@ string GetPCMAudio(uint64_t id, string dir, int32_t sr) SilkDecode(silk, pcm, sr); errno_t err; - FILE* fPCM; + FILE *fPCM; err = fopen_s(&fPCM, pcmpath.c_str(), "wb"); if (err != 0) { printf("Error: could not open input file %s\n", pcmpath.c_str()); @@ -332,7 +326,6 @@ string GetPCMAudio(uint64_t id, string dir, int32_t sr) return pcmpath; } - OcrResult_t GetOcrResult(string path) { OcrResult_t ret = { -1, "" }; From 2a27dec354b4ce28dfe85cdf8ae37c9a193ce4fc Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 30 Jan 2025 20:34:45 +0800 Subject: [PATCH 03/41] Refactor: replace C-style code with modern C++ idioms --- WeChatFerry/spy/rpc_server.cpp | 196 ++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 90 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 1d09e30..71c8f60 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -39,18 +39,19 @@ namespace fs = std::filesystem; -bool gIsLogging = false; -bool gIsListening = false; -bool gIsListeningPyq = false; -mutex gMutex; -condition_variable gCV; -queue gMsgQueue; +constexpr size_t DEFAULT_BUF_SIZE = 16 * 1024 * 1024; -static int lport = 0; -static DWORD lThreadId = 0; -static bool lIsRunning = false; -static nng_socket cmdSock, msgSock; // TODO: 断开检测 -static uint8_t gBuffer[G_BUF_SIZE] = { 0 }; +static int cmdPort = 0; +static bool isRpcRunning = false; +static bool isReveivingMsg = false; +static HANDLE cmdThread = NULL; +static HANDLE msgThread = NULL; +static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 +static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 + +auto &msgHandler = MessageHandler::getInstance(); + +static std::string BuildUrl(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } bool func_is_login(uint8_t *out, size_t *len) { @@ -116,7 +117,7 @@ bool func_get_msg_types(uint8_t *out, size_t *len) rsp.func = Functions_FUNC_GET_MSG_TYPES; rsp.which_msg = Response_types_tag; - MsgTypes_t types = GetMsgTypes(); + MsgTypes_t types = msgHandler.GetMsgTypes(); rsp.msg.types.types.funcs.encode = encode_types; rsp.msg.types.types.arg = &types; @@ -429,67 +430,68 @@ bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t *len) static void PushMessage() { - static uint8_t buffer[G_BUF_SIZE] = { 0 }; - int rv; Response rsp = Response_init_default; rsp.func = Functions_FUNC_ENABLE_RECV_TXT; rsp.which_msg = Response_wxmsg_tag; + std::vector msgBuffer(DEFAULT_BUF_SIZE); - pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); + pb_ostream_t stream = pb_ostream_from_buffer(msgBuffer.data(), msgBuffer.size()); - char url[URL_SIZE + 1] = { 0 }; - sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport + 1); + std::string url = BuildUrl(cmdPort + 1); if ((rv = nng_pair1_open(&msgSock)) != 0) { LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); return; } - if ((rv = nng_listen(msgSock, url, NULL, 0)) != 0) { + if ((rv = nng_listen(msgSock, url.c_str(), NULL, 0)) != 0) { LOG_ERROR("nng_listen error {}", nng_strerror(rv)); return; } - LOG_INFO("MSG Server listening on {}", url); - if ((rv = nng_setopt_ms(msgSock, NNG_OPT_SENDTIMEO, 2000)) != 0) { + LOG_INFO("MSG Server listening on {}", url.c_str()); + if ((rv = nng_setopt_ms(msgSock, NNG_OPT_SENDTIMEO, 5000)) != 0) { LOG_ERROR("nng_setopt_ms: {}", nng_strerror(rv)); return; } - while (gIsListening) { - unique_lock lock(gMutex); - if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) { - while (!gMsgQueue.empty()) { - auto wxmsg = gMsgQueue.front(); - rsp.msg.wxmsg.id = wxmsg.id; - rsp.msg.wxmsg.is_self = wxmsg.is_self; - rsp.msg.wxmsg.is_group = wxmsg.is_group; - rsp.msg.wxmsg.type = wxmsg.type; - rsp.msg.wxmsg.ts = wxmsg.ts; - rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str(); - rsp.msg.wxmsg.content = (char *)wxmsg.content.c_str(); - rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str(); - rsp.msg.wxmsg.sign = (char *)wxmsg.sign.c_str(); - rsp.msg.wxmsg.thumb = (char *)wxmsg.thumb.c_str(); - rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str(); - rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str(); - gMsgQueue.pop(); - LOG_DEBUG("Push msg: {}", wxmsg.content); - pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - continue; - } + while (msgHandler.isMessageListening()) { + std::unique_lock lock(msgHandler.getMutex()); + std::optional msgOpt; + auto hasMessage = [&]() { + msgOpt = msgHandler.popMessage(); + return msgOpt.has_value(); + }; - rv = nng_send(msgSock, buffer, stream.bytes_written, 0); - if (rv != 0) { - LOG_ERROR("msgSock-nng_send: {}", nng_strerror(rv)); - } - LOG_DEBUG("Send data length {}", stream.bytes_written); + if (msgHandler.getConditionVariable().wait_for(lock, std::chrono::milliseconds(1000), hasMessage)) { + WxMsg_t wxmsg = std::move(msgOpt.value()); + rsp.msg.wxmsg.id = wxmsg.id; + rsp.msg.wxmsg.is_self = wxmsg.is_self; + rsp.msg.wxmsg.is_group = wxmsg.is_group; + rsp.msg.wxmsg.type = wxmsg.type; + rsp.msg.wxmsg.ts = wxmsg.ts; + rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str(); + rsp.msg.wxmsg.content = (char *)wxmsg.content.c_str(); + rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str(); + rsp.msg.wxmsg.sign = (char *)wxmsg.sign.c_str(); + rsp.msg.wxmsg.thumb = (char *)wxmsg.thumb.c_str(); + rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str(); + rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str(); + + LOG_DEBUG("Push msg: {}", wxmsg.content); + pb_ostream_t stream = pb_ostream_from_buffer(msgBuffer.data(), msgBuffer.size()); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + continue; } + + rv = nng_send(msgSock, msgBuffer.data(), stream.bytes_written, 0); + if (rv != 0) { + LOG_ERROR("msgSock-nng_send: {}", nng_strerror(rv)); + } + LOG_DEBUG("Send data length {}", stream.bytes_written); } } - nng_close(msgSock); } bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len) @@ -497,22 +499,18 @@ bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len) Response rsp = Response_init_default; rsp.func = Functions_FUNC_ENABLE_RECV_TXT; rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; + rsp.msg.status = msgHandler.ListenMsg(); - if (!gIsListening) { - ListenMessage(); + if (rsp.msg.status == 0) { if (pyq) { - ListenPyq(); + msgHandler.ListenPyq(); } - HANDLE msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL); + msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL); if (msgThread == NULL) { rsp.msg.status = GetLastError(); LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); - } else { - CloseHandle(msgThread); } } - 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)); @@ -528,10 +526,15 @@ bool func_disable_recv_txt(uint8_t *out, size_t *len) Response rsp = Response_init_default; rsp.func = Functions_FUNC_DISABLE_RECV_TXT; rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; + rsp.msg.status = msgHandler.UnListenMsg(); - UnListenPyq(); - UnListenMessage(); // 可能需要1秒之后才能退出,见 PushMessage + if (rsp.msg.status == 0) { + msgHandler.UnListenPyq(); + if (msgThread != NULL) { + TerminateThread(msgThread, 0); + msgThread = NULL; + } + } pb_ostream_t stream = pb_ostream_from_buffer(out, *len); if (!pb_encode(&stream, Response_fields, &rsp)) { @@ -990,52 +993,51 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len return ret; } -static int RunServer() +static int RunRpcServer() { - int rv = 0; - char url[URL_SIZE + 1] = { 0 }; - sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport); + int rv = 0; + std::string url = BuildUrl(cmdPort); if ((rv = nng_pair1_open(&cmdSock)) != 0) { LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); return rv; } - if ((rv = nng_listen(cmdSock, (char *)url, NULL, 0)) != 0) { + if ((rv = nng_listen(cmdSock, url.c_str(), NULL, 0)) != 0) { LOG_ERROR("nng_listen error {}", nng_strerror(rv)); return rv; } - LOG_INFO("CMD Server listening on {}", (char *)url); + LOG_INFO("CMD Server listening on {}", url.c_str()); if ((rv = nng_setopt_ms(cmdSock, NNG_OPT_SENDTIMEO, 1000)) != 0) { LOG_ERROR("nng_setopt_ms error: {}", nng_strerror(rv)); return rv; } - lIsRunning = true; - while (lIsRunning) { + std::vector cmdBuffer(DEFAULT_BUF_SIZE); + isRpcRunning = true; + while (isRpcRunning) { uint8_t *in = NULL; - size_t in_len, out_len = G_BUF_SIZE; + size_t in_len, out_len = cmdBuffer.size(); if ((rv = nng_recv(cmdSock, &in, &in_len, NNG_FLAG_ALLOC)) != 0) { LOG_ERROR("cmdSock-nng_recv error: {}", nng_strerror(rv)); break; } try { // LOG_BUFFER(in, in_len); - if (dispatcher(in, in_len, gBuffer, &out_len)) { + if (dispatcher(in, in_len, cmdBuffer.data(), &out_len)) { LOG_DEBUG("Send data length {}", out_len); - // LOG_BUFFER(gBuffer, out_len); - rv = nng_send(cmdSock, gBuffer, out_len, 0); + // LOG_BUFFER(cmdBuffer.data(), out_len); + rv = nng_send(cmdSock, cmdBuffer.data(), out_len, 0); if (rv != 0) { LOG_ERROR("cmdSock-nng_send: {}", nng_strerror(rv)); } } else { // Error LOG_ERROR("Dispatcher failed..."); - rv = nng_send(cmdSock, gBuffer, 0, 0); + rv = nng_send(cmdSock, cmdBuffer.data(), 0, 0); if (rv != 0) { LOG_ERROR("cmdSock-nng_send: {}", nng_strerror(rv)); } - // break; } } catch (const std::exception &e) { LOG_ERROR(GB2312ToUtf8(e.what())); @@ -1045,21 +1047,22 @@ static int RunServer() nng_free(in, in_len); } RpcStopServer(); - LOG_DEBUG("Leave RunServer"); + LOG_DEBUG("Leave RunRpcServer"); return rv; } int RpcStartServer(int port) { - if (lIsRunning) { - return 0; + if (isRpcRunning) { + LOG_WARN("RPC 服务已经启动"); + return 1; } - lport = port; - - HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunServer, NULL, NULL, &lThreadId); - if (rpcThread != 0) { - CloseHandle(rpcThread); + cmdPort = port; + cmdThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunRpcServer, NULL, NULL, NULL); + if (cmdThread == NULL) { + LOG_ERROR("CreateThread failed: {}", GetLastError()); + return -1; } #if ENABLE_WX_LOG EnableLog(); @@ -1069,16 +1072,29 @@ int RpcStartServer(int port) int RpcStopServer() { - if (lIsRunning) { - nng_close(cmdSock); - nng_close(msgSock); - // UnListenMessage(); - lIsRunning = false; - Sleep(1000); - LOG_INFO("Server stoped."); + if (!isRpcRunning) { + LOG_WARN("RPC 服务未启动"); + return 1; } + + nng_close(cmdSock); + nng_close(msgSock); + msgHandler.UnListenPyq(); + msgHandler.UnListenMsg(); #if ENABLE_WX_LOG DisableLog(); #endif + if (cmdThread != NULL) { + WaitForSingleObject(cmdThread, INFINITE); + CloseHandle(cmdThread); + cmdThread = NULL; + } + + if (msgThread != NULL) { + WaitForSingleObject(msgThread, INFINITE); + CloseHandle(msgThread); + msgThread = NULL; + } + isRpcRunning = false; return 0; } From 7f4f1c54d6cb3246cea13ce836aaf3d01643a25c Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 30 Jan 2025 20:47:06 +0800 Subject: [PATCH 04/41] Remove unused code --- WeChatFerry/spy/rpc_server.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 71c8f60..84740d6 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -33,21 +33,16 @@ #include "user_info.h" #include "util.h" -#define URL_SIZE 20 -#define BASE_URL "tcp://0.0.0.0" -#define G_BUF_SIZE (16 * 1024 * 1024) - namespace fs = std::filesystem; constexpr size_t DEFAULT_BUF_SIZE = 16 * 1024 * 1024; -static int cmdPort = 0; -static bool isRpcRunning = false; -static bool isReveivingMsg = false; -static HANDLE cmdThread = NULL; -static HANDLE msgThread = NULL; -static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 -static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 +static int cmdPort = 0; +static bool isRpcRunning = false; +static HANDLE cmdThread = NULL; +static HANDLE msgThread = NULL; +static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 +static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 auto &msgHandler = MessageHandler::getInstance(); From d59aa751cb6056ae832356148cdfb6e72e13fbf6 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 30 Jan 2025 22:30:56 +0800 Subject: [PATCH 05/41] Refactoring --- WeChatFerry/spy/rpc_server.cpp | 895 ++++++++++----------------------- 1 file changed, 279 insertions(+), 616 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 84740d6..2192558 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -48,12 +48,14 @@ auto &msgHandler = MessageHandler::getInstance(); static std::string BuildUrl(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } -bool func_is_login(uint8_t *out, size_t *len) +template +static bool FillResponse(int which_msg, uint8_t *out, size_t *len, AssignFunc assign) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_IS_LOGIN; - rsp.which_msg = Response_status_tag; - rsp.msg.status = IsLogin(); + Response rsp = Response_init_default; + rsp.func = funcType; + rsp.which_msg = which_msg; + + assign(rsp); pb_ostream_t stream = pb_ostream_from_buffer(out, *len); if (!pb_encode(&stream, Response_fields, &rsp)) { @@ -61,366 +63,199 @@ bool func_is_login(uint8_t *out, size_t *len) return false; } *len = stream.bytes_written; - return true; } -bool func_get_self_wxid(uint8_t *out, size_t *len) +static bool func_is_login(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_SELF_WXID; - rsp.which_msg = Response_str_tag; - - string wxid = GetSelfWxid(); - rsp.msg.str = (char *)wxid.c_str(); - - 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; + return FillResponse(Response_status_tag, out, len, + [](Response &rsp) { rsp.msg.status = IsLogin(); }); } -bool func_get_user_info(uint8_t *out, size_t *len) +static bool func_get_self_wxid(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_USER_INFO; - rsp.which_msg = Response_ui_tag; - - UserInfo_t ui = GetUserInfo(); - rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); - rsp.msg.ui.name = (char *)ui.name.c_str(); - rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); - rsp.msg.ui.home = (char *)ui.home.c_str(); - - 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; + return FillResponse(Response_str_tag, out, len, [](Response &rsp) { + std::string wxid = GetSelfWxid(); + rsp.msg.str = wxid.empty() ? nullptr : (char *)wxid.c_str(); + }); } -bool func_get_msg_types(uint8_t *out, size_t *len) +static bool func_get_user_info(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_MSG_TYPES; - rsp.which_msg = Response_types_tag; - - MsgTypes_t types = msgHandler.GetMsgTypes(); - rsp.msg.types.types.funcs.encode = encode_types; - rsp.msg.types.types.arg = &types; - - 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; + return FillResponse(Response_ui_tag, out, len, [](Response &rsp) { + UserInfo_t ui = GetUserInfo(); + rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); + rsp.msg.ui.name = (char *)ui.name.c_str(); + rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); + rsp.msg.ui.home = (char *)ui.home.c_str(); + }); } -bool func_get_contacts(uint8_t *out, size_t *len) +static bool func_get_msg_types(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_CONTACTS; - rsp.which_msg = Response_contacts_tag; - - vector contacts = GetContacts(); - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; - - 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; + return FillResponse(Response_types_tag, out, len, [](Response &rsp) { + static MsgTypes_t types = msgHandler.GetMsgTypes(); + rsp.msg.types.types.funcs.encode = encode_types; + rsp.msg.types.types.arg = &types; + }); } -bool func_get_db_names(uint8_t *out, size_t *len) +static bool func_get_contacts(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_DB_NAMES; - rsp.which_msg = Response_dbs_tag; - - DbNames_t dbnames = GetDbNames(); - rsp.msg.dbs.names.funcs.encode = encode_dbnames; - rsp.msg.dbs.names.arg = &dbnames; - - 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; + return FillResponse(Response_contacts_tag, out, len, [](Response &rsp) { + static std::vector contacts = GetContacts(); + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; + }); } -bool func_get_db_tables(char *db, uint8_t *out, size_t *len) +static bool func_get_db_names(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_DB_TABLES; - rsp.which_msg = Response_tables_tag; - - DbTables_t tables = GetDbTables(db); - rsp.msg.tables.tables.funcs.encode = encode_tables; - rsp.msg.tables.tables.arg = &tables; - - 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; + return FillResponse(Response_dbs_tag, out, len, [](Response &rsp) { + static DbNames_t dbnames = GetDbNames(); + rsp.msg.dbs.names.funcs.encode = encode_dbnames; + rsp.msg.dbs.names.arg = &dbnames; + }); } -bool func_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len) +static bool func_get_db_tables(char *db, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_AUDIO_MSG; - rsp.which_msg = Response_str_tag; - string path = ""; - - if (dir == NULL) { - LOG_ERROR("Empty dir."); - } else { - path = GetAudio(id, dir); - } - - rsp.msg.str = (char *)path.c_str(); - - 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; + return FillResponse(Response_tables_tag, out, len, [db](Response &rsp) { + static DbTables_t tables = GetDbTables(db); + rsp.msg.tables.tables.funcs.encode = encode_tables; + rsp.msg.tables.tables.arg = &tables; + }); } -bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) +static bool func_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_TXT; - rsp.which_msg = Response_status_tag; - - if ((txt.msg == NULL) || (txt.receiver == NULL)) { - LOG_ERROR("Empty message or receiver."); - rsp.msg.status = -1; // Empty message or empty receiver - } else { - string msg(txt.msg); - string receiver(txt.receiver); - string aters(txt.aters ? txt.aters : ""); - - SendTextMessage(receiver, msg, aters); - rsp.msg.status = 0; - } - - 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; + return FillResponse(Response_str_tag, out, len, [id, dir](Response &rsp) { + std::string path = (dir == nullptr) ? "" : GetAudio(id, dir); + rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); + }); } -bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) +static bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_IMG; - rsp.which_msg = Response_status_tag; - - if ((path == NULL) || (receiver == NULL)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else if (!fs::exists(String2Wstring(path))) { - LOG_ERROR("Path does not exists: {}", path); - rsp.msg.status = -2; - } else { - SendImageMessage(receiver, path); - rsp.msg.status = 0; - } - - 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; + return FillResponse(Response_status_tag, out, len, [txt](Response &rsp) { + if ((txt.msg == NULL) || (txt.receiver == NULL)) { + LOG_ERROR("Empty message or receiver."); + rsp.msg.status = -1; + } else { + std::string msg(txt.msg); + std::string receiver(txt.receiver); + std::string aters(txt.aters ? txt.aters : ""); + SendTextMessage(receiver, msg, aters); + rsp.msg.status = 0; + } + }); } -bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) +static bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_FILE; - rsp.which_msg = Response_status_tag; - - if ((path == NULL) || (receiver == NULL)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else if (!fs::exists(String2Wstring(path))) { - LOG_ERROR("Path does not exists: {}", path); - rsp.msg.status = -2; - } else { - SendFileMessage(receiver, path); - rsp.msg.status = 0; - } - - 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; + return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { + if ((path == NULL) || (receiver == NULL)) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else if (!fs::exists(String2Wstring(path))) { + LOG_ERROR("Path does not exist: {}", path); + rsp.msg.status = -2; + } else { + SendImageMessage(receiver, path); + rsp.msg.status = 0; + } + }); } -bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len) +static bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_EMOTION; - rsp.which_msg = Response_status_tag; - - if ((path == NULL) || (receiver == NULL)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else { - SendEmotionMessage(receiver, path); - rsp.msg.status = 0; - } - - 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; + return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { + if ((path == nullptr) || (receiver == nullptr)) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else if (!fs::exists(String2Wstring(path))) { + LOG_ERROR("Path does not exist: {}", path); + rsp.msg.status = -2; + } else { + SendFileMessage(receiver, path); + rsp.msg.status = 0; + } + }); } -bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) +static bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_XML; - rsp.which_msg = Response_status_tag; - - if ((xml.content == NULL) || (xml.receiver == NULL)) { - LOG_ERROR("Empty content or receiver."); - rsp.msg.status = -1; - } else { - string receiver(xml.receiver); - string content(xml.content); - string path(xml.path ? xml.path : ""); - uint64_t type = (uint64_t)xml.type; - SendXmlMessage(receiver, content, path, type); - rsp.msg.status = 0; - } - - 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; + return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { + if ((path == nullptr) || (receiver == nullptr)) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else { + SendEmotionMessage(receiver, path); + rsp.msg.status = 0; + } + }); } -bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) +static bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_RICH_TXT; - rsp.which_msg = Response_status_tag; - - if (rt.receiver == NULL) { - LOG_ERROR("Empty receiver."); - rsp.msg.status = -1; - } else { - 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; + return FillResponse(Response_status_tag, out, len, [xml](Response &rsp) { + if ((xml.content == nullptr) || (xml.receiver == nullptr)) { + LOG_ERROR("Empty content or receiver."); + rsp.msg.status = -1; + } else { + std::string receiver(xml.receiver); + std::string content(xml.content); + std::string path(xml.path ? xml.path : ""); + uint64_t type = static_cast(xml.type); + SendXmlMessage(receiver, content, path, type); + rsp.msg.status = 0; + } + }); } -bool func_send_pat_msg(char *roomid, char *wxid, uint8_t *out, size_t *len) +static bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_PAT_MSG; - rsp.which_msg = Response_status_tag; + return FillResponse(Response_status_tag, out, len, [rt](Response &rsp) { + if (rt.receiver == nullptr) { + LOG_ERROR("Empty receiver."); + rsp.msg.status = -1; + } else { + RichText_t rtt; + rtt.account = std::string(rt.account ? rt.account : ""); + rtt.digest = std::string(rt.digest ? rt.digest : ""); + rtt.name = std::string(rt.name ? rt.name : ""); + rtt.receiver = std::string(rt.receiver ? rt.receiver : ""); + rtt.thumburl = std::string(rt.thumburl ? rt.thumburl : ""); + rtt.title = std::string(rt.title ? rt.title : ""); + rtt.url = std::string(rt.url ? rt.url : ""); - if ((roomid == NULL) || (wxid == NULL)) { - LOG_ERROR("Empty roomid or wxid."); - rsp.msg.status = -1; - } else { - rsp.msg.status = SendPatMessage(roomid, wxid); - } - - 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; + rsp.msg.status = SendRichTextMessage(rtt); + } + }); } -bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t *len) +static bool func_send_pat_msg(char *roomid, char *wxid, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_FORWARD_MSG; - rsp.which_msg = Response_status_tag; + return FillResponse(Response_status_tag, out, len, [roomid, wxid](Response &rsp) { + if ((roomid == nullptr) || (wxid == nullptr)) { + LOG_ERROR("Empty roomid or wxid."); + rsp.msg.status = -1; + } else { + rsp.msg.status = SendPatMessage(roomid, wxid); + } + }); +} - if (receiver == NULL) { - LOG_ERROR("Empty roomid or wxid."); - rsp.msg.status = -1; - } else { - rsp.msg.status = ForwardMessage(id, receiver); - } - - 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 bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t *len) +{ + return FillResponse(Response_status_tag, out, len, [id, receiver](Response &rsp) { + if (receiver == nullptr) { + LOG_ERROR("Empty receiver."); + rsp.msg.status = -1; + } else { + rsp.msg.status = ForwardMessage(id, receiver); + } + }); } static void PushMessage() @@ -489,351 +324,179 @@ static void PushMessage() } } -bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len) +static bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ENABLE_RECV_TXT; - rsp.which_msg = Response_status_tag; - rsp.msg.status = msgHandler.ListenMsg(); - - if (rsp.msg.status == 0) { - if (pyq) { - msgHandler.ListenPyq(); + return FillResponse(Response_status_tag, out, len, [pyq](Response &rsp) { + rsp.msg.status = msgHandler.ListenMsg(); + if (rsp.msg.status == 0) { + if (pyq) { + msgHandler.ListenPyq(); + } + msgThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)PushMessage, nullptr, 0, nullptr); + if (msgThread == nullptr) { + rsp.msg.status = GetLastError(); + LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); + } } - msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL); - if (msgThread == NULL) { - rsp.msg.status = GetLastError(); - LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); + }); +} + +static bool func_disable_recv_txt(uint8_t *out, size_t *len) +{ + return FillResponse(Response_status_tag, out, len, [](Response &rsp) { + rsp.msg.status = msgHandler.UnListenMsg(); + if (rsp.msg.status == 0) { + msgHandler.UnListenPyq(); + if (msgThread != nullptr) { + TerminateThread(msgThread, 0); + msgThread = nullptr; + } } - } - 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; + }); } -bool func_disable_recv_txt(uint8_t *out, size_t *len) +static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DISABLE_RECV_TXT; - rsp.which_msg = Response_status_tag; - rsp.msg.status = msgHandler.UnListenMsg(); - - if (rsp.msg.status == 0) { - msgHandler.UnListenPyq(); - if (msgThread != NULL) { - TerminateThread(msgThread, 0); - msgThread = NULL; + return FillResponse(Response_rows_tag, out, len, [db, sql](Response &rsp) { + static DbRows_t rows; + if ((db == nullptr) || (sql == nullptr)) { + LOG_ERROR("Empty db or sql."); + } else { + rows = ExecDbQuery(db, sql); } - } - - 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; + rsp.msg.rows.rows.arg = &rows; + rsp.msg.rows.rows.funcs.encode = encode_rows; + }); } -bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) +static bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_EXEC_DB_QUERY; - rsp.which_msg = Response_rows_tag; - DbRows_t rows; - - if ((db == NULL) || (sql == NULL)) { - LOG_ERROR("Empty db or sql."); - } else { - rows = ExecDbQuery(db, sql); - } - - rsp.msg.rows.rows.arg = &rows; - rsp.msg.rows.rows.funcs.encode = encode_rows; - - 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; + return FillResponse(Response_status_tag, out, len, + [id](Response &rsp) { rsp.msg.status = RefreshPyq(id); }); } -bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) +static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_REFRESH_PYQ; - rsp.which_msg = Response_status_tag; - - rsp.msg.status = RefreshPyq(id); - - 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; + return FillResponse(Response_status_tag, out, len, [att](Response &rsp) { + std::string thumb = att.thumb ? att.thumb : ""; + std::string extra = att.extra ? att.extra : ""; + rsp.msg.status = DownloadAttach(att.id, thumb, extra); + }); } -bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) +static bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DOWNLOAD_ATTACH; - rsp.which_msg = Response_status_tag; - - uint64_t id = att.id; - string thumb = string(att.thumb ? att.thumb : ""); - string extra = string(att.extra ? att.extra : ""); - - rsp.msg.status = DownloadAttach(id, thumb, extra); - - 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; + return FillResponse(Response_status_tag, out, len, + [id](Response &rsp) { rsp.msg.status = RevokeMsg(id); }); } -bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len) +static bool func_refresh_qrcode(uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_REVOKE_MSG; - rsp.which_msg = Response_status_tag; - - rsp.msg.status = RevokeMsg(id); - - 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; + return FillResponse(Response_str_tag, out, len, [](Response &rsp) { + std::string url = GetLoginUrl(); + rsp.msg.str = url.empty() ? nullptr : (char *)url.c_str(); + }); } -bool func_refresh_qrcode(uint8_t *out, size_t *len) +static bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_REFRESH_QRCODE; - rsp.which_msg = Response_str_tag; - - rsp.msg.str = (char *)GetLoginUrl().c_str(); - - 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; -} - -bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_RECV_TRANSFER; - rsp.which_msg = Response_status_tag; - - if ((wxid == NULL) || (tfid == NULL) || (taid == NULL)) { - rsp.msg.status = -1; - LOG_ERROR("Empty wxid, tfid or taid."); - } else { - rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); - } - - 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; + return FillResponse(Response_status_tag, out, len, [wxid, tfid, taid](Response &rsp) { + if ((wxid == nullptr) || (tfid == nullptr) || (taid == nullptr)) { + LOG_ERROR("Empty wxid, tfid, or taid."); + rsp.msg.status = -1; + } else { + rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); + } + }); } #if 0 -bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) +static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ACCEPT_FRIEND; - rsp.which_msg = Response_status_tag; - - if ((v3 == NULL) || (v4 == NULL)) { - rsp.msg.status = -1; - LOG_ERROR("Empty V3 or V4."); - } else { - rsp.msg.status = AcceptNewFriend(v3, v4, scene); - } - - 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; + return FillResponse(Response_status_tag, out, len, [v3, v4, scene](Response &rsp) { + if ((v3 == nullptr) || (v4 == nullptr)) { + LOG_ERROR("Empty V3 or V4."); + rsp.msg.status = -1; + } else { + rsp.msg.status = AcceptNewFriend(v3, v4, scene); + } + }); } -bool func_get_contact_info(string wxid, uint8_t *out, size_t *len) +static bool func_get_contact_info(std::string wxid, uint8_t *out, size_t *len) { - /*借用 Functions_FUNC_GET_CONTACTS */ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_CONTACT_INFO; - rsp.which_msg = Response_contacts_tag; + return FillResponse(Response_contacts_tag, out, len, [wxid](Response &rsp) { + static std::vector contacts; + contacts.clear(); + contacts.push_back(GetContactByWxid(wxid)); - vector contacts; - contacts.push_back(GetContactByWxid(wxid)); - - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; - - 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; + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; + }); } #endif -bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) +static bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DECRYPT_IMAGE; - rsp.which_msg = Response_str_tag; - string path = ""; - - if ((dec.src == NULL) || (dec.dst == NULL)) { - LOG_ERROR("Empty src or dst."); - } else { - path = DecryptImage(dec.src, dec.dst); - } - - rsp.msg.str = (char *)path.c_str(); - - 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; + return FillResponse(Response_str_tag, out, len, [dec](Response &rsp) { + std::string path; + if ((dec.src == nullptr) || (dec.dst == nullptr)) { + LOG_ERROR("Empty src or dst."); + } else { + path = DecryptImage(dec.src, dec.dst); + } + rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); + }); } -bool func_exec_ocr(char *path, uint8_t *out, size_t *len) +static bool func_exec_ocr(char *path, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_EXEC_OCR; - rsp.which_msg = Response_ocr_tag; - OcrResult_t ret = { -1, "" }; - - if (path == NULL) { - LOG_ERROR("Empty path."); - } else { - ret = GetOcrResult(path); - } - - rsp.msg.ocr.status = ret.status; - rsp.msg.ocr.result = (char *)ret.result.c_str(); - - 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; + return FillResponse(Response_ocr_tag, out, len, [path](Response &rsp) { + OcrResult_t ret = { -1, "" }; + if (path == nullptr) { + LOG_ERROR("Empty path."); + } else { + ret = GetOcrResult(path); + } + rsp.msg.ocr.status = ret.status; + rsp.msg.ocr.result = ret.result.empty() ? nullptr : (char *)ret.result.c_str(); + }); } -bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) +static bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((roomid == NULL) || (wxids == NULL)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = AddChatroomMember(roomid, wxids); - } - - 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; + return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { + if ((roomid == nullptr) || (wxids == nullptr)) { + LOG_ERROR("Empty roomid or wxids."); + rsp.msg.status = -1; + } else { + rsp.msg.status = AddChatroomMember(roomid, wxids); + } + }); } -bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) +static bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DEL_ROOM_MEMBERS; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((roomid == NULL) || (wxids == NULL)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = DelChatroomMember(roomid, wxids); - } - - 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; + return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { + if ((roomid == nullptr) || (wxids == nullptr)) { + LOG_ERROR("Empty roomid or wxids."); + rsp.msg.status = -1; + } else { + rsp.msg.status = DelChatroomMember(roomid, wxids); + } + }); } -bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) +static bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) { - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_INV_ROOM_MEMBERS; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((roomid == NULL) || (wxids == NULL)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = InviteChatroomMember(roomid, wxids); - } - - 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; + return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { + if ((roomid == nullptr) || (wxids == nullptr)) { + LOG_ERROR("Empty roomid or wxids."); + rsp.msg.status = -1; + } else { + rsp.msg.status = InviteChatroomMember(roomid, wxids); + } + }); } static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) From bfe333675371ca0cc8bd1b84e09c0efac0a2074e Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 00:50:19 +0800 Subject: [PATCH 06/41] refactor: use template to simplify response logic --- WeChatFerry/spy/fill_response.h | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 WeChatFerry/spy/fill_response.h diff --git a/WeChatFerry/spy/fill_response.h b/WeChatFerry/spy/fill_response.h new file mode 100644 index 0000000..2cf1ddb --- /dev/null +++ b/WeChatFerry/spy/fill_response.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include "log.hpp" +#include "pb_encode.h" +#include "pb_types.h" + +static const std::unordered_map rpc_function_map + = { { Functions_FUNC_IS_LOGIN, Response_status_tag }, + { Functions_FUNC_GET_SELF_WXID, Response_str_tag }, + { Functions_FUNC_GET_USER_INFO, Response_ui_tag }, + { Functions_FUNC_GET_MSG_TYPES, Response_types_tag }, + { Functions_FUNC_GET_CONTACTS, Response_contacts_tag }, + { Functions_FUNC_GET_DB_NAMES, Response_dbs_tag }, + { Functions_FUNC_GET_DB_TABLES, Response_tables_tag }, + { Functions_FUNC_GET_AUDIO_MSG, Response_str_tag }, + { Functions_FUNC_SEND_TXT, Response_status_tag }, + { Functions_FUNC_SEND_IMG, Response_status_tag }, + { Functions_FUNC_SEND_FILE, Response_status_tag }, + { Functions_FUNC_SEND_RICH_TXT, Response_status_tag }, + { Functions_FUNC_SEND_PAT_MSG, Response_status_tag }, + { Functions_FUNC_FORWARD_MSG, Response_status_tag }, + { Functions_FUNC_SEND_EMOTION, Response_status_tag }, + { Functions_FUNC_ENABLE_RECV_TXT, Response_status_tag }, + { Functions_FUNC_DISABLE_RECV_TXT, Response_status_tag }, + { Functions_FUNC_EXEC_DB_QUERY, Response_rows_tag }, + { Functions_FUNC_REFRESH_PYQ, Response_status_tag }, + { Functions_FUNC_DOWNLOAD_ATTACH, Response_status_tag }, + { Functions_FUNC_RECV_TRANSFER, Response_status_tag }, + { Functions_FUNC_REVOKE_MSG, Response_status_tag }, + { Functions_FUNC_REFRESH_QRCODE, Response_str_tag }, + { Functions_FUNC_DECRYPT_IMAGE, Response_str_tag }, + { Functions_FUNC_EXEC_OCR, Response_ocr_tag }, + { Functions_FUNC_ADD_ROOM_MEMBERS, Response_status_tag }, + { Functions_FUNC_DEL_ROOM_MEMBERS, Response_status_tag }, + { Functions_FUNC_INV_ROOM_MEMBERS, Response_status_tag } }; + +template bool fill_response(uint8_t *out, size_t *len, AssignFunc assign) +{ + Response rsp = Response_init_default; + rsp.func = FuncType; + + auto it = rpc_function_map.find(FuncType); + if (it == rpc_function_map.end()) { + LOG_ERROR("Unknown function type: {}", FuncType); + return false; + } + rsp.which_msg = it->second; + + assign(rsp); + + 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; +} From 86a55cf00cdf2640b6c484124ff61c82ccf3483c Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 01:08:55 +0800 Subject: [PATCH 07/41] refactoring --- WeChatFerry/spy/rpc_server.cpp | 4 +- WeChatFerry/spy/user_info.cpp | 78 ++++++++++++++++++++++------------ WeChatFerry/spy/user_info.h | 20 +++++++-- 3 files changed, 70 insertions(+), 32 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 2192558..ab99536 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -75,7 +75,7 @@ static bool func_is_login(uint8_t *out, size_t *len) static bool func_get_self_wxid(uint8_t *out, size_t *len) { return FillResponse(Response_str_tag, out, len, [](Response &rsp) { - std::string wxid = GetSelfWxid(); + std::string wxid = user_info::get_self_wxid(); rsp.msg.str = wxid.empty() ? nullptr : (char *)wxid.c_str(); }); } @@ -83,7 +83,7 @@ static bool func_get_self_wxid(uint8_t *out, size_t *len) static bool func_get_user_info(uint8_t *out, size_t *len) { return FillResponse(Response_ui_tag, out, len, [](Response &rsp) { - UserInfo_t ui = GetUserInfo(); + UserInfo_t ui = user_info::get_user_info(); rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); rsp.msg.ui.name = (char *)ui.name.c_str(); rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index a273592..7566ff3 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -1,7 +1,14 @@ -#include "user_info.h" +#include +#include + +#include "fill_response.h" #include "log.hpp" +#include "user_info.h" #include "util.h" +namespace user_info +{ + extern UINT64 g_WeChatWinDllAddr; #define OS_USER_HOME 0x5932770 @@ -9,50 +16,69 @@ extern UINT64 g_WeChatWinDllAddr; #define OS_USER_NAME 0x595C3D8 #define OS_USER_MOBILE 0x595C318 -static char home[MAX_PATH] = { 0 }; - -string GetHomePath() +std::string get_home_path() { - if (home[0] == 0) { - string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; - strncpy_s(home, path.c_str(), path.size()); - } + static std::once_flag flag; + static std::string home_path; - return string(home); + std::call_once(flag, [] { + std::string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; + home_path = std::filesystem::absolute(path).string(); + }); + + return home_path; } -string GetSelfWxid() +std::optional get_self_wxid() { - UINT64 wxidType = 0; + UINT64 wxid_type = 0; try { - wxidType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); - if (wxidType == 0xF) { + wxid_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); + if (wxid_type == 0xF) { return GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID); } else { return GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID); } } catch (...) { - LOG_ERROR("wxid type: {:#x}", wxidType); - LOG_BUFFER((uint8_t *)(g_WeChatWinDllAddr + OS_USER_WXID), 20); - return "empty_wxid"; + LOG_ERROR("Failed to get wxid, type: {:#x}", wxid_type); + LOG_BUFFER(reinterpret_cast(g_WeChatWinDllAddr + OS_USER_WXID), 20); + return std::nullopt; } } -UserInfo_t GetUserInfo() +UserInfo_t get_user_info() { UserInfo_t ui; + auto wxid = get_self_wxid(); + ui.wxid = wxid.value_or("unknown_wxid"); - ui.wxid = GetSelfWxid(); - - UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); - if (nameType == 0xF) { - ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME); - } else { // 0x1F - ui.name = GET_STRING(g_WeChatWinDllAddr + OS_USER_NAME); - } + UINT64 name_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); + ui.name = (name_type == 0xF) ? GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME) + : GET_STRING(g_WeChatWinDllAddr + OS_USER_NAME); ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_MOBILE); - ui.home = GetHomePath(); + ui.home = get_home_path(); return ui; } + +bool rpc_get_self_wxid(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { + auto wxid = get_self_wxid(); + rsp.msg.str = wxid ? wxid->c_str() : "error"; + }); +} + +bool rpc_get_user_info(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { + UserInfo_t ui = get_user_info(); + rsp.msg.ui.wxid = ui.wxid.c_str(); + rsp.msg.ui.name = ui.name.c_str(); + rsp.msg.ui.mobile = ui.mobile.c_str(); + rsp.msg.ui.home = ui.home.c_str(); + }); +} + +} // namespace user_info diff --git a/WeChatFerry/spy/user_info.h b/WeChatFerry/spy/user_info.h index 8d70dc7..a959b04 100644 --- a/WeChatFerry/spy/user_info.h +++ b/WeChatFerry/spy/user_info.h @@ -1,12 +1,24 @@ #pragma once +#include #include #include "pb_types.h" -using namespace std; +namespace user_info +{ -string GetHomePath(); -string GetSelfWxid(); +// 获取 WeChat 数据存储路径 +std::string get_home_path(); -UserInfo_t GetUserInfo(); +// 获取自身 wxid +std::optional get_self_wxid(); + +// 获取用户信息 +UserInfo_t get_user_info(); + +// RPC 方法 +bool rpc_get_self_wxid(uint8_t *out, size_t *len); +bool rpc_get_user_info(uint8_t *out, size_t *len); + +} // namespace user_info From bc40b6e922a5afdf90da792721e2a38434302573 Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 09:54:08 +0800 Subject: [PATCH 08/41] Fix logging and compiling errors --- WeChatFerry/spy/fill_response.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/WeChatFerry/spy/fill_response.h b/WeChatFerry/spy/fill_response.h index 2cf1ddb..f4e19c0 100644 --- a/WeChatFerry/spy/fill_response.h +++ b/WeChatFerry/spy/fill_response.h @@ -1,7 +1,10 @@ #pragma once +#include #include +#include "wcf.pb.h" + #include "log.hpp" #include "pb_encode.h" #include "pb_types.h" @@ -43,7 +46,7 @@ template bool fill_response(uint8_t *o auto it = rpc_function_map.find(FuncType); if (it == rpc_function_map.end()) { - LOG_ERROR("Unknown function type: {}", FuncType); + LOG_ERROR("Unknown function type: {}", magic_enum::enum_name(rsp.func)); return false; } rsp.which_msg = it->second; From f2c017de104d58f874659c89a4d71f6aca0ff7aa Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 09:55:44 +0800 Subject: [PATCH 09/41] Refatoring --- WeChatFerry/spy/receive_msg.cpp | 4 +-- WeChatFerry/spy/send_msg.cpp | 4 +-- WeChatFerry/spy/user_info.cpp | 58 ++++++++++++++++++--------------- WeChatFerry/spy/user_info.h | 2 +- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index 4aa92e3..5becce8 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -49,10 +49,10 @@ QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) if (wxMsg.roomid.find("@chatroom") != std::string::npos) { wxMsg.is_group = true; - wxMsg.sender = wxMsg.is_self ? GetSelfWxid() : GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID); + wxMsg.sender = wxMsg.is_self ? user_info::get_self_wxid() : GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID); } else { wxMsg.is_group = false; - wxMsg.sender = wxMsg.is_self ? GetSelfWxid() : wxMsg.roomid; + wxMsg.sender = wxMsg.is_self ? user_info::get_self_wxid() : wxMsg.roomid; } } catch (const std::exception &e) { LOG_ERROR(GB2312ToUtf8(e.what())); diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index dca37f7..4e5bbdb 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -7,11 +7,11 @@ #include "log.hpp" #include "send_msg.h" #include "spy_types.h" +#include "user_info.h" #include "util.h" extern HANDLE g_hEvent; extern QWORD g_WeChatWinDllAddr; -extern string GetSelfWxid(); // Defined in spy.cpp #define SRTM_SIZE 0x3F0 @@ -263,7 +263,7 @@ void SendXmlMessage(string receiver, string xml, string path, QWORD type) WxString *pReceiver = NewWxStringFromStr(receiver); WxString *pXml = NewWxStringFromStr(xml); WxString *pPath = NewWxStringFromStr(path); - WxString *pSender = NewWxStringFromStr(GetSelfWxid()); + WxString *pSender = NewWxStringFromStr(user_info::get_self_wxid()); sendXmlMsg(pBuf, (QWORD)pSender, (QWORD)pReceiver, (QWORD)pXml, (QWORD)pPath, (QWORD)(&nullBuf), type, 0x4, sign, pBuf2); diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index 7566ff3..6cf95b7 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -6,17 +6,17 @@ #include "user_info.h" #include "util.h" -namespace user_info -{ - extern UINT64 g_WeChatWinDllAddr; +namespace user_info +{ #define OS_USER_HOME 0x5932770 #define OS_USER_WXID 0x595C270 #define OS_USER_NAME 0x595C3D8 #define OS_USER_MOBILE 0x595C318 -std::string get_home_path() + std::string + get_home_path() { static std::once_flag flag; static std::string home_path; @@ -29,28 +29,34 @@ std::string get_home_path() return home_path; } -std::optional get_self_wxid() +std::string get_self_wxid() { - UINT64 wxid_type = 0; - try { - wxid_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); - if (wxid_type == 0xF) { - return GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID); - } else { - return GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID); + static std::once_flag flag; + static std::string wxid; + + std::call_once(flag, [] { + UINT64 wxid_type = 0; + try { + wxid_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); + if (wxid_type == 0xF) { + wxid = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID); + } else { + wxid = GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID); + } + + } catch (...) { + LOG_ERROR("Failed to get wxid, type: {:#x}", wxid_type); + LOG_BUFFER(reinterpret_cast(g_WeChatWinDllAddr + OS_USER_WXID), 20); + wxid = "获取wxid失败"; } - } catch (...) { - LOG_ERROR("Failed to get wxid, type: {:#x}", wxid_type); - LOG_BUFFER(reinterpret_cast(g_WeChatWinDllAddr + OS_USER_WXID), 20); - return std::nullopt; - } + }); + return wxid; } UserInfo_t get_user_info() { UserInfo_t ui; - auto wxid = get_self_wxid(); - ui.wxid = wxid.value_or("unknown_wxid"); + ui.wxid = get_self_wxid(); UINT64 name_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); ui.name = (name_type == 0xF) ? GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME) @@ -64,20 +70,18 @@ UserInfo_t get_user_info() bool rpc_get_self_wxid(uint8_t *out, size_t *len) { - return fill_response(out, len, [](Response &rsp) { - auto wxid = get_self_wxid(); - rsp.msg.str = wxid ? wxid->c_str() : "error"; - }); + return fill_response( + out, len, [](Response &rsp) { rsp.msg.str = (char *)get_self_wxid().c_str(); }); } bool rpc_get_user_info(uint8_t *out, size_t *len) { return fill_response(out, len, [](Response &rsp) { UserInfo_t ui = get_user_info(); - rsp.msg.ui.wxid = ui.wxid.c_str(); - rsp.msg.ui.name = ui.name.c_str(); - rsp.msg.ui.mobile = ui.mobile.c_str(); - rsp.msg.ui.home = ui.home.c_str(); + rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); + rsp.msg.ui.name = (char *)ui.name.c_str(); + rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); + rsp.msg.ui.home = (char *)ui.home.c_str(); }); } diff --git a/WeChatFerry/spy/user_info.h b/WeChatFerry/spy/user_info.h index a959b04..f248ba7 100644 --- a/WeChatFerry/spy/user_info.h +++ b/WeChatFerry/spy/user_info.h @@ -12,7 +12,7 @@ namespace user_info std::string get_home_path(); // 获取自身 wxid -std::optional get_self_wxid(); +std::string get_self_wxid(); // 获取用户信息 UserInfo_t get_user_info(); From b109bd72d263f83cea3b6910f1c9b6aedd3731d7 Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 10:18:02 +0800 Subject: [PATCH 10/41] Refactoring --- WeChatFerry/spy/contact_mgmt.cpp | 138 +++++++++++++++++++------------ WeChatFerry/spy/contact_mgmt.h | 27 ++++-- WeChatFerry/spy/rpc_server.cpp | 11 +-- 3 files changed, 108 insertions(+), 68 deletions(-) diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index 84f916a..1adae24 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -1,10 +1,15 @@ #pragma execution_character_set("utf-8") #include "contact_mgmt.h" +#include "fill_response.h" #include "log.hpp" #include "util.h" using namespace std; + +namespace contact_mgmt +{ + extern QWORD g_WeChatWinDllAddr; #define OS_GET_CONTACT_MGR 0x1B417A0 @@ -18,30 +23,29 @@ extern QWORD g_WeChatWinDllAddr; #define OS_CONTACT_GENDER 0x0E #define OS_CONTACT_STEP 0x6A8 -typedef QWORD (*GetContactMgr_t)(); -typedef QWORD (*GetContactList_t)(QWORD, QWORD); +using get_contact_mgr_t = QWORD (*)(); +using get_contact_list_t = QWORD (*)(QWORD, QWORD); #define FEAT_LEN 5 static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 }; static const uint8_t FEAT_PROVINCE[FEAT_LEN] = { 0xE2, 0xEA, 0xA8, 0xD1, 0x18 }; static const uint8_t FEAT_CITY[FEAT_LEN] = { 0x1D, 0x02, 0x5B, 0xBF, 0x18 }; -static QWORD FindMem(QWORD start, QWORD end, const void *target, size_t len) +static QWORD find_mem(QWORD start, QWORD end, const void *target, size_t len) { - uint8_t *p = (uint8_t *)start; - while ((QWORD)p < end) { - if (memcmp((void *)p, target, len) == 0) { - return (QWORD)p; + uint8_t *p = reinterpret_cast(start); + while (reinterpret_cast(p) < end) { + if (memcmp(p, target, len) == 0) { + return reinterpret_cast(p); } p++; } - return 0; } -static string GetCntString(QWORD start, QWORD end, const uint8_t *feat, size_t len) +static string get_cnt_string(QWORD start, QWORD end, const uint8_t *feat, size_t len) { - QWORD pfeat = FindMem(start, end, feat, len); + QWORD pfeat = find_mem(start, end, feat, len); if (pfeat == 0) { return ""; } @@ -54,21 +58,23 @@ static string GetCntString(QWORD start, QWORD end, const uint8_t *feat, size_t l return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat)); } -vector GetContacts() +vector get_contacts() { vector contacts; - GetContactMgr_t funcGetContactMgr = (GetContactMgr_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_MGR); - GetContactList_t funcGetContactList = (GetContactList_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_LIST); + get_contact_mgr_t func_get_contact_mgr + = reinterpret_cast(g_WeChatWinDllAddr + OS_GET_CONTACT_MGR); + get_contact_list_t func_get_contact_list + = reinterpret_cast(g_WeChatWinDllAddr + OS_GET_CONTACT_LIST); - QWORD mgr = funcGetContactMgr(); + QWORD mgr = func_get_contact_mgr(); QWORD addr[3] = { 0 }; - if (funcGetContactList(mgr, (QWORD)addr) != 1) { - LOG_ERROR("GetContacts failed"); + if (func_get_contact_list(mgr, reinterpret_cast(addr)) != 1) { + LOG_ERROR("get_contacts failed"); return contacts; } - QWORD pstart = (QWORD)addr[0]; - QWORD pend = (QWORD)addr[2]; + QWORD pstart = addr[0]; + QWORD pend = addr[2]; while (pstart < pend) { RpcContact_t cnt; QWORD pbin = GET_QWORD(pstart + OS_CONTACT_BIN); @@ -79,15 +85,11 @@ vector GetContacts() cnt.remark = GetStringByWstrAddr(pstart + OS_CONTACT_REMARK); cnt.name = GetStringByWstrAddr(pstart + OS_CONTACT_NAME); - cnt.country = GetCntString(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN); - cnt.province = GetCntString(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN); - cnt.city = GetCntString(pbin, pbin + lenbin, FEAT_CITY, FEAT_LEN); + cnt.country = get_cnt_string(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN); + cnt.province = get_cnt_string(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN); + cnt.city = get_cnt_string(pbin, pbin + lenbin, FEAT_CITY, FEAT_LEN); - if (pbin == 0) { - cnt.gender = 0; - } else { - cnt.gender = (DWORD) * (uint8_t *)(pbin + OS_CONTACT_GENDER); - } + cnt.gender = (pbin == 0) ? 0 : static_cast(*(uint8_t *)(pbin + OS_CONTACT_GENDER)); contacts.push_back(cnt); pstart += OS_CONTACT_STEP; @@ -96,68 +98,69 @@ vector GetContacts() return contacts; } -#if 0 -int AcceptNewFriend(string v3, string v4, int scene) +int accept_new_friend(string v3, string v4, int scene) { - int success = 0; - - DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1; - DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2; - DWORD acceptNewFriendCall3 = g_WeChatWinDllAddr + g_WxCalls.anf.call3; - DWORD acceptNewFriendCall4 = g_WeChatWinDllAddr + g_WxCalls.anf.call4; + int success = -1; +#if 0 + DWORD accept_new_friend_call1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1; + DWORD accept_new_friend_call2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2; + DWORD accept_new_friend_call3 = g_WeChatWinDllAddr + g_WxCalls.anf.call3; + DWORD accept_new_friend_call4 = g_WeChatWinDllAddr + g_WxCalls.anf.call4; char buffer[0x40] = { 0 }; char nullbuffer[0x3CC] = { 0 }; LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene); - wstring wsV3 = String2Wstring(v3); - wstring wsV4 = String2Wstring(v4); - WxString wxV3(wsV3); - WxString wxV4(wsV4); + wstring ws_v3 = String2Wstring(v3); + wstring ws_v4 = String2Wstring(v4); + WxString wx_v3(ws_v3); + WxString wx_v4(ws_v4); __asm { pushad; pushfd; lea ecx, buffer; - call acceptNewFriendCall1; + call accept_new_friend_call1; mov esi, 0x0; mov edi, scene; push esi; push edi; sub esp, 0x14; mov ecx, esp; - lea eax, wxV4; + lea eax, wx_v4; push eax; - call acceptNewFriendCall2; + call accept_new_friend_call2; sub esp, 0x8; push 0x0; lea eax, nullbuffer; push eax; - lea eax, wxV3; + lea eax, wx_v3; push eax; lea ecx, buffer; - call acceptNewFriendCall3; + call accept_new_friend_call3; mov success, eax; lea ecx, buffer; - call acceptNewFriendCall4; + call accept_new_friend_call4; popfd; popad; } - +#endif return success; // 成功返回 1 } -/*没啥用,非好友获取不到*/ -RpcContact_t GetContactByWxid(string wxid) +RpcContact_t get_contact_by_wxid(string wxid) { RpcContact_t contact; +#if 0 char buff[0x440] = { 0 }; - wstring wsWxid = String2Wstring(wxid); - WxString pri(wsWxid); + wstring ws_wxid = String2Wstring(wxid); + WxString pri(ws_wxid); + DWORD contact_mgr_addr = g_WeChatWinDllAddr + 0x75A4A0; DWORD get_contact_addr = g_WeChatWinDllAddr + 0xC04E00; DWORD free_contact_addr = g_WeChatWinDllAddr + 0xEA7880; + __asm { PUSHAD PUSHFD @@ -173,10 +176,10 @@ RpcContact_t GetContactByWxid(string wxid) } contact.wxid = wxid; - contact.code = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxCode); - contact.remark = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxRemark); - contact.name = GetStringByWstrAddr((DWORD)buff + g_WxCalls.contact.wxName); - contact.gender = GET_DWORD((DWORD)buff + 0x148); + contact.code = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxCode); + contact.remark = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxRemark); + contact.name = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxName); + contact.gender = GET_DWORD(reinterpret_cast(buff) + 0x148); __asm { PUSHAD @@ -186,7 +189,32 @@ RpcContact_t GetContactByWxid(string wxid) POPFD POPAD } - +#endif return contact; } -#endif + +bool rpc_get_contacts(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { + vector contacts = get_contacts(); + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; + }); +} + +bool rpc_get_contact_info(const string &wxid, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + vector contacts = { get_contact_by_wxid(wxid) }; + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; + }); +} + +bool rpc_accept_friend(const string &v3, const string &v4, int scene, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = accept_friend(v3, v4, scene); }); +} + +} // namespace contact_mgmt diff --git a/WeChatFerry/spy/contact_mgmt.h b/WeChatFerry/spy/contact_mgmt.h index 460bf89..3ff0662 100644 --- a/WeChatFerry/spy/contact_mgmt.h +++ b/WeChatFerry/spy/contact_mgmt.h @@ -1,11 +1,28 @@ #pragma once -#include "string" +#include #include #include "pb_types.h" -vector GetContacts(); -int AcceptNewFriend(std::string v3, std::string v4, int scene); -int AddFriendByWxid(std::string wxid, std::string msg); -RpcContact_t GetContactByWxid(std::string wxid); +namespace contact_mgmt +{ + +// 获取所有联系人 +std::vector get_contacts(); + +// 根据 wxid 获取联系人信息 +RpcContact_t get_contact_by_wxid(const std::string &wxid); + +// 接受好友请求 +int accept_friend(const std::string &v3, const std::string &v4, int scene); + +// 发送好友请求 +// int add_friend_by_wxid(const std::string &wxid, const std::string &msg); + +// RPC 方法 +bool rpc_get_contacts(uint8_t *out, size_t *len); +bool rpc_get_contact_info(const std::string &wxid, uint8_t *out, size_t *len); +bool rpc_accept_friend(const std::string &v3, const std::string &v4, int scene, uint8_t *out, size_t *len); + +} // namespace contact_mgmt diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index ab99536..e90fa6a 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -103,7 +103,7 @@ static bool func_get_msg_types(uint8_t *out, size_t *len) static bool func_get_contacts(uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [](Response &rsp) { - static std::vector contacts = GetContacts(); + static std::vector contacts = contact_mgmt::get_contacts(); rsp.msg.contacts.contacts.funcs.encode = encode_contacts; rsp.msg.contacts.contacts.arg = &contacts; }); @@ -410,7 +410,6 @@ static bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *o }); } -#if 0 static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) { return FillResponse(Response_status_tag, out, len, [v3, v4, scene](Response &rsp) { @@ -418,7 +417,7 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, LOG_ERROR("Empty V3 or V4."); rsp.msg.status = -1; } else { - rsp.msg.status = AcceptNewFriend(v3, v4, scene); + rsp.msg.status = contact_mgmt::accept_friend(v3, v4, scene); } }); } @@ -426,15 +425,11 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, static bool func_get_contact_info(std::string wxid, uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [wxid](Response &rsp) { - static std::vector contacts; - contacts.clear(); - contacts.push_back(GetContactByWxid(wxid)); - + std::vector contacts = contact_mgmt::get_contact_by_wxid(wxid); rsp.msg.contacts.contacts.funcs.encode = encode_contacts; rsp.msg.contacts.contacts.arg = &contacts; }); } -#endif static bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) { From 065db1d236fcb781dbc75388e6360a35091fcf22 Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 10:51:35 +0800 Subject: [PATCH 11/41] Fix function signature --- WeChatFerry/spy/contact_mgmt.cpp | 12 ++++++------ WeChatFerry/spy/contact_mgmt.h | 2 +- WeChatFerry/spy/rpc_server.cpp | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index 1adae24..192b20f 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -3,15 +3,15 @@ #include "contact_mgmt.h" #include "fill_response.h" #include "log.hpp" +#include "pb_util.h" #include "util.h" using namespace std; -namespace contact_mgmt -{ - extern QWORD g_WeChatWinDllAddr; +namespace contact_mgmt +{ #define OS_GET_CONTACT_MGR 0x1B417A0 #define OS_GET_CONTACT_LIST 0x219ED10 #define OS_CONTACT_BIN 0x200 @@ -98,7 +98,7 @@ vector get_contacts() return contacts; } -int accept_new_friend(string v3, string v4, int scene) +int accept_new_friend(const std::string &v3, const std::string &v4, int scene) { int success = -1; #if 0 @@ -149,7 +149,7 @@ int accept_new_friend(string v3, string v4, int scene) return success; // 成功返回 1 } -RpcContact_t get_contact_by_wxid(string wxid) +RpcContact_t get_contact_by_wxid(const string &wxid) { RpcContact_t contact; #if 0 @@ -214,7 +214,7 @@ bool rpc_get_contact_info(const string &wxid, uint8_t *out, size_t *len) bool rpc_accept_friend(const string &v3, const string &v4, int scene, uint8_t *out, size_t *len) { return fill_response( - out, len, [&](Response &rsp) { rsp.msg.status = accept_friend(v3, v4, scene); }); + out, len, [&](Response &rsp) { rsp.msg.status = accept_new_friend(v3, v4, scene); }); } } // namespace contact_mgmt diff --git a/WeChatFerry/spy/contact_mgmt.h b/WeChatFerry/spy/contact_mgmt.h index 3ff0662..0fb8091 100644 --- a/WeChatFerry/spy/contact_mgmt.h +++ b/WeChatFerry/spy/contact_mgmt.h @@ -15,7 +15,7 @@ std::vector get_contacts(); RpcContact_t get_contact_by_wxid(const std::string &wxid); // 接受好友请求 -int accept_friend(const std::string &v3, const std::string &v4, int scene); +int accept_new_friend(const std::string &v3, const std::string &v4, int scene); // 发送好友请求 // int add_friend_by_wxid(const std::string &wxid, const std::string &msg); diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index e90fa6a..5d4ecb8 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -103,9 +103,9 @@ static bool func_get_msg_types(uint8_t *out, size_t *len) static bool func_get_contacts(uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [](Response &rsp) { - static std::vector contacts = contact_mgmt::get_contacts(); - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; + std::vector contacts = contact_mgmt::get_contacts(); + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; }); } @@ -417,7 +417,7 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, LOG_ERROR("Empty V3 or V4."); rsp.msg.status = -1; } else { - rsp.msg.status = contact_mgmt::accept_friend(v3, v4, scene); + rsp.msg.status = contact_mgmt::accept_new_friend(v3, v4, scene); } }); } @@ -425,7 +425,7 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, static bool func_get_contact_info(std::string wxid, uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [wxid](Response &rsp) { - std::vector contacts = contact_mgmt::get_contact_by_wxid(wxid); + std::vector contacts = { contact_mgmt::get_contact_by_wxid(wxid) }; rsp.msg.contacts.contacts.funcs.encode = encode_contacts; rsp.msg.contacts.contacts.arg = &contacts; }); From da4dcec8bce2ecc1d700e8d1bf905334c38d4f3f Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 11:06:26 +0800 Subject: [PATCH 12/41] Refactoring --- WeChatFerry/spy/chatroom_mgmt.cpp | 150 +++++++++++++++--------------- WeChatFerry/spy/chatroom_mgmt.h | 21 ++++- WeChatFerry/spy/rpc_server.cpp | 6 +- 3 files changed, 94 insertions(+), 83 deletions(-) diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index 0950d45..602042e 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -1,113 +1,109 @@ -#include "framework.h" -#include -#include +#pragma execution_character_set("utf-8") #include "chatroom_mgmt.h" +#include "fill_response.h" #include "log.hpp" +#include "pb_util.h" #include "util.h" using namespace std; extern QWORD g_WeChatWinDllAddr; +namespace chatroom_mgmt +{ #define OS_GET_CHATROOM_MGR 0x1B83BD0 #define OS_ADD_MEMBERS 0x2155100 #define OS_DELETE_MEMBERS 0x2155740 #define OS_INVITE_MEMBERS 0x2154AE0 -typedef QWORD (*GetChatRoomMgr_t)(); -typedef QWORD (*AddMemberToChatRoom_t)(QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*DelMemberFromChatRoom_t)(QWORD, QWORD, QWORD); -typedef QWORD (*InviteMemberToChatRoom_t)(QWORD, QWORD, QWORD, QWORD); +using get_chatroom_mgr_t = QWORD (*)(); +using add_member_to_chatroom_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD); +using del_member_from_chatroom_t = QWORD (*)(QWORD, QWORD, QWORD); +using invite_member_to_chatroom_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD); -int AddChatroomMember(string roomid, string wxids) +static vector parse_wxids(const string &wxids) { - int status = -1; - - if (roomid.empty() || wxids.empty()) { - LOG_ERROR("Empty roomid or wxids."); - return status; - } - - GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR); - AddMemberToChatRoom_t AddMembers = (AddMemberToChatRoom_t)(g_WeChatWinDllAddr + OS_ADD_MEMBERS); - - vector vMembers; - vector vWxMembers; + vector wx_members; wstringstream wss(String2Wstring(wxids)); - while (wss.good()) { - wstring wstr; - getline(wss, wstr, L','); - vMembers.push_back(wstr); - WxString wxMember(vMembers.back()); - vWxMembers.push_back(wxMember); + wstring wstr; + while (getline(wss, wstr, L',')) { + wx_members.emplace_back(wstr); } - - QWORD temp[2] = { 0 }; - WxString *pWxRoomid = NewWxStringFromStr(roomid); - QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start; - - QWORD mgr = GetChatRoomMgr(); - status = (int)AddMembers(mgr, pMembers, (QWORD)pWxRoomid, (QWORD)temp); - return status; + return wx_members; } -int DelChatroomMember(string roomid, string wxids) +int add_chatroom_member(const string &roomid, const string &wxids) { - int status = -1; - if (roomid.empty() || wxids.empty()) { LOG_ERROR("Empty roomid or wxids."); - return status; + return -1; } - GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR); - DelMemberFromChatRoom_t DelMembers = (DelMemberFromChatRoom_t)(g_WeChatWinDllAddr + OS_DELETE_MEMBERS); + get_chatroom_mgr_t get_chatroom_mgr + = reinterpret_cast(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR); + add_member_to_chatroom_t add_members + = reinterpret_cast(g_WeChatWinDllAddr + OS_ADD_MEMBERS); - vector vMembers; - vector vWxMembers; - wstringstream wss(String2Wstring(wxids)); - while (wss.good()) { - wstring wstr; - getline(wss, wstr, L','); - vMembers.push_back(wstr); - WxString wxMember(vMembers.back()); - vWxMembers.push_back(wxMember); - } + vector wx_members = parse_wxids(wxids); + WxString *p_wx_roomid = NewWxStringFromStr(roomid); + QWORD p_members = reinterpret_cast(&wx_members.front()); - WxString *pWxRoomid = NewWxStringFromStr(roomid); - QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start; - - QWORD mgr = GetChatRoomMgr(); - status = (int)DelMembers(mgr, pMembers, (QWORD)pWxRoomid); - return status; + return static_cast(add_members(get_chatroom_mgr(), p_members, reinterpret_cast(p_wx_roomid), 0)); } -int InviteChatroomMember(string roomid, string wxids) +int del_chatroom_member(const string &roomid, const string &wxids) { - int status = -1; - if (roomid.empty() || wxids.empty()) { LOG_ERROR("Empty roomid or wxids."); - return status; + return -1; } - InviteMemberToChatRoom_t InviteMembers = (InviteMemberToChatRoom_t)(g_WeChatWinDllAddr + OS_INVITE_MEMBERS); + get_chatroom_mgr_t get_chatroom_mgr + = reinterpret_cast(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR); + del_member_from_chatroom_t del_members + = reinterpret_cast(g_WeChatWinDllAddr + OS_DELETE_MEMBERS); - vector vMembers; - vector vWxMembers; - wstringstream wss(String2Wstring(wxids)); - while (wss.good()) { - wstring wstr; - getline(wss, wstr, L','); - vMembers.push_back(wstr); - WxString wxMember(vMembers.back()); - vWxMembers.push_back(wxMember); - } - QWORD temp[2] = { 0 }; - wstring wsRoomid = String2Wstring(roomid); - WxString *pWxRoomid = NewWxStringFromWstr(wsRoomid); - QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start; + vector wx_members = parse_wxids(wxids); + WxString *p_wx_roomid = NewWxStringFromStr(roomid); + QWORD p_members = reinterpret_cast(&wx_members.front()); - status = (int)InviteMembers((QWORD)wsRoomid.c_str(), pMembers, (QWORD)pWxRoomid, (QWORD)temp); - return status; + return static_cast(del_members(get_chatroom_mgr(), p_members, reinterpret_cast(p_wx_roomid))); } + +int invite_chatroom_member(const string &roomid, const string &wxids) +{ + if (roomid.empty() || wxids.empty()) { + LOG_ERROR("Empty roomid or wxids."); + return -1; + } + + invite_member_to_chatroom_t invite_members + = reinterpret_cast(g_WeChatWinDllAddr + OS_INVITE_MEMBERS); + + vector wx_members = parse_wxids(wxids); + WxString *p_wx_roomid = NewWxStringFromStr(roomid); + QWORD p_members = reinterpret_cast(&wx_members.front()); + + return static_cast(invite_members(reinterpret_cast(p_wx_roomid->c_str()), p_members, + reinterpret_cast(p_wx_roomid), 0)); +} + +bool rpc_add_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = add_chatroom_member(roomid, wxids); }); +} + +bool rpc_del_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = del_chatroom_member(roomid, wxids); }); +} + +bool rpc_invite_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = invite_chatroom_member(roomid, wxids); }); +} + +} // namespace chatroom_mgmt diff --git a/WeChatFerry/spy/chatroom_mgmt.h b/WeChatFerry/spy/chatroom_mgmt.h index da1eabf..2f9b9a6 100644 --- a/WeChatFerry/spy/chatroom_mgmt.h +++ b/WeChatFerry/spy/chatroom_mgmt.h @@ -2,6 +2,21 @@ #include -int AddChatroomMember(std::string roomid, std::string wxids); -int DelChatroomMember(std::string roomid, std::string wxids); -int InviteChatroomMember(std::string roomid, std::string wxids); +namespace chatroom_mgmt +{ + +// 添加成员到群聊 +int add_chatroom_member(const std::string &roomid, const std::string &wxids); + +// 从群聊中移除成员 +int del_chatroom_member(const std::string &roomid, const std::string &wxids); + +// 邀请成员加入群聊 +int invite_chatroom_member(const std::string &roomid, const std::string &wxids); + +// RPC 方法 +bool rpc_add_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); +bool rpc_del_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); +bool rpc_invite_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); + +} // namespace chatroom_mgmt diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 5d4ecb8..10a5f85 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -465,7 +465,7 @@ static bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_ LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = AddChatroomMember(roomid, wxids); + rsp.msg.status = chatroom_mgmt::add_chatroom_member(roomid, wxids); } }); } @@ -477,7 +477,7 @@ static bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_ LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = DelChatroomMember(roomid, wxids); + rsp.msg.status = chatroom_mgmt::del_chatroom_member(roomid, wxids); } }); } @@ -489,7 +489,7 @@ static bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, si LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = InviteChatroomMember(roomid, wxids); + rsp.msg.status = chatroom_mgmt::invite_chatroom_member(roomid, wxids); } }); } From 2033ae2ab8be0c1a5121b89a0888245a3024585f Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 31 Jan 2025 11:17:41 +0800 Subject: [PATCH 13/41] Refactoring --- WeChatFerry/spy/chatroom_mgmt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index 602042e..db496b3 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -84,7 +84,7 @@ int invite_chatroom_member(const string &roomid, const string &wxids) WxString *p_wx_roomid = NewWxStringFromStr(roomid); QWORD p_members = reinterpret_cast(&wx_members.front()); - return static_cast(invite_members(reinterpret_cast(p_wx_roomid->c_str()), p_members, + return static_cast(invite_members(reinterpret_cast(p_wx_roomid->wptr), p_members, reinterpret_cast(p_wx_roomid), 0)); } From ff5f2378c0f472f650d0324d34bc1a04769d2755 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 1 Feb 2025 08:45:28 +0800 Subject: [PATCH 14/41] Refactoring --- WeChatFerry/spy/exec_sql.cpp | 289 +++++++++++++++++++-------------- WeChatFerry/spy/exec_sql.h | 31 +++- WeChatFerry/spy/rpc_server.cpp | 6 +- 3 files changed, 200 insertions(+), 126 deletions(-) diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 834c856..5ba9457 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -1,10 +1,16 @@ -#include +#include +#include #include "exec_sql.h" +#include "fill_response.h" #include "log.hpp" #include "sqlite3.h" #include "util.h" +extern UINT64 g_WeChatWinDllAddr; + +namespace exec_sql +{ #define OFFSET_DB_INSTANCE 0x5902000 #define OFFSET_DB_MICROMSG 0xB8 #define OFFSET_DB_CHAT_MSG 0x2C8 @@ -16,131 +22,138 @@ #define OFFSET_DB_NAME 0x28 #define OFFSET_DB_MSG_MGR 0x595F900 -extern UINT64 g_WeChatWinDllAddr; +using db_map_t = std::map; +static db_map_t db_map; -typedef map dbMap_t; -static dbMap_t dbMap; - -static void GetDbHandle(QWORD base, QWORD offset) +static void get_db_handle(QWORD base, QWORD offset) { - wchar_t *wsp = (wchar_t *)(*(QWORD *)(base + offset + OFFSET_DB_NAME)); - string dbname = Wstring2String(wstring(wsp)); - dbMap[dbname] = GET_QWORD(base + offset); + auto *wsp = reinterpret_cast(*(QWORD *)(base + offset + OFFSET_DB_NAME)); + std::string dbname = Wstring2String(std::wstring(wsp)); + db_map[dbname] = GET_QWORD(base + offset); } -static void GetMsgDbHandle(QWORD msgMgrAddr) +static void get_msg_db_handle(QWORD msg_mgr_addr) { - QWORD dbIndex = GET_QWORD(msgMgrAddr + 0x68); - QWORD pStart = GET_QWORD(msgMgrAddr + 0x50); - for (uint32_t i = 0; i < dbIndex; i++) { - QWORD dbAddr = GET_QWORD(pStart + i * 0x08); - if (dbAddr) { + QWORD db_index = GET_QWORD(msg_mgr_addr + 0x68); + QWORD p_start = GET_QWORD(msg_mgr_addr + 0x50); + for (uint32_t i = 0; i < db_index; i++) { + QWORD db_addr = GET_QWORD(p_start + i * 0x08); + if (db_addr) { // MSGi.db - string dbname = Wstring2String(GET_WSTRING(dbAddr)); - dbMap[dbname] = GET_QWORD(dbAddr + 0x78); + std::string dbname = Wstring2String(GET_WSTRING(db_addr)); + db_map[dbname] = GET_QWORD(db_addr + 0x78); // MediaMsgi.db - QWORD mmdbAddr = GET_QWORD(dbAddr + 0x20); - string mmdbname = Wstring2String(GET_WSTRING(mmdbAddr + 0x78)); - dbMap[mmdbname] = GET_QWORD(mmdbAddr + 0x50); + QWORD mmdb_addr = GET_QWORD(db_addr + 0x20); + std::string mmdbname = Wstring2String(GET_WSTRING(mmdb_addr + 0x78)); + db_map[mmdbname] = GET_QWORD(mmdb_addr + 0x50); } } } -dbMap_t GetDbHandles() +db_map_t get_db_handles() { - dbMap.clear(); + db_map.clear(); + QWORD db_instance_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE); - QWORD dbInstanceAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE); + get_db_handle(db_instance_addr, OFFSET_DB_MICROMSG); // MicroMsg.db + get_db_handle(db_instance_addr, OFFSET_DB_CHAT_MSG); // ChatMsg.db + get_db_handle(db_instance_addr, OFFSET_DB_MISC); // Misc.db + get_db_handle(db_instance_addr, OFFSET_DB_EMOTION); // Emotion.db + get_db_handle(db_instance_addr, OFFSET_DB_MEDIA); // Media.db + get_db_handle(db_instance_addr, OFFSET_DB_FUNCTION_MSG); // Function.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_MICROMSG); // MicroMsg.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_CHAT_MSG); // ChatMsg.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_MISC); // Misc.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_EMOTION); // Emotion.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_MEDIA); // Media.db - GetDbHandle(dbInstanceAddr, OFFSET_DB_FUNCTION_MSG); // Function.db + get_msg_db_handle(GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR)); // MSGi.db & MediaMsgi.db - GetMsgDbHandle(GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR)); // MSGi.db & MediaMsgi.db - - return dbMap; + return db_map; } -DbNames_t GetDbNames() +DbNames_t get_db_names() { - DbNames_t names; - if (dbMap.empty()) { - dbMap = GetDbHandles(); + if (db_map.empty()) { + db_map = get_db_handles(); } - for (auto &[k, v] : dbMap) { + DbNames_t names; + for (const auto &[k, _] : db_map) { names.push_back(k); } - return names; } -static int cbGetTables(void *ret, int argc, char **argv, char **azColName) +static int cb_get_tables(void *ret, int argc, char **argv, char **azColName) { - DbTables_t *tbls = (DbTables_t *)ret; + auto *tables = static_cast(ret); DbTable_t tbl; for (int i = 0; i < argc; i++) { if (strcmp(azColName[i], "name") == 0) { tbl.name = argv[i] ? argv[i] : ""; } else if (strcmp(azColName[i], "sql") == 0) { - string sql(argv[i]); + std::string sql(argv[i]); sql.erase(std::remove(sql.begin(), sql.end(), '\t'), sql.end()); - tbl.sql = sql.c_str(); + tbl.sql = sql; } } - tbls->push_back(tbl); + tables->push_back(tbl); return 0; } -DbTables_t GetDbTables(const string db) +DbTables_t get_db_tables(const std::string &db) { DbTables_t tables; - if (dbMap.empty()) { - dbMap = GetDbHandles(); + if (db_map.empty()) { + db_map = get_db_handles(); } - auto it = dbMap.find(db); - if (it == dbMap.end()) { - return tables; // DB not found + auto it = db_map.find(db); + if (it == db_map.end()) { + return tables; } - const char *sql = "select name, sql from sqlite_master where type=\"table\";"; - Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + SQLITE3_EXEC_OFFSET); - - p_Sqlite3_exec(it->second, sql, (Sqlite3_callback)cbGetTables, (void *)&tables, 0); + constexpr const char *sql = "SELECT name FROM sqlite_master WHERE type='table';"; + Sqlite3_exec p_sqlite3_exec = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_EXEC_OFFSET); + p_sqlite3_exec(it->second, sql, (Sqlite3_callback)cb_get_tables, (void *)&tables, nullptr); return tables; } -DbRows_t ExecDbQuery(const string db, const string sql) +DbRows_t exec_db_query(const std::string &db, const std::string &sql) { DbRows_t rows; - Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + SQLITE3_PREPARE_OFFSET); - Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + SQLITE3_STEP_OFFSET); - Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + SQLITE3_COLUMN_COUNT_OFFSET); - Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + SQLITE3_COLUMN_NAME_OFFSET); - Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + SQLITE3_COLUMN_TYPE_OFFSET); - Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BLOB_OFFSET); - Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + SQLITE3_COLUMN_BYTES_OFFSET); - Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + SQLITE3_FINALIZE_OFFSET); - if (dbMap.empty()) { - dbMap = GetDbHandles(); + Sqlite3_prepare func_prepare = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_PREPARE_OFFSET); + Sqlite3_step func_step = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_STEP_OFFSET); + Sqlite3_column_count func_column_count + = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_COLUMN_COUNT_OFFSET); + Sqlite3_column_name func_column_name + = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_COLUMN_NAME_OFFSET); + Sqlite3_column_type func_column_type + = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_COLUMN_TYPE_OFFSET); + Sqlite3_column_blob func_column_blob + = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_COLUMN_BLOB_OFFSET); + Sqlite3_column_bytes func_column_bytes + = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_COLUMN_BYTES_OFFSET); + Sqlite3_finalize func_finalize = reinterpret_cast(g_WeChatWinDllAddr + SQLITE3_FINALIZE_OFFSET); + + if (db_map.empty()) { + db_map = get_db_handles(); + } + + auto it = db_map.find(db); + if (it == db_map.end() || it->second == 0) { + LOG_WARN("Empty handle for database '{}', retrying...", db); + db_map = get_db_handles(); + it = db_map.find(db); + if (it == db_map.end() || it->second == 0) { + LOG_ERROR("Failed to get handle for database '{}'", db); + return rows; + } } QWORD *stmt; - QWORD handle = dbMap[db]; - if (handle == 0) { - LOG_WARN("Empty handle, retrying..."); - dbMap = GetDbHandles(); - } - - int rc = func_prepare(dbMap[db], sql.c_str(), -1, &stmt, 0); + int rc = func_prepare(it->second, sql.c_str(), -1, &stmt, nullptr); if (rc != SQLITE_OK) { + LOG_ERROR("SQL prepare failed for '{}': error code {}", db, rc); return rows; } @@ -154,79 +167,119 @@ DbRows_t ExecDbQuery(const string db, const string sql) int length = func_column_bytes(stmt, i); const void *blob = func_column_blob(stmt, i); - if (length && (field.type != 5)) { - field.content.reserve(length); - copy((uint8_t *)blob, (uint8_t *)blob + length, back_inserter(field.content)); + if (length > 0 && field.type != SQLITE_NULL) { + field.content.resize(length); + std::memcpy(field.content.data(), blob, length); } row.push_back(field); } rows.push_back(row); } + + func_finalize(stmt); return rows; } -int GetLocalIdandDbidx(uint64_t id, uint64_t *localId, uint32_t *dbIdx) +int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx) { - QWORD msgMgrAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); - int dbIndex = (int)GET_QWORD(msgMgrAddr + 0x68); // 总不能 int 还不够吧? - QWORD pStart = GET_QWORD(msgMgrAddr + 0x50); + if (!local_id || !db_idx) { + LOG_ERROR("Invalid pointer arguments!"); + return -1; + } - *dbIdx = 0; - for (int i = dbIndex - 1; i >= 0; i--) { // 从后往前遍历 - QWORD dbAddr = GET_QWORD(pStart + i * 0x08); - if (dbAddr) { - string dbname = Wstring2String(GET_WSTRING(dbAddr)); - dbMap[dbname] = GET_QWORD(dbAddr + 0x78); - string sql = "SELECT localId FROM MSG WHERE MsgSvrID=" + to_string(id) + ";"; - DbRows_t rows = ExecDbQuery(dbname, sql); - if (rows.empty()) { - continue; - } - DbRow_t row = rows.front(); - if (row.empty()) { - continue; - } - DbField_t field = row.front(); - if ((field.column.compare("localId") != 0) && (field.type != 1)) { - continue; - } + QWORD msg_mgr_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); + int db_index = static_cast(GET_QWORD(msg_mgr_addr + 0x68)); // 总不能 int 还不够吧? + QWORD p_start = GET_QWORD(msg_mgr_addr + 0x50); - *localId = strtoull((const char *)(field.content.data()), NULL, 10); - *dbIdx = (uint32_t)(GET_QWORD(GET_QWORD(dbAddr + 0x28) + 0x1E8) >> 32); - - return 0; + *db_idx = 0; + for (int i = db_index - 1; i >= 0; i--) { // 从后往前遍历 + QWORD db_addr = GET_QWORD(p_start + i * 0x08); + if (!db_addr) { + continue; } + + std::string dbname = Wstring2String(GET_WSTRING(db_addr)); + db_map[dbname] = GET_QWORD(db_addr + 0x78); + + std::string sql = "SELECT localId FROM MSG WHERE MsgSvrID=" + std::to_string(id) + ";"; + DbRows_t rows = exec_db_query(dbname, sql); + + if (rows.empty() || rows.front().empty()) { + continue; + } + + const DbField_t &field = rows.front().front(); + if (field.column != "localId" || field.type != SQLITE_INTEGER) { + continue; + } + + std::string id_str(field.content.begin(), field.content.end()); + try { + *local_id = std::stoull(id_str); + } catch (const std::exception &e) { + LOG_ERROR("Failed to parse localId: {}", e.what()); + continue; + } + + *db_idx = static_cast(GET_QWORD(GET_QWORD(db_addr + 0x28) + 0x1E8) >> 32); + return 0; } return -1; } -vector GetAudioData(uint64_t id) +std::vector get_audio_data(uint64_t id) { - QWORD msgMgrAddr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); - int dbIndex = (int)GET_QWORD(msgMgrAddr + 0x68); + QWORD msg_mgr_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); + int db_index = static_cast(GET_QWORD(msg_mgr_addr + 0x68)); - string sql = "SELECT Buf FROM Media WHERE Reserved0=" + to_string(id) + ";"; - for (int i = dbIndex - 1; i >= 0; i--) { - string dbname = "MediaMSG" + to_string(i) + ".db"; - DbRows_t rows = ExecDbQuery(dbname, sql); - if (rows.empty()) { + std::string sql = "SELECT Buf FROM Media WHERE Reserved0=" + std::to_string(id) + ";"; + for (int i = db_index - 1; i >= 0; i--) { + std::string dbname = "MediaMSG" + std::to_string(i) + ".db"; + DbRows_t rows = exec_db_query(dbname, sql); + + if (rows.empty() || rows.front().empty()) { continue; } - DbRow_t row = rows.front(); - if (row.empty()) { - continue; - } - DbField_t field = row.front(); - if (field.column.compare("Buf") != 0) { + + const DbField_t &field = rows.front().front(); + if (field.column != "Buf" || field.content.empty()) { continue; } // 首字节为 0x02,估计是混淆用的?去掉。 - vector rv(field.content.begin() + 1, field.content.end()); + if (field.content.front() == 0x02) { + return std::vector(field.content.begin() + 1, field.content.end()); + } - return rv; + return field.content; } - return vector(); + return {}; } + +bool rpc_get_db_names(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + rsp.msg.dbs.names.funcs.encode = encode_dbnames; + rsp.msg.dbs.names.arg = &get_db_names(); + }); +} + +bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + rsp.msg.tables.tables.funcs.encode = encode_tables; + rsp.msg.tables.tables.arg = &get_db_tables(db); + }); +} + +bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + rsp.msg.rows.rows.funcs.encode = encode_rows; + rsp.msg.rows.rows.arg = &exec_db_query(db, sql); + }); +} + +} // namespace exec_sql diff --git a/WeChatFerry/spy/exec_sql.h b/WeChatFerry/spy/exec_sql.h index ea7fc8f..538f06e 100644 --- a/WeChatFerry/spy/exec_sql.h +++ b/WeChatFerry/spy/exec_sql.h @@ -1,11 +1,32 @@ #pragma once +#include +#include #include #include "pb_types.h" -DbNames_t GetDbNames(); -DbTables_t GetDbTables(const string db); -DbRows_t ExecDbQuery(const string db, const string sql); -int GetLocalIdandDbidx(uint64_t id, uint64_t *localId, uint32_t *dbIdx); -vector GetAudioData(uint64_t msgid); +namespace exec_sql +{ + +// 获取数据库名称列表 +DbNames_t get_db_names(); + +// 获取指定数据库的表列表 +DbTables_t get_db_tables(const std::string &db); + +// 执行 SQL 查询 +DbRows_t exec_db_query(const std::string &db, const std::string &sql); + +// 获取本地消息 ID 和数据库索引 +std::optional> get_local_id_and_dbidx(uint64_t id); + +// 获取音频数据 +std::vector get_audio_data(uint64_t msg_id); + +// RPC 方法 +bool rpc_get_db_names(uint8_t *out, size_t *len); +bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len); +bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len); + +} // namespace exec_sql diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 10a5f85..b558f38 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -112,7 +112,7 @@ static bool func_get_contacts(uint8_t *out, size_t *len) static bool func_get_db_names(uint8_t *out, size_t *len) { return FillResponse(Response_dbs_tag, out, len, [](Response &rsp) { - static DbNames_t dbnames = GetDbNames(); + static DbNames_t dbnames = exec_sql::get_db_names(); rsp.msg.dbs.names.funcs.encode = encode_dbnames; rsp.msg.dbs.names.arg = &dbnames; }); @@ -121,7 +121,7 @@ static bool func_get_db_names(uint8_t *out, size_t *len) static bool func_get_db_tables(char *db, uint8_t *out, size_t *len) { return FillResponse(Response_tables_tag, out, len, [db](Response &rsp) { - static DbTables_t tables = GetDbTables(db); + static DbTables_t tables = exec_sql::get_db_tables(db); rsp.msg.tables.tables.funcs.encode = encode_tables; rsp.msg.tables.tables.arg = &tables; }); @@ -362,7 +362,7 @@ static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) if ((db == nullptr) || (sql == nullptr)) { LOG_ERROR("Empty db or sql."); } else { - rows = ExecDbQuery(db, sql); + rows = exec_sql::exec_db_query(db, sql); } rsp.msg.rows.rows.arg = &rows; rsp.msg.rows.rows.funcs.encode = encode_rows; From ada071c7d2a3bc241c5a7b786682a34e8a942995 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 1 Feb 2025 18:48:56 +0800 Subject: [PATCH 15/41] Refactoring --- WeChatFerry/spy/exec_sql.cpp | 1 + WeChatFerry/spy/exec_sql.h | 2 +- WeChatFerry/spy/funcs.cpp | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 5ba9457..3c8e369 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -4,6 +4,7 @@ #include "exec_sql.h" #include "fill_response.h" #include "log.hpp" +#include "pb_util.h" #include "sqlite3.h" #include "util.h" diff --git a/WeChatFerry/spy/exec_sql.h b/WeChatFerry/spy/exec_sql.h index 538f06e..411c338 100644 --- a/WeChatFerry/spy/exec_sql.h +++ b/WeChatFerry/spy/exec_sql.h @@ -19,7 +19,7 @@ DbTables_t get_db_tables(const std::string &db); DbRows_t exec_db_query(const std::string &db, const std::string &sql); // 获取本地消息 ID 和数据库索引 -std::optional> get_local_id_and_dbidx(uint64_t id); +int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx); // 获取音频数据 std::vector get_audio_data(uint64_t msg_id); diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index 56b1b8c..0ec2959 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -202,7 +202,7 @@ int DownloadAttach(QWORD id, string thumb, string extra) return 0; } - if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) { + if (exec_sql::get_local_id_and_dbidx(id, &localId, &dbIdx) != 0) { LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id)); return status; } @@ -285,7 +285,7 @@ string GetAudio(QWORD id, string dir) return mp3path; } - vector silk = GetAudioData(id); + vector silk = exec_sql::get_audio_data(id); if (silk.size() == 0) { LOG_ERROR("Empty audio data."); return ""; @@ -305,7 +305,7 @@ string GetPCMAudio(uint64_t id, string dir, int32_t sr) return pcmpath; } vector pcm; - vector silk = GetAudioData(id); + vector silk = exec_sql::get_audio_data(id); if (silk.size() == 0) { LOG_ERROR("Empty audio data."); return ""; From 7dd1887dcfa10ad3d6af83d391512cfa826c522f Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 2 Feb 2025 08:54:12 +0800 Subject: [PATCH 16/41] Refactoring --- WeChatFerry/spy/exec_sql.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 3c8e369..0ed9982 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -262,24 +262,27 @@ std::vector get_audio_data(uint64_t id) bool rpc_get_db_names(uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { + DbNames_t names = get_db_names(); rsp.msg.dbs.names.funcs.encode = encode_dbnames; - rsp.msg.dbs.names.arg = &get_db_names(); + rsp.msg.dbs.names.arg = &names; }); } bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { + DbTables_t tables = get_db_tables(db); rsp.msg.tables.tables.funcs.encode = encode_tables; - rsp.msg.tables.tables.arg = &get_db_tables(db); + rsp.msg.tables.tables.arg = &tables; }); } bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { + DbRows_t rows = exec_db_query(db, sql); rsp.msg.rows.rows.funcs.encode = encode_rows; - rsp.msg.rows.rows.arg = &exec_db_query(db, sql); + rsp.msg.rows.rows.arg = &rows; }); } From e5480bf6671fb9bd154cbee157d04c3f8ca41a43 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Feb 2025 21:20:22 +0800 Subject: [PATCH 17/41] Refactoring --- WeChatFerry/spy/send_msg.cpp | 450 +++++++++++++++++++++-------------- WeChatFerry/spy/send_msg.h | 95 ++++++-- 2 files changed, 344 insertions(+), 201 deletions(-) diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index 4e5bbdb..b9451e3 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -1,11 +1,11 @@ - -#include "framework.h" +#include "send_msg.h" + #include #include #include "exec_sql.h" +#include "fill_response.h" #include "log.hpp" -#include "send_msg.h" #include "spy_types.h" #include "user_info.h" #include "util.h" @@ -32,242 +32,326 @@ extern QWORD g_WeChatWinDllAddr; #define OS_XML_BUFSIGN 0x24F0D70 #define OS_SEND_XML 0x20CF360 -typedef QWORD (*New_t)(QWORD); -typedef QWORD (*Free_t)(QWORD); -typedef QWORD (*SendMsgMgr_t)(); -typedef QWORD (*GetAppMsgMgr_t)(); -typedef QWORD (*SendTextMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*SendImageMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*SendFileMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD, - QWORD); -typedef QWORD (*SendRichTextMsg_t)(QWORD, QWORD, QWORD); -typedef QWORD (*SendPatMsg_t)(QWORD, QWORD); -typedef QWORD (*ForwardMsg_t)(QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*GetEmotionMgr_t)(); -typedef QWORD (*SendEmotion_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); - -typedef QWORD (*XmlBufSign_t)(QWORD, QWORD, QWORD); -typedef QWORD (*SendXmlMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); - -void SendTextMessage(string wxid, string msg, string atWxids) +SendMsgManager &SendMsgManager::get_instance() { - QWORD success = 0; - wstring wsWxid = String2Wstring(wxid); - wstring wsMsg = String2Wstring(msg); - WxString wxMsg(wsMsg); - WxString wxWxid(wsWxid); - - vector vAtWxids; - vector vWxAtWxids; - if (!atWxids.empty()) { - wstringstream wss(String2Wstring(atWxids)); - while (wss.good()) { - wstring wstr; - getline(wss, wstr, L','); - vAtWxids.push_back(wstr); - WxString wxAtWxid(vAtWxids.back()); - vWxAtWxids.push_back(wxAtWxid); - } - } else { - WxString wxEmpty = WxString(); - vWxAtWxids.push_back(wxEmpty); - } - - QWORD wxAters = (QWORD) & ((RawVector_t *)&vWxAtWxids)->start; - - char buffer[0x460] = { 0 }; - SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR); - SendTextMsg_t funcSendTextMsg = (SendTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_TEXT); - Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE); - funcSendMsgMgr(); - success = funcSendTextMsg((QWORD)(&buffer), (QWORD)(&wxWxid), (QWORD)(&wxMsg), wxAters, 1, 1, 0, 0); - funcFree((QWORD)(&buffer)); + static SendMsgManager instance; + return instance; } -void SendImageMessage(string wxid, string path) +SendMsgManager::SendMsgManager() { - wstring wsWxid = String2Wstring(wxid); - wstring wsPath = String2Wstring(path); + func_new = reinterpret_cast(g_WeChatWinDllAddr + OS_NEW); + func_free = reinterpret_cast(g_WeChatWinDllAddr + OS_FREE); + func_send_msg_mgr = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_MSG_MGR); + func_send_text = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_TEXT); + func_send_image = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_IMAGE); + func_send_file = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_FILE); + func_send_rich_text = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_RICH_TEXT); + func_send_pat = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_PAT_MSG); + func_forward = reinterpret_cast(g_WeChatWinDllAddr + OS_FORWARD_MSG); + func_send_emotion = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_EMOTION); + func_send_xml = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_XML); +} - WxString wxWxid(wsWxid); - WxString wxPath(wsPath); +std::unique_ptr SendMsgManager::new_wx_string(const std::string &str) +{ + return std::make_unique(String2Wstring(str)); +} - New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW); - Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE); - SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR); - SendImageMsg_t funcSendImage = (SendImageMsg_t)(g_WeChatWinDllAddr + OS_SEND_IMAGE); +std::vector SendMsgManager::parse_wxids(const string &wxids) +{ + vector wx_members; + wstringstream wss(String2Wstring(wxids)); + wstring wstr; + while (getline(wss, wstr, L',')) { + wx_members.emplace_back(wstr); + } + return wx_members; +} + +void SendMsgManager::send_text(const std::string &wxid, const std::string &msg, const std::string &at_wxids) +{ + auto wxWxid = new_wx_string(wxid); + auto wxMsg = new_wx_string(msg); + + std::vector wx_at_wxids; + if (!at_wxids.empty()) { + wx_at_wxids = parse_wxids(at_wxids); + } else { + wx_at_wxids.emplace_back(); + } + + QWORD wx_ater_list = reinterpret_cast(&(wx_at_wxids.front())); + + char buffer[0x460] = { 0 }; + func_send_msg_mgr(); + func_send_text(reinterpret_cast(&buffer), reinterpret_cast(wxWxid.get()), + reinterpret_cast(wxMsg.get()), wx_ater_list, 1, 1, 0, 0); + func_free(reinterpret_cast(&buffer)); +} + +void SendMsgManager::send_image(const std::string &wxid, const std::string &path) +{ + auto wxWxid = new_wx_string(wxid); + auto wxPath = new_wx_string(path); char msg[0x460] = { 0 }; char msgTmp[0x460] = { 0 }; - QWORD *flag[10] = { 0 }; + QWORD *flag[10] = { nullptr }; QWORD tmp1 = 0, tmp2 = 0; - QWORD pMsgTmp = funcNew((QWORD)(&msgTmp)); + QWORD pMsgTmp = func_new(reinterpret_cast(&msgTmp)); flag[8] = &tmp1; flag[9] = &tmp2; - flag[1] = (QWORD *)(pMsgTmp); + flag[1] = reinterpret_cast(pMsgTmp); - QWORD pMsg = funcNew((QWORD)(&msg)); - QWORD sendMgr = funcSendMsgMgr(); - funcSendImage(sendMgr, pMsg, (QWORD)(&wxWxid), (QWORD)(&wxPath), (QWORD)(&flag)); - funcFree(pMsg); - funcFree(pMsgTmp); + QWORD pMsg = func_new(reinterpret_cast(&msg)); + QWORD sendMgr = func_send_msg_mgr(); + + funcSendImage(sendMgr, pMsg, reinterpret_cast(wxWxid.get()), reinterpret_cast(wxPath.get()), + reinterpret_cast(&flag)); + + func_free(pMsg); + func_free(pMsgTmp); } -void SendFileMessage(string wxid, string path) +void SendMsgManager::send_file(const std::string &wxid, const std::string &path) { - wstring wsWxid = String2Wstring(wxid); - wstring wsPath = String2Wstring(path); - - WxString wxWxid(wsWxid); - WxString wxPath(wsPath); - - New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW); - Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE); - GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR); - SendFileMsg_t funcSendFile = (SendFileMsg_t)(g_WeChatWinDllAddr + OS_SEND_FILE); + auto wxWxid = new_wx_string(wxid); + auto wxPath = new_wx_string(path); char msg[0x460] = { 0 }; QWORD tmp1[4] = { 0 }; QWORD tmp2[4] = { 0 }; QWORD tmp3[4] = { 0 }; - QWORD pMsg = funcNew((QWORD)(&msg)); - QWORD appMgr = funcGetAppMsgMgr(); - funcSendFile(appMgr, pMsg, (QWORD)(&wxWxid), (QWORD)(&wxPath), 1, tmp1, 0, tmp2, 0, tmp3, 0, 0); - funcFree(pMsg); + QWORD pMsg = func_new(reinterpret_cast(&msg)); + QWORD appMgr = func_get_app_mgr(); + + func_send_file(appMgr, pMsg, reinterpret_cast(wxWxid.get()), reinterpret_cast(wxPath.get()), 1, tmp1, + 0, tmp2, 0, tmp3, 0, 0); + + func_free(pMsg); } -int SendRichTextMessage(RichText_t &rt) -{ // TODO: Fix memory leak +void SendMsgManager::send_xml(const std::string &receiver, const std::string &xml, const std::string &path, + uint64_t type) +{ + std::unique_ptr buff(new char[0x500]()); + std::unique_ptr buff2(new char[0x500]()); + char nullBuf[0x1C] = { 0 }; + + func_new(reinterpret_cast(buff.get())); + func_new(reinterpret_cast(buff2.get())); + + QWORD sbuf[4] = { 0, 0, 0, 0 }; + QWORD sign = func_xml_buf_sign(reinterpret_cast(buff2.get()), reinterpret_cast(sbuf), 0x1); + + auto wxReceiver = new_wx_string(receiver); + auto wxXml = new_wx_string(xml); + auto wxPath = new_wx_string(path); + auto wxSender = new_wx_string(user_info::get_self_wxid()); + + func_send_xml(reinterpret_cast(buff.get()), reinterpret_cast(wxSender.get()), + reinterpret_cast(wxReceiver.get()), reinterpret_cast(wxXml.get()), + reinterpret_cast(wxPath.get()), reinterpret_cast(nullBuf), type, 0x4, sign, + reinterpret_cast(buff2.get())); + + func_free(reinterpret_cast(buff.get())); + func_free(reinterpret_cast(buff2.get())); +} + +void SendMsgManager::send_emotion(const std::string &wxid, const std::string &path) +{ + auto wxWxid = new_wx_string(wxid); + auto wxPath = new_wx_string(path); + + std::unique_ptr buff(new QWORD[8]()); // 0x20 bytes = 8 * QWORD + + if (!buff) { + LOG_ERROR("Out of Memory..."); + return; + } + + QWORD mgr = func_get_emotion_mgr(); + func_send_emotion(mgr, reinterpret_cast(wxPath.get()), reinterpret_cast(buff.get()), + reinterpret_cast(wxWxid.get()), 2, reinterpret_cast(buff.get()), 0, + reinterpret_cast(buff.get())); +} + +int SendMsgManager::send_rich_text(RichText_t &rt) +{ QWORD status = -1; - New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_RTM_NEW); - Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_RTM_FREE); - GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR); - SendRichTextMsg_t funcForwordPublicMsg = (SendRichTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_RICH_TEXT); - - char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE); - if (buff == NULL) { + char *buff = static_cast(HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE)); + if (!buff) { LOG_ERROR("Out of Memory..."); return -1; } memset(buff, 0, SRTM_SIZE); - funcNew((QWORD)buff); - WxString *pReceiver = NewWxStringFromStr(rt.receiver); - WxString *pTitle = NewWxStringFromStr(rt.title); - WxString *pUrl = NewWxStringFromStr(rt.url); - WxString *pThumburl = NewWxStringFromStr(rt.thumburl); - WxString *pDigest = NewWxStringFromStr(rt.digest); - WxString *pAccount = NewWxStringFromStr(rt.account); - WxString *pName = NewWxStringFromStr(rt.name); + func_new(reinterpret_cast(buff)); - memcpy(buff + 0x8, pTitle, sizeof(WxString)); - memcpy(buff + 0x48, pUrl, sizeof(WxString)); - memcpy(buff + 0xB0, pThumburl, sizeof(WxString)); - memcpy(buff + 0xF0, pDigest, sizeof(WxString)); - memcpy(buff + 0x2C0, pAccount, sizeof(WxString)); - memcpy(buff + 0x2E0, pName, sizeof(WxString)); + auto pReceiver = new_wx_string(rt.receiver); + auto pTitle = new_wx_string(rt.title); + auto pUrl = new_wx_string(rt.url); + auto pThumburl = new_wx_string(rt.thumburl); + auto pDigest = new_wx_string(rt.digest); + auto pAccount = new_wx_string(rt.account); + auto pName = new_wx_string(rt.name); - QWORD mgr = funcGetAppMsgMgr(); - status = funcForwordPublicMsg(mgr, (QWORD)(pReceiver), (QWORD)(buff)); - funcFree((QWORD)buff); + memcpy(buff + 0x8, pTitle.get(), sizeof(WxString)); + memcpy(buff + 0x48, pUrl.get(), sizeof(WxString)); + memcpy(buff + 0xB0, pThumburl.get(), sizeof(WxString)); + memcpy(buff + 0xF0, pDigest.get(), sizeof(WxString)); + memcpy(buff + 0x2C0, pAccount.get(), sizeof(WxString)); + memcpy(buff + 0x2E0, pName.get(), sizeof(WxString)); - return (int)status; + QWORD mgr = func_get_app_mgr(); + status = func_send_rich_text(mgr, reinterpret_cast(pReceiver.get()), reinterpret_cast(buff)); + func_free(reinterpret_cast(buff)); + + return static_cast(status); } -int SendPatMessage(string roomid, string wxid) +int SendMsgManager::send_pat(const std::string &roomid, const std::string &wxid) { QWORD status = -1; - wstring wsRoomid = String2Wstring(roomid); - wstring wsWxid = String2Wstring(wxid); - WxString wxRoomid(wsRoomid); - WxString wxWxid(wsWxid); + auto wxRoomid = new_wx_string(roomid); + auto wxWxid = new_wx_string(wxid); - SendPatMsg_t funcSendPatMsg = (SendPatMsg_t)(g_WeChatWinDllAddr + OS_SEND_PAT_MSG); + status = func_send_pat(reinterpret_cast(wxRoomid.get()), reinterpret_cast(wxWxid.get())); - status = funcSendPatMsg((QWORD)(&wxRoomid), (QWORD)(&wxWxid)); - return (int)status; + return static_cast(status); } -int ForwardMessage(QWORD msgid, string receiver) +int SendMsgManager::forward_message(QWORD msgid, const std::string &receiver) { - int status = -1; uint32_t dbIdx = 0; QWORD localId = 0; - ForwardMsg_t funcForwardMsg = (ForwardMsg_t)(g_WeChatWinDllAddr + OS_FORWARD_MSG); - if (GetLocalIdandDbidx(msgid, &localId, &dbIdx) != 0) { - LOG_ERROR("Failed to get localId, Please check id: {}", to_string(msgid)); - return status; + if (exec_sql::get_local_id_and_dbidx(msgid, &localId, &dbIdx) != 0) { + LOG_ERROR("Failed to get localId, Please check id: {}", msgid); + return -1; } - WxString *pReceiver = NewWxStringFromStr(receiver); - LARGE_INTEGER l; - l.HighPart = dbIdx; - l.LowPart = (DWORD)localId; + l.HighPart = dbIdx; + l.LowPart = static_cast(localId); + auto wxReceiver = new_wx_string(receiver); - status = (int)funcForwardMsg((QWORD)pReceiver, l.QuadPart, 0x4, 0x0); - - return status; + return static_cast(func_forward(reinterpret_cast(wxReceiver.get()), l.QuadPart, 0x4, 0x0)); } -void SendEmotionMessage(string wxid, string path) +// RPC 方法 + +bool SendMsgManager::rpc_send_text(TextMsg &text, uint8_t *out, size_t *len) { - GetEmotionMgr_t GetEmotionMgr = (GetEmotionMgr_t)(g_WeChatWinDllAddr + OS_GET_EMOTION_MGR); - SendEmotion_t SendEmotion = (SendEmotion_t)(g_WeChatWinDllAddr + OS_SEND_EMOTION); - - WxString *pWxPath = NewWxStringFromStr(path); - WxString *pWxWxid = NewWxStringFromStr(wxid); - - QWORD *buff = (QWORD *)HeapAlloc(GetProcessHeap(), 0, 0x20); - if (buff == NULL) { - LOG_ERROR("Out of Memory..."); - return; - } - - memset(buff, 0, 0x20); - QWORD mgr = GetEmotionMgr(); - SendEmotion(mgr, (QWORD)pWxPath, (QWORD)buff, (QWORD)pWxWxid, 2, (QWORD)buff, 0, (QWORD)buff); + return fill_response(out, len, [&](Response &rsp) { + if (text.msg.empty() || text.receiver.empty()) { + LOG_ERROR("Empty message or receiver."); + rsp.msg.status = -1; + } else { + send_text(text.receiver, text.msg, text.aters); + rsp.msg.status = 0; + } + }); } -void SendXmlMessage(string receiver, string xml, string path, QWORD type) +bool SendMsgManager::rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) { - if (g_WeChatWinDllAddr == 0) { - return; - } - - New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW); - Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE); - - XmlBufSign_t xmlBufSign = (XmlBufSign_t)(g_WeChatWinDllAddr + OS_XML_BUFSIGN); - SendXmlMsg_t sendXmlMsg = (SendXmlMsg_t)(g_WeChatWinDllAddr + OS_SEND_XML); - - char buff[0x500] = { 0 }; - char buff2[0x500] = { 0 }; - char nullBuf[0x1C] = { 0 }; - - QWORD pBuf = (QWORD)(&buff); - QWORD pBuf2 = (QWORD)(&buff2); - - funcNew(pBuf); - funcNew(pBuf2); - - QWORD sbuf[4] = { 0, 0, 0, 0 }; - - QWORD sign = xmlBufSign(pBuf2, (QWORD)(&sbuf), 0x1); - - WxString *pReceiver = NewWxStringFromStr(receiver); - WxString *pXml = NewWxStringFromStr(xml); - WxString *pPath = NewWxStringFromStr(path); - WxString *pSender = NewWxStringFromStr(user_info::get_self_wxid()); - - sendXmlMsg(pBuf, (QWORD)pSender, (QWORD)pReceiver, (QWORD)pXml, (QWORD)pPath, (QWORD)(&nullBuf), type, 0x4, sign, - pBuf2); - - funcFree((QWORD)&buff); - funcFree((QWORD)&buff2); + return fill_response(out, len, [&](Response &rsp) { + if (path.empty() || receiver.empty()) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else { + send_image(receiver, path); + rsp.msg.status = 0; + } + }); +} + +bool SendMsgManager::rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (path.empty() || receiver.empty()) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else { + send_file(receiver, path); + rsp.msg.status = 0; + } + }); +} + +bool SendMsgManager::rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (path.empty() || receiver.empty()) { + LOG_ERROR("Empty path or receiver."); + rsp.msg.status = -1; + } else { + send_emotion(receiver, path); + rsp.msg.status = 0; + } + }); +} + +bool SendMsgManager::rpc_send_xml(const XmlMsg &rt, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (rt.content.empty() || rt.receiver.empty()) { + LOG_ERROR("Empty content or receiver."); + rsp.msg.status = -1; + } else { + send_xml(rt.receiver, rt.content, rt.path, rt.type); + rsp.msg.status = 0; + } + }); +} + +bool SendMsgManager::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (rt.receiver.empty()) { + LOG_ERROR("Empty receiver."); + rsp.msg.status = -1; + } else { + RichText_t rtt { + .name = rt.name, + .account = rt.account, + .title = rt.title, + .digest = rt.digest, + .url = rt.url, + .thumburl = rt.thumburl, + .receiver = rt.receiver, + }; + rsp.msg.status = send_rich_text(rtt); + } + }); +} + +bool SendMsgManager::rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (roomid.empty() || wxid.empty()) { + LOG_ERROR("Empty roomid or wxid."); + rsp.msg.status = -1; + } else { + rsp.msg.status = send_pat(roomid, wxid); + } + }); +} + +bool SendMsgManager::rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + if (receiver.empty()) { + LOG_ERROR("Empty receiver."); + rsp.msg.status = -1; + } else { + rsp.msg.status = forward(msgid, receiver); + } + }); } diff --git a/WeChatFerry/spy/send_msg.h b/WeChatFerry/spy/send_msg.h index 0218a5d..c0c4e9d 100644 --- a/WeChatFerry/spy/send_msg.h +++ b/WeChatFerry/spy/send_msg.h @@ -1,24 +1,83 @@ #pragma once +#include #include -using namespace std; +#include "spy_types.h" +#include "wcf.pb.h" -typedef struct { - string name; - string account; - string title; - string digest; - string url; - string thumburl; - string receiver; -} RichText_t; +struct RichText_t { + std::string name; + std::string account; + std::string title; + std::string digest; + std::string url; + std::string thumburl; + std::string receiver; +}; -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, uint64_t type); -void SendEmotionMessage(string wxid, string path); -int SendRichTextMessage(RichText_t &rt); -int SendPatMessage(string roomid, string wxid); -int ForwardMessage(uint64_t msgid, string receiver); +class SendMsgManager +{ +public: + static SendMsgManager &get_instance(); + + void send_text(const std::string &wxid, const std::string &msg, const std::string &at_wxids = ""); + void send_image(const std::string &wxid, const std::string &path); + void send_file(const std::string &wxid, const std::string &path); + void send_xml(const std::string &receiver, const std::string &xml, const std::string &path, uint64_t type); + void send_emotion(const std::string &wxid, const std::string &path); + int send_rich_text(RichText_t &rt); + int send_pat(const std::string &roomid, const std::string &wxid); + int forward(uint64_t msgid, const std::string &receiver); + + // RPC 方法 + bool rpc_send_text(TextMsg &text, uint8_t *out, size_t *len); + bool rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); + bool rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); + bool rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); + bool rpc_send_xml(const XmlMsg &rt, uint8_t *out, size_t *len); + bool rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len); + bool rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len); + bool rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len); + +private: + SendMsgManager(); + ~SendMsgManager() = default; + + SendMsgManager(const SendMsgManager &) = delete; + SendMsgManager &operator=(const SendMsgManager &) = delete; + + using New_t = QWORD (*)(QWORD); + using Free_t = QWORD (*)(QWORD); + using SendMsgMgr_t = QWORD (*)(); + using GetAppMgr_t = QWORD (*)(); + using SendText_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); + using SendImage_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD); + using SendFile_t + = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD); + using SendRichText_t = QWORD (*)(QWORD, QWORD, QWORD); + using SendPat_t = QWORD (*)(QWORD, QWORD); + using Forward_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD); + using GetEmotionMgr_t = QWORD (*)(); + using SendEmotion_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); + using XmlBufSign_t = QWORD (*)(QWORD, QWORD, QWORD); + using SendXml_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); + + New_t func_new; + Free_t func_free; + SendMsgMgr_t func_send_msg_mgr; + GetAppMgr_t func_get_app_mgr; + SendText_t func_send_text; + SendImage_t func_send_image; + SendFile_t func_send_file; + SendRichText_t func_send_rich_text; + SendPat_t func_send_pat; + Forward_t func_forward; + GetEmotionMgr_t func_get_emotion_mgr; + SendEmotion_t func_send_emotion; + XmlBufSign_t func_xml_buf_sign; + SendXml_t func_send_xml; + + std::unique_ptr new_wx_string(const std::string &str); + std::vector parse_wxids(const std::string &wxids); +}; From b79e163cc992dd97b34231e07bb9122a51e70591 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Feb 2025 21:36:39 +0800 Subject: [PATCH 18/41] Refactoring --- WeChatFerry/spy/rpc_server.cpp | 16 ++++++++-------- WeChatFerry/spy/send_msg.h | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index b558f38..e474d5f 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -145,7 +145,7 @@ static bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) std::string msg(txt.msg); std::string receiver(txt.receiver); std::string aters(txt.aters ? txt.aters : ""); - SendTextMessage(receiver, msg, aters); + SendMsgManager::send_text(receiver, msg, aters); rsp.msg.status = 0; } }); @@ -161,7 +161,7 @@ static bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { - SendImageMessage(receiver, path); + SendMsgManager::send_image(receiver, path); rsp.msg.status = 0; } }); @@ -177,7 +177,7 @@ static bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { - SendFileMessage(receiver, path); + SendMsgManager::send_file(receiver, path); rsp.msg.status = 0; } }); @@ -190,7 +190,7 @@ static bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t * LOG_ERROR("Empty path or receiver."); rsp.msg.status = -1; } else { - SendEmotionMessage(receiver, path); + SendMsgManager::send_emotion(receiver, path); rsp.msg.status = 0; } }); @@ -207,7 +207,7 @@ static bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) std::string content(xml.content); std::string path(xml.path ? xml.path : ""); uint64_t type = static_cast(xml.type); - SendXmlMessage(receiver, content, path, type); + SendMsgManager::send_xml(receiver, content, path, type); rsp.msg.status = 0; } }); @@ -229,7 +229,7 @@ static bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) rtt.title = std::string(rt.title ? rt.title : ""); rtt.url = std::string(rt.url ? rt.url : ""); - rsp.msg.status = SendRichTextMessage(rtt); + rsp.msg.status = SendMsgManager::send_rich_text(rtt); } }); } @@ -241,7 +241,7 @@ static bool func_send_pat_msg(char *roomid, char *wxid, uint8_t *out, size_t *le LOG_ERROR("Empty roomid or wxid."); rsp.msg.status = -1; } else { - rsp.msg.status = SendPatMessage(roomid, wxid); + rsp.msg.status = SendMsgManager::send_pat(roomid, wxid); } }); } @@ -253,7 +253,7 @@ static bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t * LOG_ERROR("Empty receiver."); rsp.msg.status = -1; } else { - rsp.msg.status = ForwardMessage(id, receiver); + rsp.msg.status = SendMsgManager::forward(id, receiver); } }); } diff --git a/WeChatFerry/spy/send_msg.h b/WeChatFerry/spy/send_msg.h index c0c4e9d..a49c68e 100644 --- a/WeChatFerry/spy/send_msg.h +++ b/WeChatFerry/spy/send_msg.h @@ -2,6 +2,7 @@ #include #include +#include #include "spy_types.h" #include "wcf.pb.h" From 0fd3449894649a7607910e40b53e8e4219fc2f0b Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Feb 2025 21:40:22 +0800 Subject: [PATCH 19/41] Refactoring --- WeChatFerry/spy/rpc_server.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index e474d5f..3891939 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -45,6 +45,7 @@ static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 auto &msgHandler = MessageHandler::getInstance(); +auto &sendMgr = SendMsgManager::get_instance(); static std::string BuildUrl(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } @@ -145,7 +146,7 @@ static bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) std::string msg(txt.msg); std::string receiver(txt.receiver); std::string aters(txt.aters ? txt.aters : ""); - SendMsgManager::send_text(receiver, msg, aters); + sendMgr.send_text(receiver, msg, aters); rsp.msg.status = 0; } }); @@ -161,7 +162,7 @@ static bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { - SendMsgManager::send_image(receiver, path); + sendMgr.send_image(receiver, path); rsp.msg.status = 0; } }); @@ -177,7 +178,7 @@ static bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { - SendMsgManager::send_file(receiver, path); + sendMgr.send_file(receiver, path); rsp.msg.status = 0; } }); @@ -190,7 +191,7 @@ static bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t * LOG_ERROR("Empty path or receiver."); rsp.msg.status = -1; } else { - SendMsgManager::send_emotion(receiver, path); + sendMgr.send_emotion(receiver, path); rsp.msg.status = 0; } }); @@ -207,7 +208,7 @@ static bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) std::string content(xml.content); std::string path(xml.path ? xml.path : ""); uint64_t type = static_cast(xml.type); - SendMsgManager::send_xml(receiver, content, path, type); + sendMgr.send_xml(receiver, content, path, type); rsp.msg.status = 0; } }); @@ -229,7 +230,7 @@ static bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) rtt.title = std::string(rt.title ? rt.title : ""); rtt.url = std::string(rt.url ? rt.url : ""); - rsp.msg.status = SendMsgManager::send_rich_text(rtt); + rsp.msg.status = sendMgr.send_rich_text(rtt); } }); } @@ -241,7 +242,7 @@ static bool func_send_pat_msg(char *roomid, char *wxid, uint8_t *out, size_t *le LOG_ERROR("Empty roomid or wxid."); rsp.msg.status = -1; } else { - rsp.msg.status = SendMsgManager::send_pat(roomid, wxid); + rsp.msg.status = sendMgr.send_pat(roomid, wxid); } }); } @@ -253,7 +254,7 @@ static bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t * LOG_ERROR("Empty receiver."); rsp.msg.status = -1; } else { - rsp.msg.status = SendMsgManager::forward(id, receiver); + rsp.msg.status = sendMgr.forward(id, receiver); } }); } From ff1a8c980784536fe8d3238aa8e96c43f45a4e23 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Feb 2025 23:18:20 +0800 Subject: [PATCH 20/41] Refactoring --- WeChatFerry/spy/spy_types.h | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/WeChatFerry/spy/spy_types.h b/WeChatFerry/spy/spy_types.h index 7fd1008..56f7c51 100644 --- a/WeChatFerry/spy/spy_types.h +++ b/WeChatFerry/spy/spy_types.h @@ -5,29 +5,42 @@ typedef uint64_t QWORD; -struct WxString { +class WxString +{ + +public: const wchar_t *wptr; DWORD size; DWORD capacity; const char *ptr; DWORD clen; + WxString() { - wptr = NULL; + wptr = nullptr; size = 0; capacity = 0; - ptr = NULL; + ptr = nullptr; clen = 0; } - WxString(std::wstring &ws) + WxString(std::wstring ws) : internal_ws(std::move(ws)) { - wptr = ws.c_str(); - size = (DWORD)ws.size(); - capacity = (DWORD)ws.capacity(); - ptr = NULL; + wptr = internal_ws.c_str(); + size = static_cast(internal_ws.size()); + capacity = static_cast(internal_ws.capacity()); + ptr = nullptr; clen = 0; } + + WxString(const WxString &) = delete; + WxString &operator=(const WxString &) = delete; + + WxString(WxString &&) noexcept = default; + WxString &operator=(WxString &&) noexcept = default; + +private: + std::wstring internal_ws; }; typedef struct RawVector { From b426e84241ae11647eba1bce5500ddcdbce9e9e5 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Feb 2025 23:18:41 +0800 Subject: [PATCH 21/41] Refatoring --- WeChatFerry/spy/rpc_server.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 3891939..f4419ac 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -221,16 +221,7 @@ static bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) LOG_ERROR("Empty receiver."); rsp.msg.status = -1; } else { - RichText_t rtt; - rtt.account = std::string(rt.account ? rt.account : ""); - rtt.digest = std::string(rt.digest ? rt.digest : ""); - rtt.name = std::string(rt.name ? rt.name : ""); - rtt.receiver = std::string(rt.receiver ? rt.receiver : ""); - rtt.thumburl = std::string(rt.thumburl ? rt.thumburl : ""); - rtt.title = std::string(rt.title ? rt.title : ""); - rtt.url = std::string(rt.url ? rt.url : ""); - - rsp.msg.status = sendMgr.send_rich_text(rtt); + rsp.msg.status = sendMgr.send_rich_text(rt); } }); } From 66e14be1361f91d00503ac83f7d6ad3d3fadf65f Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 05:27:07 +0800 Subject: [PATCH 22/41] Refactoring --- WeChatFerry/spy/send_msg.cpp | 42 +++++++++++++++--------------------- WeChatFerry/spy/send_msg.h | 23 ++++++++++---------- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index b9451e3..153f12a 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -10,11 +10,8 @@ #include "user_info.h" #include "util.h" -extern HANDLE g_hEvent; extern QWORD g_WeChatWinDllAddr; -#define SRTM_SIZE 0x3F0 - #define OS_NEW 0x1B5E140 #define OS_FREE 0x1B55850 #define OS_SEND_MSG_MGR 0x1B53FD0 @@ -53,6 +50,10 @@ SendMsgManager::SendMsgManager() func_send_xml = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_XML); } +std::unique_ptr SendMsgManager::new_wx_string(const char *str) +{ + return new_wx_string(str ? std::string(str) : std::string()); +} std::unique_ptr SendMsgManager::new_wx_string(const std::string &str) { return std::make_unique(String2Wstring(str)); @@ -108,8 +109,8 @@ void SendMsgManager::send_image(const std::string &wxid, const std::string &path QWORD pMsg = func_new(reinterpret_cast(&msg)); QWORD sendMgr = func_send_msg_mgr(); - funcSendImage(sendMgr, pMsg, reinterpret_cast(wxWxid.get()), reinterpret_cast(wxPath.get()), - reinterpret_cast(&flag)); + func_send_image(sendMgr, pMsg, reinterpret_cast(wxWxid.get()), reinterpret_cast(wxPath.get()), + reinterpret_cast(&flag)); func_free(pMsg); func_free(pMsgTmp); @@ -179,8 +180,9 @@ void SendMsgManager::send_emotion(const std::string &wxid, const std::string &pa reinterpret_cast(buff.get())); } -int SendMsgManager::send_rich_text(RichText_t &rt) +int SendMsgManager::send_rich_text(const RichText &rt) { +#define SRTM_SIZE 0x3F0 QWORD status = -1; char *buff = static_cast(HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE)); @@ -226,7 +228,7 @@ int SendMsgManager::send_pat(const std::string &roomid, const std::string &wxid) return static_cast(status); } -int SendMsgManager::forward_message(QWORD msgid, const std::string &receiver) +int SendMsgManager::forward(QWORD msgid, const std::string &receiver) { uint32_t dbIdx = 0; QWORD localId = 0; @@ -245,15 +247,14 @@ int SendMsgManager::forward_message(QWORD msgid, const std::string &receiver) } // RPC 方法 - -bool SendMsgManager::rpc_send_text(TextMsg &text, uint8_t *out, size_t *len) +bool SendMsgManager::rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { - if (text.msg.empty() || text.receiver.empty()) { + if (text.msg == nullptr || text.receiver == nullptr || strlen(text.msg) == 0 || strlen(text.receiver) == 0) { LOG_ERROR("Empty message or receiver."); rsp.msg.status = -1; } else { - send_text(text.receiver, text.msg, text.aters); + send_text(text.receiver, text.msg, text.aters ? text.aters : ""); rsp.msg.status = 0; } }); @@ -298,14 +299,14 @@ bool SendMsgManager::rpc_send_emotion(const std::string &path, const std::string }); } -bool SendMsgManager::rpc_send_xml(const XmlMsg &rt, uint8_t *out, size_t *len) +bool SendMsgManager::rpc_send_xml(const XmlMsg &xml, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { - if (rt.content.empty() || rt.receiver.empty()) { + if (xml.content == nullptr || xml.receiver == nullptr) { LOG_ERROR("Empty content or receiver."); rsp.msg.status = -1; } else { - send_xml(rt.receiver, rt.content, rt.path, rt.type); + send_xml(xml.receiver, xml.content, xml.path, xml.type); rsp.msg.status = 0; } }); @@ -314,20 +315,11 @@ bool SendMsgManager::rpc_send_xml(const XmlMsg &rt, uint8_t *out, size_t *len) bool SendMsgManager::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { - if (rt.receiver.empty()) { + if (rt.receiver == nullptr) { LOG_ERROR("Empty receiver."); rsp.msg.status = -1; } else { - RichText_t rtt { - .name = rt.name, - .account = rt.account, - .title = rt.title, - .digest = rt.digest, - .url = rt.url, - .thumburl = rt.thumburl, - .receiver = rt.receiver, - }; - rsp.msg.status = send_rich_text(rtt); + rsp.msg.status = send_rich_text(rt); } }); } diff --git a/WeChatFerry/spy/send_msg.h b/WeChatFerry/spy/send_msg.h index a49c68e..e7a3fa7 100644 --- a/WeChatFerry/spy/send_msg.h +++ b/WeChatFerry/spy/send_msg.h @@ -7,15 +7,15 @@ #include "spy_types.h" #include "wcf.pb.h" -struct RichText_t { - std::string name; - std::string account; - std::string title; - std::string digest; - std::string url; - std::string thumburl; - std::string receiver; -}; +// struct RichText_t { +// std::string name; +// std::string account; +// std::string title; +// std::string digest; +// std::string url; +// std::string thumburl; +// std::string receiver; +// }; class SendMsgManager { @@ -27,12 +27,12 @@ public: void send_file(const std::string &wxid, const std::string &path); void send_xml(const std::string &receiver, const std::string &xml, const std::string &path, uint64_t type); void send_emotion(const std::string &wxid, const std::string &path); - int send_rich_text(RichText_t &rt); + int send_rich_text(const RichText &rt); int send_pat(const std::string &roomid, const std::string &wxid); int forward(uint64_t msgid, const std::string &receiver); // RPC 方法 - bool rpc_send_text(TextMsg &text, uint8_t *out, size_t *len); + bool rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len); bool rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); bool rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); bool rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); @@ -79,6 +79,7 @@ private: XmlBufSign_t func_xml_buf_sign; SendXml_t func_send_xml; + std::unique_ptr new_wx_string(const char *str); std::unique_ptr new_wx_string(const std::string &str); std::vector parse_wxids(const std::string &wxids); }; From 796e078c0ca9abce14939817709bae77e1f416b0 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 10:09:33 +0800 Subject: [PATCH 23/41] Remove unused code --- WeChatFerry/spy/send_msg.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/WeChatFerry/spy/send_msg.h b/WeChatFerry/spy/send_msg.h index e7a3fa7..66908d6 100644 --- a/WeChatFerry/spy/send_msg.h +++ b/WeChatFerry/spy/send_msg.h @@ -7,16 +7,6 @@ #include "spy_types.h" #include "wcf.pb.h" -// struct RichText_t { -// std::string name; -// std::string account; -// std::string title; -// std::string digest; -// std::string url; -// std::string thumburl; -// std::string receiver; -// }; - class SendMsgManager { public: From ade2c1c22a589ac69cd1dd5b28df89ae74e404a7 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 13:29:02 +0800 Subject: [PATCH 24/41] Refactoring --- README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.MD b/README.MD index f2f79fa..46ee088 100644 --- a/README.MD +++ b/README.MD @@ -168,7 +168,7 @@ sdk.WxDestroySDK() ### 调试日志 ```c - DbgMsg("ListenMessage"); // 封装的 OutputDebugString + util::dbg_msg("ListenMessage"); // 封装的 OutputDebugString OutputDebugString(L"ListenMessage\n"); MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0); ``` From c96d85db30595d5b2db42f8b3b0c74844664090d Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 15:35:09 +0800 Subject: [PATCH 25/41] Refactoring --- WeChatFerry/com/log.hpp | 2 +- WeChatFerry/com/util.cpp | 400 +++++++++++------------------- WeChatFerry/com/util.h | 100 +++++--- WeChatFerry/sdk/injector.cpp | 2 +- WeChatFerry/sdk/sdk.cpp | 4 +- WeChatFerry/spy/chatroom_mgmt.cpp | 2 +- WeChatFerry/spy/contact_mgmt.cpp | 23 +- WeChatFerry/spy/exec_sql.cpp | 13 +- WeChatFerry/spy/funcs.cpp | 9 +- WeChatFerry/spy/receive_msg.cpp | 25 +- WeChatFerry/spy/rpc_server.cpp | 9 +- WeChatFerry/spy/send_msg.cpp | 4 +- WeChatFerry/spy/spy.cpp | 41 ++- WeChatFerry/spy/spy.h | 2 - WeChatFerry/spy/user_info.cpp | 20 +- 15 files changed, 294 insertions(+), 362 deletions(-) diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp index 4f30b27..4be5e76 100644 --- a/WeChatFerry/com/log.hpp +++ b/WeChatFerry/com/log.hpp @@ -48,7 +48,7 @@ inline void InitLogger(const std::string &path) logger = spdlog::rotating_logger_mt(DEFAULT_LOGGER_NAME, filename.string(), DEFAULT_LOGGER_MAX_SIZE, DEFAULT_LOGGER_MAX_FILES); } catch (const spdlog::spdlog_ex &ex) { - MessageBox(NULL, String2Wstring(ex.what()).c_str(), L"Init LOGGER ERROR", MB_ICONERROR); + MessageBox(NULL, util::s2w(ex.what()).c_str(), L"Init LOGGER ERROR", MB_ICONERROR); return; } diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index 0134592..21b0039 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -1,177 +1,67 @@ -#include "Shlwapi.h" -#include "framework.h" +#include "util.h" + #include #include +#include #include #include #include #include #include +#include "framework.h" + #include "log.hpp" -#include "util.h" #pragma comment(lib, "shlwapi") #pragma comment(lib, "Version.lib") -using namespace std; - -wstring String2Wstring(string s) +namespace util { - if (s.empty()) - return wstring(); - int size_needed = MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), NULL, 0); - wstring ws(size_needed, 0); - MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), &ws[0], size_needed); + +std::wstring s2w(const std::string &s) +{ + if (s.empty()) return std::wstring(); + int size_needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast(s.size()), nullptr, 0); + std::wstring ws(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast(s.size()), &ws[0], size_needed); return ws; } -string Wstring2String(wstring ws) +std::string w2s(const std::wstring &ws) { - if (ws.empty()) - return string(); - int size_needed = WideCharToMultiByte(CP_UTF8, 0, &ws[0], (int)ws.size(), NULL, 0, NULL, NULL); - string s(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, &ws[0], (int)ws.size(), &s[0], size_needed, NULL, NULL); + if (ws.empty()) return std::string(); + int size_needed + = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast(ws.size()), nullptr, 0, nullptr, nullptr); + std::string s(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast(ws.size()), &s[0], size_needed, nullptr, nullptr); return s; } -string GB2312ToUtf8(const char *gb2312) +std::string gb2312_to_utf8(const char *gb2312) { - int size_needed = 0; + if (!gb2312) return ""; - size_needed = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0); - wstring ws(size_needed, 0); + int size_needed = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, nullptr, 0); + std::wstring ws(size_needed, 0); MultiByteToWideChar(CP_ACP, 0, gb2312, -1, &ws[0], size_needed); - size_needed = WideCharToMultiByte(CP_UTF8, 0, &ws[0], -1, NULL, 0, NULL, NULL); - string s(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, &ws[0], -1, &s[0], size_needed, NULL, NULL); + size_needed = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, nullptr, 0, nullptr, nullptr); + std::string s(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, &s[0], size_needed, nullptr, nullptr); return s; } -static int GetWeChatPath(wchar_t *path) +DWORD get_wechat_pid() { - int ret = -1; - HKEY hKey = NULL; - // HKEY_CURRENT_USER\Software\Tencent\WeChat InstallPath = xx - if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, L"Software\\Tencent\\WeChat", &hKey)) { - ret = GetLastError(); - return ret; - } + DWORD pid = 0; + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) return 0; - DWORD Type = REG_SZ; - DWORD cbData = MAX_PATH * sizeof(WCHAR); - if (ERROR_SUCCESS != RegQueryValueEx(hKey, L"InstallPath", 0, &Type, (LPBYTE)path, &cbData)) { - ret = GetLastError(); - goto __exit; - } - - if (path != NULL) { - PathAppend(path, WECHAREXE); - } - -__exit: - if (hKey) { - RegCloseKey(hKey); - } - - return ERROR_SUCCESS; -} - -static int GetWeChatWinDLLPath(wchar_t *path) -{ - int ret = GetWeChatPath(path); - if (ret != ERROR_SUCCESS) { - return ret; - } - - PathRemoveFileSpecW(path); - PathAppendW(path, WECHATWINDLL); - if (!PathFileExists(path)) { - // 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29] - PathRemoveFileSpec(path); - _wfinddata_t findData; - wstring dir = wstring(path) + L"\\[*.*"; - intptr_t handle = _wfindfirst(dir.c_str(), &findData); - if (handle == -1) { // 检查是否成功 - return -1; - } - wstring dllPath = wstring(path) + L"\\" + findData.name; - wcscpy_s(path, MAX_PATH, dllPath.c_str()); - PathAppend(path, WECHATWINDLL); - } - - return ret; -} - -static bool GetFileVersion(const wchar_t *filePath, wchar_t *version) -{ - if (wcslen(filePath) > 0 && PathFileExists(filePath)) { - VS_FIXEDFILEINFO *pVerInfo = NULL; - DWORD dwTemp, dwSize; - BYTE *pData = NULL; - UINT uLen; - - dwSize = GetFileVersionInfoSize(filePath, &dwTemp); - if (dwSize == 0) { - return false; - } - - pData = new BYTE[dwSize + 1]; - if (pData == NULL) { - return false; - } - - if (!GetFileVersionInfo(filePath, 0, dwSize, pData)) { - delete[] pData; - return false; - } - - if (!VerQueryValue(pData, TEXT("\\"), (void **)&pVerInfo, &uLen)) { - delete[] pData; - return false; - } - - UINT64 verMS = pVerInfo->dwFileVersionMS; - UINT64 verLS = pVerInfo->dwFileVersionLS; - UINT64 major = HIWORD(verMS); - UINT64 minor = LOWORD(verMS); - UINT64 build = HIWORD(verLS); - UINT64 revision = LOWORD(verLS); - delete[] pData; - - StringCbPrintf(version, 0x20, TEXT("%d.%d.%d.%d"), major, minor, build, revision); - - return true; - } - - return false; -} - -int GetWeChatVersion(wchar_t *version) -{ - WCHAR Path[MAX_PATH] = { 0 }; - - int ret = GetWeChatWinDLLPath(Path); - if (ret != ERROR_SUCCESS) { - return ret; - } - - ret = GetFileVersion(Path, version); - - return ret; -} - -DWORD GetWeChatPid() -{ - DWORD pid = 0; - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { - wstring strProcess = pe32.szExeFile; - if (strProcess == WECHAREXE) { + if (std::wstring(pe32.szExeFile) == WECHATEXE) { pid = pe32.th32ProcessID; break; } @@ -180,52 +70,20 @@ DWORD GetWeChatPid() return pid; } -enum class WindowsArchiture { x32, x64 }; -static WindowsArchiture GetWindowsArchitecture() +int open_wechat(DWORD *pid) { -#ifdef _WIN64 - return WindowsArchiture::x64; -#else - return WindowsArchiture::x32; -#endif -} + *pid = get_wechat_pid(); + if (*pid) return ERROR_SUCCESS; -BOOL IsProcessX64(DWORD pid) -{ - BOOL isWow64 = false; - HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid); - if (!hProcess) - return false; - BOOL result = IsWow64Process(hProcess, &isWow64); - CloseHandle(hProcess); - if (!result) - return false; - if (isWow64) - return false; - else if (GetWindowsArchitecture() == WindowsArchiture::x32) - return false; - else - return true; -} - -int OpenWeChat(DWORD *pid) -{ - *pid = GetWeChatPid(); - if (*pid) { - return ERROR_SUCCESS; + WCHAR path[MAX_PATH] = { 0 }; + if (GetModuleFileNameW(nullptr, path, MAX_PATH) == 0) { + return GetLastError(); } - int ret = -1; STARTUPINFO si = { sizeof(si) }; - WCHAR Path[MAX_PATH] = { 0 }; PROCESS_INFORMATION pi = { 0 }; - ret = GetWeChatPath(Path); - if (ERROR_SUCCESS != ret) { - return ret; - } - - if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { + if (!CreateProcessW(nullptr, path, nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)) { return GetLastError(); } @@ -233,115 +91,153 @@ int OpenWeChat(DWORD *pid) CloseHandle(pi.hProcess); *pid = pi.dwProcessId; - return ERROR_SUCCESS; } -size_t GetWstringByAddress(UINT64 addr, wchar_t *buffer, UINT64 buffer_size) +static std::optional get_wechat_win_dll_path() { - size_t strLength = GET_DWORD(addr + 8); - if (strLength == 0) { - return 0; - } else if (strLength > buffer_size) { - strLength = buffer_size - 1; + char path[MAX_PATH] = { 0 }; + if (GetWeChatPath(path) != ERROR_SUCCESS) { + return std::nullopt; } - wmemcpy_s(buffer, strLength + 1, GET_WSTRING(addr), strLength + 1); + PathRemoveFileSpecA(path); + PathAppendA(path, WECHATWINDLL); - return strLength; + if (!PathFileExistsA(path)) { + // 微信 3.7+ 版本增加了一层目录 + PathRemoveFileSpecA(path); + _finddata_t findData; + std::string dir = std::string(path) + "\\[*.*"; + intptr_t handle = _findfirst(dir.c_str(), &findData); + if (handle == -1) { + return std::nullopt; + } + _findclose(handle); + + std::string dllPath = std::string(path) + "\\" + findData.name + "\\" + WECHATWINDLL; + return dllPath; + } + + return std::string(path); } -string GetStringByAddress(UINT64 addr) +static std::optional get_file_version(const std::string &filePath) { - size_t strLength = GET_DWORD(addr + 8); - return Wstring2String(wstring(GET_WSTRING(addr), strLength)); + if (filePath.empty() || !PathFileExistsA(filePath.c_str())) { + return std::nullopt; + } + + DWORD handle = 0; + DWORD size = GetFileVersionInfoSizeA(filePath.c_str(), &handle); + if (size == 0) { + return std::nullopt; + } + + std::vector data(size); + if (!GetFileVersionInfoA(filePath.c_str(), 0, size, data.data())) { + return std::nullopt; + } + + VS_FIXEDFILEINFO *verInfo = nullptr; + UINT len = 0; + if (!VerQueryValueA(data.data(), "\\", reinterpret_cast(&verInfo), &len) || len == 0) { + return std::nullopt; + } + + char version[32]; + StringCbPrintfA(version, sizeof(version), "%d.%d.%d.%d", HIWORD(verInfo->dwFileVersionMS), + LOWORD(verInfo->dwFileVersionMS), HIWORD(verInfo->dwFileVersionLS), + LOWORD(verInfo->dwFileVersionLS)); + + return std::string(version); } -string GetStringByStrAddr(UINT64 addr) +std::string get_wechat_version() { - size_t strLength = GET_DWORD(addr + 8); - return strLength ? string(GET_STRING(addr), strLength) : string(); + std::string version = ""; + + auto dllPath = get_wechat_win_dll_path(); + if (!dllPath) { + return version; + } + + version = get_file_version(*dllPath); + return version ? version : ""; } -string GetStringByWstrAddr(UINT64 addr) +uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr) { - size_t strLength = GET_DWORD(addr + 8); - return strLength ? Wstring2String(wstring(GET_WSTRING(addr), strLength)) : string(); -} - -UINT32 GetMemoryIntByAddress(HANDLE hProcess, UINT64 addr) -{ - UINT32 value = 0; + uint32_t value = 0; + if (!addr || !hProcess) return value; unsigned char data[4] = { 0 }; - if (ReadProcessMemory(hProcess, (LPVOID)addr, data, 4, 0)) { - value = data[0] & 0xFF; - value |= ((data[1] << 8) & 0xFF00); - value |= ((data[2] << 16) & 0xFF0000); - value |= ((data[3] << 24) & 0xFF000000); + if (ReadProcessMemory(hProcess, reinterpret_cast(addr), data, sizeof(data), nullptr)) { + value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); } return value; } -wstring GetUnicodeInfoByAddress(HANDLE hProcess, UINT64 address) +std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t address) { - wstring value = L""; + if (!hProcess || !address) return L""; - UINT64 strAddress = GetMemoryIntByAddress(hProcess, address); - UINT64 strLen = GetMemoryIntByAddress(hProcess, address + 0x4); - if (strLen > 500) - return value; + uint64_t str_address = get_memory_int_by_address(hProcess, address); + uint64_t str_len = get_memory_int_by_address(hProcess, address + 0x4); + if (str_len > 500) return L""; wchar_t cValue[500] = { 0 }; - memset(cValue, 0, sizeof(cValue) / sizeof(wchar_t)); - if (ReadProcessMemory(hProcess, (LPVOID)strAddress, cValue, (strLen + 1) * 2, 0)) { - value = wstring(cValue); + if (ReadProcessMemory(hProcess, reinterpret_cast(str_address), cValue, (str_len + 1) * sizeof(wchar_t), + nullptr)) { + return std::wstring(cValue); } - return value; + return L""; } -void DbgMsg(const char *zcFormat, ...) +void dbg_msg(const char *format, ...) { - // initialize use of the variable argument array - va_list vaArgs; - va_start(vaArgs, zcFormat); + if (!format) return; - // reliably acquire the size - // from a copy of the variable argument array - // and a functionally reliable call to mock the formatting - va_list vaArgsCopy; - va_copy(vaArgsCopy, vaArgs); - const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy); - va_end(vaArgsCopy); + va_list args; + va_start(args, format); - // return a formatted string without risking memory mismanagement - // and without assuming any compiler or platform specific behavior - std::vector zc(iLen + 1); - std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs); - va_end(vaArgs); - std::string strText(zc.data(), iLen); + va_list args_copy; + va_copy(args_copy, args); + int len = vsnprintf(nullptr, 0, format, args_copy); + va_end(args_copy); - OutputDebugStringA(strText.c_str()); + std::vector buffer(len + 1); + vsnprintf(buffer.data(), buffer.size(), format, args); + va_end(args); + + OutputDebugStringA(buffer.data()); } -WxString *NewWxStringFromStr(const string &str) { return NewWxStringFromWstr(String2Wstring(str)); } - -WxString *NewWxStringFromWstr(const wstring &ws) +std::unique_ptr new_wx_string(const char *str) { - WxString *p = (WxString *)HeapAlloc(GetProcessHeap(), 0, sizeof(WxString)); - wchar_t *pWstring = (wchar_t *)HeapAlloc(GetProcessHeap(), 0, (ws.size() + 1) * 2); - if (p == NULL || pWstring == NULL) { - LOG_ERROR("Out of Memory..."); - return NULL; + return new_wx_string(str ? std::string(str) : std::string()); +} + +std::unique_ptr new_wx_string(const std::string &str) { return std::make_unique(s2w(str)); } + +std::unique_ptr new_wx_string(const wchar_t *wstr) +{ + return new_wx_string(wstr ? std::wstring(wstr) : std::wstring()); +} + +std::unique_ptr new_wx_string(const std::wstring &wstr) { return std::make_unique(wstr); } + +std::vector parse_wxids(const std::string &wxids) +{ + std::vector wx_members; + std::wstringstream wss(s2w(wxids)); + std::wstring wstr; + while (getline(wss, wstr, L',')) { + wx_members.emplace_back(wstr); } - - wmemcpy(pWstring, ws.c_str(), ws.size() + 1); - p->wptr = pWstring; - p->size = (DWORD)ws.size(); - p->capacity = (DWORD)ws.size(); - p->ptr = 0; - p->clen = 0; - return p; + return wx_members; } + +} // namespace util diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h index 8f252df..9169ddd 100644 --- a/WeChatFerry/com/util.h +++ b/WeChatFerry/com/util.h @@ -1,41 +1,81 @@ #pragma once +#include #include #include "spy_types.h" -#define WECHAREXE L"WeChat.exe" -#define WECHATWINDLL L"WeChatWin.dll" -#define WCFSDKDLL L"sdk.dll" -#define WCFSPYDLL L"spy.dll" -#define WCFSPYDLL_DEBUG L"spy_debug.dll" +namespace util +{ -#define GET_UINT64(addr) ((UINT64) * (UINT64 *)(addr)) -#define GET_DWORD(addr) ((DWORD) * (UINT64 *)(addr)) -#define GET_QWORD(addr) ((UINT64) * (UINT64 *)(addr)) -#define GET_STRING(addr) ((CHAR *)(*(UINT64 *)(addr))) -#define GET_WSTRING(addr) ((WCHAR *)(*(UINT64 *)(addr))) -#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) -#define GET_WSTRING_FROM_P(addr) ((WCHAR *)(addr)) +inline constexpr wchar_t WECHATEXE[] = L"WeChat.exe"; +inline constexpr wchar_t WECHATWINDLL[] = L"WeChatWin.dll"; +inline constexpr wchar_t WCFSDKDLL[] = L"sdk.dll"; +inline constexpr wchar_t WCFSPYDLL[] = L"spy.dll"; +inline constexpr wchar_t WCFSPYDLL_DEBUG[] = L"spy_debug.dll"; -typedef struct PortPath { +struct PortPath { int port; char path[MAX_PATH]; -} PortPath_t; +}; -DWORD GetWeChatPid(); -BOOL IsProcessX64(DWORD pid); -int OpenWeChat(DWORD *pid); -int GetWeChatVersion(wchar_t *version); -size_t GetWstringByAddress(UINT64 address, wchar_t *buffer, UINT64 buffer_size); -UINT32 GetMemoryIntByAddress(HANDLE hProcess, UINT64 address); -std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, UINT64 address); -std::wstring String2Wstring(std::string s); -std::string Wstring2String(std::wstring ws); -std::string GB2312ToUtf8(const char *gb2312); -std::string GetStringByAddress(UINT64 address); -std::string GetStringByStrAddr(UINT64 addr); -std::string GetStringByWstrAddr(UINT64 addr); -void DbgMsg(const char *zcFormat, ...); -WxString *NewWxStringFromStr(const std::string &str); -WxString *NewWxStringFromWstr(const std::wstring &ws); +inline DWORD get_dword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } +inline QWORD get_qword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } +inline uint64_t get_uint64(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } +inline std::string get_p_string(uint64_t addr) { return addr ? std::string(reinterpret_cast(addr)) : ""; } +inline std::string get_p_string(uint64_t addr, size_t len) +{ + return addr ? std::string(reinterpret_cast(addr), len) : ""; +} +inline std::wstring get_p_wstring(uint64_t addr) +{ + return addr ? std::wstring(reinterpret_cast(addr)) : L""; +} +inline std::wstring get_p_wstring(uint64_t addr, size_t len) +{ + return addr ? std::wstring(reinterpret_cast(addr), len) : L""; +} +inline std::string get_pp_string(uint64_t addr) +{ + if (!addr) return ""; + + const char *ptr = *reinterpret_cast(addr); + return (ptr && *ptr) ? std::string(ptr) : ""; +} +inline std::wstring get_pp_wstring(uint64_t addr) +{ + if (!addr) return L""; + + const wchar_t *ptr = *reinterpret_cast(addr); + return (ptr && *ptr) ? std::wstring(ptr) : ""; +} +inline std::string get_pp_len_string(uint64_t addr) +{ + size_t len = get_dword(addr + 8); + return (addr && len) ? std::string(*reinterpret_cast(addr), len) : L""; +} +inline std::wstring get_pp_len_wstring(uint64_t addr) +{ + size_t len = get_dword(addr + 8); + return (addr && len) ? std::wstring(*reinterpret_cast(addr), len) : L""; +} +inline std::string get_str_by_wstr_addr(uint64_t addr) { return w2s(get_pp_len_wstring(addr)); } + +DWORD get_wechat_pid(); +int open_wechat(DWORD *pid); +std::string get_wechat_version(); +uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr); +std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t addr); +std::wstring s2w(const std::string &s); +std::string w2s(const std::wstring &ws); +std::string gb2312_to_utf8(const char *gb2312); +void dbg_msg(const char *format, ...); + +std::unique_ptr new_wx_string(const char *str); +std::unique_ptr new_wx_string(const wchar_t *wstr); +std::unique_ptr new_wx_string(const std::string &str); +std::unique_ptr new_wx_string(const std::wstring &wstr); + +std::vector parse_wxids(const std::string &wxids); + +} // namespace util diff --git a/WeChatFerry/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp index cc06298..975faa9 100644 --- a/WeChatFerry/sdk/injector.cpp +++ b/WeChatFerry/sdk/injector.cpp @@ -80,7 +80,7 @@ HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) WaitForSingleObject(hThread, -1); CloseHandle(hThread); - *injectedBase = GetTargetModuleBase(hProcess, filesystem::path(Wstring2String(dllPath)).filename().string()); + *injectedBase = GetTargetModuleBase(hProcess, filesystem::path(util::w2s(dllPath)).filename().string()); VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); // CloseHandle(hProcess); // Close when exit diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index 8b1c790..fca3b0f 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -28,7 +28,7 @@ static std::optional ReadDisclaimerText(const char *filePath) } std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return String2Wstring(content); + return util::s2w(content); } static bool ShowDisclaimer() @@ -94,7 +94,7 @@ int WxInitSDK(bool debug, int port) return ERROR_FILE_NOT_FOUND; // DLL 文件路径不存在 } - status = OpenWeChat(&wcPid); + status = util::open_wechat(&wcPid); if (status != 0) { MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); return status; diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index db496b3..589fd52 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -24,7 +24,7 @@ using invite_member_to_chatroom_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD); static vector parse_wxids(const string &wxids) { vector wx_members; - wstringstream wss(String2Wstring(wxids)); + wstringstream wss(util::s2w(wxids)); wstring wstr; while (getline(wss, wstr, L',')) { wx_members.emplace_back(wstr); diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index 192b20f..85c5740 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -1,6 +1,7 @@ #pragma execution_character_set("utf-8") #include "contact_mgmt.h" + #include "fill_response.h" #include "log.hpp" #include "pb_util.h" @@ -55,7 +56,7 @@ static string get_cnt_string(QWORD start, QWORD end, const uint8_t *feat, size_t return ""; } - return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat)); + return util::w2s(util::get_p_wstring(pfeat + FEAT_LEN + 4, lfeat)); } vector get_contacts() @@ -80,10 +81,10 @@ vector get_contacts() QWORD pbin = GET_QWORD(pstart + OS_CONTACT_BIN); QWORD lenbin = GET_DWORD(pstart + OS_CONTACT_BIN_LEN); - cnt.wxid = GetStringByWstrAddr(pstart + OS_CONTACT_WXID); - cnt.code = GetStringByWstrAddr(pstart + OS_CONTACT_CODE); - cnt.remark = GetStringByWstrAddr(pstart + OS_CONTACT_REMARK); - cnt.name = GetStringByWstrAddr(pstart + OS_CONTACT_NAME); + cnt.wxid = util::get_str_by_wstr_addr(pstart + OS_CONTACT_WXID); + cnt.code = util::get_str_by_wstr_addr(pstart + OS_CONTACT_CODE); + cnt.remark = util::get_str_by_wstr_addr(pstart + OS_CONTACT_REMARK); + cnt.name = util::get_str_by_wstr_addr(pstart + OS_CONTACT_NAME); cnt.country = get_cnt_string(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN); cnt.province = get_cnt_string(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN); @@ -112,8 +113,8 @@ int accept_new_friend(const std::string &v3, const std::string &v4, int scene) LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene); - wstring ws_v3 = String2Wstring(v3); - wstring ws_v4 = String2Wstring(v4); + wstring ws_v3 = util::s2w(v3); + wstring ws_v4 = util::s2w(v4); WxString wx_v3(ws_v3); WxString wx_v4(ws_v4); @@ -154,7 +155,7 @@ RpcContact_t get_contact_by_wxid(const string &wxid) RpcContact_t contact; #if 0 char buff[0x440] = { 0 }; - wstring ws_wxid = String2Wstring(wxid); + wstring ws_wxid = util::s2w(wxid); WxString pri(ws_wxid); DWORD contact_mgr_addr = g_WeChatWinDllAddr + 0x75A4A0; @@ -176,9 +177,9 @@ RpcContact_t get_contact_by_wxid(const string &wxid) } contact.wxid = wxid; - contact.code = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxCode); - contact.remark = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxRemark); - contact.name = GetStringByWstrAddr(reinterpret_cast(buff) + g_WxCalls.contact.wxName); + contact.code = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxCode); + contact.remark = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxRemark); + contact.name = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxName); contact.gender = GET_DWORD(reinterpret_cast(buff) + 0x148); __asm { diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 0ed9982..89678c1 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -1,7 +1,8 @@ -#include +#include "exec_sql.h" + +#include #include -#include "exec_sql.h" #include "fill_response.h" #include "log.hpp" #include "pb_util.h" @@ -29,7 +30,7 @@ static db_map_t db_map; static void get_db_handle(QWORD base, QWORD offset) { auto *wsp = reinterpret_cast(*(QWORD *)(base + offset + OFFSET_DB_NAME)); - std::string dbname = Wstring2String(std::wstring(wsp)); + std::string dbname = util::w2s(std::wstring(wsp)); db_map[dbname] = GET_QWORD(base + offset); } @@ -41,12 +42,12 @@ static void get_msg_db_handle(QWORD msg_mgr_addr) QWORD db_addr = GET_QWORD(p_start + i * 0x08); if (db_addr) { // MSGi.db - std::string dbname = Wstring2String(GET_WSTRING(db_addr)); + std::string dbname = util::w2s(get_pp_wstring(db_addr)); db_map[dbname] = GET_QWORD(db_addr + 0x78); // MediaMsgi.db QWORD mmdb_addr = GET_QWORD(db_addr + 0x20); - std::string mmdbname = Wstring2String(GET_WSTRING(mmdb_addr + 0x78)); + std::string mmdbname = util::w2s(get_pp_wstring(mmdb_addr + 0x78)); db_map[mmdbname] = GET_QWORD(mmdb_addr + 0x50); } } @@ -199,7 +200,7 @@ int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx) continue; } - std::string dbname = Wstring2String(GET_WSTRING(db_addr)); + std::string dbname = util::w2s(get_pp_wstring(db_addr)); db_map[dbname] = GET_QWORD(db_addr + 0x78); std::string sql = "SELECT localId FROM MSG WHERE MsgSvrID=" + std::to_string(id) + ";"; diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index 0ec2959..94b8b64 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -1,12 +1,13 @@ #pragma warning(disable : 4244) +#include "funcs.h" -#include "framework.h" #include #include +#include "framework.h" + #include "codec.h" #include "exec_sql.h" -#include "funcs.h" #include "log.hpp" #include "receive_msg.h" #include "spy_types.h" @@ -342,7 +343,7 @@ OcrResult_t GetOcrResult(string path) QWORD *pUnk1 = &unk1; QWORD *pUnk2 = &unk2; // 路径分隔符有要求,必须为 `\` - wstring wsPath = String2Wstring(fs::path(path).make_preferred().string()); + wstring wsPath = util::s2w(fs::path(path).make_preferred().string()); WxString wxPath(wsPath); vector *pv = (vector *)HeapAlloc(GetProcessHeap(), 0, 0x20); RawVector_t *pRv = (RawVector_t *)pv; @@ -358,7 +359,7 @@ OcrResult_t GetOcrResult(string path) QWORD header = GET_QWORD(buff); for (QWORD i = 0; i < count; i++) { QWORD content = GET_QWORD(header); - ret.result += Wstring2String(GET_WSTRING(content + 0x28)); + ret.result += util::w2s(get_pp_wstring(content + 0x28)); ret.result += "\n"; header = content; } diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index 5becce8..6ce84a2 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -1,4 +1,5 @@ - +#include "receive_msg.h" + #include #include #include @@ -6,7 +7,6 @@ #include "framework.h" #include "log.hpp" -#include "receive_msg.h" #include "user_info.h" #include "util.h" @@ -42,20 +42,21 @@ QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) wxMsg.type = GET_DWORD(arg2 + OS_RECV_MSG_TYPE); wxMsg.is_self = GET_DWORD(arg2 + OS_RECV_MSG_SELF); wxMsg.ts = GET_DWORD(arg2 + OS_RECV_MSG_TS); - wxMsg.content = GetStringByWstrAddr(arg2 + OS_RECV_MSG_CONTENT); - wxMsg.sign = GetStringByWstrAddr(arg2 + OS_RECV_MSG_SIGN); - wxMsg.xml = GetStringByWstrAddr(arg2 + OS_RECV_MSG_XML); - wxMsg.roomid = GetStringByWstrAddr(arg2 + OS_RECV_MSG_ROOMID); + wxMsg.content = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_CONTENT); + wxMsg.sign = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_SIGN); + wxMsg.xml = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_XML); + wxMsg.roomid = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_ROOMID); if (wxMsg.roomid.find("@chatroom") != std::string::npos) { wxMsg.is_group = true; - wxMsg.sender = wxMsg.is_self ? user_info::get_self_wxid() : GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID); + wxMsg.sender + = wxMsg.is_self ? user_info::get_self_wxid() : util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_WXID); } else { wxMsg.is_group = false; wxMsg.sender = wxMsg.is_self ? user_info::get_self_wxid() : wxMsg.roomid; } } catch (const std::exception &e) { - LOG_ERROR(GB2312ToUtf8(e.what())); + LOG_ERROR(util::gb2312_to_utf8(e.what())); } { @@ -77,7 +78,7 @@ QWORD MessageHandler::PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a return p; } - LOG_INFO("【WX】\n{}", GB2312ToUtf8((char *)p)); + LOG_INFO("【WX】\n{}", util::gb2312_to_utf8((char *)p)); return p; } @@ -99,9 +100,9 @@ void MessageHandler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) wxMsg.is_group = false; wxMsg.id = GET_QWORD(startAddr); wxMsg.ts = GET_DWORD(startAddr + OS_PYQ_MSG_TS); - wxMsg.xml = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_XML); - wxMsg.sender = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_SENDER); - wxMsg.content = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_CONTENT); + wxMsg.xml = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_XML); + wxMsg.sender = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_SENDER); + wxMsg.content = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_CONTENT); { std::unique_lock lock(handler.mutex_); diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index f4419ac..111a0a1 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -1,5 +1,7 @@ #pragma warning(disable : 4251) +#include "rpc_server.h" + #include #include #include @@ -26,7 +28,6 @@ #include "pb_types.h" #include "pb_util.h" #include "receive_msg.h" -#include "rpc_server.h" #include "send_msg.h" #include "spy.h" #include "spy_types.h" @@ -158,7 +159,7 @@ static bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) if ((path == NULL) || (receiver == NULL)) { LOG_ERROR("Empty path or receiver."); rsp.msg.status = -1; - } else if (!fs::exists(String2Wstring(path))) { + } else if (!fs::exists(util::s2w(path))) { LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { @@ -174,7 +175,7 @@ static bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len if ((path == nullptr) || (receiver == nullptr)) { LOG_ERROR("Empty path or receiver."); rsp.msg.status = -1; - } else if (!fs::exists(String2Wstring(path))) { + } else if (!fs::exists(util::s2w(path))) { LOG_ERROR("Path does not exist: {}", path); rsp.msg.status = -2; } else { @@ -685,7 +686,7 @@ static int RunRpcServer() } } } catch (const std::exception &e) { - LOG_ERROR(GB2312ToUtf8(e.what())); + LOG_ERROR(util::gb2312_to_utf8(e.what())); } catch (...) { LOG_ERROR("Unknow exception."); } diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index 153f12a..1134cbd 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -56,13 +56,13 @@ std::unique_ptr SendMsgManager::new_wx_string(const char *str) } std::unique_ptr SendMsgManager::new_wx_string(const std::string &str) { - return std::make_unique(String2Wstring(str)); + return std::make_unique(util::s2w(str)); } std::vector SendMsgManager::parse_wxids(const string &wxids) { vector wx_members; - wstringstream wss(String2Wstring(wxids)); + wstringstream wss(util::s2w(wxids)); wstring wstr; while (getline(wss, wstr, L',')) { wx_members.emplace_back(wstr); diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index e179aa0..f78b65d 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -1,44 +1,37 @@ -#include +#include "spy.h" + +#include +#include #include "log.hpp" #include "rpc_server.h" -#include "spy.h" #include "util.h" +constexpr std::string_view SUPPORT_VERSION = "3.9.11.25"; + UINT64 g_WeChatWinDllAddr = 0; -static bool IsWxVersionMatched(const wchar_t *version) -{ - if (wcscmp(version, SUPPORT_VERSION) != 0) { - return false; - } - return true; -} - void InitSpy(LPVOID args) { - - wchar_t version[16] = { 0 }; - PortPath_t *pp = (PortPath_t *)args; + auto *pp = static_cast(args); Log::InitLogger(pp->path); - g_WeChatWinDllAddr = (UINT64)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址 - if (g_WeChatWinDllAddr == 0) { - LOG_ERROR("获取 wechatWin.dll 模块地址失败"); + if (auto dll_addr = GetModuleHandle(L"WeChatWin.dll")) { + g_WeChatWinDllAddr = reinterpret_cast(dll_addr); + } else { + LOG_ERROR("获取 WeChatWin.dll 模块地址失败"); return; // TODO: 退出进程,避免后面操作失败 } - if (!GetWeChatVersion(version)) { // 获取微信版本 - LOG_ERROR("获取微信版本失败"); - return; - } - LOG_INFO("WeChat version: {}", Wstring2String(version).c_str()); - if (!IsWxVersionMatched(version)) { - LOG_ERROR("不支持当前版本"); - MessageBox(NULL, L"不支持当前版本", L"错误", 0); + std::string version = util::get_wechat_version(); + std::string msg = "WCF 支持版本: " + SUPPORT_VERSION + ",当前版本: " + version; + if (version != SUPPORT_VERSION) { + LOG_ERROR(msg); + MessageBoxA(NULL, msg.c_str(), "错误", MB_ICONERROR); return; } + LOG_INFO(msg); RpcStartServer(pp->port); } diff --git a/WeChatFerry/spy/spy.h b/WeChatFerry/spy/spy.h index 525109a..3aa41dd 100644 --- a/WeChatFerry/spy/spy.h +++ b/WeChatFerry/spy/spy.h @@ -2,7 +2,5 @@ #include "framework.h" -#define SUPPORT_VERSION L"3.9.11.25" - void InitSpy(int port); void CleanupSpy(); diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index 6cf95b7..2515d44 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -1,9 +1,10 @@ -#include +#include "user_info.h" + +#include #include #include "fill_response.h" #include "log.hpp" -#include "user_info.h" #include "util.h" extern UINT64 g_WeChatWinDllAddr; @@ -15,14 +16,13 @@ namespace user_info #define OS_USER_NAME 0x595C3D8 #define OS_USER_MOBILE 0x595C318 - std::string - get_home_path() +std::string get_home_path() { static std::once_flag flag; static std::string home_path; std::call_once(flag, [] { - std::string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; + std::string path = util::w2s(get_pp_wstring(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; home_path = std::filesystem::absolute(path).string(); }); @@ -39,9 +39,9 @@ std::string get_self_wxid() try { wxid_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); if (wxid_type == 0xF) { - wxid = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID); + wxid = util::get_p_string(g_WeChatWinDllAddr + OS_USER_WXID); } else { - wxid = GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID); + wxid = util::get_pp_string(g_WeChatWinDllAddr + OS_USER_WXID); } } catch (...) { @@ -59,10 +59,10 @@ UserInfo_t get_user_info() ui.wxid = get_self_wxid(); UINT64 name_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); - ui.name = (name_type == 0xF) ? GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME) - : GET_STRING(g_WeChatWinDllAddr + OS_USER_NAME); + ui.name = (name_type == 0xF) ? util::get_p_string(g_WeChatWinDllAddr + OS_USER_NAME) + : util::get_pp_string(g_WeChatWinDllAddr + OS_USER_NAME); - ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_MOBILE); + ui.mobile = util::get_p_string(g_WeChatWinDllAddr + OS_USER_MOBILE); ui.home = get_home_path(); return ui; From dc51b7b5a79db4f8e64b0249bc9fd5521d2866e5 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 17:27:35 +0800 Subject: [PATCH 26/41] Refactoring --- WeChatFerry/com/util.cpp | 141 +++++++++++++++++------------- WeChatFerry/com/util.h | 30 ++++--- WeChatFerry/spy/chatroom_mgmt.cpp | 14 +-- WeChatFerry/spy/contact_mgmt.cpp | 8 +- WeChatFerry/spy/exec_sql.cpp | 40 ++++----- WeChatFerry/spy/funcs.cpp | 20 ++--- WeChatFerry/spy/funcs.h | 4 +- WeChatFerry/spy/receive_msg.cpp | 12 +-- WeChatFerry/spy/receive_msg.h | 2 +- WeChatFerry/spy/spy.cpp | 2 +- WeChatFerry/spy/user_info.cpp | 6 +- 11 files changed, 152 insertions(+), 127 deletions(-) diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index 21b0039..7d13348 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -2,14 +2,13 @@ #include #include -#include -#include +#include #include -#include -#include #include #include "framework.h" +#include +#include #include "log.hpp" @@ -61,7 +60,7 @@ DWORD get_wechat_pid() PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { - if (std::wstring(pe32.szExeFile) == WECHATEXE) { + if (w2s(pe32.szExeFile) == WECHATEXE) { pid = pe32.th32ProcessID; break; } @@ -70,100 +69,125 @@ DWORD get_wechat_pid() return pid; } -int open_wechat(DWORD *pid) +int open_wechat(DWORD &pid) { - *pid = get_wechat_pid(); - if (*pid) return ERROR_SUCCESS; + pid = get_wechat_pid(); + if (pid != 0) { + return ERROR_SUCCESS; + } - WCHAR path[MAX_PATH] = { 0 }; - if (GetModuleFileNameW(nullptr, path, MAX_PATH) == 0) { - return GetLastError(); + auto wechat_path = util::get_wechat_path(); + if (!wechat_path) { + LOG_ERROR("获取 WeChat 安装路径失败"); + return ERROR_FILE_NOT_FOUND; } STARTUPINFO si = { sizeof(si) }; - PROCESS_INFORMATION pi = { 0 }; - - if (!CreateProcessW(nullptr, path, nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)) { + PROCESS_INFORMATION pi = {}; + if (!CreateProcessA(wechat_path->c_str(), nullptr, nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr, + &si, &pi)) { return GetLastError(); } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); - *pid = pi.dwProcessId; + pid = pi.dwProcessId; return ERROR_SUCCESS; } -static std::optional get_wechat_win_dll_path() +std::optional get_wechat_path() { - char path[MAX_PATH] = { 0 }; - if (GetWeChatPath(path) != ERROR_SUCCESS) { + HKEY hKey; + if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Tencent\\WeChat", 0, KEY_READ, &hKey) != ERROR_SUCCESS) { + LOG_ERROR("无法打开注册表项"); return std::nullopt; } - PathRemoveFileSpecA(path); - PathAppendA(path, WECHATWINDLL); - - if (!PathFileExistsA(path)) { - // 微信 3.7+ 版本增加了一层目录 - PathRemoveFileSpecA(path); - _finddata_t findData; - std::string dir = std::string(path) + "\\[*.*"; - intptr_t handle = _findfirst(dir.c_str(), &findData); - if (handle == -1) { - return std::nullopt; - } - _findclose(handle); - - std::string dllPath = std::string(path) + "\\" + findData.name + "\\" + WECHATWINDLL; - return dllPath; + char path[MAX_PATH] = { 0 }; + DWORD type = REG_SZ; + DWORD size = sizeof(path); + if (RegQueryValueExA(hKey, "InstallPath", nullptr, &type, reinterpret_cast(path), &size) != ERROR_SUCCESS) { + RegCloseKey(hKey); + LOG_ERROR("无法读取注册表中的 InstallPath"); + return std::nullopt; } + RegCloseKey(hKey); + PathAppendA(path, WECHATEXE); return std::string(path); } -static std::optional get_file_version(const std::string &filePath) +std::optional get_wechat_win_dll_path() { - if (filePath.empty() || !PathFileExistsA(filePath.c_str())) { + auto wechat_path = get_wechat_path(); + if (!wechat_path) { return std::nullopt; } - DWORD handle = 0; - DWORD size = GetFileVersionInfoSizeA(filePath.c_str(), &handle); + std::string dll_path = *wechat_path; + PathRemoveFileSpecA(dll_path.data()); + PathAppendA(dll_path.data(), WECHATWINDLL); + + if (PathFileExistsA(dll_path.c_str())) { + return dll_path; + } + + // 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29] + PathRemoveFileSpecA(dll_path.data()); + WIN32_FIND_DATAA find_data; + HANDLE hFind = FindFirstFileA((dll_path + "\\*.*").c_str(), &find_data); + if (hFind == INVALID_HANDLE_VALUE) { + return std::nullopt; + } + FindClose(hFind); + + std::string versioned_path = dll_path + "\\" + find_data.cFileName + WECHATWINDLL; + return PathFileExistsA(versioned_path.c_str()) ? std::optional(versioned_path) : std::nullopt; +} + +std::optional get_file_version(const std::string &file_path) +{ + if (!PathFileExistsA(file_path.c_str())) { + return std::nullopt; + } + + DWORD dummy = 0; + DWORD size = GetFileVersionInfoSizeA(file_path.c_str(), &dummy); if (size == 0) { return std::nullopt; } - std::vector data(size); - if (!GetFileVersionInfoA(filePath.c_str(), 0, size, data.data())) { + std::vector buffer(size); + if (!GetFileVersionInfoA(file_path.c_str(), 0, size, buffer.data())) { return std::nullopt; } - VS_FIXEDFILEINFO *verInfo = nullptr; - UINT len = 0; - if (!VerQueryValueA(data.data(), "\\", reinterpret_cast(&verInfo), &len) || len == 0) { + VS_FIXEDFILEINFO *ver_info = nullptr; + UINT ver_size = 0; + if (!VerQueryValueA(buffer.data(), "\\", reinterpret_cast(&ver_info), &ver_size)) { return std::nullopt; } - char version[32]; - StringCbPrintfA(version, sizeof(version), "%d.%d.%d.%d", HIWORD(verInfo->dwFileVersionMS), - LOWORD(verInfo->dwFileVersionMS), HIWORD(verInfo->dwFileVersionLS), - LOWORD(verInfo->dwFileVersionLS)); - - return std::string(version); + return fmt::format("{}.{}.{}.{}", HIWORD(ver_info->dwFileVersionMS), LOWORD(ver_info->dwFileVersionMS), + HIWORD(ver_info->dwFileVersionLS), LOWORD(ver_info->dwFileVersionLS)); } std::string get_wechat_version() { - std::string version = ""; - - auto dllPath = get_wechat_win_dll_path(); - if (!dllPath) { - return version; + auto dll_path = get_wechat_win_dll_path(); + if (!dll_path) { + LOG_ERROR("无法获取 WeChatWin.dll 路径"); + return ""; } - version = get_file_version(*dllPath); - return version ? version : ""; + auto version = get_file_version(*dll_path); + if (!version) { + LOG_ERROR("无法获取 WeChat 版本信息"); + return ""; + } + + return *version; } uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr) @@ -171,10 +195,7 @@ uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr) uint32_t value = 0; if (!addr || !hProcess) return value; - unsigned char data[4] = { 0 }; - if (ReadProcessMemory(hProcess, reinterpret_cast(addr), data, sizeof(data), nullptr)) { - value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); - } + ReadProcessMemory(hProcess, reinterpret_cast(addr), &value, sizeof(value), nullptr); return value; } diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h index 9169ddd..71d0bd7 100644 --- a/WeChatFerry/com/util.h +++ b/WeChatFerry/com/util.h @@ -1,15 +1,17 @@ #pragma once #include +#include #include +#include #include "spy_types.h" namespace util { -inline constexpr wchar_t WECHATEXE[] = L"WeChat.exe"; -inline constexpr wchar_t WECHATWINDLL[] = L"WeChatWin.dll"; +inline constexpr char WECHATEXE[] = "WeChat.exe"; +inline constexpr char WECHATWINDLL[] = "WeChatWin.dll"; inline constexpr wchar_t WCFSDKDLL[] = L"sdk.dll"; inline constexpr wchar_t WCFSPYDLL[] = L"spy.dll"; inline constexpr wchar_t WCFSPYDLL_DEBUG[] = L"spy_debug.dll"; @@ -19,6 +21,16 @@ struct PortPath { char path[MAX_PATH]; }; +DWORD get_wechat_pid(); +int open_wechat(DWORD *pid); +std::string get_wechat_version(); +uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr); +std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t addr); +std::wstring s2w(const std::string &s); +std::string w2s(const std::wstring &ws); +std::string gb2312_to_utf8(const char *gb2312); +void dbg_msg(const char *format, ...); + inline DWORD get_dword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } inline QWORD get_qword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } inline uint64_t get_uint64(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; } @@ -47,12 +59,12 @@ inline std::wstring get_pp_wstring(uint64_t addr) if (!addr) return L""; const wchar_t *ptr = *reinterpret_cast(addr); - return (ptr && *ptr) ? std::wstring(ptr) : ""; + return (ptr && *ptr) ? std::wstring(ptr) : L""; } inline std::string get_pp_len_string(uint64_t addr) { size_t len = get_dword(addr + 8); - return (addr && len) ? std::string(*reinterpret_cast(addr), len) : L""; + return (addr && len) ? std::string(*reinterpret_cast(addr), len) : ""; } inline std::wstring get_pp_len_wstring(uint64_t addr) { @@ -61,16 +73,6 @@ inline std::wstring get_pp_len_wstring(uint64_t addr) } inline std::string get_str_by_wstr_addr(uint64_t addr) { return w2s(get_pp_len_wstring(addr)); } -DWORD get_wechat_pid(); -int open_wechat(DWORD *pid); -std::string get_wechat_version(); -uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr); -std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t addr); -std::wstring s2w(const std::string &s); -std::string w2s(const std::wstring &ws); -std::string gb2312_to_utf8(const char *gb2312); -void dbg_msg(const char *format, ...); - std::unique_ptr new_wx_string(const char *str); std::unique_ptr new_wx_string(const wchar_t *wstr); std::unique_ptr new_wx_string(const std::string &str); diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index 589fd52..5cef8df 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -45,10 +45,10 @@ int add_chatroom_member(const string &roomid, const string &wxids) = reinterpret_cast(g_WeChatWinDllAddr + OS_ADD_MEMBERS); vector wx_members = parse_wxids(wxids); - WxString *p_wx_roomid = NewWxStringFromStr(roomid); + auto wx_roomid = util::new_wx_string(roomid); QWORD p_members = reinterpret_cast(&wx_members.front()); - return static_cast(add_members(get_chatroom_mgr(), p_members, reinterpret_cast(p_wx_roomid), 0)); + return static_cast(add_members(get_chatroom_mgr(), p_members, reinterpret_cast(wx_roomid.get()), 0)); } int del_chatroom_member(const string &roomid, const string &wxids) @@ -64,10 +64,10 @@ int del_chatroom_member(const string &roomid, const string &wxids) = reinterpret_cast(g_WeChatWinDllAddr + OS_DELETE_MEMBERS); vector wx_members = parse_wxids(wxids); - WxString *p_wx_roomid = NewWxStringFromStr(roomid); + auto wx_roomid = util::new_wx_string(roomid); QWORD p_members = reinterpret_cast(&wx_members.front()); - return static_cast(del_members(get_chatroom_mgr(), p_members, reinterpret_cast(p_wx_roomid))); + return static_cast(del_members(get_chatroom_mgr(), p_members, reinterpret_cast(wx_roomid.get()))); } int invite_chatroom_member(const string &roomid, const string &wxids) @@ -81,11 +81,11 @@ int invite_chatroom_member(const string &roomid, const string &wxids) = reinterpret_cast(g_WeChatWinDllAddr + OS_INVITE_MEMBERS); vector wx_members = parse_wxids(wxids); - WxString *p_wx_roomid = NewWxStringFromStr(roomid); + auto wx_roomid = util::new_wx_string(roomid); QWORD p_members = reinterpret_cast(&wx_members.front()); - return static_cast(invite_members(reinterpret_cast(p_wx_roomid->wptr), p_members, - reinterpret_cast(p_wx_roomid), 0)); + return static_cast(invite_members(reinterpret_cast(wx_roomid.get()->wptr), p_members, + reinterpret_cast(wx_roomid.get()), 0)); } bool rpc_add_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index 85c5740..6c6c631 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -51,7 +51,7 @@ static string get_cnt_string(QWORD start, QWORD end, const uint8_t *feat, size_t return ""; } - DWORD lfeat = GET_DWORD(pfeat + len); + DWORD lfeat = util::get_dword(pfeat + len); if (lfeat <= 2) { return ""; } @@ -78,8 +78,8 @@ vector get_contacts() QWORD pend = addr[2]; while (pstart < pend) { RpcContact_t cnt; - QWORD pbin = GET_QWORD(pstart + OS_CONTACT_BIN); - QWORD lenbin = GET_DWORD(pstart + OS_CONTACT_BIN_LEN); + QWORD pbin = util::get_qword(pstart + OS_CONTACT_BIN); + QWORD lenbin = util::get_dword(pstart + OS_CONTACT_BIN_LEN); cnt.wxid = util::get_str_by_wstr_addr(pstart + OS_CONTACT_WXID); cnt.code = util::get_str_by_wstr_addr(pstart + OS_CONTACT_CODE); @@ -180,7 +180,7 @@ RpcContact_t get_contact_by_wxid(const string &wxid) contact.code = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxCode); contact.remark = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxRemark); contact.name = util::get_str_by_wstr_addr(reinterpret_cast(buff) + g_WxCalls.contact.wxName); - contact.gender = GET_DWORD(reinterpret_cast(buff) + 0x148); + contact.gender = util::get_dword(reinterpret_cast(buff) + 0x148); __asm { PUSHAD diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 89678c1..1993ecd 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -31,24 +31,24 @@ static void get_db_handle(QWORD base, QWORD offset) { auto *wsp = reinterpret_cast(*(QWORD *)(base + offset + OFFSET_DB_NAME)); std::string dbname = util::w2s(std::wstring(wsp)); - db_map[dbname] = GET_QWORD(base + offset); + db_map[dbname] = util::get_qword(base + offset); } static void get_msg_db_handle(QWORD msg_mgr_addr) { - QWORD db_index = GET_QWORD(msg_mgr_addr + 0x68); - QWORD p_start = GET_QWORD(msg_mgr_addr + 0x50); + QWORD db_index = util::get_qword(msg_mgr_addr + 0x68); + QWORD p_start = util::get_qword(msg_mgr_addr + 0x50); for (uint32_t i = 0; i < db_index; i++) { - QWORD db_addr = GET_QWORD(p_start + i * 0x08); + QWORD db_addr = util::get_qword(p_start + i * 0x08); if (db_addr) { // MSGi.db - std::string dbname = util::w2s(get_pp_wstring(db_addr)); - db_map[dbname] = GET_QWORD(db_addr + 0x78); + std::string dbname = util::w2s(util::get_pp_wstring(db_addr)); + db_map[dbname] = util::get_qword(db_addr + 0x78); // MediaMsgi.db - QWORD mmdb_addr = GET_QWORD(db_addr + 0x20); - std::string mmdbname = util::w2s(get_pp_wstring(mmdb_addr + 0x78)); - db_map[mmdbname] = GET_QWORD(mmdb_addr + 0x50); + QWORD mmdb_addr = util::get_qword(db_addr + 0x20); + std::string mmdbname = util::w2s(util::get_pp_wstring(mmdb_addr + 0x78)); + db_map[mmdbname] = util::get_qword(mmdb_addr + 0x50); } } } @@ -56,7 +56,7 @@ static void get_msg_db_handle(QWORD msg_mgr_addr) db_map_t get_db_handles() { db_map.clear(); - QWORD db_instance_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE); + QWORD db_instance_addr = util::get_qword(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE); get_db_handle(db_instance_addr, OFFSET_DB_MICROMSG); // MicroMsg.db get_db_handle(db_instance_addr, OFFSET_DB_CHAT_MSG); // ChatMsg.db @@ -65,7 +65,7 @@ db_map_t get_db_handles() get_db_handle(db_instance_addr, OFFSET_DB_MEDIA); // Media.db get_db_handle(db_instance_addr, OFFSET_DB_FUNCTION_MSG); // Function.db - get_msg_db_handle(GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR)); // MSGi.db & MediaMsgi.db + get_msg_db_handle(util::get_qword(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR)); // MSGi.db & MediaMsgi.db return db_map; } @@ -189,19 +189,19 @@ int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx) return -1; } - QWORD msg_mgr_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); - int db_index = static_cast(GET_QWORD(msg_mgr_addr + 0x68)); // 总不能 int 还不够吧? - QWORD p_start = GET_QWORD(msg_mgr_addr + 0x50); + QWORD msg_mgr_addr = util::get_qword(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); + int db_index = static_cast(util::get_qword(msg_mgr_addr + 0x68)); // 总不能 int 还不够吧? + QWORD p_start = util::get_qword(msg_mgr_addr + 0x50); *db_idx = 0; for (int i = db_index - 1; i >= 0; i--) { // 从后往前遍历 - QWORD db_addr = GET_QWORD(p_start + i * 0x08); + QWORD db_addr = util::get_qword(p_start + i * 0x08); if (!db_addr) { continue; } - std::string dbname = util::w2s(get_pp_wstring(db_addr)); - db_map[dbname] = GET_QWORD(db_addr + 0x78); + std::string dbname = util::w2s(util::get_pp_wstring(db_addr)); + db_map[dbname] = util::get_qword(db_addr + 0x78); std::string sql = "SELECT localId FROM MSG WHERE MsgSvrID=" + std::to_string(id) + ";"; DbRows_t rows = exec_db_query(dbname, sql); @@ -223,7 +223,7 @@ int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx) continue; } - *db_idx = static_cast(GET_QWORD(GET_QWORD(db_addr + 0x28) + 0x1E8) >> 32); + *db_idx = static_cast(util::get_qword(util::get_qword(db_addr + 0x28) + 0x1E8) >> 32); return 0; } @@ -232,8 +232,8 @@ int get_local_id_and_dbidx(uint64_t id, uint64_t *local_id, uint32_t *db_idx) std::vector get_audio_data(uint64_t id) { - QWORD msg_mgr_addr = GET_QWORD(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); - int db_index = static_cast(GET_QWORD(msg_mgr_addr + 0x68)); + QWORD msg_mgr_addr = util::get_qword(g_WeChatWinDllAddr + OFFSET_DB_MSG_MGR); + int db_index = static_cast(util::get_qword(msg_mgr_addr + 0x68)); std::string sql = "SELECT Buf FROM Media WHERE Reserved0=" + std::to_string(id) + ";"; for (int i = db_index - 1; i >= 0; i--) { diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index 94b8b64..b27642d 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -51,7 +51,7 @@ typedef QWORD (*PushAttachTask_t)(QWORD, QWORD, QWORD, QWORD); typedef QWORD (*GetOCRManager_t)(); typedef QWORD (*DoOCRTask_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); -int IsLogin(void) { return (int)GET_QWORD(g_WeChatWinDllAddr + OS_LOGIN_STATUS); } +int IsLogin(void) { return (int)util::get_qword(g_WeChatWinDllAddr + OS_LOGIN_STATUS); } static string get_key(uint8_t header1, uint8_t header2, uint8_t *key) { @@ -230,7 +230,7 @@ int DownloadAttach(QWORD id, string thumb, string extra) GetChatMgr(); GetMgrByPrefixLocalId(l.QuadPart, pChatMsg); - QWORD type = GET_QWORD(buff + 0x38); + QWORD type = util::get_qword(reinterpret_cast(buff) + 0x38); string save_path = ""; string thumb_path = ""; @@ -262,12 +262,12 @@ int DownloadAttach(QWORD id, string thumb, string extra) // 创建父目录,由于路径来源于微信,不做检查 fs::create_directory(fs::path(save_path).parent_path().string()); - int temp = 1; - WxString *pSavePath = NewWxStringFromStr(save_path); - WxString *pThumbPath = NewWxStringFromStr(thumb_path); + int temp = 1; + auto wx_save_path = util::new_wx_string(save_path); + auto wx_thumb_path = util::new_wx_string(thumb_path); - memcpy(&buff[0x280], pThumbPath, sizeof(WxString)); - memcpy(&buff[0x2A0], pSavePath, sizeof(WxString)); + memcpy(&buff[0x280], wx_thumb_path.get(), sizeof(WxString)); + memcpy(&buff[0x2A0], wx_save_path.get(), sizeof(WxString)); memcpy(&buff[0x40C], &temp, sizeof(temp)); QWORD mgr = GetPreDownLoadMgr(); @@ -354,11 +354,11 @@ OcrResult_t GetOcrResult(string path) QWORD mgr = GetOCRManager(); ret.status = (int)DoOCRTask(mgr, (QWORD)&wxPath, unused, (QWORD)buff, (QWORD)&pUnk1, (QWORD)&pUnk2); - QWORD count = GET_QWORD(buff + 0x8); + QWORD count = util::get_qword(buff + 0x8); if (count > 0) { - QWORD header = GET_QWORD(buff); + QWORD header = util::get_qword(buff); for (QWORD i = 0; i < count; i++) { - QWORD content = GET_QWORD(header); + QWORD content = util::get_qword(header); ret.result += util::w2s(get_pp_wstring(content + 0x28)); ret.result += "\n"; header = content; diff --git a/WeChatFerry/spy/funcs.h b/WeChatFerry/spy/funcs.h index cc0f89d..c25f076 100644 --- a/WeChatFerry/spy/funcs.h +++ b/WeChatFerry/spy/funcs.h @@ -3,6 +3,8 @@ #include "stdint.h" #include +#include "pb_types.h" + int IsLogin(void); std::string GetAudio(uint64_t id, std::string dir); std::string GetPCMAudio(uint64_t id, std::string dir, int32_t sr); @@ -11,5 +13,5 @@ int RefreshPyq(uint64_t id); int DownloadAttach(uint64_t id, std::string thumb, std::string extra); int RevokeMsg(uint64_t id); OcrResult_t GetOcrResult(std::string path); -string GetLoginUrl(); +std::string GetLoginUrl(); int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid); diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index 6ce84a2..ceab7dc 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -38,10 +38,10 @@ QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) auto &handler = getInstance(); WxMsg_t wxMsg = {}; try { - wxMsg.id = GET_QWORD(arg2 + OS_RECV_MSG_ID); - wxMsg.type = GET_DWORD(arg2 + OS_RECV_MSG_TYPE); - wxMsg.is_self = GET_DWORD(arg2 + OS_RECV_MSG_SELF); - wxMsg.ts = GET_DWORD(arg2 + OS_RECV_MSG_TS); + wxMsg.id = util::get_qword(arg2 + OS_RECV_MSG_ID); + wxMsg.type = util::get_dword(arg2 + OS_RECV_MSG_TYPE); + wxMsg.is_self = util::get_dword(arg2 + OS_RECV_MSG_SELF); + wxMsg.ts = util::get_dword(arg2 + OS_RECV_MSG_TS); wxMsg.content = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_CONTENT); wxMsg.sign = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_SIGN); wxMsg.xml = util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_XML); @@ -98,8 +98,8 @@ void MessageHandler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) wxMsg.type = 0x00; wxMsg.is_self = false; wxMsg.is_group = false; - wxMsg.id = GET_QWORD(startAddr); - wxMsg.ts = GET_DWORD(startAddr + OS_PYQ_MSG_TS); + wxMsg.id = util::get_qword(startAddr); + wxMsg.ts = util::get_dword(startAddr + OS_PYQ_MSG_TS); wxMsg.xml = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_XML); wxMsg.sender = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_SENDER); wxMsg.content = util::get_str_by_wstr_addr(startAddr + OS_PYQ_MSG_CONTENT); diff --git a/WeChatFerry/spy/receive_msg.h b/WeChatFerry/spy/receive_msg.h index 0e2f314..a2559ef 100644 --- a/WeChatFerry/spy/receive_msg.h +++ b/WeChatFerry/spy/receive_msg.h @@ -5,11 +5,11 @@ #include #include #include -#include #include "MinHook.h" #include "pb_types.h" +#include "spy_types.h" class MessageHandler { diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index f78b65d..5fbe07f 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -13,7 +13,7 @@ UINT64 g_WeChatWinDllAddr = 0; void InitSpy(LPVOID args) { - auto *pp = static_cast(args); + auto *pp = static_cast(args); Log::InitLogger(pp->path); if (auto dll_addr = GetModuleHandle(L"WeChatWin.dll")) { diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index 2515d44..48ad23e 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -22,7 +22,7 @@ std::string get_home_path() static std::string home_path; std::call_once(flag, [] { - std::string path = util::w2s(get_pp_wstring(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; + std::string path = util::w2s(util::get_pp_wstring(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\"; home_path = std::filesystem::absolute(path).string(); }); @@ -37,7 +37,7 @@ std::string get_self_wxid() std::call_once(flag, [] { UINT64 wxid_type = 0; try { - wxid_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); + wxid_type = util::get_qword(g_WeChatWinDllAddr + OS_USER_WXID + 0x18); if (wxid_type == 0xF) { wxid = util::get_p_string(g_WeChatWinDllAddr + OS_USER_WXID); } else { @@ -58,7 +58,7 @@ UserInfo_t get_user_info() UserInfo_t ui; ui.wxid = get_self_wxid(); - UINT64 name_type = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); + UINT64 name_type = util::get_qword(g_WeChatWinDllAddr + OS_USER_NAME + 0x18); ui.name = (name_type == 0xF) ? util::get_p_string(g_WeChatWinDllAddr + OS_USER_NAME) : util::get_pp_string(g_WeChatWinDllAddr + OS_USER_NAME); From 1bec8ce8a2a01b1baa8e9c90d9570b570d98b0bb Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 17:34:48 +0800 Subject: [PATCH 27/41] Refactoring --- WeChatFerry/com/util.cpp | 64 +++++++++++++++++++++------------------- WeChatFerry/spy/spy.cpp | 2 +- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index 7d13348..ed2a302 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -52,7 +52,7 @@ std::string gb2312_to_utf8(const char *gb2312) return s; } -DWORD get_wechat_pid() +static DWORD get_wechat_pid() { DWORD pid = 0; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); @@ -69,34 +69,7 @@ DWORD get_wechat_pid() return pid; } -int open_wechat(DWORD &pid) -{ - pid = get_wechat_pid(); - if (pid != 0) { - return ERROR_SUCCESS; - } - - auto wechat_path = util::get_wechat_path(); - if (!wechat_path) { - LOG_ERROR("获取 WeChat 安装路径失败"); - return ERROR_FILE_NOT_FOUND; - } - - STARTUPINFO si = { sizeof(si) }; - PROCESS_INFORMATION pi = {}; - if (!CreateProcessA(wechat_path->c_str(), nullptr, nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr, - &si, &pi)) { - return GetLastError(); - } - - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - - pid = pi.dwProcessId; - return ERROR_SUCCESS; -} - -std::optional get_wechat_path() +static std::optional get_wechat_path() { HKEY hKey; if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Tencent\\WeChat", 0, KEY_READ, &hKey) != ERROR_SUCCESS) { @@ -118,7 +91,7 @@ std::optional get_wechat_path() return std::string(path); } -std::optional get_wechat_win_dll_path() +static std::optional get_wechat_win_dll_path() { auto wechat_path = get_wechat_path(); if (!wechat_path) { @@ -146,7 +119,7 @@ std::optional get_wechat_win_dll_path() return PathFileExistsA(versioned_path.c_str()) ? std::optional(versioned_path) : std::nullopt; } -std::optional get_file_version(const std::string &file_path) +static std::optional get_file_version(const std::string &file_path) { if (!PathFileExistsA(file_path.c_str())) { return std::nullopt; @@ -190,6 +163,35 @@ std::string get_wechat_version() return *version; } +int open_wechat(DWORD &pid) +{ + pid = get_wechat_pid(); + if (pid != 0) { + return ERROR_SUCCESS; + } + + auto wechat_path = util::get_wechat_path(); + if (!wechat_path) { + LOG_ERROR("获取 WeChat 安装路径失败"); + return ERROR_FILE_NOT_FOUND; + } + + STARTUPINFOA si = { sizeof(si) }; + PROCESS_INFORMATION pi = {}; + + std::string command_line = *wechat_path; + if (!CreateProcessA(nullptr, command_line.data(), nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr, + &si, &pi)) { + return GetLastError(); + } + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + pid = pi.dwProcessId; + return ERROR_SUCCESS; +} + uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr) { uint32_t value = 0; diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index 5fbe07f..26fc287 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -24,7 +24,7 @@ void InitSpy(LPVOID args) } std::string version = util::get_wechat_version(); - std::string msg = "WCF 支持版本: " + SUPPORT_VERSION + ",当前版本: " + version; + std::string msg = fmt::format("WCF 支持版本: {},当前版本: {}", SUPPORT_VERSION, version); if (version != SUPPORT_VERSION) { LOG_ERROR(msg); MessageBoxA(NULL, msg.c_str(), "错误", MB_ICONERROR); From e012efc682604ee289f0c0f62afc98e353485fad Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 20:40:46 +0800 Subject: [PATCH 28/41] Refactoring --- WeChatFerry/com/log.hpp | 9 +- WeChatFerry/com/util.cpp | 5 +- WeChatFerry/com/util.h | 7 -- WeChatFerry/sdk/injector.cpp | 181 ++++++++++++++++------------------- WeChatFerry/sdk/injector.h | 12 ++- WeChatFerry/sdk/sdk.cpp | 96 +++++++++---------- 6 files changed, 146 insertions(+), 164 deletions(-) diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp index 4be5e76..380a8c6 100644 --- a/WeChatFerry/com/log.hpp +++ b/WeChatFerry/com/log.hpp @@ -3,13 +3,12 @@ #include #include #include -#include -#include -#include #include #include -#include "util.h" +#include +#include +#include #define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__) #define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__) @@ -48,7 +47,7 @@ inline void InitLogger(const std::string &path) logger = spdlog::rotating_logger_mt(DEFAULT_LOGGER_NAME, filename.string(), DEFAULT_LOGGER_MAX_SIZE, DEFAULT_LOGGER_MAX_FILES); } catch (const spdlog::spdlog_ex &ex) { - MessageBox(NULL, util::s2w(ex.what()).c_str(), L"Init LOGGER ERROR", MB_ICONERROR); + MessageBoxA(NULL, ex.what(), "Init LOGGER ERROR", MB_ICONERROR); return; } diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index ed2a302..2481124 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -18,6 +18,9 @@ namespace util { +constexpr std::wstring_view WECHATEXE = L"WeChat.exe"; +constexpr std::string_view WECHATWINDLL = "WeChatWin.dll"; + std::wstring s2w(const std::string &s) { if (s.empty()) return std::wstring(); @@ -60,7 +63,7 @@ static DWORD get_wechat_pid() PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { - if (w2s(pe32.szExeFile) == WECHATEXE) { + if (pe32.szExeFile == WECHATEXE) { pid = pe32.th32ProcessID; break; } diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h index 71d0bd7..c4715cd 100644 --- a/WeChatFerry/com/util.h +++ b/WeChatFerry/com/util.h @@ -9,13 +9,6 @@ namespace util { - -inline constexpr char WECHATEXE[] = "WeChat.exe"; -inline constexpr char WECHATWINDLL[] = "WeChatWin.dll"; -inline constexpr wchar_t WCFSDKDLL[] = L"sdk.dll"; -inline constexpr wchar_t WCFSPYDLL[] = L"spy.dll"; -inline constexpr wchar_t WCFSPYDLL_DEBUG[] = L"spy_debug.dll"; - struct PortPath { int port; char path[MAX_PATH]; diff --git a/WeChatFerry/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp index 975faa9..d990854 100644 --- a/WeChatFerry/sdk/injector.cpp +++ b/WeChatFerry/sdk/injector.cpp @@ -1,112 +1,108 @@ -#include "framework.h" -#include "psapi.h" -#include -#include +#include "injector.h" -#include "injector.h" -#include "util.h" +#include + +#include "psapi.h" using namespace std; -HMODULE GetTargetModuleBase(HANDLE process, string dll) +static void handle_injection_error(HANDLE process, LPVOID remote_address, const std::string &error_msg) { - DWORD cbNeeded; - HMODULE moduleHandleList[512]; - BOOL ret = EnumProcessModulesEx(process, moduleHandleList, sizeof(moduleHandleList), &cbNeeded, LIST_MODULES_64BIT); - if (!ret) { - MessageBox(NULL, L"获取模块失败", L"GetTargetModuleBase", 0); + MessageBoxA(NULL, error_msg.c_str(), "Error", MB_ICONERROR); + if (remote_address) { + VirtualFreeEx(process, remote_address, 0, MEM_RELEASE); + } + if (process) { + CloseHandle(process); + } +} + +HMODULE get_target_module_base(HANDLE process, const string &dll) +{ + DWORD needed; + HMODULE modules[512]; + if (!EnumProcessModulesEx(process, modules, sizeof(modules), &needed, LIST_MODULES_64BIT)) { + MessageBoxA(NULL, "获取模块失败", "get_target_module_base", 0); return NULL; } - if (cbNeeded > sizeof(moduleHandleList)) { - MessageBox(NULL, L"模块数量过多", L"GetTargetModuleBase", 0); - return NULL; - } - DWORD processCount = cbNeeded / sizeof(HMODULE); - - char moduleName[32]; - for (DWORD i = 0; i < processCount; i++) { - GetModuleBaseNameA(process, moduleHandleList[i], moduleName, 32); - if (!strncmp(dll.c_str(), moduleName, dll.size())) { - return moduleHandleList[i]; + DWORD count = needed / sizeof(HMODULE); + char module_name[MAX_PATH]; + for (DWORD i = 0; i < count; i++) { + GetModuleBaseNameA(process, modules[i], module_name, sizeof(module_name)); + if (!strncmp(dll.c_str(), module_name, dll.size())) { + return modules[i]; } } return NULL; } -HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) +HANDLE inject_dll(DWORD pid, const string &dll_path, HMODULE *injected_base) { - HANDLE hThread; - SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR); + SIZE_T path_size = dll_path.size() + 1; // 1. 打开目标进程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (hProcess == NULL) { - MessageBox(NULL, L"打开进程失败", L"InjectDll", 0); + if (!hProcess) { + MessageBoxA(NULL, "打开进程失败", "inject_dll", 0); return NULL; } // 2. 在目标进程的内存里开辟空间 - LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0); + LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, path_size, MEM_COMMIT, PAGE_READWRITE); + if (!pRemoteAddress) { + handle_injection_error(hProcess, NULL, "DLL 路径写入失败"); return NULL; } // 3. 把 dll 的路径写入到目标进程的内存空间中 - WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL); + WriteProcessMemory(hProcess, pRemoteAddress, dll_path.c_str(), path_size, NULL); - // 3. 创建一个远程线程,让目标进程调用 LoadLibrary - HMODULE k32 = GetModuleHandle(L"kernel32.dll"); - if (k32 == NULL) { - MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); + // 4. 创建一个远程线程,让目标进程调用 LoadLibrary + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + if (!k32) { + handle_injection_error(hProcess, pRemoteAddress, "获取 kernel32 失败"); return NULL; } - FARPROC libAddr = GetProcAddress(k32, "LoadLibraryW"); + FARPROC libAddr = GetProcAddress(k32, "LoadLibraryA"); if (!libAddr) { - MessageBox(NULL, L"获取 LoadLibrary 失败", L"InjectDll", 0); + handle_injection_error(hProcess, pRemoteAddress, "获取 LoadLibrary 失败"); return NULL; } - hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); - CloseHandle(hProcess); - MessageBox(NULL, L"CreateRemoteThread 失败", L"InjectDll", 0); + HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, pRemoteAddress, 0, NULL); + if (!hThread) { + handle_injection_error(hProcess, pRemoteAddress, "CreateRemoteThread 失败"); return NULL; } - WaitForSingleObject(hThread, -1); + WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); - *injectedBase = GetTargetModuleBase(hProcess, filesystem::path(util::w2s(dllPath)).filename().string()); + *injected_base = get_target_module_base(hProcess, filesystem::path(dll_path).filename().string()); VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); - // CloseHandle(hProcess); // Close when exit - return hProcess; } -bool EjectDll(HANDLE process, HMODULE dllBase) +bool eject_dll(HANDLE process, HMODULE dll_base) { - HANDLE hThread = NULL; - - // 使目标进程调用 FreeLibrary,卸载 DLL - HMODULE k32 = GetModuleHandle(L"kernel32.dll"); - if (k32 == NULL) { - MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); - return NULL; + HMODULE k32 = GetModuleHandleA("kernel32.dll"); + if (!k32) { + MessageBoxA(NULL, "获取 kernel32 失败", "eject_dll", 0); + return false; } FARPROC libAddr = GetProcAddress(k32, "FreeLibraryAndExitThread"); if (!libAddr) { - MessageBox(NULL, L"获取 FreeLibrary 失败", L"InjectDll", 0); - return NULL; + MessageBoxA(NULL, "获取 FreeLibrary 失败", "eject_dll", 0); + return false; } - hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, (LPVOID)dllBase, 0, NULL); - if (hThread == NULL) { - MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0); + + HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, (LPVOID)dll_base, 0, NULL); + if (!hThread) { + MessageBoxA(NULL, "FreeLibrary 调用失败!", "eject_dll", 0); return false; } @@ -116,38 +112,34 @@ bool EjectDll(HANDLE process, HMODULE dllBase) return true; } -static UINT64 GetFuncOffset(LPCWSTR dllPath, LPCSTR funcName) +static uint64_t get_func_offset(const string &dll_path, const string &func_name) { - HMODULE dll = LoadLibrary(dllPath); - if (dll == NULL) { - MessageBox(NULL, L"获取 DLL 失败", L"GetFuncOffset", 0); + HMODULE dll = LoadLibraryA(dll_path.c_str()); + if (!dll) { + MessageBoxA(NULL, "获取 DLL 失败", "get_func_offset", 0); return 0; } - LPVOID absAddr = GetProcAddress(dll, funcName); - UINT64 offset = (UINT64)absAddr - (UINT64)dll; + LPVOID absAddr = GetProcAddress(dll, func_name.c_str()); + uint64_t offset = reinterpret_cast(absAddr) - reinterpret_cast(dll); FreeLibrary(dll); return offset; } -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPDWORD ret) +bool call_dll_func(HANDLE process, const string &dll_path, HMODULE dll_base, const string &func_name, DWORD *ret) { - UINT64 offset = GetFuncOffset(dllPath, funcName); - if (offset == 0) { - return false; + uint64_t offset = get_func_offset(dll_path, func_name); + if (offset == 0 || offset > (UINT64_MAX - reinterpret_cast(dll_base))) { + return false; // 避免溢出 } - UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); - if (pFunc <= (UINT64)dllBase) { - return false; - } - + uint64_t pFunc = reinterpret_cast(dll_base) + offset; HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, NULL, 0, NULL); - if (hThread == NULL) { + if (!hThread) { return false; } WaitForSingleObject(hThread, INFINITE); - if (ret != NULL) { + if (ret) { GetExitCodeThread(hThread, ret); } @@ -155,35 +147,32 @@ bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcNa return true; } -bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - LPDWORD ret) +bool call_dll_func_ex(HANDLE process, const string &dll_path, HMODULE dll_base, const string &func_name, + LPVOID parameter, size_t size, DWORD *ret) { - UINT64 offset = GetFuncOffset(dllPath, funcName); - if (offset == 0) { - return false; + uint64_t offset = get_func_offset(dll_path, func_name); + if (offset == 0 || offset > (UINT64_MAX - reinterpret_cast(dll_base))) { + return false; // 避免溢出 } - UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); - if (pFunc <= (UINT64)dllBase) { + uint64_t pFunc = reinterpret_cast(dll_base) + offset; + LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, size, MEM_COMMIT, PAGE_READWRITE); + if (!pRemoteAddress) { + MessageBoxA(NULL, "申请内存失败", "call_dll_func_ex", 0); return false; } - LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, sz, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"申请内存失败", L"CallDllFuncEx", 0); - return NULL; - } - - WriteProcessMemory(process, pRemoteAddress, parameter, sz, NULL); + WriteProcessMemory(process, pRemoteAddress, parameter, size, NULL); HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - MessageBox(NULL, L"远程调用失败", L"CallDllFuncEx", 0); + if (!hThread) { + VirtualFreeEx(process, pRemoteAddress, 0, MEM_RELEASE); + MessageBoxA(NULL, "远程调用失败", "call_dll_func_ex", 0); return false; } + WaitForSingleObject(hThread, INFINITE); - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - if (ret != NULL) { + VirtualFreeEx(process, pRemoteAddress, 0, MEM_RELEASE); + if (ret) { GetExitCodeThread(hThread, ret); } diff --git a/WeChatFerry/sdk/injector.h b/WeChatFerry/sdk/injector.h index 07b4a28..83988a6 100644 --- a/WeChatFerry/sdk/injector.h +++ b/WeChatFerry/sdk/injector.h @@ -1,9 +1,11 @@ #pragma once +#include + #include "framework.h" -HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase); -bool EjectDll(HANDLE process, HMODULE dllBase); -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, DWORD *ret); -bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - DWORD *ret); +HANDLE inject_dll(DWORD pid, const std::string &dll_path, HMODULE *injected_base); +bool eject_dll(HANDLE process, HMODULE dll_base); +bool call_dll_func(HANDLE process, const std::string &dll_path, HMODULE dll_base, const std::string &func, DWORD *ret); +bool call_dll_func_ex(HANDLE process, const std::string &dll_path, HMODULE dll_base, const std::string &func, + LPVOID parameter, size_t size, DWORD *ret); diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index fca3b0f..69ff632 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -1,4 +1,5 @@ -#include "framework.h" +#include "sdk.h" + #include #include #include @@ -6,55 +7,56 @@ #include #include #include + +#include "framework.h" #include #include "injector.h" -#include "sdk.h" #include "util.h" -static BOOL injected = false; +static bool injected = false; static HANDLE wcProcess = NULL; static HMODULE spyBase = NULL; -static std::wstring spyDllPath; +static std::string spyDllPath; -constexpr char DISCLAIMER_FILE[] = ".license_accepted.flag"; -constexpr char DISCLAIMER_TEXT_FILE[] = "DISCLAIMER.md"; +constexpr std::string_view WCFSDKDLL = "sdk.dll"; +constexpr std::string_view WCFSPYDLL = "spy.dll"; +constexpr std::string_view WCFSPYDLL_DEBUG = "spy_debug.dll"; +constexpr std::string_view DISCLAIMER_FLAG = ".license_accepted.flag"; +constexpr std::string_view DISCLAIMER_TEXT_FILE = "DISCLAIMER.md"; -static std::optional ReadDisclaimerText(const char *filePath) +static std::optional read_disclaimer_text(const std::string &path) { - std::ifstream file(filePath, std::ios::binary); + std::ifstream file(path, std::ios::binary); if (!file.is_open()) { return std::nullopt; // 文件打开失败 } - std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return util::s2w(content); + return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); } -static bool ShowDisclaimer() +static bool show_disclaimer() { - if (std::filesystem::exists(DISCLAIMER_FILE)) { + if (std::filesystem::exists(DISCLAIMER_FLAG)) { return true; } - std::optional disclaimerTextOpt = ReadDisclaimerText(DISCLAIMER_TEXT_FILE); - if (!disclaimerTextOpt.has_value() || disclaimerTextOpt->empty()) { - MessageBox(NULL, L"免责声明文件为空或读取失败。", L"错误", MB_ICONERROR); + auto disclaimerTextOpt = read_disclaimer_text(std::string(DISCLAIMER_TEXT_FILE)); + if (!disclaimerTextOpt || disclaimerTextOpt->empty()) { + MessageBoxA(NULL, "免责声明文件为空或读取失败。", "错误", MB_ICONERROR); return false; } - std::wstring disclaimerText = *disclaimerTextOpt; - - int result = MessageBox(NULL, disclaimerText.c_str(), L"免责声明", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2); - + int result + = MessageBoxA(NULL, disclaimerTextOpt->c_str(), "免责声明", MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2); if (result == IDCANCEL) { - MessageBox(NULL, L"您拒绝了免责声明,程序将退出。", L"提示", MB_ICONINFORMATION); + MessageBoxA(NULL, "您拒绝了免责声明,程序将退出。", "提示", MB_ICONINFORMATION); return false; } - std::ofstream flagFile(DISCLAIMER_FILE, std::ios::out | std::ios::trunc); + std::ofstream flagFile(std::string(DISCLAIMER_FLAG), std::ios::out | std::ios::trunc); if (!flagFile) { - MessageBox(NULL, L"无法创建协议标志文件。", L"错误", MB_ICONERROR); + MessageBoxA(NULL, "无法创建协议标志文件。", "错误", MB_ICONERROR); return false; } flagFile << "User accepted the license agreement."; @@ -62,62 +64,56 @@ static bool ShowDisclaimer() return true; } -static std::wstring GetDllPath(bool debug) +static std::string get_dll_path(bool debug) { - WCHAR buffer[MAX_PATH] = { 0 }; - GetModuleFileName(GetModuleHandle(WCFSDKDLL), buffer, MAX_PATH); + char buffer[MAX_PATH] = { 0 }; + GetModuleFileNameA(GetModuleHandleA(WCFSDKDLL), buffer, MAX_PATH); std::filesystem::path path(buffer); - path.remove_filename(); // 移除文件名,保留目录路径 - + path.remove_filename(); // 只保留目录路径 path /= debug ? WCFSPYDLL_DEBUG : WCFSPYDLL; if (!std::filesystem::exists(path)) { - MessageBox(NULL, path.c_str(), L"文件不存在", MB_ICONERROR); - return L""; + MessageBoxA(NULL, path.string().c_str(), "文件不存在", MB_ICONERROR); + return ""; } - return path.wstring(); + return path.string(); } int WxInitSDK(bool debug, int port) { - if (!ShowDisclaimer()) { + if (!show_disclaimer()) { exit(-1); // 用户拒绝协议,退出程序 } int status = 0; DWORD wcPid = 0; - spyDllPath = GetDllPath(debug); + spyDllPath = get_dll_path(debug); if (spyDllPath.empty()) { return ERROR_FILE_NOT_FOUND; // DLL 文件路径不存在 } status = util::open_wechat(&wcPid); if (status != 0) { - MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); + MessageBoxA(NULL, "打开微信失败", "WxInitSDK", 0); return status; } - if (!IsProcessX64(wcPid)) { - MessageBox(NULL, L"只支持 64 位微信", L"WxInitSDK", 0); - return -1; - } - std::this_thread::sleep_for(std::chrono::seconds(2)); // 等待微信打开 - wcProcess = InjectDll(wcPid, spyDllPath.c_str(), &spyBase); + wcProcess = inject_dll(wcPid, spyDllPath, &spyBase); if (wcProcess == NULL) { - MessageBox(NULL, L"注入失败", L"WxInitSDK", 0); + MessageBoxA(NULL, "注入失败", "WxInitSDK", 0); return -1; } - PortPath_t pp = { 0 }; - pp.port = port; - sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); + util::PortPath pp = { 0 }; + pp.port = port; + snprintf(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - if (!CallDllFuncEx(wcProcess, spyDllPath.c_str(), spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { - MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0); + if (!call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { + MessageBoxA(NULL, "初始化失败", "WxInitSDK", 0); return -1; } @@ -128,16 +124,16 @@ int WxInitSDK(bool debug, int port) int WxDestroySDK() { if (!injected) { + return 1; // 未注入 + } + + if (!call_dll_func(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL)) { return -1; } - if (!CallDllFunc(wcProcess, spyDllPath.c_str(), spyBase, "CleanupSpy", NULL)) { + if (!eject_dll(wcProcess, spyBase)) { return -2; } - if (!EjectDll(wcProcess, spyBase)) { - return -3; // TODO: Unify error codes - } - return 0; } From 1cbd3a3ebe9c81d6797b6a7dd27ea8d4d915dbee Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 21:00:29 +0800 Subject: [PATCH 29/41] Refatoring --- WeChatFerry/com/util.cpp | 6 +++--- WeChatFerry/com/util.h | 2 +- WeChatFerry/sdk/sdk.cpp | 11 ++++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index 2481124..9bc0753 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -18,8 +18,8 @@ namespace util { -constexpr std::wstring_view WECHATEXE = L"WeChat.exe"; -constexpr std::string_view WECHATWINDLL = "WeChatWin.dll"; +constexpr char WECHATEXE[] = "WeChat.exe"; +constexpr char WECHATWINDLL[] = "WeChatWin.dll"; std::wstring s2w(const std::string &s) { @@ -63,7 +63,7 @@ static DWORD get_wechat_pid() PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { - if (pe32.szExeFile == WECHATEXE) { + if (pe32.szExeFile == s2w(WECHATEXE)) { pid = pe32.th32ProcessID; break; } diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h index c4715cd..de61c80 100644 --- a/WeChatFerry/com/util.h +++ b/WeChatFerry/com/util.h @@ -15,7 +15,7 @@ struct PortPath { }; DWORD get_wechat_pid(); -int open_wechat(DWORD *pid); +int open_wechat(DWORD &pid); std::string get_wechat_version(); uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr); std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t addr); diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index 69ff632..6f9b4c3 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -19,9 +19,10 @@ static HANDLE wcProcess = NULL; static HMODULE spyBase = NULL; static std::string spyDllPath; -constexpr std::string_view WCFSDKDLL = "sdk.dll"; -constexpr std::string_view WCFSPYDLL = "spy.dll"; -constexpr std::string_view WCFSPYDLL_DEBUG = "spy_debug.dll"; +constexpr char WCFSDKDLL[] = "sdk.dll"; +constexpr char WCFSPYDLL[] = "spy.dll"; +constexpr char WCFSPYDLL_DEBUG[] = "spy_debug.dll"; + constexpr std::string_view DISCLAIMER_FLAG = ".license_accepted.flag"; constexpr std::string_view DISCLAIMER_TEXT_FILE = "DISCLAIMER.md"; @@ -95,7 +96,7 @@ int WxInitSDK(bool debug, int port) return ERROR_FILE_NOT_FOUND; // DLL 文件路径不存在 } - status = util::open_wechat(&wcPid); + status = util::open_wechat(wcPid); if (status != 0) { MessageBoxA(NULL, "打开微信失败", "WxInitSDK", 0); return status; @@ -112,7 +113,7 @@ int WxInitSDK(bool debug, int port) pp.port = port; snprintf(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - if (!call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { + if (!call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(util::PortPath), NULL)) { MessageBoxA(NULL, "初始化失败", "WxInitSDK", 0); return -1; } From 9e306e2452832583a1a9498ef6045893ad1e120e Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 22:07:36 +0800 Subject: [PATCH 30/41] Refactoring --- WeChatFerry/com/log.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp index 380a8c6..4a08c8b 100644 --- a/WeChatFerry/com/log.hpp +++ b/WeChatFerry/com/log.hpp @@ -1,5 +1,9 @@ #pragma once +#ifdef ENABLE_DEBUG_LOG +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#endif + #include #include #include @@ -58,11 +62,10 @@ inline void InitLogger(const std::string &path) spdlog::set_level(spdlog::level::debug); logger->flush_on(spdlog::level::debug); #else - spdlog::set_level(spdlog::level::info); logger->flush_on(spdlog::level::info); #endif - SPDLOG_DEBUG("Logger initialized with default settings."); + LOG_DEBUG("InitLogger with debug level"); } #ifdef ENABLE_DEBUG_LOG @@ -79,7 +82,7 @@ inline void log_buffer(uint8_t *buffer, size_t len) } } - SPDLOG_DEBUG(oss.str()); + LOG_DEBUG(oss.str()); } #endif From 0d228745acfc057a79588c70b6202090f61db187 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 22:29:54 +0800 Subject: [PATCH 31/41] Refactoring --- WeChatFerry/com/util.cpp | 47 +++++++++++++++++++++++++--------------- WeChatFerry/sdk/sdk.cpp | 4 +++- WeChatFerry/spy/spy.cpp | 5 +++-- WeChatFerry/spy/spy.h | 2 +- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp index 9bc0753..2c45632 100644 --- a/WeChatFerry/com/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -1,6 +1,7 @@ #include "util.h" #include +#include #include #include #include @@ -15,6 +16,8 @@ #pragma comment(lib, "shlwapi") #pragma comment(lib, "Version.lib") +namespace fs = std::filesystem; + namespace util { @@ -101,47 +104,57 @@ static std::optional get_wechat_win_dll_path() return std::nullopt; } - std::string dll_path = *wechat_path; - PathRemoveFileSpecA(dll_path.data()); - PathAppendA(dll_path.data(), WECHATWINDLL); + fs::path dll_path = *wechat_path; + dll_path = dll_path.parent_path(); - if (PathFileExistsA(dll_path.c_str())) { - return dll_path; + fs::path wechat_dll_path = dll_path / WECHATWINDLL; + if (fs::exists(wechat_dll_path)) { // 尝试直接查找 WeChatWin.dll + return wechat_dll_path.string(); } // 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29] - PathRemoveFileSpecA(dll_path.data()); - WIN32_FIND_DATAA find_data; - HANDLE hFind = FindFirstFileA((dll_path + "\\*.*").c_str(), &find_data); - if (hFind == INVALID_HANDLE_VALUE) { - return std::nullopt; + std::optional found_path; + for (const auto &entry : fs::directory_iterator(dll_path)) { + if (entry.is_directory()) { + fs::path possible_dll = entry.path() / WECHATWINDLL; + if (fs::exists(possible_dll)) { + found_path = possible_dll.string(); + break; // 取第一个找到的版本号文件夹 + } + } } - FindClose(hFind); - std::string versioned_path = dll_path + "\\" + find_data.cFileName + WECHATWINDLL; - return PathFileExistsA(versioned_path.c_str()) ? std::optional(versioned_path) : std::nullopt; + if (!found_path) { + LOG_ERROR("未找到 WeChatWin.dll"); + } + + return found_path; } -static std::optional get_file_version(const std::string &file_path) +static std::optional get_file_version(const std::string &path) { - if (!PathFileExistsA(file_path.c_str())) { + if (!PathFileExistsA(path.c_str())) { + LOG_ERROR("文件不存在: {}", path); return std::nullopt; } DWORD dummy = 0; - DWORD size = GetFileVersionInfoSizeA(file_path.c_str(), &dummy); + DWORD size = GetFileVersionInfoSizeA(path.c_str(), &dummy); if (size == 0) { + LOG_ERROR("无法获取文件版本信息大小: {}", path); return std::nullopt; } std::vector buffer(size); - if (!GetFileVersionInfoA(file_path.c_str(), 0, size, buffer.data())) { + if (!GetFileVersionInfoA(path.c_str(), 0, size, buffer.data())) { + LOG_ERROR("无法获取文件版本信息: {}", path); return std::nullopt; } VS_FIXEDFILEINFO *ver_info = nullptr; UINT ver_size = 0; if (!VerQueryValueA(buffer.data(), "\\", reinterpret_cast(&ver_info), &ver_size)) { + LOG_ERROR("无法获取文件版本信息: {}", path); return std::nullopt; } diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index 6f9b4c3..0635c70 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -113,8 +113,10 @@ int WxInitSDK(bool debug, int port) pp.port = port; snprintf(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - if (!call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(util::PortPath), NULL)) { + bool ok = call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(util::PortPath), &status); + if (!ok || status != 0) { MessageBoxA(NULL, "初始化失败", "WxInitSDK", 0); + WxDestroySDK(); return -1; } diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index 26fc287..785f116 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -11,7 +11,7 @@ constexpr std::string_view SUPPORT_VERSION = "3.9.11.25"; UINT64 g_WeChatWinDllAddr = 0; -void InitSpy(LPVOID args) +int InitSpy(LPVOID args) { auto *pp = static_cast(args); @@ -28,11 +28,12 @@ void InitSpy(LPVOID args) if (version != SUPPORT_VERSION) { LOG_ERROR(msg); MessageBoxA(NULL, msg.c_str(), "错误", MB_ICONERROR); - return; + return -1; } LOG_INFO(msg); RpcStartServer(pp->port); + return 0; } void CleanupSpy() diff --git a/WeChatFerry/spy/spy.h b/WeChatFerry/spy/spy.h index 3aa41dd..07825e6 100644 --- a/WeChatFerry/spy/spy.h +++ b/WeChatFerry/spy/spy.h @@ -2,5 +2,5 @@ #include "framework.h" -void InitSpy(int port); +int InitSpy(int port); void CleanupSpy(); From 53370ca8b6f66094330a22811f512bc9a47b7683 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 4 Feb 2025 22:52:36 +0800 Subject: [PATCH 32/41] Refactoring --- WeChatFerry/sdk/sdk.cpp | 13 +++++++------ WeChatFerry/spy/spy.cpp | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index 0635c70..e1dbdc8 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -108,20 +108,20 @@ int WxInitSDK(bool debug, int port) MessageBoxA(NULL, "注入失败", "WxInitSDK", 0); return -1; } + injected = true; util::PortPath pp = { 0 }; pp.port = port; snprintf(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - bool ok = call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(util::PortPath), &status); - if (!ok || status != 0) { - MessageBoxA(NULL, "初始化失败", "WxInitSDK", 0); + status = -3; // TODO: 统一错误码 + bool success = call_dll_func_ex(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(util::PortPath), + (DWORD *)&status); + if (!success || status != 0) { WxDestroySDK(); - return -1; } - injected = true; - return 0; + return status; } int WxDestroySDK() @@ -137,6 +137,7 @@ int WxDestroySDK() if (!eject_dll(wcProcess, spyBase)) { return -2; } + injected = false; return 0; } diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index 785f116..edb89b6 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -20,7 +20,7 @@ int InitSpy(LPVOID args) g_WeChatWinDllAddr = reinterpret_cast(dll_addr); } else { LOG_ERROR("获取 WeChatWin.dll 模块地址失败"); - return; // TODO: 退出进程,避免后面操作失败 + return -1; } std::string version = util::get_wechat_version(); @@ -28,7 +28,7 @@ int InitSpy(LPVOID args) if (version != SUPPORT_VERSION) { LOG_ERROR(msg); MessageBoxA(NULL, msg.c_str(), "错误", MB_ICONERROR); - return -1; + return -2; } LOG_INFO(msg); From b5d2f39002889ac6577babbac5b22987aa69348c Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 5 Feb 2025 08:16:44 +0800 Subject: [PATCH 33/41] Refactoring --- WeChatFerry/spy/spy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index edb89b6..db59d50 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -27,7 +27,7 @@ int InitSpy(LPVOID args) std::string msg = fmt::format("WCF 支持版本: {},当前版本: {}", SUPPORT_VERSION, version); if (version != SUPPORT_VERSION) { LOG_ERROR(msg); - MessageBoxA(NULL, msg.c_str(), "错误", MB_ICONERROR); + MessageBoxA(NULL, msg.c_str(), "微信版本错误", MB_ICONERROR); return -2; } From b99a3aa377ccebb9f40fadc8d2e4717846d2554c Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 5 Feb 2025 08:44:16 +0800 Subject: [PATCH 34/41] Refactoring --- WeChatFerry/spy/chatroom_mgmt.cpp | 2 +- WeChatFerry/spy/contact_mgmt.cpp | 2 +- WeChatFerry/spy/exec_sql.cpp | 2 +- WeChatFerry/spy/{fill_response.h => rpc_helper.h} | 0 WeChatFerry/spy/send_msg.cpp | 2 +- WeChatFerry/spy/user_info.cpp | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename WeChatFerry/spy/{fill_response.h => rpc_helper.h} (100%) diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index 5cef8df..d7d156f 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -1,9 +1,9 @@ #pragma execution_character_set("utf-8") #include "chatroom_mgmt.h" -#include "fill_response.h" #include "log.hpp" #include "pb_util.h" +#include "rpc_helper.h" #include "util.h" using namespace std; diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index 6c6c631..f100c3b 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -2,9 +2,9 @@ #include "contact_mgmt.h" -#include "fill_response.h" #include "log.hpp" #include "pb_util.h" +#include "rpc_helper.h" #include "util.h" using namespace std; diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 1993ecd..5581357 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -3,9 +3,9 @@ #include #include -#include "fill_response.h" #include "log.hpp" #include "pb_util.h" +#include "rpc_helper.h" #include "sqlite3.h" #include "util.h" diff --git a/WeChatFerry/spy/fill_response.h b/WeChatFerry/spy/rpc_helper.h similarity index 100% rename from WeChatFerry/spy/fill_response.h rename to WeChatFerry/spy/rpc_helper.h diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index 1134cbd..ff1609d 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -4,8 +4,8 @@ #include #include "exec_sql.h" -#include "fill_response.h" #include "log.hpp" +#include "rpc_helper.h" #include "spy_types.h" #include "user_info.h" #include "util.h" diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index 48ad23e..c58e471 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -3,8 +3,8 @@ #include #include -#include "fill_response.h" #include "log.hpp" +#include "rpc_helper.h" #include "util.h" extern UINT64 g_WeChatWinDllAddr; From 228ebbf4d1354c8d37cef21c2cfce28e12d0434b Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 5 Feb 2025 09:17:50 +0800 Subject: [PATCH 35/41] Refactoring --- WeChatFerry/sdk/SDK.vcxproj | 1 - WeChatFerry/sdk/SDK.vcxproj.filters | 3 -- WeChatFerry/spy/Spy.vcxproj | 29 ++++++++--------- WeChatFerry/spy/Spy.vcxproj.filters | 31 ++++++++++--------- ...chatroom_mgmt.cpp => chatroom_manager.cpp} | 2 +- .../{chatroom_mgmt.h => chatroom_manager.h} | 0 .../{contact_mgmt.cpp => contact_manager.cpp} | 2 +- .../spy/{contact_mgmt.h => contact_manager.h} | 0 .../{exec_sql.cpp => database_executor.cpp} | 2 +- .../spy/{exec_sql.h => database_executor.h} | 0 .../{receive_msg.cpp => message_handler.cpp} | 4 +-- .../spy/{receive_msg.h => message_handler.h} | 0 .../spy/{send_msg.cpp => message_sender.cpp} | 6 ++-- .../spy/{send_msg.h => message_sender.h} | 0 .../spy/{funcs.cpp => misc_manager.cpp} | 6 ++-- WeChatFerry/spy/{funcs.h => misc_manager.h} | 0 WeChatFerry/spy/rpc_server.cpp | 14 ++++----- .../{user_info.cpp => userinfo_manager.cpp} | 2 +- .../spy/{user_info.h => userinfo_manager.h} | 0 19 files changed, 51 insertions(+), 51 deletions(-) rename WeChatFerry/spy/{chatroom_mgmt.cpp => chatroom_manager.cpp} (99%) rename WeChatFerry/spy/{chatroom_mgmt.h => chatroom_manager.h} (100%) rename WeChatFerry/spy/{contact_mgmt.cpp => contact_manager.cpp} (99%) rename WeChatFerry/spy/{contact_mgmt.h => contact_manager.h} (100%) rename WeChatFerry/spy/{exec_sql.cpp => database_executor.cpp} (99%) rename WeChatFerry/spy/{exec_sql.h => database_executor.h} (100%) rename WeChatFerry/spy/{receive_msg.cpp => message_handler.cpp} (99%) rename WeChatFerry/spy/{receive_msg.h => message_handler.h} (100%) rename WeChatFerry/spy/{send_msg.cpp => message_sender.cpp} (99%) rename WeChatFerry/spy/{send_msg.h => message_sender.h} (100%) rename WeChatFerry/spy/{funcs.cpp => misc_manager.cpp} (99%) rename WeChatFerry/spy/{funcs.h => misc_manager.h} (100%) rename WeChatFerry/spy/{user_info.cpp => userinfo_manager.cpp} (98%) rename WeChatFerry/spy/{user_info.h => userinfo_manager.h} (100%) diff --git a/WeChatFerry/sdk/SDK.vcxproj b/WeChatFerry/sdk/SDK.vcxproj index 5f549ad..cb0fd9d 100644 --- a/WeChatFerry/sdk/SDK.vcxproj +++ b/WeChatFerry/sdk/SDK.vcxproj @@ -141,7 +141,6 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry - diff --git a/WeChatFerry/sdk/SDK.vcxproj.filters b/WeChatFerry/sdk/SDK.vcxproj.filters index 323d545..5adfeab 100644 --- a/WeChatFerry/sdk/SDK.vcxproj.filters +++ b/WeChatFerry/sdk/SDK.vcxproj.filters @@ -27,9 +27,6 @@ 头文件 - - 头文件 - diff --git a/WeChatFerry/spy/Spy.vcxproj b/WeChatFerry/spy/Spy.vcxproj index 6a66d2d..3f601af 100644 --- a/WeChatFerry/spy/Spy.vcxproj +++ b/WeChatFerry/spy/Spy.vcxproj @@ -247,19 +247,20 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry - - - + + + - - + + + - + - + @@ -268,16 +269,16 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry - - + + - - - + + + - + - + diff --git a/WeChatFerry/spy/Spy.vcxproj.filters b/WeChatFerry/spy/Spy.vcxproj.filters index 3bf11bb..dea6857 100644 --- a/WeChatFerry/spy/Spy.vcxproj.filters +++ b/WeChatFerry/spy/Spy.vcxproj.filters @@ -24,16 +24,16 @@ 头文件 - + 头文件 - + 头文件 - + 头文件 - + 头文件 @@ -63,16 +63,16 @@ nnrpc - + 头文件 - + 头文件 头文件 - + 头文件 @@ -87,6 +87,9 @@ 头文件 + + 头文件 + @@ -95,16 +98,16 @@ 源文件 - + 源文件 - + 源文件 - + 源文件 - + 源文件 @@ -125,13 +128,13 @@ nnrpc - + 源文件 - + 源文件 - + 源文件 diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_manager.cpp similarity index 99% rename from WeChatFerry/spy/chatroom_mgmt.cpp rename to WeChatFerry/spy/chatroom_manager.cpp index d7d156f..c8b2042 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_manager.cpp @@ -1,6 +1,6 @@ #pragma execution_character_set("utf-8") -#include "chatroom_mgmt.h" +#include "chatroom_manager.h" #include "log.hpp" #include "pb_util.h" #include "rpc_helper.h" diff --git a/WeChatFerry/spy/chatroom_mgmt.h b/WeChatFerry/spy/chatroom_manager.h similarity index 100% rename from WeChatFerry/spy/chatroom_mgmt.h rename to WeChatFerry/spy/chatroom_manager.h diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_manager.cpp similarity index 99% rename from WeChatFerry/spy/contact_mgmt.cpp rename to WeChatFerry/spy/contact_manager.cpp index f100c3b..17cc7f8 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_manager.cpp @@ -1,6 +1,6 @@ #pragma execution_character_set("utf-8") -#include "contact_mgmt.h" +#include "contact_manager.h" #include "log.hpp" #include "pb_util.h" diff --git a/WeChatFerry/spy/contact_mgmt.h b/WeChatFerry/spy/contact_manager.h similarity index 100% rename from WeChatFerry/spy/contact_mgmt.h rename to WeChatFerry/spy/contact_manager.h diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/database_executor.cpp similarity index 99% rename from WeChatFerry/spy/exec_sql.cpp rename to WeChatFerry/spy/database_executor.cpp index 5581357..7ff8290 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/database_executor.cpp @@ -1,4 +1,4 @@ -#include "exec_sql.h" +#include "database_executor.h" #include #include diff --git a/WeChatFerry/spy/exec_sql.h b/WeChatFerry/spy/database_executor.h similarity index 100% rename from WeChatFerry/spy/exec_sql.h rename to WeChatFerry/spy/database_executor.h diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/message_handler.cpp similarity index 99% rename from WeChatFerry/spy/receive_msg.cpp rename to WeChatFerry/spy/message_handler.cpp index ceab7dc..cf8b884 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/message_handler.cpp @@ -1,4 +1,4 @@ -#include "receive_msg.h" +#include "message_handler.h" #include #include @@ -7,7 +7,7 @@ #include "framework.h" #include "log.hpp" -#include "user_info.h" +#include "userinfo_manager.h" #include "util.h" extern QWORD g_WeChatWinDllAddr; diff --git a/WeChatFerry/spy/receive_msg.h b/WeChatFerry/spy/message_handler.h similarity index 100% rename from WeChatFerry/spy/receive_msg.h rename to WeChatFerry/spy/message_handler.h diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/message_sender.cpp similarity index 99% rename from WeChatFerry/spy/send_msg.cpp rename to WeChatFerry/spy/message_sender.cpp index ff1609d..36b4d5f 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/message_sender.cpp @@ -1,13 +1,13 @@ -#include "send_msg.h" +#include "message_sender.h" #include #include -#include "exec_sql.h" +#include "database_executor.h" #include "log.hpp" #include "rpc_helper.h" #include "spy_types.h" -#include "user_info.h" +#include "userinfo_manager.h" #include "util.h" extern QWORD g_WeChatWinDllAddr; diff --git a/WeChatFerry/spy/send_msg.h b/WeChatFerry/spy/message_sender.h similarity index 100% rename from WeChatFerry/spy/send_msg.h rename to WeChatFerry/spy/message_sender.h diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/misc_manager.cpp similarity index 99% rename from WeChatFerry/spy/funcs.cpp rename to WeChatFerry/spy/misc_manager.cpp index b27642d..f6f252f 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/misc_manager.cpp @@ -1,5 +1,5 @@ #pragma warning(disable : 4244) -#include "funcs.h" +#include "misc_manager.h" #include #include @@ -7,9 +7,9 @@ #include "framework.h" #include "codec.h" -#include "exec_sql.h" +#include "database_executor.h" #include "log.hpp" -#include "receive_msg.h" +#include "message_handler.h" #include "spy_types.h" #include "util.h" diff --git a/WeChatFerry/spy/funcs.h b/WeChatFerry/spy/misc_manager.h similarity index 100% rename from WeChatFerry/spy/funcs.h rename to WeChatFerry/spy/misc_manager.h diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 111a0a1..96e71f7 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -20,18 +20,18 @@ #include "wcf.pb.h" -#include "chatroom_mgmt.h" -#include "contact_mgmt.h" -#include "exec_sql.h" -#include "funcs.h" +#include "chatroom_manager.h" +#include "contact_manager.h" +#include "database_executor.h" +#include "misc_manager.h" #include "log.hpp" #include "pb_types.h" #include "pb_util.h" -#include "receive_msg.h" -#include "send_msg.h" +#include "message_handler.h" +#include "message_sender.h" #include "spy.h" #include "spy_types.h" -#include "user_info.h" +#include "userinfo_manager.h" #include "util.h" namespace fs = std::filesystem; diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/userinfo_manager.cpp similarity index 98% rename from WeChatFerry/spy/user_info.cpp rename to WeChatFerry/spy/userinfo_manager.cpp index c58e471..b8720ef 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/userinfo_manager.cpp @@ -1,4 +1,4 @@ -#include "user_info.h" +#include "userinfo_manager.h" #include #include diff --git a/WeChatFerry/spy/user_info.h b/WeChatFerry/spy/userinfo_manager.h similarity index 100% rename from WeChatFerry/spy/user_info.h rename to WeChatFerry/spy/userinfo_manager.h From 505eefd03ce3f1fe0311dc4adff7d20937d3b735 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 5 Feb 2025 16:05:40 +0800 Subject: [PATCH 36/41] Refactoring --- WeChatFerry/spy/chatroom_manager.cpp | 4 +- WeChatFerry/spy/chatroom_manager.h | 4 +- WeChatFerry/spy/contact_manager.cpp | 4 +- WeChatFerry/spy/contact_manager.h | 4 +- WeChatFerry/spy/database_executor.cpp | 4 +- WeChatFerry/spy/database_executor.h | 4 +- WeChatFerry/spy/message_handler.cpp | 43 +++++++++++---------- WeChatFerry/spy/message_handler.h | 12 ++++-- WeChatFerry/spy/message_sender.cpp | 54 ++++++++++++++------------- WeChatFerry/spy/message_sender.h | 17 ++++++--- WeChatFerry/spy/misc_manager.cpp | 8 ++-- WeChatFerry/spy/rpc_server.cpp | 26 ++++++------- WeChatFerry/spy/userinfo_manager.cpp | 4 +- WeChatFerry/spy/userinfo_manager.h | 4 +- 14 files changed, 104 insertions(+), 88 deletions(-) diff --git a/WeChatFerry/spy/chatroom_manager.cpp b/WeChatFerry/spy/chatroom_manager.cpp index c8b2042..00a9bf7 100644 --- a/WeChatFerry/spy/chatroom_manager.cpp +++ b/WeChatFerry/spy/chatroom_manager.cpp @@ -9,7 +9,7 @@ using namespace std; extern QWORD g_WeChatWinDllAddr; -namespace chatroom_mgmt +namespace chatroom { #define OS_GET_CHATROOM_MGR 0x1B83BD0 #define OS_ADD_MEMBERS 0x2155100 @@ -106,4 +106,4 @@ bool rpc_invite_chatroom_member(const string &roomid, const string &wxids, uint8 out, len, [&](Response &rsp) { rsp.msg.status = invite_chatroom_member(roomid, wxids); }); } -} // namespace chatroom_mgmt +} // namespace chatroom diff --git a/WeChatFerry/spy/chatroom_manager.h b/WeChatFerry/spy/chatroom_manager.h index 2f9b9a6..9791ed7 100644 --- a/WeChatFerry/spy/chatroom_manager.h +++ b/WeChatFerry/spy/chatroom_manager.h @@ -2,7 +2,7 @@ #include -namespace chatroom_mgmt +namespace chatroom { // 添加成员到群聊 @@ -19,4 +19,4 @@ bool rpc_add_chatroom_member(const std::string &roomid, const std::string &wxids bool rpc_del_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); bool rpc_invite_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); -} // namespace chatroom_mgmt +} // namespace chatroom diff --git a/WeChatFerry/spy/contact_manager.cpp b/WeChatFerry/spy/contact_manager.cpp index 17cc7f8..bb4efe8 100644 --- a/WeChatFerry/spy/contact_manager.cpp +++ b/WeChatFerry/spy/contact_manager.cpp @@ -11,7 +11,7 @@ using namespace std; extern QWORD g_WeChatWinDllAddr; -namespace contact_mgmt +namespace contact { #define OS_GET_CONTACT_MGR 0x1B417A0 #define OS_GET_CONTACT_LIST 0x219ED10 @@ -218,4 +218,4 @@ bool rpc_accept_friend(const string &v3, const string &v4, int scene, uint8_t *o out, len, [&](Response &rsp) { rsp.msg.status = accept_new_friend(v3, v4, scene); }); } -} // namespace contact_mgmt +} // namespace contact diff --git a/WeChatFerry/spy/contact_manager.h b/WeChatFerry/spy/contact_manager.h index 0fb8091..5b330c0 100644 --- a/WeChatFerry/spy/contact_manager.h +++ b/WeChatFerry/spy/contact_manager.h @@ -5,7 +5,7 @@ #include "pb_types.h" -namespace contact_mgmt +namespace contact { // 获取所有联系人 @@ -25,4 +25,4 @@ bool rpc_get_contacts(uint8_t *out, size_t *len); bool rpc_get_contact_info(const std::string &wxid, uint8_t *out, size_t *len); bool rpc_accept_friend(const std::string &v3, const std::string &v4, int scene, uint8_t *out, size_t *len); -} // namespace contact_mgmt +} // namespace contact diff --git a/WeChatFerry/spy/database_executor.cpp b/WeChatFerry/spy/database_executor.cpp index 7ff8290..3f850a3 100644 --- a/WeChatFerry/spy/database_executor.cpp +++ b/WeChatFerry/spy/database_executor.cpp @@ -11,7 +11,7 @@ extern UINT64 g_WeChatWinDllAddr; -namespace exec_sql +namespace db { #define OFFSET_DB_INSTANCE 0x5902000 #define OFFSET_DB_MICROMSG 0xB8 @@ -287,4 +287,4 @@ bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *o }); } -} // namespace exec_sql +} // namespace db diff --git a/WeChatFerry/spy/database_executor.h b/WeChatFerry/spy/database_executor.h index 411c338..4f2752d 100644 --- a/WeChatFerry/spy/database_executor.h +++ b/WeChatFerry/spy/database_executor.h @@ -6,7 +6,7 @@ #include "pb_types.h" -namespace exec_sql +namespace db { // 获取数据库名称列表 @@ -29,4 +29,4 @@ bool rpc_get_db_names(uint8_t *out, size_t *len); bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len); bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len); -} // namespace exec_sql +} // namespace db diff --git a/WeChatFerry/spy/message_handler.cpp b/WeChatFerry/spy/message_handler.cpp index cf8b884..849382e 100644 --- a/WeChatFerry/spy/message_handler.cpp +++ b/WeChatFerry/spy/message_handler.cpp @@ -33,7 +33,9 @@ extern QWORD g_WeChatWinDllAddr; #define OS_PYQ_MSG_CALL 0x2E42C90 #define OS_WXLOG 0x2613D20 -QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) +namespace message +{ +QWORD Handler::DispatchMsg(QWORD arg1, QWORD arg2) { auto &handler = getInstance(); WxMsg_t wxMsg = {}; @@ -50,10 +52,10 @@ QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) if (wxMsg.roomid.find("@chatroom") != std::string::npos) { wxMsg.is_group = true; wxMsg.sender - = wxMsg.is_self ? user_info::get_self_wxid() : util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_WXID); + = wxMsg.is_self ? userinfo::get_self_wxid() : util::get_str_by_wstr_addr(arg2 + OS_RECV_MSG_WXID); } else { wxMsg.is_group = false; - wxMsg.sender = wxMsg.is_self ? user_info::get_self_wxid() : wxMsg.roomid; + wxMsg.sender = wxMsg.is_self ? userinfo::get_self_wxid() : wxMsg.roomid; } } catch (const std::exception &e) { LOG_ERROR(util::gb2312_to_utf8(e.what())); @@ -68,8 +70,8 @@ QWORD MessageHandler::DispatchMsg(QWORD arg1, QWORD arg2) return handler.realRecvMsg(arg1, arg2); } -QWORD MessageHandler::PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, - QWORD a9, QWORD a10, QWORD a11, QWORD a12) +QWORD Handler::PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, QWORD a9, + QWORD a10, QWORD a11, QWORD a12) { auto &handler = getInstance(); @@ -82,7 +84,7 @@ QWORD MessageHandler::PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a return p; } -void MessageHandler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) +void Handler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) { auto &handler = getInstance(); QWORD startAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_START); @@ -114,27 +116,27 @@ void MessageHandler::DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) } } -MessageHandler &MessageHandler::getInstance() +Handler &Handler::getInstance() { - static MessageHandler instance; + static Handler instance; return instance; } -MessageHandler::MessageHandler() +Handler::Handler() { isLogging = false; isListeningMsg = false; isListeningPyq = false; } -MessageHandler::~MessageHandler() +Handler::~Handler() { DisableLog(); UnListenMsg(); UnListenPyq(); } -MsgTypes_t MessageHandler::GetMsgTypes() +MsgTypes_t Handler::GetMsgTypes() { return { { 0x00, "朋友圈消息" }, { 0x01, "文字" }, @@ -171,7 +173,7 @@ MsgTypes_t MessageHandler::GetMsgTypes() { 0x41000031, "文件" } }; } -std::optional MessageHandler::popMessage() +std::optional Handler::popMessage() { std::lock_guard lock(mutex_); if (msgQueue_.empty()) { @@ -182,7 +184,7 @@ std::optional MessageHandler::popMessage() return msg; } -int MessageHandler::EnableLog() +int Handler::EnableLog() { if (isLogging) return 1; @@ -196,7 +198,7 @@ int MessageHandler::EnableLog() return 0; } -int MessageHandler::DisableLog() +int Handler::DisableLog() { if (!isLogging) return 1; if (MH_DisableHook(funcWxLog) != MH_OK) return -1; @@ -205,7 +207,7 @@ int MessageHandler::DisableLog() return 0; } -int MessageHandler::ListenMsg() +int Handler::ListenMsg() { if (isListeningMsg) return 1; @@ -218,7 +220,7 @@ int MessageHandler::ListenMsg() return 0; } -int MessageHandler::UnListenMsg() +int Handler::UnListenMsg() { if (!isListeningMsg) return 1; if (MH_DisableHook(funcRecvMsg) != MH_OK) return -1; @@ -227,7 +229,7 @@ int MessageHandler::UnListenMsg() return 0; } -int MessageHandler::ListenPyq() +int Handler::ListenPyq() { if (isListeningPyq) return 1; @@ -240,7 +242,7 @@ int MessageHandler::ListenPyq() return 0; } -int MessageHandler::UnListenPyq() +int Handler::UnListenPyq() { if (!isListeningPyq) return 1; if (MH_DisableHook(funcRecvPyq) != MH_OK) return -1; @@ -249,7 +251,7 @@ int MessageHandler::UnListenPyq() return 0; } -MH_STATUS MessageHandler::InitializeHook() +MH_STATUS Handler::InitializeHook() { if (isMH_Initialized) return MH_OK; MH_STATUS status = MH_Initialize(); @@ -257,10 +259,11 @@ MH_STATUS MessageHandler::InitializeHook() return status; } -MH_STATUS MessageHandler::UninitializeHook() +MH_STATUS Handler::UninitializeHook() { if (!isMH_Initialized || isLogging || isListeningMsg || isListeningPyq) return MH_OK; MH_STATUS status = MH_Uninitialize(); if (status == MH_OK) isMH_Initialized = false; return status; } +} \ No newline at end of file diff --git a/WeChatFerry/spy/message_handler.h b/WeChatFerry/spy/message_handler.h index a2559ef..1fb06ee 100644 --- a/WeChatFerry/spy/message_handler.h +++ b/WeChatFerry/spy/message_handler.h @@ -11,10 +11,12 @@ #include "pb_types.h" #include "spy_types.h" -class MessageHandler +namespace message { + +class Handler { public: - static MessageHandler &getInstance(); + static Handler &getInstance(); // 0: 成功, -1: 失败, 1: 已经开启 int EnableLog(); @@ -35,8 +37,8 @@ public: std::mutex &getMutex() { return mutex_; }; private: - MessageHandler(); - ~MessageHandler(); + Handler(); + ~Handler(); mutable std::mutex mutex_; std::condition_variable cv_; @@ -64,3 +66,5 @@ private: QWORD a10, QWORD a11, QWORD a12); static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3); }; + +} // namespace message diff --git a/WeChatFerry/spy/message_sender.cpp b/WeChatFerry/spy/message_sender.cpp index 36b4d5f..0c79503 100644 --- a/WeChatFerry/spy/message_sender.cpp +++ b/WeChatFerry/spy/message_sender.cpp @@ -29,13 +29,16 @@ extern QWORD g_WeChatWinDllAddr; #define OS_XML_BUFSIGN 0x24F0D70 #define OS_SEND_XML 0x20CF360 -SendMsgManager &SendMsgManager::get_instance() +namespace message { - static SendMsgManager instance; + +Sender &Sender::get_instance() +{ + static Sender instance; return instance; } -SendMsgManager::SendMsgManager() +Sender::Sender() { func_new = reinterpret_cast(g_WeChatWinDllAddr + OS_NEW); func_free = reinterpret_cast(g_WeChatWinDllAddr + OS_FREE); @@ -50,16 +53,16 @@ SendMsgManager::SendMsgManager() func_send_xml = reinterpret_cast(g_WeChatWinDllAddr + OS_SEND_XML); } -std::unique_ptr SendMsgManager::new_wx_string(const char *str) +std::unique_ptr Sender::new_wx_string(const char *str) { return new_wx_string(str ? std::string(str) : std::string()); } -std::unique_ptr SendMsgManager::new_wx_string(const std::string &str) +std::unique_ptr Sender::new_wx_string(const std::string &str) { return std::make_unique(util::s2w(str)); } -std::vector SendMsgManager::parse_wxids(const string &wxids) +std::vector Sender::parse_wxids(const string &wxids) { vector wx_members; wstringstream wss(util::s2w(wxids)); @@ -70,7 +73,7 @@ std::vector SendMsgManager::parse_wxids(const string &wxids) return wx_members; } -void SendMsgManager::send_text(const std::string &wxid, const std::string &msg, const std::string &at_wxids) +void Sender::send_text(const std::string &wxid, const std::string &msg, const std::string &at_wxids) { auto wxWxid = new_wx_string(wxid); auto wxMsg = new_wx_string(msg); @@ -91,7 +94,7 @@ void SendMsgManager::send_text(const std::string &wxid, const std::string &msg, func_free(reinterpret_cast(&buffer)); } -void SendMsgManager::send_image(const std::string &wxid, const std::string &path) +void Sender::send_image(const std::string &wxid, const std::string &path) { auto wxWxid = new_wx_string(wxid); auto wxPath = new_wx_string(path); @@ -116,7 +119,7 @@ void SendMsgManager::send_image(const std::string &wxid, const std::string &path func_free(pMsgTmp); } -void SendMsgManager::send_file(const std::string &wxid, const std::string &path) +void Sender::send_file(const std::string &wxid, const std::string &path) { auto wxWxid = new_wx_string(wxid); auto wxPath = new_wx_string(path); @@ -135,8 +138,7 @@ void SendMsgManager::send_file(const std::string &wxid, const std::string &path) func_free(pMsg); } -void SendMsgManager::send_xml(const std::string &receiver, const std::string &xml, const std::string &path, - uint64_t type) +void Sender::send_xml(const std::string &receiver, const std::string &xml, const std::string &path, uint64_t type) { std::unique_ptr buff(new char[0x500]()); std::unique_ptr buff2(new char[0x500]()); @@ -151,7 +153,7 @@ void SendMsgManager::send_xml(const std::string &receiver, const std::string &xm auto wxReceiver = new_wx_string(receiver); auto wxXml = new_wx_string(xml); auto wxPath = new_wx_string(path); - auto wxSender = new_wx_string(user_info::get_self_wxid()); + auto wxSender = new_wx_string(userinfo::get_self_wxid()); func_send_xml(reinterpret_cast(buff.get()), reinterpret_cast(wxSender.get()), reinterpret_cast(wxReceiver.get()), reinterpret_cast(wxXml.get()), @@ -162,7 +164,7 @@ void SendMsgManager::send_xml(const std::string &receiver, const std::string &xm func_free(reinterpret_cast(buff2.get())); } -void SendMsgManager::send_emotion(const std::string &wxid, const std::string &path) +void Sender::send_emotion(const std::string &wxid, const std::string &path) { auto wxWxid = new_wx_string(wxid); auto wxPath = new_wx_string(path); @@ -180,7 +182,7 @@ void SendMsgManager::send_emotion(const std::string &wxid, const std::string &pa reinterpret_cast(buff.get())); } -int SendMsgManager::send_rich_text(const RichText &rt) +int Sender::send_rich_text(const RichText &rt) { #define SRTM_SIZE 0x3F0 QWORD status = -1; @@ -216,7 +218,7 @@ int SendMsgManager::send_rich_text(const RichText &rt) return static_cast(status); } -int SendMsgManager::send_pat(const std::string &roomid, const std::string &wxid) +int Sender::send_pat(const std::string &roomid, const std::string &wxid) { QWORD status = -1; @@ -228,12 +230,12 @@ int SendMsgManager::send_pat(const std::string &roomid, const std::string &wxid) return static_cast(status); } -int SendMsgManager::forward(QWORD msgid, const std::string &receiver) +int Sender::forward(QWORD msgid, const std::string &receiver) { uint32_t dbIdx = 0; QWORD localId = 0; - if (exec_sql::get_local_id_and_dbidx(msgid, &localId, &dbIdx) != 0) { + if (db::get_local_id_and_dbidx(msgid, &localId, &dbIdx) != 0) { LOG_ERROR("Failed to get localId, Please check id: {}", msgid); return -1; } @@ -247,7 +249,7 @@ int SendMsgManager::forward(QWORD msgid, const std::string &receiver) } // RPC 方法 -bool SendMsgManager::rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len) +bool Sender::rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (text.msg == nullptr || text.receiver == nullptr || strlen(text.msg) == 0 || strlen(text.receiver) == 0) { @@ -260,7 +262,7 @@ bool SendMsgManager::rpc_send_text(const TextMsg &text, uint8_t *out, size_t *le }); } -bool SendMsgManager::rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { @@ -273,7 +275,7 @@ bool SendMsgManager::rpc_send_image(const std::string &path, const std::string & }); } -bool SendMsgManager::rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { @@ -286,7 +288,7 @@ bool SendMsgManager::rpc_send_file(const std::string &path, const std::string &r }); } -bool SendMsgManager::rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { @@ -299,7 +301,7 @@ bool SendMsgManager::rpc_send_emotion(const std::string &path, const std::string }); } -bool SendMsgManager::rpc_send_xml(const XmlMsg &xml, uint8_t *out, size_t *len) +bool Sender::rpc_send_xml(const XmlMsg &xml, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (xml.content == nullptr || xml.receiver == nullptr) { @@ -312,7 +314,7 @@ bool SendMsgManager::rpc_send_xml(const XmlMsg &xml, uint8_t *out, size_t *len) }); } -bool SendMsgManager::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len) +bool Sender::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (rt.receiver == nullptr) { @@ -324,7 +326,7 @@ bool SendMsgManager::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t }); } -bool SendMsgManager::rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len) +bool Sender::rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (roomid.empty() || wxid.empty()) { @@ -336,7 +338,7 @@ bool SendMsgManager::rpc_send_pat(const std::string &roomid, const std::string & }); } -bool SendMsgManager::rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { if (receiver.empty()) { @@ -347,3 +349,5 @@ bool SendMsgManager::rpc_forward(uint64_t msgid, const std::string &receiver, ui } }); } + +} \ No newline at end of file diff --git a/WeChatFerry/spy/message_sender.h b/WeChatFerry/spy/message_sender.h index 66908d6..e528065 100644 --- a/WeChatFerry/spy/message_sender.h +++ b/WeChatFerry/spy/message_sender.h @@ -7,10 +7,13 @@ #include "spy_types.h" #include "wcf.pb.h" -class SendMsgManager +namespace message +{ + +class Sender { public: - static SendMsgManager &get_instance(); + static Sender &get_instance(); void send_text(const std::string &wxid, const std::string &msg, const std::string &at_wxids = ""); void send_image(const std::string &wxid, const std::string &path); @@ -32,11 +35,11 @@ public: bool rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len); private: - SendMsgManager(); - ~SendMsgManager() = default; + Sender(); + ~Sender() = default; - SendMsgManager(const SendMsgManager &) = delete; - SendMsgManager &operator=(const SendMsgManager &) = delete; + Sender(const Sender &) = delete; + Sender &operator=(const Sender &) = delete; using New_t = QWORD (*)(QWORD); using Free_t = QWORD (*)(QWORD); @@ -73,3 +76,5 @@ private: std::unique_ptr new_wx_string(const std::string &str); std::vector parse_wxids(const std::string &wxids); }; + +} \ No newline at end of file diff --git a/WeChatFerry/spy/misc_manager.cpp b/WeChatFerry/spy/misc_manager.cpp index f6f252f..6454c0b 100644 --- a/WeChatFerry/spy/misc_manager.cpp +++ b/WeChatFerry/spy/misc_manager.cpp @@ -172,7 +172,7 @@ static int GetNextPage(QWORD id) int RefreshPyq(QWORD id) { - auto &msgHandler = MessageHandler::getInstance(); + auto &msgHandler = message::Handler::getInstance(); if (!msgHandler.isPyqListening()) { LOG_ERROR("没有启动朋友圈消息接收,参考:enable_receiving_msg"); return -1; @@ -203,7 +203,7 @@ int DownloadAttach(QWORD id, string thumb, string extra) return 0; } - if (exec_sql::get_local_id_and_dbidx(id, &localId, &dbIdx) != 0) { + if (db::get_local_id_and_dbidx(id, &localId, &dbIdx) != 0) { LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id)); return status; } @@ -286,7 +286,7 @@ string GetAudio(QWORD id, string dir) return mp3path; } - vector silk = exec_sql::get_audio_data(id); + vector silk = db::get_audio_data(id); if (silk.size() == 0) { LOG_ERROR("Empty audio data."); return ""; @@ -306,7 +306,7 @@ string GetPCMAudio(uint64_t id, string dir, int32_t sr) return pcmpath; } vector pcm; - vector silk = exec_sql::get_audio_data(id); + vector silk = db::get_audio_data(id); if (silk.size() == 0) { LOG_ERROR("Empty audio data."); return ""; diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 96e71f7..dbbbf36 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -45,8 +45,8 @@ static HANDLE msgThread = NULL; static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 -auto &msgHandler = MessageHandler::getInstance(); -auto &sendMgr = SendMsgManager::get_instance(); +auto &msgHandler = message::Handler::getInstance(); +auto &sendMgr = message::Sender::get_instance(); static std::string BuildUrl(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } @@ -77,7 +77,7 @@ static bool func_is_login(uint8_t *out, size_t *len) static bool func_get_self_wxid(uint8_t *out, size_t *len) { return FillResponse(Response_str_tag, out, len, [](Response &rsp) { - std::string wxid = user_info::get_self_wxid(); + std::string wxid = userinfo::get_self_wxid(); rsp.msg.str = wxid.empty() ? nullptr : (char *)wxid.c_str(); }); } @@ -85,7 +85,7 @@ static bool func_get_self_wxid(uint8_t *out, size_t *len) static bool func_get_user_info(uint8_t *out, size_t *len) { return FillResponse(Response_ui_tag, out, len, [](Response &rsp) { - UserInfo_t ui = user_info::get_user_info(); + UserInfo_t ui = userinfo::get_user_info(); rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); rsp.msg.ui.name = (char *)ui.name.c_str(); rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); @@ -105,7 +105,7 @@ static bool func_get_msg_types(uint8_t *out, size_t *len) static bool func_get_contacts(uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [](Response &rsp) { - std::vector contacts = contact_mgmt::get_contacts(); + std::vector contacts = contact::get_contacts(); rsp.msg.contacts.contacts.funcs.encode = encode_contacts; rsp.msg.contacts.contacts.arg = &contacts; }); @@ -114,7 +114,7 @@ static bool func_get_contacts(uint8_t *out, size_t *len) static bool func_get_db_names(uint8_t *out, size_t *len) { return FillResponse(Response_dbs_tag, out, len, [](Response &rsp) { - static DbNames_t dbnames = exec_sql::get_db_names(); + static DbNames_t dbnames = db::get_db_names(); rsp.msg.dbs.names.funcs.encode = encode_dbnames; rsp.msg.dbs.names.arg = &dbnames; }); @@ -123,7 +123,7 @@ static bool func_get_db_names(uint8_t *out, size_t *len) static bool func_get_db_tables(char *db, uint8_t *out, size_t *len) { return FillResponse(Response_tables_tag, out, len, [db](Response &rsp) { - static DbTables_t tables = exec_sql::get_db_tables(db); + static DbTables_t tables = db::get_db_tables(db); rsp.msg.tables.tables.funcs.encode = encode_tables; rsp.msg.tables.tables.arg = &tables; }); @@ -355,7 +355,7 @@ static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) if ((db == nullptr) || (sql == nullptr)) { LOG_ERROR("Empty db or sql."); } else { - rows = exec_sql::exec_db_query(db, sql); + rows = db::exec_db_query(db, sql); } rsp.msg.rows.rows.arg = &rows; rsp.msg.rows.rows.funcs.encode = encode_rows; @@ -410,7 +410,7 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, LOG_ERROR("Empty V3 or V4."); rsp.msg.status = -1; } else { - rsp.msg.status = contact_mgmt::accept_new_friend(v3, v4, scene); + rsp.msg.status = contact::accept_new_friend(v3, v4, scene); } }); } @@ -418,7 +418,7 @@ static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, static bool func_get_contact_info(std::string wxid, uint8_t *out, size_t *len) { return FillResponse(Response_contacts_tag, out, len, [wxid](Response &rsp) { - std::vector contacts = { contact_mgmt::get_contact_by_wxid(wxid) }; + std::vector contacts = { contact::get_contact_by_wxid(wxid) }; rsp.msg.contacts.contacts.funcs.encode = encode_contacts; rsp.msg.contacts.contacts.arg = &contacts; }); @@ -458,7 +458,7 @@ static bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_ LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = chatroom_mgmt::add_chatroom_member(roomid, wxids); + rsp.msg.status = chatroom::add_chatroom_member(roomid, wxids); } }); } @@ -470,7 +470,7 @@ static bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_ LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = chatroom_mgmt::del_chatroom_member(roomid, wxids); + rsp.msg.status = chatroom::del_chatroom_member(roomid, wxids); } }); } @@ -482,7 +482,7 @@ static bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, si LOG_ERROR("Empty roomid or wxids."); rsp.msg.status = -1; } else { - rsp.msg.status = chatroom_mgmt::invite_chatroom_member(roomid, wxids); + rsp.msg.status = chatroom::invite_chatroom_member(roomid, wxids); } }); } diff --git a/WeChatFerry/spy/userinfo_manager.cpp b/WeChatFerry/spy/userinfo_manager.cpp index b8720ef..eddf0d5 100644 --- a/WeChatFerry/spy/userinfo_manager.cpp +++ b/WeChatFerry/spy/userinfo_manager.cpp @@ -9,7 +9,7 @@ extern UINT64 g_WeChatWinDllAddr; -namespace user_info +namespace userinfo { #define OS_USER_HOME 0x5932770 #define OS_USER_WXID 0x595C270 @@ -85,4 +85,4 @@ bool rpc_get_user_info(uint8_t *out, size_t *len) }); } -} // namespace user_info +} // namespace userinfo diff --git a/WeChatFerry/spy/userinfo_manager.h b/WeChatFerry/spy/userinfo_manager.h index f248ba7..6868817 100644 --- a/WeChatFerry/spy/userinfo_manager.h +++ b/WeChatFerry/spy/userinfo_manager.h @@ -5,7 +5,7 @@ #include "pb_types.h" -namespace user_info +namespace userinfo { // 获取 WeChat 数据存储路径 @@ -21,4 +21,4 @@ UserInfo_t get_user_info(); bool rpc_get_self_wxid(uint8_t *out, size_t *len); bool rpc_get_user_info(uint8_t *out, size_t *len); -} // namespace user_info +} // namespace userinfo From d4707997ba2a82c8ef67d3da996df9529af0719c Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 5 Feb 2025 23:07:46 +0800 Subject: [PATCH 37/41] Refacoring --- WeChatFerry/spy/misc_manager.cpp | 239 ++++++++++++------------------- WeChatFerry/spy/misc_manager.h | 44 ++++-- WeChatFerry/spy/rpc_server.cpp | 24 ++-- 3 files changed, 139 insertions(+), 168 deletions(-) diff --git a/WeChatFerry/spy/misc_manager.cpp b/WeChatFerry/spy/misc_manager.cpp index 6454c0b..d6b9afe 100644 --- a/WeChatFerry/spy/misc_manager.cpp +++ b/WeChatFerry/spy/misc_manager.cpp @@ -18,6 +18,8 @@ namespace fs = std::filesystem; extern QWORD g_WeChatWinDllAddr; +namespace misc +{ #define HEADER_PNG1 0x89 #define HEADER_PNG2 0x50 #define HEADER_JPG1 0xFF @@ -38,117 +40,73 @@ extern QWORD g_WeChatWinDllAddr; #define OS_PUSH_ATTACH_TASK 0x1CDF4E0 #define OS_LOGIN_QR_CODE 0x59620D8 -typedef QWORD (*GetSNSDataMgr_t)(); -typedef QWORD (*GetSnsTimeLineMgr_t)(); -typedef QWORD (*GetSNSFirstPage_t)(QWORD, QWORD, QWORD); -typedef QWORD (*GetSNSNextPageScene_t)(QWORD, QWORD); -typedef QWORD (*GetChatMgr_t)(); -typedef QWORD (*NewChatMsg_t)(QWORD); -typedef QWORD (*FreeChatMsg_t)(QWORD); -typedef QWORD (*GetPreDownLoadMgr_t)(); -typedef QWORD (*GetMgrByPrefixLocalId_t)(QWORD, QWORD); -typedef QWORD (*PushAttachTask_t)(QWORD, QWORD, QWORD, QWORD); -typedef QWORD (*GetOCRManager_t)(); -typedef QWORD (*DoOCRTask_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); +using get_sns_data_mgr_t = QWORD (*)(); +using get_sns_timeline_mgr_t = QWORD (*)(); +using get_sns_first_page_t = QWORD (*)(QWORD, QWORD, QWORD); +using get_sns_next_page_scene_t = QWORD (*)(QWORD, QWORD); +using get_chat_mgr_t = QWORD (*)(); +using new_chat_msg_t = QWORD (*)(QWORD); +using free_chat_msg_t = QWORD (*)(QWORD); +using get_pre_download_mgr_t = QWORD (*)(); +using get_mgr_by_prefix_localid_t = QWORD (*)(QWORD, QWORD); +using push_attach_task_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD); +using get_ocr_manager_t = QWORD (*)(); +using do_ocr_task_t = QWORD (*)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); -int IsLogin(void) { return (int)util::get_qword(g_WeChatWinDllAddr + OS_LOGIN_STATUS); } +bool is_logged_in() { return util::get_qword(g_WeChatWinDllAddr + OS_LOGIN_STATUS) != 0; } -static string get_key(uint8_t header1, uint8_t header2, uint8_t *key) +static std::string detect_image_extension(uint8_t header1, uint8_t header2, uint8_t &key) { - // PNG? - *key = HEADER_PNG1 ^ header1; - if ((HEADER_PNG2 ^ *key) == header2) { - return ".png"; - } - - // JPG? - *key = HEADER_JPG1 ^ header1; - if ((HEADER_JPG2 ^ *key) == header2) { - return ".jpg"; - } - - // GIF? - *key = HEADER_GIF1 ^ header1; - if ((HEADER_GIF2 ^ *key) == header2) { - return ".gif"; - } - - return ""; // 错误 + if ((key = HEADER_PNG1 ^ header1) && (HEADER_PNG2 ^ key) == header2) return ".png"; + if ((key = HEADER_JPG1 ^ header1) && (HEADER_JPG2 ^ key) == header2) return ".jpg"; + if ((key = HEADER_GIF1 ^ header1) && (HEADER_GIF2 ^ key) == header2) return ".gif"; + return ""; } -string DecryptImage(string src, string dir) +std::string decrypt_image(const fs::path &src, const fs::path &dst_dir) { if (!fs::exists(src)) { - LOG_ERROR("File not exists: {}", src); + LOG_ERROR("文件不存在: {}", src.string()); return ""; } - ifstream in(src.c_str(), ios::binary); - if (!in.is_open()) { - LOG_ERROR("Failed to read file {}", src); + std::ifstream in(src, std::ios::binary); + if (!in) { + LOG_ERROR("无法打开文件: {}", src.string()); return ""; } - filebuf *pfb = in.rdbuf(); - size_t size = pfb->pubseekoff(0, ios::end, ios::in); - pfb->pubseekpos(0, ios::in); - - vector buff; - buff.reserve(size); - char *pBuf = buff.data(); - pfb->sgetn(pBuf, size); - in.close(); + std::vector buffer(std::istreambuf_iterator(in), {}); + if (buffer.size() < 2) return ""; uint8_t key = 0x00; - string ext = get_key(pBuf[0], pBuf[1], &key); - if (ext.empty()) { - LOG_ERROR("Failed to get key."); + auto ext = detect_image_extension(buffer[0], buffer[1], key); + if (!ext) { + LOG_ERROR("无法检测文件类型."); return ""; } - for (size_t i = 0; i < size; i++) { - pBuf[i] ^= key; - } + std::for_each(buffer.begin(), buffer.end(), [key](char &c) { c ^= key; }); - string dst = ""; + fs::path dst_path = dst_dir / (src.stem().string() + *ext); + if (!fs::exists(dst_dir)) fs::create_directories(dst_dir); - if (dir.empty()) { - dst = fs::path(src).replace_extension(ext).string(); - } else { - dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); - - // 判断dir文件夹是否存在,若不存在则创建(否则将无法创建出文件) - if (!fs::exists(dst)) { // 判断该文件夹是否存在 - bool success = fs::create_directories(dst); // Windows创建文件夹 - if (!success) { // 创建失败 - LOG_ERROR("Failed to mkdir:{}", dst); - return ""; - } - } - - dst += fs::path(src).stem().string() + ext; - } - - replace(dst.begin(), dst.end(), '\\', '/'); - - ofstream out(dst.c_str(), ios::binary); - if (!out.is_open()) { - LOG_ERROR("Failed to write file {}", dst); + std::ofstream out(dst_path, std::ios::binary); + if (!out) { + LOG_ERROR("写入文件失败: {}", dst_path.string()); return ""; } - out.write(pBuf, size); - out.close(); - - return dst; + out.write(buffer.data(), buffer.size()); + return dst_path.string(); } -static int GetFirstPage() +static int get_first_page() { int status = -1; - GetSNSDataMgr_t GetSNSDataMgr = (GetSNSDataMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_DATA_MGR); - GetSNSFirstPage_t GetSNSFirstPage = (GetSNSFirstPage_t)(g_WeChatWinDllAddr + OS_GET_SNS_FIRST_PAGE); + get_sns_data_mgr_t GetSNSDataMgr = (get_sns_data_mgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_DATA_MGR); + get_sns_first_page_t GetSNSFirstPage = (get_sns_first_page_t)(g_WeChatWinDllAddr + OS_GET_SNS_FIRST_PAGE); QWORD buff[16] = { 0 }; QWORD mgr = GetSNSDataMgr(); @@ -157,12 +115,13 @@ static int GetFirstPage() return status; } -static int GetNextPage(QWORD id) +static int get_next_page(QWORD id) { int status = -1; - GetSnsTimeLineMgr_t GetSnsTimeLineMgr = (GetSnsTimeLineMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_TIMELINE_MGR); - GetSNSNextPageScene_t GetSNSNextPageScene = (GetSNSNextPageScene_t)(g_WeChatWinDllAddr + OS_GET_SNS_NEXT_PAGE); + get_sns_timeline_mgr_t GetSnsTimeLineMgr = (get_sns_timeline_mgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_TIMELINE_MGR); + get_sns_next_page_scene_t GetSNSNextPageScene + = (get_sns_next_page_scene_t)(g_WeChatWinDllAddr + OS_GET_SNS_NEXT_PAGE); QWORD mgr = GetSnsTimeLineMgr(); status = (int)GetSNSNextPageScene(mgr, id); @@ -170,7 +129,7 @@ static int GetNextPage(QWORD id) return status; } -int RefreshPyq(QWORD id) +int refresh_pyq(uint64_t id) { auto &msgHandler = message::Handler::getInstance(); if (!msgHandler.isPyqListening()) { @@ -179,10 +138,10 @@ int RefreshPyq(QWORD id) } if (id == 0) { - return GetFirstPage(); + return get_first_page(); } - return GetNextPage(id); + return get_next_page(id); } /******************************************************************************* @@ -193,7 +152,7 @@ int RefreshPyq(QWORD id) * thumb:图片或者视频的缩略图路径;如果是视频,后缀为 mp4 后就是存在路径了 * extra:图片、文件的路径 *******************************************************************************/ -int DownloadAttach(QWORD id, string thumb, string extra) +int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extra) { int status = -1; QWORD localId; @@ -208,13 +167,13 @@ int DownloadAttach(QWORD id, string thumb, string extra) return status; } - NewChatMsg_t NewChatMsg = (NewChatMsg_t)(g_WeChatWinDllAddr + OS_NEW_CHAT_MSG); - FreeChatMsg_t FreeChatMsg = (FreeChatMsg_t)(g_WeChatWinDllAddr + OS_FREE_CHAT_MSG); - GetChatMgr_t GetChatMgr = (GetChatMgr_t)(g_WeChatWinDllAddr + OS_GET_CHAT_MGR); - GetPreDownLoadMgr_t GetPreDownLoadMgr = (GetPreDownLoadMgr_t)(g_WeChatWinDllAddr + OS_GET_PRE_DOWNLOAD_MGR); - PushAttachTask_t PushAttachTask = (PushAttachTask_t)(g_WeChatWinDllAddr + OS_PUSH_ATTACH_TASK); - GetMgrByPrefixLocalId_t GetMgrByPrefixLocalId - = (GetMgrByPrefixLocalId_t)(g_WeChatWinDllAddr + OS_GET_MGR_BY_PREFIX_LOCAL_ID); + new_chat_msg_t NewChatMsg = (new_chat_msg_t)(g_WeChatWinDllAddr + OS_NEW_CHAT_MSG); + free_chat_msg_t FreeChatMsg = (free_chat_msg_t)(g_WeChatWinDllAddr + OS_FREE_CHAT_MSG); + get_chat_mgr_t GetChatMgr = (get_chat_mgr_t)(g_WeChatWinDllAddr + OS_GET_CHAT_MGR); + get_pre_download_mgr_t GetPreDownLoadMgr = (get_pre_download_mgr_t)(g_WeChatWinDllAddr + OS_GET_PRE_DOWNLOAD_MGR); + push_attach_task_t PushAttachTask = (push_attach_task_t)(g_WeChatWinDllAddr + OS_PUSH_ATTACH_TASK); + get_mgr_by_prefix_localid_t GetMgrByPrefixLocalId + = (get_mgr_by_prefix_localid_t)(g_WeChatWinDllAddr + OS_GET_MGR_BY_PREFIX_LOCAL_ID); LARGE_INTEGER l; l.HighPart = dbIdx; @@ -260,7 +219,7 @@ int DownloadAttach(QWORD id, string thumb, string extra) LOG_DEBUG("path: {}", save_path); // 创建父目录,由于路径来源于微信,不做检查 - fs::create_directory(fs::path(save_path).parent_path().string()); + fs::create_directory(fs::path(save_path).parent_path()); int temp = 1; auto wx_save_path = util::new_wx_string(save_path); @@ -277,57 +236,50 @@ int DownloadAttach(QWORD id, string thumb, string extra) return status; } -string GetAudio(QWORD id, string dir) +std::string get_audio(uint64_t id, const fs::path &dir) { - string mp3path = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); - mp3path += to_string(id) + ".mp3"; - replace(mp3path.begin(), mp3path.end(), '\\', '/'); - if (fs::exists(mp3path)) { // 不重复下载 - return mp3path; - } + if (!fs::exists(dir)) fs::create_directories(dir); - vector silk = db::get_audio_data(id); - if (silk.size() == 0) { + fs::path mp3path = dir / (std::to_string(id) + ".mp3"); + if (fs::exists(mp3path)) return mp3path.string(); + + auto silk = db::get_audio_data(id); + if (silk.empty()) { LOG_ERROR("Empty audio data."); return ""; } - Silk2Mp3(silk, mp3path, 24000); - - return mp3path; + Silk2Mp3(silk, mp3path.string(), 24000); + return mp3path.string(); } -string GetPCMAudio(uint64_t id, string dir, int32_t sr) +std::string get_pcm_audio(uint64_t id, const fs::path &dir, int32_t sr) { - string pcmpath = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); - pcmpath += to_string(id) + ".pcm"; - replace(pcmpath.begin(), pcmpath.end(), '\\', '/'); - if (fs::exists(pcmpath)) { // 不重复下载 - return pcmpath; - } - vector pcm; - vector silk = db::get_audio_data(id); - if (silk.size() == 0) { + if (!fs::exists(dir)) fs::create_directories(dir); + + fs::path pcmpath = dir / (std::to_string(id) + ".pcm"); + if (fs::exists(pcmpath)) return pcmpath.string(); + + auto silk = db::get_audio_data(id); + if (silk.empty()) { LOG_ERROR("Empty audio data."); - return ""; + return std::nullopt; } + std::vector pcm; SilkDecode(silk, pcm, sr); - errno_t err; - FILE *fPCM; - err = fopen_s(&fPCM, pcmpath.c_str(), "wb"); - if (err != 0) { - printf("Error: could not open input file %s\n", pcmpath.c_str()); - exit(0); + + std::ofstream out(pcmpath, std::ios::binary); + if (!out) { + LOG_ERROR("Failed to write file: {}", pcmpath.string()); + return std::nullopt; } - fwrite(pcm.data(), sizeof(uint8_t), pcm.size(), fPCM); - fclose(fPCM); - - return pcmpath; + out.write(reinterpret_cast(pcm.data()), pcm.size()); + return pcmpath.string(); } -OcrResult_t GetOcrResult(string path) +OcrResult_t get_ocr_result(const std::filesystem::path &path) { OcrResult_t ret = { -1, "" }; #if 0 // 参数没调好,会抛异常,看看有没有好心人来修复 @@ -336,8 +288,8 @@ OcrResult_t GetOcrResult(string path) return ret; } - GetOCRManager_t GetOCRManager = (GetOCRManager_t)(g_WeChatWinDllAddr + 0x1D6C3C0); - DoOCRTask_t DoOCRTask = (DoOCRTask_t)(g_WeChatWinDllAddr + 0x2D10BC0); + get_ocr_manager_t GetOCRManager = (get_ocr_manager_t)(g_WeChatWinDllAddr + 0x1D6C3C0); + do_ocr_task_t DoOCRTask = (do_ocr_task_t)(g_WeChatWinDllAddr + 0x2D10BC0); QWORD unk1 = 0, unk2 = 0, unused = 0; QWORD *pUnk1 = &unk1; @@ -368,7 +320,7 @@ OcrResult_t GetOcrResult(string path) return ret; } -int RevokeMsg(QWORD id) +int revoke_message(uint64_t id) { int status = -1; #if 0 // 这个挺鸡肋的,因为自己发的消息没法直接获得 msgid,就这样吧 @@ -382,23 +334,20 @@ int RevokeMsg(QWORD id) return status; } -string GetLoginUrl() +std::string get_login_url() { LPVOID targetAddress = reinterpret_cast(g_WeChatWinDllAddr) + OS_LOGIN_QR_CODE; - - char *dataPtr = *reinterpret_cast(targetAddress); // 读取指针内容 + char *dataPtr = *reinterpret_cast(targetAddress); if (!dataPtr) { - LOG_ERROR("Failed to get login url"); - return "error"; + LOG_ERROR("Failed to get login URL."); + return ""; } - - // 读取字符串内容 - std::string data(dataPtr, 22); - return "http://weixin.qq.com/x/" + data; + return "http://weixin.qq.com/x/" + std::string(dataPtr, 22); } -int ReceiveTransfer(string wxid, string transferid, string transactionid) +int receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid) { // 别想了,这个不实现了 return -1; } +} // namespace misc \ No newline at end of file diff --git a/WeChatFerry/spy/misc_manager.h b/WeChatFerry/spy/misc_manager.h index c25f076..b3e58ba 100644 --- a/WeChatFerry/spy/misc_manager.h +++ b/WeChatFerry/spy/misc_manager.h @@ -1,17 +1,39 @@ #pragma once -#include "stdint.h" +#include +#include +#include #include +#include #include "pb_types.h" -int IsLogin(void); -std::string GetAudio(uint64_t id, std::string dir); -std::string GetPCMAudio(uint64_t id, std::string dir, int32_t sr); -std::string DecryptImage(std::string src, std::string dst); -int RefreshPyq(uint64_t id); -int DownloadAttach(uint64_t id, std::string thumb, std::string extra); -int RevokeMsg(uint64_t id); -OcrResult_t GetOcrResult(std::string path); -std::string GetLoginUrl(); -int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid); +namespace misc +{ + +bool is_logged_in(); + +std::string get_audio(uint64_t id, const std::filesystem::path &dir); +std::string get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr); +std::string decrypt_image(const std::filesystem::path &src, const std::filesystem::path &dst); +std::string get_login_url(); + +int refresh_pyq(uint64_t id); +int download_attachment(uint64_t id, const std::filesystem::path &thumb, const std::filesystem::path &extra); +int revoke_message(uint64_t id); + +OcrResult_t get_ocr_result(const std::filesystem::path &path); +int receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid); + +// RPC +bool rpc_is_logged_in(uint8_t *out, size_t *len); +bool rpc_get_audio(uint64_t id, const std::filesystem::path &dir, uint8_t *out, size_t *len); +bool rpc_get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr, uint8_t *out, size_t *len); +bool rpc_decrypt_image(const DecPath &dec, uint8_t *out, size_t *len); +bool rpc_get_login_url(uint8_t *out, size_t *len); +bool rpc_refresh_pyq(uint64_t id, uint8_t *out, size_t *len); +bool rpc_download_attachment(uint64_t id, const std::filesystem::path &thumb, const std::filesystem::path &extra, uint8_t *out, size_t *len); +bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len); +bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len); +bool rpc_receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid, uint8_t *out, size_t *len); +} // namespace misc diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index dbbbf36..b23b27c 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -23,12 +23,12 @@ #include "chatroom_manager.h" #include "contact_manager.h" #include "database_executor.h" -#include "misc_manager.h" #include "log.hpp" -#include "pb_types.h" -#include "pb_util.h" #include "message_handler.h" #include "message_sender.h" +#include "misc_manager.h" +#include "pb_types.h" +#include "pb_util.h" #include "spy.h" #include "spy_types.h" #include "userinfo_manager.h" @@ -71,7 +71,7 @@ static bool FillResponse(int which_msg, uint8_t *out, size_t *len, AssignFunc as static bool func_is_login(uint8_t *out, size_t *len) { return FillResponse(Response_status_tag, out, len, - [](Response &rsp) { rsp.msg.status = IsLogin(); }); + [](Response &rsp) { rsp.msg.status = misc::is_logged_in(); }); } static bool func_get_self_wxid(uint8_t *out, size_t *len) @@ -132,7 +132,7 @@ static bool func_get_db_tables(char *db, uint8_t *out, size_t *len) static bool func_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len) { return FillResponse(Response_str_tag, out, len, [id, dir](Response &rsp) { - std::string path = (dir == nullptr) ? "" : GetAudio(id, dir); + std::string path = (dir == nullptr) ? "" : misc::get_audio(id, dir); rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); }); } @@ -365,7 +365,7 @@ static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) static bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) { return FillResponse(Response_status_tag, out, len, - [id](Response &rsp) { rsp.msg.status = RefreshPyq(id); }); + [id](Response &rsp) { rsp.msg.status = misc::refresh_pyq(id); }); } static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) @@ -373,20 +373,20 @@ static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) return FillResponse(Response_status_tag, out, len, [att](Response &rsp) { std::string thumb = att.thumb ? att.thumb : ""; std::string extra = att.extra ? att.extra : ""; - rsp.msg.status = DownloadAttach(att.id, thumb, extra); + rsp.msg.status = misc::download_attachment(att.id, thumb, extra); }); } static bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len) { return FillResponse(Response_status_tag, out, len, - [id](Response &rsp) { rsp.msg.status = RevokeMsg(id); }); + [id](Response &rsp) { rsp.msg.status = misc::revoke_message(id); }); } static bool func_refresh_qrcode(uint8_t *out, size_t *len) { return FillResponse(Response_str_tag, out, len, [](Response &rsp) { - std::string url = GetLoginUrl(); + std::string url = misc::get_login_url(); rsp.msg.str = url.empty() ? nullptr : (char *)url.c_str(); }); } @@ -398,7 +398,7 @@ static bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *o LOG_ERROR("Empty wxid, tfid, or taid."); rsp.msg.status = -1; } else { - rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); + rsp.msg.status = misc::receive_transfer(wxid, tfid, taid); } }); } @@ -431,7 +431,7 @@ static bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) if ((dec.src == nullptr) || (dec.dst == nullptr)) { LOG_ERROR("Empty src or dst."); } else { - path = DecryptImage(dec.src, dec.dst); + path = misc::decrypt_image(dec.src, dec.dst); } rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); }); @@ -444,7 +444,7 @@ static bool func_exec_ocr(char *path, uint8_t *out, size_t *len) if (path == nullptr) { LOG_ERROR("Empty path."); } else { - ret = GetOcrResult(path); + ret = misc::get_ocr_result(path); } rsp.msg.ocr.status = ret.status; rsp.msg.ocr.result = ret.result.empty() ? nullptr : (char *)ret.result.c_str(); From 730f51344cc706075560a96d3836be263f774d68 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 6 Feb 2025 07:02:19 +0800 Subject: [PATCH 38/41] Refactoring --- WeChatFerry/spy/misc_manager.cpp | 37 ++++++++++++++++---------------- WeChatFerry/spy/misc_manager.h | 4 ++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/WeChatFerry/spy/misc_manager.cpp b/WeChatFerry/spy/misc_manager.cpp index d6b9afe..4cf414f 100644 --- a/WeChatFerry/spy/misc_manager.cpp +++ b/WeChatFerry/spy/misc_manager.cpp @@ -81,14 +81,14 @@ std::string decrypt_image(const fs::path &src, const fs::path &dst_dir) uint8_t key = 0x00; auto ext = detect_image_extension(buffer[0], buffer[1], key); - if (!ext) { + if (!ext.empty()) { LOG_ERROR("无法检测文件类型."); return ""; } std::for_each(buffer.begin(), buffer.end(), [key](char &c) { c ^= key; }); - fs::path dst_path = dst_dir / (src.stem().string() + *ext); + fs::path dst_path = dst_dir / (src.stem().string() + ext); if (!fs::exists(dst_dir)) fs::create_directories(dst_dir); std::ofstream out(dst_path, std::ios::binary); @@ -163,7 +163,7 @@ int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extr } if (db::get_local_id_and_dbidx(id, &localId, &dbIdx) != 0) { - LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id)); + LOG_ERROR("获取 localId 失败, 请检查消息 id: {} 是否正确", to_string(id)); return status; } @@ -181,7 +181,7 @@ int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extr char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, 0x460); if (buff == nullptr) { - LOG_ERROR("Failed to allocate memory."); + LOG_ERROR("申请内存失败."); return status; } @@ -191,9 +191,7 @@ int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extr QWORD type = util::get_qword(reinterpret_cast(buff) + 0x38); - string save_path = ""; - string thumb_path = ""; - + fs::path save_path, thumb_path; switch (type) { case 0x03: { // Image: extra save_path = extra; @@ -210,20 +208,21 @@ int download_attachment(uint64_t id, const fs::path &thumb, const fs::path &extr break; } default: - break; + LOG_ERROR("不支持的文件类型: {}", type); + return -2; } if (fs::exists(save_path)) { // 不重复下载。TODO: 通过文件大小来判断 return 0; } - LOG_DEBUG("path: {}", save_path); + LOG_DEBUG("保存路径: {}", save_path.string()); // 创建父目录,由于路径来源于微信,不做检查 - fs::create_directory(fs::path(save_path).parent_path()); + fs::create_directory(save_path.parent_path()); int temp = 1; - auto wx_save_path = util::new_wx_string(save_path); - auto wx_thumb_path = util::new_wx_string(thumb_path); + auto wx_save_path = util::new_wx_string(save_path.string()); + auto wx_thumb_path = util::new_wx_string(thumb_path.string()); memcpy(&buff[0x280], wx_thumb_path.get(), sizeof(WxString)); memcpy(&buff[0x2A0], wx_save_path.get(), sizeof(WxString)); @@ -245,7 +244,7 @@ std::string get_audio(uint64_t id, const fs::path &dir) auto silk = db::get_audio_data(id); if (silk.empty()) { - LOG_ERROR("Empty audio data."); + LOG_ERROR("没有获取到语音数据."); return ""; } @@ -262,8 +261,8 @@ std::string get_pcm_audio(uint64_t id, const fs::path &dir, int32_t sr) auto silk = db::get_audio_data(id); if (silk.empty()) { - LOG_ERROR("Empty audio data."); - return std::nullopt; + LOG_ERROR("没有获取到语音数据."); + return ""; } std::vector pcm; @@ -271,8 +270,8 @@ std::string get_pcm_audio(uint64_t id, const fs::path &dir, int32_t sr) std::ofstream out(pcmpath, std::ios::binary); if (!out) { - LOG_ERROR("Failed to write file: {}", pcmpath.string()); - return std::nullopt; + LOG_ERROR("创建文件失败: {}", pcmpath.string()); + return ""; } out.write(reinterpret_cast(pcm.data()), pcm.size()); @@ -339,7 +338,7 @@ std::string get_login_url() LPVOID targetAddress = reinterpret_cast(g_WeChatWinDllAddr) + OS_LOGIN_QR_CODE; char *dataPtr = *reinterpret_cast(targetAddress); if (!dataPtr) { - LOG_ERROR("Failed to get login URL."); + LOG_ERROR("获取二维码失败."); return ""; } return "http://weixin.qq.com/x/" + std::string(dataPtr, 22); @@ -350,4 +349,4 @@ int receive_transfer(const std::string &wxid, const std::string &transferid, con // 别想了,这个不实现了 return -1; } -} // namespace misc \ No newline at end of file +} // namespace misc diff --git a/WeChatFerry/spy/misc_manager.h b/WeChatFerry/spy/misc_manager.h index b3e58ba..378dc42 100644 --- a/WeChatFerry/spy/misc_manager.h +++ b/WeChatFerry/spy/misc_manager.h @@ -6,6 +6,8 @@ #include #include +#include "wcf.pb.h" + #include "pb_types.h" namespace misc @@ -26,6 +28,7 @@ OcrResult_t get_ocr_result(const std::filesystem::path &path); int receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid); // RPC +// clang-format off bool rpc_is_logged_in(uint8_t *out, size_t *len); bool rpc_get_audio(uint64_t id, const std::filesystem::path &dir, uint8_t *out, size_t *len); bool rpc_get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr, uint8_t *out, size_t *len); @@ -36,4 +39,5 @@ bool rpc_download_attachment(uint64_t id, const std::filesystem::path &thumb, co bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len); bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len); bool rpc_receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid, uint8_t *out, size_t *len); +// clang-format on } // namespace misc From 8653f6f521733a836abb029f416a7cea4890f5c3 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 6 Feb 2025 07:44:52 +0800 Subject: [PATCH 39/41] Refactoring --- WeChatFerry/spy/rpc_helper.h | 41 +++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/WeChatFerry/spy/rpc_helper.h b/WeChatFerry/spy/rpc_helper.h index f4e19c0..8aa76fc 100644 --- a/WeChatFerry/spy/rpc_helper.h +++ b/WeChatFerry/spy/rpc_helper.h @@ -9,7 +9,9 @@ #include "pb_encode.h" #include "pb_types.h" -static const std::unordered_map rpc_function_map +using FunctionHandler = std::function; + +static const std::unordered_map rpc_tag_map = { { Functions_FUNC_IS_LOGIN, Response_status_tag }, { Functions_FUNC_GET_SELF_WXID, Response_str_tag }, { Functions_FUNC_GET_USER_INFO, Response_ui_tag }, @@ -39,13 +41,46 @@ static const std::unordered_map rpc_function_map { Functions_FUNC_DEL_ROOM_MEMBERS, Response_status_tag }, { Functions_FUNC_INV_ROOM_MEMBERS, Response_status_tag } }; +const std::unordered_map rpc_function_map = { + { Functions_FUNC_IS_LOGIN, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_SELF_WXID, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_USER_INFO, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_MSG_TYPES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_CONTACTS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_DB_NAMES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_DB_TABLES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_GET_AUDIO_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_IMG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_FILE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_RICH_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_PAT_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_FORWARD_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_SEND_EMOTION, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_ENABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_DISABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_EXEC_DB_QUERY, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_REFRESH_PYQ, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_DOWNLOAD_ATTACH, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_RECV_TRANSFER, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_REVOKE_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_REFRESH_QRCODE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_DECRYPT_IMAGE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_EXEC_OCR, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + { Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, + // clang-format off + // clang-format on +}; + template bool fill_response(uint8_t *out, size_t *len, AssignFunc assign) { Response rsp = Response_init_default; rsp.func = FuncType; - auto it = rpc_function_map.find(FuncType); - if (it == rpc_function_map.end()) { + auto it = rpc_tag_map.find(FuncType); + if (it == rpc_tag_map.end()) { LOG_ERROR("Unknown function type: {}", magic_enum::enum_name(rsp.func)); return false; } From 2e240c3731c6f129f36d14ce77d996abfdee4d19 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 6 Feb 2025 08:05:35 +0800 Subject: [PATCH 40/41] Refactoring --- WeChatFerry/spy/message_handler.cpp | 41 ++ WeChatFerry/spy/message_handler.h | 7 +- WeChatFerry/spy/rpc_helper.h | 41 +- WeChatFerry/spy/rpc_server.cpp | 568 +++------------------------- 4 files changed, 106 insertions(+), 551 deletions(-) diff --git a/WeChatFerry/spy/message_handler.cpp b/WeChatFerry/spy/message_handler.cpp index 849382e..c1070e8 100644 --- a/WeChatFerry/spy/message_handler.cpp +++ b/WeChatFerry/spy/message_handler.cpp @@ -7,6 +7,7 @@ #include "framework.h" #include "log.hpp" +#include "rpc_helper.h" #include "userinfo_manager.h" #include "util.h" @@ -266,4 +267,44 @@ MH_STATUS Handler::UninitializeHook() if (status == MH_OK) isMH_Initialized = false; return status; } + +bool Handler::rpc_get_msg_types() +{ + return fill_response(out, len, [&](Response &rsp) { + MsgTypes_t types = GetMsgTypes(); + rsp.msg.types.types.funcs.encode = encode_types; + rsp.msg.types.types.arg = &types; + }); +} + +bool rpc_enable_recv_msg(void *cb, bool pyq, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [cb, pyq](Response &rsp) { + auto &handler = Handler::getInstance(); + rsp.msg.status = handler.ListenMsg(); + if (rsp.msg.status == 0) { + if (pyq) { + msgHandler.ListenPyq(); + } + msgThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)cb, nullptr, 0, nullptr); + if (msgThread == nullptr) { + rsp.msg.status = GetLastError(); + LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); + } + } + }); +} +bool Handler::rpc_disable_recv_msg(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { + rsp.msg.status = UnListenMsg(); + if (rsp.msg.status == 0) { + UnListenPyq(); + if (msgThread != nullptr) { + TerminateThread(msgThread, 0); + msgThread = nullptr; + } + } + }); +} } \ No newline at end of file diff --git a/WeChatFerry/spy/message_handler.h b/WeChatFerry/spy/message_handler.h index 1fb06ee..c9e0898 100644 --- a/WeChatFerry/spy/message_handler.h +++ b/WeChatFerry/spy/message_handler.h @@ -11,7 +11,8 @@ #include "pb_types.h" #include "spy_types.h" -namespace message { +namespace message +{ class Handler { @@ -36,6 +37,10 @@ public: std::condition_variable &getConditionVariable() { return cv_; }; std::mutex &getMutex() { return mutex_; }; + bool rpc_get_msg_types(); + bool rpc_enable_recv_msg(void *cb, bool pyq, uint8_t *out, size_t *len); + bool rpc_disable_recv_msg(uint8_t *out, size_t *len); + private: Handler(); ~Handler(); diff --git a/WeChatFerry/spy/rpc_helper.h b/WeChatFerry/spy/rpc_helper.h index 8aa76fc..963bcf7 100644 --- a/WeChatFerry/spy/rpc_helper.h +++ b/WeChatFerry/spy/rpc_helper.h @@ -1,16 +1,15 @@ #pragma once -#include #include +#include + #include "wcf.pb.h" #include "log.hpp" #include "pb_encode.h" #include "pb_types.h" -using FunctionHandler = std::function; - static const std::unordered_map rpc_tag_map = { { Functions_FUNC_IS_LOGIN, Response_status_tag }, { Functions_FUNC_GET_SELF_WXID, Response_str_tag }, @@ -23,6 +22,7 @@ static const std::unordered_map rpc_tag_map { Functions_FUNC_SEND_TXT, Response_status_tag }, { Functions_FUNC_SEND_IMG, Response_status_tag }, { Functions_FUNC_SEND_FILE, Response_status_tag }, + { Functions_FUNC_SEND_XML, Response_status_tag }, { Functions_FUNC_SEND_RICH_TXT, Response_status_tag }, { Functions_FUNC_SEND_PAT_MSG, Response_status_tag }, { Functions_FUNC_FORWARD_MSG, Response_status_tag }, @@ -32,6 +32,8 @@ static const std::unordered_map rpc_tag_map { Functions_FUNC_EXEC_DB_QUERY, Response_rows_tag }, { Functions_FUNC_REFRESH_PYQ, Response_status_tag }, { Functions_FUNC_DOWNLOAD_ATTACH, Response_status_tag }, + { Functions_FUNC_GET_CONTACT_INFO, Response_contacts_tag }, + { Functions_FUNC_ACCEPT_FRIEND, Response_status_tag }, { Functions_FUNC_RECV_TRANSFER, Response_status_tag }, { Functions_FUNC_REVOKE_MSG, Response_status_tag }, { Functions_FUNC_REFRESH_QRCODE, Response_str_tag }, @@ -41,39 +43,6 @@ static const std::unordered_map rpc_tag_map { Functions_FUNC_DEL_ROOM_MEMBERS, Response_status_tag }, { Functions_FUNC_INV_ROOM_MEMBERS, Response_status_tag } }; -const std::unordered_map rpc_function_map = { - { Functions_FUNC_IS_LOGIN, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_SELF_WXID, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_USER_INFO, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_MSG_TYPES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_CONTACTS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_DB_NAMES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_DB_TABLES, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_GET_AUDIO_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_IMG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_FILE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_RICH_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_PAT_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_FORWARD_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_SEND_EMOTION, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_ENABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_DISABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_EXEC_DB_QUERY, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_REFRESH_PYQ, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_DOWNLOAD_ATTACH, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_RECV_TRANSFER, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_REVOKE_MSG, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_REFRESH_QRCODE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_DECRYPT_IMAGE, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_EXEC_OCR, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - { Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *out_len) { return; } }, - // clang-format off - // clang-format on -}; - template bool fill_response(uint8_t *out, size_t *len, AssignFunc assign) { Response rsp = Response_init_default; diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index b23b27c..999166d 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -45,213 +45,51 @@ static HANDLE msgThread = NULL; static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 -auto &msgHandler = message::Handler::getInstance(); -auto &sendMgr = message::Sender::get_instance(); +using FunctionHandler = std::function; -static std::string BuildUrl(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } +inline std::string build_url(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } +void receive_message_callback(); -template -static bool FillResponse(int which_msg, uint8_t *out, size_t *len, AssignFunc assign) -{ - Response rsp = Response_init_default; - rsp.func = funcType; - rsp.which_msg = which_msg; +auto &handler = message::Handler::getInstance(); +auto &sender = message::Sender::get_instance(); - assign(rsp); +const std::unordered_map rpc_function_map = { + // clang-format off + { Functions_FUNC_IS_LOGIN, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_is_logged_in(out, len); } }, + { Functions_FUNC_GET_SELF_WXID, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_self_wxid(out, len)} }, + { Functions_FUNC_GET_USER_INFO, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_user_info(out, len); } }, + { Functions_FUNC_GET_MSG_TYPES, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_get_msg_types(out, len); } }, + { Functions_FUNC_GET_CONTACTS, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contacts(out, len); } }, + { Functions_FUNC_GET_DB_NAMES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_names(out, len); } }, + { Functions_FUNC_GET_DB_TABLES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_tables(r.msg.str, out, len); } }, + { Functions_FUNC_GET_AUDIO_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_audio(r.msg.am.id, r.msg.am.dir, out, len); } }, + { Functions_FUNC_SEND_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_text(r.msg.txt, out, len); } }, + { Functions_FUNC_SEND_IMG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_image(r.msg.file.path, r.msg.file.receiver, out, len); } }, + { Functions_FUNC_SEND_FILE, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_file(r.msg.file.path, r.msg.file.receiver, out, len); } }, + { Functions_FUNC_SEND_XML, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_xml(r.msg.xml, out, len); } }, + { Functions_FUNC_SEND_RICH_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_rich_text(r.msg.rt, out, len); } }, + { Functions_FUNC_SEND_PAT_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_pat(r.msg.pm.roomid, r.msg.pm.wxid, out, len); } }, + { Functions_FUNC_FORWARD_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_forward(r.msg.fm.id, r.msg.fm.receiver, out, len); } }, + { Functions_FUNC_SEND_EMOTION, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_emotion(r.msg.file.path, r.msg.file.receiver, out, len); } }, + { Functions_FUNC_ENABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_enable_recv_msg(receive_message_callback, r.msg.flag, out, len); } }, + { Functions_FUNC_DISABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_disable_recv_msg(out, len); } }, + { Functions_FUNC_EXEC_DB_QUERY, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_exec_db_query(r.msg.query.db, r.msg.query.sql, out, len); } }, + { Functions_FUNC_REFRESH_PYQ, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_refresh_pyq(r.msg.ui64, out, len); } }, + { Functions_FUNC_DOWNLOAD_ATTACH, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_download_attachment(r.msg.att, out, len); } }, + { Functions_FUNC_GET_CONTACT_INFO, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contact_info(r.msg.str, out, len); } }, + { Functions_FUNC_ACCEPT_FRIEND, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_accept_friend(r.msg.v, out, len); } }, + { Functions_FUNC_RECV_TRANSFER, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_receive_transfer(r.msg.tf, out, len); } }, + { Functions_FUNC_REVOKE_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::revoke_message(r.msg.ui64, out, len); } }, + { Functions_FUNC_REFRESH_QRCODE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_login_url(out, len); } }, + { Functions_FUNC_DECRYPT_IMAGE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_decrypt_image(r.msg.dec, out, len); } }, + { Functions_FUNC_EXEC_OCR, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_ocr_result(r.msg.str, out, len); } }, + { Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_add_chatroom_member(r.msg.m, out, len); } }, + { Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_del_chatroom_member(r.msg.m, out, len); } }, + { Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_invite_chatroom_memberr.msg.m, out, len); } }, + // clang-format on +}; - 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 bool func_is_login(uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, - [](Response &rsp) { rsp.msg.status = misc::is_logged_in(); }); -} - -static bool func_get_self_wxid(uint8_t *out, size_t *len) -{ - return FillResponse(Response_str_tag, out, len, [](Response &rsp) { - std::string wxid = userinfo::get_self_wxid(); - rsp.msg.str = wxid.empty() ? nullptr : (char *)wxid.c_str(); - }); -} - -static bool func_get_user_info(uint8_t *out, size_t *len) -{ - return FillResponse(Response_ui_tag, out, len, [](Response &rsp) { - UserInfo_t ui = userinfo::get_user_info(); - rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); - rsp.msg.ui.name = (char *)ui.name.c_str(); - rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); - rsp.msg.ui.home = (char *)ui.home.c_str(); - }); -} - -static bool func_get_msg_types(uint8_t *out, size_t *len) -{ - return FillResponse(Response_types_tag, out, len, [](Response &rsp) { - static MsgTypes_t types = msgHandler.GetMsgTypes(); - rsp.msg.types.types.funcs.encode = encode_types; - rsp.msg.types.types.arg = &types; - }); -} - -static bool func_get_contacts(uint8_t *out, size_t *len) -{ - return FillResponse(Response_contacts_tag, out, len, [](Response &rsp) { - std::vector contacts = contact::get_contacts(); - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; - }); -} - -static bool func_get_db_names(uint8_t *out, size_t *len) -{ - return FillResponse(Response_dbs_tag, out, len, [](Response &rsp) { - static DbNames_t dbnames = db::get_db_names(); - rsp.msg.dbs.names.funcs.encode = encode_dbnames; - rsp.msg.dbs.names.arg = &dbnames; - }); -} - -static bool func_get_db_tables(char *db, uint8_t *out, size_t *len) -{ - return FillResponse(Response_tables_tag, out, len, [db](Response &rsp) { - static DbTables_t tables = db::get_db_tables(db); - rsp.msg.tables.tables.funcs.encode = encode_tables; - rsp.msg.tables.tables.arg = &tables; - }); -} - -static bool func_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len) -{ - return FillResponse(Response_str_tag, out, len, [id, dir](Response &rsp) { - std::string path = (dir == nullptr) ? "" : misc::get_audio(id, dir); - rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); - }); -} - -static bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [txt](Response &rsp) { - if ((txt.msg == NULL) || (txt.receiver == NULL)) { - LOG_ERROR("Empty message or receiver."); - rsp.msg.status = -1; - } else { - std::string msg(txt.msg); - std::string receiver(txt.receiver); - std::string aters(txt.aters ? txt.aters : ""); - sendMgr.send_text(receiver, msg, aters); - rsp.msg.status = 0; - } - }); -} - -static bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { - if ((path == NULL) || (receiver == NULL)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else if (!fs::exists(util::s2w(path))) { - LOG_ERROR("Path does not exist: {}", path); - rsp.msg.status = -2; - } else { - sendMgr.send_image(receiver, path); - rsp.msg.status = 0; - } - }); -} - -static bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { - if ((path == nullptr) || (receiver == nullptr)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else if (!fs::exists(util::s2w(path))) { - LOG_ERROR("Path does not exist: {}", path); - rsp.msg.status = -2; - } else { - sendMgr.send_file(receiver, path); - rsp.msg.status = 0; - } - }); -} - -static bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [path, receiver](Response &rsp) { - if ((path == nullptr) || (receiver == nullptr)) { - LOG_ERROR("Empty path or receiver."); - rsp.msg.status = -1; - } else { - sendMgr.send_emotion(receiver, path); - rsp.msg.status = 0; - } - }); -} - -static bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [xml](Response &rsp) { - if ((xml.content == nullptr) || (xml.receiver == nullptr)) { - LOG_ERROR("Empty content or receiver."); - rsp.msg.status = -1; - } else { - std::string receiver(xml.receiver); - std::string content(xml.content); - std::string path(xml.path ? xml.path : ""); - uint64_t type = static_cast(xml.type); - sendMgr.send_xml(receiver, content, path, type); - rsp.msg.status = 0; - } - }); -} - -static bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [rt](Response &rsp) { - if (rt.receiver == nullptr) { - LOG_ERROR("Empty receiver."); - rsp.msg.status = -1; - } else { - rsp.msg.status = sendMgr.send_rich_text(rt); - } - }); -} - -static bool func_send_pat_msg(char *roomid, char *wxid, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [roomid, wxid](Response &rsp) { - if ((roomid == nullptr) || (wxid == nullptr)) { - LOG_ERROR("Empty roomid or wxid."); - rsp.msg.status = -1; - } else { - rsp.msg.status = sendMgr.send_pat(roomid, wxid); - } - }); -} - -static bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [id, receiver](Response &rsp) { - if (receiver == nullptr) { - LOG_ERROR("Empty receiver."); - rsp.msg.status = -1; - } else { - rsp.msg.status = sendMgr.forward(id, receiver); - } - }); -} - -static void PushMessage() +void receive_message_callback() { int rv; Response rsp = Response_init_default; @@ -261,7 +99,7 @@ static void PushMessage() pb_ostream_t stream = pb_ostream_from_buffer(msgBuffer.data(), msgBuffer.size()); - std::string url = BuildUrl(cmdPort + 1); + std::string url = build_url(cmdPort + 1); if ((rv = nng_pair1_open(&msgSock)) != 0) { LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); return; @@ -278,15 +116,15 @@ static void PushMessage() return; } - while (msgHandler.isMessageListening()) { - std::unique_lock lock(msgHandler.getMutex()); + while (handler.isMessageListening()) { + std::unique_lock lock(handler.getMutex()); std::optional msgOpt; auto hasMessage = [&]() { - msgOpt = msgHandler.popMessage(); + msgOpt = handler.popMessage(); return msgOpt.has_value(); }; - if (msgHandler.getConditionVariable().wait_for(lock, std::chrono::milliseconds(1000), hasMessage)) { + if (handler.getConditionVariable().wait_for(lock, std::chrono::milliseconds(1000), hasMessage)) { WxMsg_t wxmsg = std::move(msgOpt.value()); rsp.msg.wxmsg.id = wxmsg.id; rsp.msg.wxmsg.is_self = wxmsg.is_self; @@ -317,176 +155,6 @@ static void PushMessage() } } -static bool func_enable_recv_txt(bool pyq, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [pyq](Response &rsp) { - rsp.msg.status = msgHandler.ListenMsg(); - if (rsp.msg.status == 0) { - if (pyq) { - msgHandler.ListenPyq(); - } - msgThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)PushMessage, nullptr, 0, nullptr); - if (msgThread == nullptr) { - rsp.msg.status = GetLastError(); - LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); - } - } - }); -} - -static bool func_disable_recv_txt(uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [](Response &rsp) { - rsp.msg.status = msgHandler.UnListenMsg(); - if (rsp.msg.status == 0) { - msgHandler.UnListenPyq(); - if (msgThread != nullptr) { - TerminateThread(msgThread, 0); - msgThread = nullptr; - } - } - }); -} - -static bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) -{ - return FillResponse(Response_rows_tag, out, len, [db, sql](Response &rsp) { - static DbRows_t rows; - if ((db == nullptr) || (sql == nullptr)) { - LOG_ERROR("Empty db or sql."); - } else { - rows = db::exec_db_query(db, sql); - } - rsp.msg.rows.rows.arg = &rows; - rsp.msg.rows.rows.funcs.encode = encode_rows; - }); -} - -static bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, - [id](Response &rsp) { rsp.msg.status = misc::refresh_pyq(id); }); -} - -static bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [att](Response &rsp) { - std::string thumb = att.thumb ? att.thumb : ""; - std::string extra = att.extra ? att.extra : ""; - rsp.msg.status = misc::download_attachment(att.id, thumb, extra); - }); -} - -static bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, - [id](Response &rsp) { rsp.msg.status = misc::revoke_message(id); }); -} - -static bool func_refresh_qrcode(uint8_t *out, size_t *len) -{ - return FillResponse(Response_str_tag, out, len, [](Response &rsp) { - std::string url = misc::get_login_url(); - rsp.msg.str = url.empty() ? nullptr : (char *)url.c_str(); - }); -} - -static bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [wxid, tfid, taid](Response &rsp) { - if ((wxid == nullptr) || (tfid == nullptr) || (taid == nullptr)) { - LOG_ERROR("Empty wxid, tfid, or taid."); - rsp.msg.status = -1; - } else { - rsp.msg.status = misc::receive_transfer(wxid, tfid, taid); - } - }); -} - -static bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [v3, v4, scene](Response &rsp) { - if ((v3 == nullptr) || (v4 == nullptr)) { - LOG_ERROR("Empty V3 or V4."); - rsp.msg.status = -1; - } else { - rsp.msg.status = contact::accept_new_friend(v3, v4, scene); - } - }); -} - -static bool func_get_contact_info(std::string wxid, uint8_t *out, size_t *len) -{ - return FillResponse(Response_contacts_tag, out, len, [wxid](Response &rsp) { - std::vector contacts = { contact::get_contact_by_wxid(wxid) }; - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; - }); -} - -static bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) -{ - return FillResponse(Response_str_tag, out, len, [dec](Response &rsp) { - std::string path; - if ((dec.src == nullptr) || (dec.dst == nullptr)) { - LOG_ERROR("Empty src or dst."); - } else { - path = misc::decrypt_image(dec.src, dec.dst); - } - rsp.msg.str = path.empty() ? nullptr : (char *)path.c_str(); - }); -} - -static bool func_exec_ocr(char *path, uint8_t *out, size_t *len) -{ - return FillResponse(Response_ocr_tag, out, len, [path](Response &rsp) { - OcrResult_t ret = { -1, "" }; - if (path == nullptr) { - LOG_ERROR("Empty path."); - } else { - ret = misc::get_ocr_result(path); - } - rsp.msg.ocr.status = ret.status; - rsp.msg.ocr.result = ret.result.empty() ? nullptr : (char *)ret.result.c_str(); - }); -} - -static bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { - if ((roomid == nullptr) || (wxids == nullptr)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = chatroom::add_chatroom_member(roomid, wxids); - } - }); -} - -static bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { - if ((roomid == nullptr) || (wxids == nullptr)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = chatroom::del_chatroom_member(roomid, wxids); - } - }); -} - -static bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) -{ - return FillResponse(Response_status_tag, out, len, [roomid, wxids](Response &rsp) { - if ((roomid == nullptr) || (wxids == nullptr)) { - LOG_ERROR("Empty roomid or wxids."); - rsp.msg.status = -1; - } else { - rsp.msg.status = chatroom::invite_chatroom_member(roomid, wxids); - } - }); -} - static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { bool ret = false; @@ -500,139 +168,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len LOG_DEBUG("{:#04x}[{}] length: {}", (uint8_t)req.func, magic_enum::enum_name(req.func), in_len); - switch (req.func) { - case Functions_FUNC_IS_LOGIN: { - ret = func_is_login(out, out_len); - break; - } - case Functions_FUNC_GET_SELF_WXID: { - ret = func_get_self_wxid(out, out_len); - break; - } - case Functions_FUNC_GET_USER_INFO: { - ret = func_get_user_info(out, out_len); - break; - } - case Functions_FUNC_GET_MSG_TYPES: { - ret = func_get_msg_types(out, out_len); - break; - } - case Functions_FUNC_GET_CONTACTS: { - ret = func_get_contacts(out, out_len); - break; - } - case Functions_FUNC_GET_DB_NAMES: { - ret = func_get_db_names(out, out_len); - break; - } - case Functions_FUNC_GET_DB_TABLES: { - ret = func_get_db_tables(req.msg.str, out, out_len); - break; - } - case Functions_FUNC_GET_AUDIO_MSG: { - ret = func_get_audio_msg(req.msg.am.id, req.msg.am.dir, out, out_len); - break; - } - case Functions_FUNC_SEND_TXT: { - ret = func_send_txt(req.msg.txt, out, out_len); - break; - } - case Functions_FUNC_SEND_IMG: { - ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } - case Functions_FUNC_SEND_FILE: { - ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } - case Functions_FUNC_SEND_RICH_TXT: { - ret = func_send_rich_txt(req.msg.rt, out, out_len); - break; - } - case Functions_FUNC_SEND_PAT_MSG: { - ret = func_send_pat_msg(req.msg.pm.roomid, req.msg.pm.wxid, out, out_len); - break; - } - case Functions_FUNC_FORWARD_MSG: { - ret = func_forward_msg(req.msg.fm.id, req.msg.fm.receiver, out, out_len); - break; - } - case Functions_FUNC_SEND_EMOTION: { - ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } -#if 0 - case Functions_FUNC_SEND_XML: { - ret = func_send_xml(req.msg.xml, out, out_len); - break; - } -#endif - case Functions_FUNC_ENABLE_RECV_TXT: { - ret = func_enable_recv_txt(req.msg.flag, out, out_len); - break; - } - case Functions_FUNC_DISABLE_RECV_TXT: { - ret = func_disable_recv_txt(out, out_len); - break; - } - case Functions_FUNC_EXEC_DB_QUERY: { - ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); - break; - } - case Functions_FUNC_REFRESH_PYQ: { - ret = func_refresh_pyq(req.msg.ui64, out, out_len); - break; - } - case Functions_FUNC_DOWNLOAD_ATTACH: { - ret = func_download_attach(req.msg.att, out, out_len); - break; - } - case Functions_FUNC_RECV_TRANSFER: { - ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); - break; - } - case Functions_FUNC_REVOKE_MSG: { - ret = func_revoke_msg(req.msg.ui64, out, out_len); - break; - } - case Functions_FUNC_REFRESH_QRCODE: { - ret = func_refresh_qrcode(out, out_len); - break; - } -#if 0 - case Functions_FUNC_ACCEPT_FRIEND: { - ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); - break; - } - case Functions_FUNC_GET_CONTACT_INFO: { - ret = func_get_contact_info(req.msg.str, out, out_len); - break; - } -#endif - case Functions_FUNC_DECRYPT_IMAGE: { - ret = func_decrypt_image(req.msg.dec, out, out_len); - break; - } - case Functions_FUNC_EXEC_OCR: { - ret = func_exec_ocr(req.msg.str, out, out_len); - break; - } - case Functions_FUNC_ADD_ROOM_MEMBERS: { - ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); - break; - } - case Functions_FUNC_DEL_ROOM_MEMBERS: { - ret = func_del_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); - break; - } - case Functions_FUNC_INV_ROOM_MEMBERS: { - ret = func_invite_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); - break; - } - default: { - LOG_ERROR("[UNKNOW FUNCTION]"); - break; - } + auto it = rpc_function_map.find(req.func); + if (it != rpc_function_map.end()) { + ret = it->second(req, out, out_len); + } else { + LOG_ERROR("[未知方法]"); } pb_release(Request_fields, &req); @@ -642,7 +182,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len static int RunRpcServer() { int rv = 0; - std::string url = BuildUrl(cmdPort); + std::string url = build_url(cmdPort); if ((rv = nng_pair1_open(&cmdSock)) != 0) { LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); return rv; @@ -725,8 +265,8 @@ int RpcStopServer() nng_close(cmdSock); nng_close(msgSock); - msgHandler.UnListenPyq(); - msgHandler.UnListenMsg(); + handler.UnListenPyq(); + handler.UnListenMsg(); #if ENABLE_WX_LOG DisableLog(); #endif From 9232bab9e06659c1a102f8fd460a63002db84519 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 6 Feb 2025 19:33:16 +0800 Subject: [PATCH 41/41] Refactoring --- WeChatFerry/spy/chatroom_manager.cpp | 12 ++- WeChatFerry/spy/chatroom_manager.h | 8 +- WeChatFerry/spy/contact_manager.cpp | 5 +- WeChatFerry/spy/contact_manager.h | 4 +- WeChatFerry/spy/database_executor.cpp | 4 +- WeChatFerry/spy/database_executor.h | 4 +- WeChatFerry/spy/message_handler.cpp | 34 +------- WeChatFerry/spy/message_handler.h | 4 +- WeChatFerry/spy/message_sender.cpp | 22 +++-- WeChatFerry/spy/message_sender.h | 16 ++-- WeChatFerry/spy/misc_manager.cpp | 63 +++++++++++++++ WeChatFerry/spy/misc_manager.h | 6 +- WeChatFerry/spy/rpc_server.cpp | 112 ++++++++++++++++---------- 13 files changed, 191 insertions(+), 103 deletions(-) diff --git a/WeChatFerry/spy/chatroom_manager.cpp b/WeChatFerry/spy/chatroom_manager.cpp index 00a9bf7..4ce74ce 100644 --- a/WeChatFerry/spy/chatroom_manager.cpp +++ b/WeChatFerry/spy/chatroom_manager.cpp @@ -88,20 +88,26 @@ int invite_chatroom_member(const string &roomid, const string &wxids) reinterpret_cast(wx_roomid.get()), 0)); } -bool rpc_add_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +bool rpc_add_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len) { + const std::string wxids = m.wxids; + const std::string roomid = m.roomid; return fill_response( out, len, [&](Response &rsp) { rsp.msg.status = add_chatroom_member(roomid, wxids); }); } -bool rpc_del_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +bool rpc_delete_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len) { + const std::string wxids = m.wxids; + const std::string roomid = m.roomid; return fill_response( out, len, [&](Response &rsp) { rsp.msg.status = del_chatroom_member(roomid, wxids); }); } -bool rpc_invite_chatroom_member(const string &roomid, const string &wxids, uint8_t *out, size_t *len) +bool rpc_invite_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len) { + const std::string wxids = m.wxids; + const std::string roomid = m.roomid; return fill_response( out, len, [&](Response &rsp) { rsp.msg.status = invite_chatroom_member(roomid, wxids); }); } diff --git a/WeChatFerry/spy/chatroom_manager.h b/WeChatFerry/spy/chatroom_manager.h index 9791ed7..3be999d 100644 --- a/WeChatFerry/spy/chatroom_manager.h +++ b/WeChatFerry/spy/chatroom_manager.h @@ -2,6 +2,8 @@ #include +#include "wcf.pb.h" + namespace chatroom { @@ -15,8 +17,8 @@ int del_chatroom_member(const std::string &roomid, const std::string &wxids); int invite_chatroom_member(const std::string &roomid, const std::string &wxids); // RPC 方法 -bool rpc_add_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); -bool rpc_del_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); -bool rpc_invite_chatroom_member(const std::string &roomid, const std::string &wxids, uint8_t *out, size_t *len); +bool rpc_add_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len); +bool rpc_delete_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len); +bool rpc_invite_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len); } // namespace chatroom diff --git a/WeChatFerry/spy/contact_manager.cpp b/WeChatFerry/spy/contact_manager.cpp index bb4efe8..0e1ecb3 100644 --- a/WeChatFerry/spy/contact_manager.cpp +++ b/WeChatFerry/spy/contact_manager.cpp @@ -212,8 +212,11 @@ bool rpc_get_contact_info(const string &wxid, uint8_t *out, size_t *len) }); } -bool rpc_accept_friend(const string &v3, const string &v4, int scene, uint8_t *out, size_t *len) +bool rpc_accept_friend(const Verification &v, uint8_t *out, size_t *len) { + const string v3 = v.v3; + const string v4 = v.v4; + int scene = v.scene; return fill_response( out, len, [&](Response &rsp) { rsp.msg.status = accept_new_friend(v3, v4, scene); }); } diff --git a/WeChatFerry/spy/contact_manager.h b/WeChatFerry/spy/contact_manager.h index 5b330c0..440091e 100644 --- a/WeChatFerry/spy/contact_manager.h +++ b/WeChatFerry/spy/contact_manager.h @@ -3,6 +3,8 @@ #include #include +#include "wcf.pb.h" + #include "pb_types.h" namespace contact @@ -23,6 +25,6 @@ int accept_new_friend(const std::string &v3, const std::string &v4, int scene); // RPC 方法 bool rpc_get_contacts(uint8_t *out, size_t *len); bool rpc_get_contact_info(const std::string &wxid, uint8_t *out, size_t *len); -bool rpc_accept_friend(const std::string &v3, const std::string &v4, int scene, uint8_t *out, size_t *len); +bool rpc_accept_friend(const Verification &v, uint8_t *out, size_t *len); } // namespace contact diff --git a/WeChatFerry/spy/database_executor.cpp b/WeChatFerry/spy/database_executor.cpp index 3f850a3..bd5a7f8 100644 --- a/WeChatFerry/spy/database_executor.cpp +++ b/WeChatFerry/spy/database_executor.cpp @@ -278,8 +278,10 @@ bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len) }); } -bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len) +bool rpc_exec_db_query(const DbQuery query, uint8_t *out, size_t *len) { + const std::string db(query.db); + const std::string sql(query.sql); return fill_response(out, len, [&](Response &rsp) { DbRows_t rows = exec_db_query(db, sql); rsp.msg.rows.rows.funcs.encode = encode_rows; diff --git a/WeChatFerry/spy/database_executor.h b/WeChatFerry/spy/database_executor.h index 4f2752d..0d50373 100644 --- a/WeChatFerry/spy/database_executor.h +++ b/WeChatFerry/spy/database_executor.h @@ -4,6 +4,8 @@ #include #include +#include "wcf.pb.h" + #include "pb_types.h" namespace db @@ -27,6 +29,6 @@ std::vector get_audio_data(uint64_t msg_id); // RPC 方法 bool rpc_get_db_names(uint8_t *out, size_t *len); bool rpc_get_db_tables(const std::string &db, uint8_t *out, size_t *len); -bool rpc_exec_db_query(const std::string &db, const std::string &sql, uint8_t *out, size_t *len); +bool rpc_exec_db_query(const DbQuery query, uint8_t *out, size_t *len); } // namespace db diff --git a/WeChatFerry/spy/message_handler.cpp b/WeChatFerry/spy/message_handler.cpp index c1070e8..3889c09 100644 --- a/WeChatFerry/spy/message_handler.cpp +++ b/WeChatFerry/spy/message_handler.cpp @@ -7,6 +7,7 @@ #include "framework.h" #include "log.hpp" +#include "pb_util.h" #include "rpc_helper.h" #include "userinfo_manager.h" #include "util.h" @@ -268,7 +269,7 @@ MH_STATUS Handler::UninitializeHook() return status; } -bool Handler::rpc_get_msg_types() +bool Handler::rpc_get_msg_types(uint8_t *out, size_t *len) { return fill_response(out, len, [&](Response &rsp) { MsgTypes_t types = GetMsgTypes(); @@ -276,35 +277,4 @@ bool Handler::rpc_get_msg_types() rsp.msg.types.types.arg = &types; }); } - -bool rpc_enable_recv_msg(void *cb, bool pyq, uint8_t *out, size_t *len) -{ - return fill_response(out, len, [cb, pyq](Response &rsp) { - auto &handler = Handler::getInstance(); - rsp.msg.status = handler.ListenMsg(); - if (rsp.msg.status == 0) { - if (pyq) { - msgHandler.ListenPyq(); - } - msgThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)cb, nullptr, 0, nullptr); - if (msgThread == nullptr) { - rsp.msg.status = GetLastError(); - LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); - } - } - }); } -bool Handler::rpc_disable_recv_msg(uint8_t *out, size_t *len) -{ - return fill_response(out, len, [](Response &rsp) { - rsp.msg.status = UnListenMsg(); - if (rsp.msg.status == 0) { - UnListenPyq(); - if (msgThread != nullptr) { - TerminateThread(msgThread, 0); - msgThread = nullptr; - } - } - }); -} -} \ No newline at end of file diff --git a/WeChatFerry/spy/message_handler.h b/WeChatFerry/spy/message_handler.h index c9e0898..c4227ec 100644 --- a/WeChatFerry/spy/message_handler.h +++ b/WeChatFerry/spy/message_handler.h @@ -37,9 +37,7 @@ public: std::condition_variable &getConditionVariable() { return cv_; }; std::mutex &getMutex() { return mutex_; }; - bool rpc_get_msg_types(); - bool rpc_enable_recv_msg(void *cb, bool pyq, uint8_t *out, size_t *len); - bool rpc_disable_recv_msg(uint8_t *out, size_t *len); + bool rpc_get_msg_types(uint8_t *out, size_t *len); private: Handler(); diff --git a/WeChatFerry/spy/message_sender.cpp b/WeChatFerry/spy/message_sender.cpp index 0c79503..c1cb7c8 100644 --- a/WeChatFerry/spy/message_sender.cpp +++ b/WeChatFerry/spy/message_sender.cpp @@ -262,8 +262,10 @@ bool Sender::rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len) }); } -bool Sender::rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_image(const PathMsg &file, uint8_t *out, size_t *len) { + std::string path(file.path); + std::string receiver(file.receiver); return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { LOG_ERROR("Empty path or receiver."); @@ -275,8 +277,10 @@ bool Sender::rpc_send_image(const std::string &path, const std::string &receiver }); } -bool Sender::rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_file(const PathMsg &file, uint8_t *out, size_t *len) { + std::string path(file.path); + std::string receiver(file.receiver); return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { LOG_ERROR("Empty path or receiver."); @@ -288,8 +292,10 @@ bool Sender::rpc_send_file(const std::string &path, const std::string &receiver, }); } -bool Sender::rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_send_emotion(const PathMsg &file, uint8_t *out, size_t *len) { + std::string path(file.path); + std::string receiver(file.receiver); return fill_response(out, len, [&](Response &rsp) { if (path.empty() || receiver.empty()) { LOG_ERROR("Empty path or receiver."); @@ -326,8 +332,10 @@ bool Sender::rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len) }); } -bool Sender::rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len) +bool Sender::rpc_send_pat(const PatMsg &pat, uint8_t *out, size_t *len) { + std::string wxid(pat.wxid); + std::string roomid(pat.roomid); return fill_response(out, len, [&](Response &rsp) { if (roomid.empty() || wxid.empty()) { LOG_ERROR("Empty roomid or wxid."); @@ -338,8 +346,10 @@ bool Sender::rpc_send_pat(const std::string &roomid, const std::string &wxid, ui }); } -bool Sender::rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len) +bool Sender::rpc_forward(const ForwardMsg &fm, uint8_t *out, size_t *len) { + uint64_t msgid = fm.id; + std::string receiver(fm.receiver); return fill_response(out, len, [&](Response &rsp) { if (receiver.empty()) { LOG_ERROR("Empty receiver."); @@ -350,4 +360,4 @@ bool Sender::rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *o }); } -} \ No newline at end of file +} diff --git a/WeChatFerry/spy/message_sender.h b/WeChatFerry/spy/message_sender.h index e528065..1f0a855 100644 --- a/WeChatFerry/spy/message_sender.h +++ b/WeChatFerry/spy/message_sender.h @@ -4,9 +4,10 @@ #include #include -#include "spy_types.h" #include "wcf.pb.h" +#include "spy_types.h" + namespace message { @@ -26,13 +27,13 @@ public: // RPC 方法 bool rpc_send_text(const TextMsg &text, uint8_t *out, size_t *len); - bool rpc_send_image(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); - bool rpc_send_file(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); - bool rpc_send_emotion(const std::string &path, const std::string &receiver, uint8_t *out, size_t *len); + bool rpc_send_image(const PathMsg &file, uint8_t *out, size_t *len); + bool rpc_send_file(const PathMsg &file, uint8_t *out, size_t *len); + bool rpc_send_emotion(const PathMsg &file, uint8_t *out, size_t *len); bool rpc_send_xml(const XmlMsg &rt, uint8_t *out, size_t *len); bool rpc_send_rich_text(const RichText &rt, uint8_t *out, size_t *len); - bool rpc_send_pat(const std::string &roomid, const std::string &wxid, uint8_t *out, size_t *len); - bool rpc_forward(uint64_t msgid, const std::string &receiver, uint8_t *out, size_t *len); + bool rpc_send_pat(const PatMsg &pat, uint8_t *out, size_t *len); + bool rpc_forward(const ForwardMsg &fm, uint8_t *out, size_t *len); private: Sender(); @@ -76,5 +77,4 @@ private: std::unique_ptr new_wx_string(const std::string &str); std::vector parse_wxids(const std::string &wxids); }; - -} \ No newline at end of file +} diff --git a/WeChatFerry/spy/misc_manager.cpp b/WeChatFerry/spy/misc_manager.cpp index 4cf414f..f6f1b3f 100644 --- a/WeChatFerry/spy/misc_manager.cpp +++ b/WeChatFerry/spy/misc_manager.cpp @@ -10,6 +10,7 @@ #include "database_executor.h" #include "log.hpp" #include "message_handler.h" +#include "rpc_helper.h" #include "spy_types.h" #include "util.h" @@ -349,4 +350,66 @@ int receive_transfer(const std::string &wxid, const std::string &transferid, con // 别想了,这个不实现了 return -1; } + +bool rpc_is_logged_in(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { rsp.msg.status = is_logged_in(); }); +} + +bool rpc_get_audio(const AudioMsg &am, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.str = (char *)get_audio(am.id, am.dir).c_str(); }); +} + +bool rpc_get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr, uint8_t *out, size_t *len) +{ + return false; +} + +bool rpc_decrypt_image(const DecPath &dec, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.str = (char *)decrypt_image(dec.src, dec.dst).c_str(); }); +} + +bool rpc_get_login_url(uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.str = (char *)get_login_url().c_str(); }); +} + +bool rpc_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) +{ + return fill_response(out, len, + [&](Response &rsp) { rsp.msg.status = refresh_pyq(id); }); +} + +bool rpc_download_attachment(const AttachMsg &att, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = download_attachment(att.id, att.thumb, att.extra); }); +} + +bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len) +{ + return fill_response(out, len, + [&](Response &rsp) { rsp.msg.status = revoke_message(id); }); +} + +bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + OcrResult_t ret = { -1, "" }; + ret = get_ocr_result(path); + rsp.msg.ocr.status = ret.status; + rsp.msg.ocr.result = (char *)ret.result.c_str(); + }); +} + +bool rpc_receive_transfer(const Transfer &tf, uint8_t *out, size_t *len) +{ + return fill_response( + out, len, [&](Response &rsp) { rsp.msg.status = receive_transfer(tf.wxid, tf.tfid, tf.taid); }); +} } // namespace misc diff --git a/WeChatFerry/spy/misc_manager.h b/WeChatFerry/spy/misc_manager.h index 378dc42..2f995ae 100644 --- a/WeChatFerry/spy/misc_manager.h +++ b/WeChatFerry/spy/misc_manager.h @@ -30,14 +30,14 @@ int receive_transfer(const std::string &wxid, const std::string &transferid, con // RPC // clang-format off bool rpc_is_logged_in(uint8_t *out, size_t *len); -bool rpc_get_audio(uint64_t id, const std::filesystem::path &dir, uint8_t *out, size_t *len); +bool rpc_get_audio(const AudioMsg &am, uint8_t *out, size_t *len); bool rpc_get_pcm_audio(uint64_t id, const std::filesystem::path &dir, int32_t sr, uint8_t *out, size_t *len); bool rpc_decrypt_image(const DecPath &dec, uint8_t *out, size_t *len); bool rpc_get_login_url(uint8_t *out, size_t *len); bool rpc_refresh_pyq(uint64_t id, uint8_t *out, size_t *len); -bool rpc_download_attachment(uint64_t id, const std::filesystem::path &thumb, const std::filesystem::path &extra, uint8_t *out, size_t *len); +bool rpc_download_attachment(const AttachMsg &att, uint8_t *out, size_t *len); bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len); bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len); -bool rpc_receive_transfer(const std::string &wxid, const std::string &transferid, const std::string &transactionid, uint8_t *out, size_t *len); +bool rpc_receive_transfer(const Transfer &tf, uint8_t *out, size_t *len); // clang-format on } // namespace misc diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 999166d..d4be76e 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -29,6 +29,7 @@ #include "misc_manager.h" #include "pb_types.h" #include "pb_util.h" +#include "rpc_helper.h" #include "spy.h" #include "spy_types.h" #include "userinfo_manager.h" @@ -44,52 +45,14 @@ static HANDLE cmdThread = NULL; static HANDLE msgThread = NULL; static nng_socket cmdSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 static nng_socket msgSock = NNG_SOCKET_INITIALIZER; // TODO: 断开检测 +auto &handler = message::Handler::getInstance(); +auto &sender = message::Sender::get_instance(); using FunctionHandler = std::function; inline std::string build_url(int port) { return "tcp://0.0.0.0:" + std::to_string(port); } -void receive_message_callback(); -auto &handler = message::Handler::getInstance(); -auto &sender = message::Sender::get_instance(); - -const std::unordered_map rpc_function_map = { - // clang-format off - { Functions_FUNC_IS_LOGIN, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_is_logged_in(out, len); } }, - { Functions_FUNC_GET_SELF_WXID, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_self_wxid(out, len)} }, - { Functions_FUNC_GET_USER_INFO, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_user_info(out, len); } }, - { Functions_FUNC_GET_MSG_TYPES, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_get_msg_types(out, len); } }, - { Functions_FUNC_GET_CONTACTS, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contacts(out, len); } }, - { Functions_FUNC_GET_DB_NAMES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_names(out, len); } }, - { Functions_FUNC_GET_DB_TABLES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_tables(r.msg.str, out, len); } }, - { Functions_FUNC_GET_AUDIO_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_audio(r.msg.am.id, r.msg.am.dir, out, len); } }, - { Functions_FUNC_SEND_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_text(r.msg.txt, out, len); } }, - { Functions_FUNC_SEND_IMG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_image(r.msg.file.path, r.msg.file.receiver, out, len); } }, - { Functions_FUNC_SEND_FILE, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_file(r.msg.file.path, r.msg.file.receiver, out, len); } }, - { Functions_FUNC_SEND_XML, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_xml(r.msg.xml, out, len); } }, - { Functions_FUNC_SEND_RICH_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_rich_text(r.msg.rt, out, len); } }, - { Functions_FUNC_SEND_PAT_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_pat(r.msg.pm.roomid, r.msg.pm.wxid, out, len); } }, - { Functions_FUNC_FORWARD_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_forward(r.msg.fm.id, r.msg.fm.receiver, out, len); } }, - { Functions_FUNC_SEND_EMOTION, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_emotion(r.msg.file.path, r.msg.file.receiver, out, len); } }, - { Functions_FUNC_ENABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_enable_recv_msg(receive_message_callback, r.msg.flag, out, len); } }, - { Functions_FUNC_DISABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_disable_recv_msg(out, len); } }, - { Functions_FUNC_EXEC_DB_QUERY, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_exec_db_query(r.msg.query.db, r.msg.query.sql, out, len); } }, - { Functions_FUNC_REFRESH_PYQ, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_refresh_pyq(r.msg.ui64, out, len); } }, - { Functions_FUNC_DOWNLOAD_ATTACH, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_download_attachment(r.msg.att, out, len); } }, - { Functions_FUNC_GET_CONTACT_INFO, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contact_info(r.msg.str, out, len); } }, - { Functions_FUNC_ACCEPT_FRIEND, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_accept_friend(r.msg.v, out, len); } }, - { Functions_FUNC_RECV_TRANSFER, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_receive_transfer(r.msg.tf, out, len); } }, - { Functions_FUNC_REVOKE_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::revoke_message(r.msg.ui64, out, len); } }, - { Functions_FUNC_REFRESH_QRCODE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_login_url(out, len); } }, - { Functions_FUNC_DECRYPT_IMAGE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_decrypt_image(r.msg.dec, out, len); } }, - { Functions_FUNC_EXEC_OCR, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_ocr_result(r.msg.str, out, len); } }, - { Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_add_chatroom_member(r.msg.m, out, len); } }, - { Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_del_chatroom_member(r.msg.m, out, len); } }, - { Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_invite_chatroom_memberr.msg.m, out, len); } }, - // clang-format on -}; - -void receive_message_callback() +static void receive_message_callback() { int rv; Response rsp = Response_init_default; @@ -155,6 +118,73 @@ void receive_message_callback() } } +static bool rpc_enable_recv_msg(bool pyq, uint8_t *out, size_t *len) +{ + return fill_response(out, len, [&](Response &rsp) { + rsp.msg.status = handler.ListenMsg(); + if (rsp.msg.status == 0) { + if (pyq) { + handler.ListenPyq(); + } + msgThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)receive_message_callback, nullptr, 0, nullptr); + if (msgThread == nullptr) { + rsp.msg.status = GetLastError(); + LOG_ERROR("func_enable_recv_txt failed: {}", rsp.msg.status); + } + } + }); +} + +static bool rpc_disable_recv_msg(uint8_t *out, size_t *len) +{ + return fill_response(out, len, [](Response &rsp) { + rsp.msg.status = handler.UnListenMsg(); + if (rsp.msg.status == 0) { + handler.UnListenPyq(); + if (msgThread != nullptr) { + TerminateThread(msgThread, 0); + msgThread = nullptr; + } + } + }); +} + +const std::unordered_map rpc_function_map = { + // clang-format off + { Functions_FUNC_IS_LOGIN, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_is_logged_in(out, len); } }, + { Functions_FUNC_GET_SELF_WXID, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_self_wxid(out, len); } }, + { Functions_FUNC_GET_USER_INFO, [](const Request &r, uint8_t *out, size_t *len) { return userinfo::rpc_get_user_info(out, len); } }, + { Functions_FUNC_GET_MSG_TYPES, [](const Request &r, uint8_t *out, size_t *len) { return handler.rpc_get_msg_types(out, len); } }, + { Functions_FUNC_GET_CONTACTS, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contacts(out, len); } }, + { Functions_FUNC_GET_DB_NAMES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_names(out, len); } }, + { Functions_FUNC_GET_DB_TABLES, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_get_db_tables(r.msg.str, out, len); } }, + { Functions_FUNC_GET_AUDIO_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_audio(r.msg.am, out, len); } }, + { Functions_FUNC_SEND_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_text(r.msg.txt, out, len); } }, + { Functions_FUNC_SEND_IMG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_image(r.msg.file, out, len); } }, + { Functions_FUNC_SEND_FILE, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_file(r.msg.file, out, len); } }, + { Functions_FUNC_SEND_XML, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_xml(r.msg.xml, out, len); } }, + { Functions_FUNC_SEND_EMOTION, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_emotion(r.msg.file, out, len); } }, + { Functions_FUNC_SEND_RICH_TXT, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_rich_text(r.msg.rt, out, len); } }, + { Functions_FUNC_SEND_PAT_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_send_pat(r.msg.pm, out, len); } }, + { Functions_FUNC_FORWARD_MSG, [](const Request &r, uint8_t *out, size_t *len) { return sender.rpc_forward(r.msg.fm, out, len); } }, + { Functions_FUNC_ENABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return rpc_enable_recv_msg(r.msg.flag, out, len); } }, + { Functions_FUNC_DISABLE_RECV_TXT, [](const Request &r, uint8_t *out, size_t *len) { return rpc_disable_recv_msg(out, len); } }, + { Functions_FUNC_EXEC_DB_QUERY, [](const Request &r, uint8_t *out, size_t *len) { return db::rpc_exec_db_query(r.msg.query, out, len); } }, + { Functions_FUNC_ACCEPT_FRIEND, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_accept_friend(r.msg.v, out, len); } }, + { Functions_FUNC_RECV_TRANSFER, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_receive_transfer(r.msg.tf, out, len); } }, + { Functions_FUNC_REFRESH_PYQ, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_refresh_pyq(r.msg.ui64, out, len); } }, + { Functions_FUNC_DOWNLOAD_ATTACH, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_download_attachment(r.msg.att, out, len); } }, + { Functions_FUNC_GET_CONTACT_INFO, [](const Request &r, uint8_t *out, size_t *len) { return contact::rpc_get_contact_info(r.msg.str, out, len); } }, + { Functions_FUNC_REVOKE_MSG, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_revoke_message(r.msg.ui64, out, len); } }, + { Functions_FUNC_REFRESH_QRCODE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_login_url(out, len); } }, + { Functions_FUNC_DECRYPT_IMAGE, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_decrypt_image(r.msg.dec, out, len); } }, + { Functions_FUNC_EXEC_OCR, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_get_ocr_result(r.msg.str, out, len); } }, + { Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_add_chatroom_member(r.msg.m, out, len); } }, + { Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_delete_chatroom_member(r.msg.m, out, len); } }, + { Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_invite_chatroom_member(r.msg.m, out, len); } }, + // clang-format on +}; + static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { bool ret = false;