From 554d62efcf617290e0142eff3b6930f2b1e0de7d Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 28 Jan 2025 20:31:51 +0800 Subject: [PATCH] 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); +};