From 9101b3716204497cffa5db5394021a4d42542f37 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 29 Jun 2024 18:18:22 +0800 Subject: [PATCH] Impl refresh pyq --- WeChatFerry/spy/funcs.cpp | 74 +++----- WeChatFerry/spy/receive_msg.cpp | 302 +++++++++++--------------------- WeChatFerry/spy/rpc_server.cpp | 44 ++--- 3 files changed, 156 insertions(+), 264 deletions(-) diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index 3c6a683..5f808b0 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -23,9 +23,14 @@ namespace fs = std::filesystem; extern bool gIsListeningPyq; extern WxCalls_t g_WxCalls; -extern UINT64 g_WeChatWinDllAddr; +extern QWORD g_WeChatWinDllAddr; -int IsLogin(void) { return (int)GET_UINT64(g_WeChatWinDllAddr + g_WxCalls.login); } +typedef QWORD (*funcGetSNSDataMgr_t)(); +typedef QWORD (*funcGetSnsTimeLineMgr_t)(); +typedef QWORD (*funcGetSNSFirstPage_t)(QWORD, QWORD, QWORD); +typedef QWORD (*funcGetSNSNextPageScene_t)(QWORD, QWORD); + +int IsLogin(void) { return (int)GET_QWORD(g_WeChatWinDllAddr + g_WxCalls.login); } static string get_key(uint8_t header1, uint8_t header2, uint8_t *key) { @@ -114,56 +119,34 @@ string DecryptImage(string src, string dir) return dst; } -#if 0 static int GetFirstPage() { - int rv = -1; - DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1; - DWORD pyqCall2 = g_WeChatWinDllAddr + g_WxCalls.pyq.call2; + int status = -1; - char buf[0xB44] = { 0 }; - __asm { - pushad; - call pyqCall1; - push 0x1; - lea ecx, buf; - push ecx; - mov ecx, eax; - call pyqCall2; - mov rv, eax; - popad; - } + funcGetSNSDataMgr_t GetSNSDataMgr = (funcGetSNSDataMgr_t)(g_WeChatWinDllAddr + 0x22A91C0); + funcGetSNSFirstPage_t GetSNSFirstPage = (funcGetSNSFirstPage_t)(g_WeChatWinDllAddr + 0x2ED9080); - return rv; + QWORD buff[16] = { 0 }; + QWORD mgr = GetSNSDataMgr(); + status = (int)GetSNSFirstPage(mgr, (QWORD)buff, 1); + + return status; } -static int GetNextPage(uint64_t id) +static int GetNextPage(QWORD id) { - int rv = -1; - DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1; - DWORD pyqCall3 = g_WeChatWinDllAddr + g_WxCalls.pyq.call3; + int status = -1; - RawVector_t tmp = { 0 }; + funcGetSnsTimeLineMgr_t GetSnsTimeLineMgr = (funcGetSnsTimeLineMgr_t)(g_WeChatWinDllAddr + 0x2E6B110); + funcGetSNSNextPageScene_t GetSNSNextPageScene = (funcGetSNSNextPageScene_t)(g_WeChatWinDllAddr + 0x2EFEC00); - __asm { - pushad; - call pyqCall1; - lea ecx, tmp; - push ecx; - mov ebx, dword ptr [id + 0x04]; - push ebx; - mov edi, dword ptr [id] - push edi; - mov ecx, eax; - call pyqCall3; - mov rv, eax; - popad; - } + QWORD mgr = GetSnsTimeLineMgr(); + status = (int)GetSNSNextPageScene(mgr, id); - return rv; + return status; } -int RefreshPyq(uint64_t id) +int RefreshPyq(QWORD id) { if (!gIsListeningPyq) { LOG_ERROR("没有启动朋友圈消息接收,参考:enable_receiving_msg"); @@ -177,10 +160,11 @@ int RefreshPyq(uint64_t id) return GetNextPage(id); } -int DownloadAttach(uint64_t id, string thumb, string extra) +#if 0 +int DownloadAttach(QWORD id, string thumb, string extra) { int status = -1; - uint64_t localId; + QWORD localId; uint32_t dbIdx; if (fs::exists(extra)) { // 第一道,不重复下载 @@ -279,10 +263,10 @@ int DownloadAttach(uint64_t id, string thumb, string extra) return status; } -int RevokeMsg(uint64_t id) +int RevokeMsg(QWORD id) { int status = -1; - uint64_t localId; + QWORD localId; uint32_t dbIdx; if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) { LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id)); @@ -325,7 +309,7 @@ int RevokeMsg(uint64_t id) } #endif -string GetAudio(uint64_t id, string dir) +string GetAudio(QWORD id, string dir) { string mp3path = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); mp3path += to_string(id) + ".mp3"; diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index 7093151..6fc96ec 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -24,11 +24,15 @@ extern QWORD g_WeChatWinDllAddr; typedef QWORD (*funcRecvMsg_t)(QWORD, QWORD); typedef QWORD (*funcWxLog_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); +typedef QWORD (*funcRecvPyq_t)(QWORD, QWORD, QWORD); static funcRecvMsg_t funcRecvMsg = nullptr; static funcRecvMsg_t realRecvMsg = nullptr; static funcWxLog_t funcWxLog = nullptr; static funcWxLog_t realWxLog = nullptr; +static funcRecvPyq_t funcRecvPyq = nullptr; +static funcRecvPyq_t realRecvPyq = nullptr; +static bool isMH_Initialized = false; MsgTypes_t GetMsgTypes() { @@ -140,6 +144,38 @@ static QWORD PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD return p; } +static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3) +{ + QWORD startAddr = *(QWORD *)(arg2 + 0x30); + QWORD endAddr = *(QWORD *)(arg2 + 0x38); + + if (startAddr == 0) { + return; + } + + while (startAddr < endAddr) { + WxMsg_t wxMsg; + + wxMsg.type = 0x00; // 朋友圈消息 + wxMsg.is_self = false; + wxMsg.is_group = false; + wxMsg.id = GET_QWORD(startAddr); + wxMsg.ts = GET_DWORD(startAddr + 0x38); + wxMsg.xml = GetStringByWstrAddr(startAddr + 0x9B8); + wxMsg.sender = GetStringByWstrAddr(startAddr + 0x18); + wxMsg.content = GetStringByWstrAddr(startAddr + 0x48); + + { + unique_lock lock(gMutex); + gMsgQueue.push(wxMsg); // 推送到队列 + } + + gCV.notify_all(); // 通知各方消息就绪 + + startAddr += 0x1618; + } +} + void EnableLog() { MH_STATUS status = MH_UNKNOWN; @@ -149,10 +185,13 @@ void EnableLog() } funcWxLog_t funcWxLog = (funcWxLog_t)(g_WeChatWinDllAddr + 0x26DA2D0); - status = MH_Initialize(); - if (status != MH_OK) { - LOG_ERROR("MH_Initialize failed: {}", to_string(status)); - return; + if (!isMH_Initialized) { + status = MH_Initialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Initialize failed: {}", to_string(status)); + return; + } + isMH_Initialized = true; } status = MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast(&realWxLog)); @@ -182,13 +221,14 @@ void DisableLog() return; } - status = MH_Uninitialize(); - if (status != MH_OK) { - LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); - return; - } - gIsLogging = false; + if (isMH_Initialized and !gIsLogging and !gIsListening and !gIsListeningPyq) { + status = MH_Uninitialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); + return; + } + } } void ListenMessage() @@ -200,10 +240,13 @@ void ListenMessage() } funcRecvMsg = (funcRecvMsg_t)(g_WeChatWinDllAddr + g_WxCalls.recvMsg.call); - status = MH_Initialize(); - if (status != MH_OK) { - LOG_ERROR("MH_Initialize failed: {}", to_string(status)); - return; + if (!isMH_Initialized) { + status = MH_Initialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Initialize failed: {}", to_string(status)); + return; + } + isMH_Initialized = true; } status = MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast(&realRecvMsg)); @@ -241,208 +284,73 @@ void UnListenMessage() } gIsListening = false; -} - -void ListenPyq() { } - -void UnListenPyq() { } - -#if 0 -// static DWORD reg_buffer = 0; -// static DWORD recvMsgHookAddr = 0; -// static DWORD recvMsgCallAddr = 0; -// static DWORD recvMsgJumpBackAddr = 0; -// static CHAR recvMsgBackupCode[5] = { 0 }; - -// static DWORD recvPyqHookAddr = 0; -// static DWORD recvPyqCallAddr = 0; -// static DWORD recvPyqJumpBackAddr = 0; -// static CHAR recvPyqBackupCode[5] = { 0 }; - -void HookAddress(DWORD hookAddr, LPVOID funcAddr, CHAR recvMsgBackupCode[5]) -{ - // 组装跳转数据 - BYTE jmpCode[5] = { 0 }; - jmpCode[0] = 0xE9; - - // 计算偏移 - *(DWORD *)&jmpCode[1] = (DWORD)funcAddr - hookAddr - 5; - - // 备份原来的代码 - ReadProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, recvMsgBackupCode, 5, 0); - // 写入新的代码 - WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, jmpCode, 5, 0); -} - -void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5]) -{ - WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, restoreCode, 5, 0); -} - -void DispatchMsg(DWORD reg) -{ - WxMsg_t wxMsg; - try { - wxMsg.id = GET_QWORD(reg + g_WxCalls.recvMsg.msgId); - wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type); - wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf); - wxMsg.ts = GET_DWORD(reg + g_WxCalls.recvMsg.ts); - wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content); - wxMsg.sign = GetStringByStrAddr(reg + g_WxCalls.recvMsg.sign); - wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml); - - string roomid = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.roomId); - if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom - wxMsg.is_group = true; - wxMsg.roomid = roomid; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxid); - } - } else { - wxMsg.is_group = false; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = roomid; - } + if (isMH_Initialized and !gIsLogging and !gIsListening and !gIsListeningPyq) { + status = MH_Uninitialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); + return; } - - wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb); - if (!wxMsg.thumb.empty()) { - wxMsg.thumb = GetHomePath() + wxMsg.thumb; - replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/'); - } - - wxMsg.extra = GetStringByStrAddr(reg + g_WxCalls.recvMsg.extra); - if (!wxMsg.extra.empty()) { - wxMsg.extra = GetHomePath() + wxMsg.extra; - replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/'); - } - } catch (const std::exception &e) { - LOG_ERROR(GB2312ToUtf8(e.what())); - } catch (...) { - LOG_ERROR("Unknow exception."); - } - - { - unique_lock lock(gMutex); - gMsgQueue.push(wxMsg); // 推送到队列 - } - - gCV.notify_all(); // 通知各方消息就绪 -} - -__declspec(naked) void RecieveMsgFunc() -{ - __asm { - pushad - pushfd - push ecx - call DispatchMsg - add esp, 0x4 - popfd - popad - call recvMsgCallAddr // 这个为被覆盖的call - jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令 - } -} - -void ListenMessage() -{ - // DbgMsg("ListenMessage"); - // OutputDebugString(L"ListenMessage\n"); - // MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0); - if (gIsListening || (g_WeChatWinDllAddr == 0)) { - return; - } - - recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook; - recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call; - recvMsgJumpBackAddr = recvMsgHookAddr + 5; - - HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode); - gIsListening = true; -} - -void UnListenMessage() -{ - if (!gIsListening) { - return; - } - UnHookAddress(recvMsgHookAddr, recvMsgBackupCode); - gIsListening = false; -} - -void DispatchPyq(DWORD reg) -{ - DWORD startAddr = *(DWORD *)(reg + g_WxCalls.pyq.start); - DWORD endAddr = *(DWORD *)(reg + g_WxCalls.pyq.end); - - if (startAddr == 0) { - return; - } - - while (startAddr < endAddr) { - WxMsg_t wxMsg; - - wxMsg.type = 0x00; // 朋友圈消息 - wxMsg.is_self = false; - wxMsg.is_group = false; - wxMsg.id = GET_QWORD(startAddr); - wxMsg.ts = GET_DWORD(startAddr + g_WxCalls.pyq.ts); - wxMsg.xml = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.xml); - wxMsg.sender = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.wxid); - wxMsg.content = GetStringByWstrAddr(startAddr + g_WxCalls.pyq.content); - - { - unique_lock lock(gMutex); - gMsgQueue.push(wxMsg); // 推送到队列 - } - - gCV.notify_all(); // 通知各方消息就绪 - - startAddr += g_WxCalls.pyq.step; - } -} - -__declspec(naked) void RecievePyqFunc() -{ - __asm { - pushad - pushfd - push [esp + 0x24] - call DispatchPyq - add esp, 0x4 - popfd - popad - call recvPyqCallAddr // 这个为被覆盖的call - jmp recvPyqJumpBackAddr // 跳回被HOOK指令的下一条指令 } } void ListenPyq() { + MH_STATUS status = MH_UNKNOWN; if (gIsListeningPyq || (g_WeChatWinDllAddr == 0)) { + LOG_WARN("gIsListeningPyq || (g_WeChatWinDllAddr == 0)"); + return; + } + funcRecvPyq = (funcRecvPyq_t)(g_WeChatWinDllAddr + 0x2EFAA10); + + if (!isMH_Initialized) { + status = MH_Initialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Initialize failed: {}", to_string(status)); + return; + } + isMH_Initialized = true; + } + + status = MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast(&realRecvPyq)); + if (status != MH_OK) { + LOG_ERROR("MH_CreateHook failed: {}", to_string(status)); return; } - recvPyqHookAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.hook; - recvPyqCallAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.call; - recvPyqJumpBackAddr = recvPyqHookAddr + 5; + status = MH_EnableHook(funcRecvPyq); + if (status != MH_OK) { + LOG_ERROR("MH_EnableHook failed: {}", to_string(status)); + return; + } - HookAddress(recvPyqHookAddr, RecievePyqFunc, recvPyqBackupCode); gIsListeningPyq = true; } void UnListenPyq() { + MH_STATUS status = MH_UNKNOWN; if (!gIsListeningPyq) { return; } - UnHookAddress(recvPyqHookAddr, recvPyqBackupCode); + status = MH_DisableHook(funcRecvPyq); + if (status != MH_OK) { + LOG_ERROR("MH_DisableHook failed: {}", to_string(status)); + return; + } + + status = MH_Uninitialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); + return; + } + gIsListeningPyq = false; + if (isMH_Initialized and !gIsLogging and !gIsListening and !gIsListeningPyq) { + status = MH_Uninitialize(); + if (status != MH_OK) { + LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); + return; + } + } } -#endif diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index ca1819d..9da06c3 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -571,6 +571,24 @@ bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) return true; } +bool func_refresh_pyq(uint64_t id, 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; +} + #if 0 bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) { @@ -618,24 +636,6 @@ bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, siz return true; } -bool func_refresh_pyq(uint64_t id, 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; -} - bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len) { Response rsp = Response_init_default; @@ -934,6 +934,10 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len 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; + } #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); @@ -943,10 +947,6 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, 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;