From 673ea9c3c0b531addc4c572ccbbf4f938bf7ab57 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 21 May 2023 20:29:21 +0800 Subject: [PATCH 01/35] Fix log path (Crash) --- sdk/injector.cpp | 32 ++++++++++++++++++++++++++++++++ sdk/injector.h | 2 ++ sdk/sdk.cpp | 29 +++++++++++++++-------------- spy/log.cpp | 27 +++++++++++++++++---------- spy/log.h | 4 +++- spy/spy.cpp | 12 +++++++++--- spy/util.h | 5 +++++ wcf/main.cpp | 7 ++----- 8 files changed, 85 insertions(+), 33 deletions(-) diff --git a/sdk/injector.cpp b/sdk/injector.cpp index 38e5f97..3717708 100644 --- a/sdk/injector.cpp +++ b/sdk/injector.cpp @@ -88,3 +88,35 @@ bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcNa CloseHandle(hThread); return true; } + +bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, + DWORD *ret) +{ + void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); + if (pFunc == NULL) { + 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); + + 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); + return false; + } + WaitForSingleObject(hThread, INFINITE); + VirtualFree(pRemoteAddress, 0, MEM_RELEASE); + if (ret != NULL) { + GetExitCodeThread(hThread, ret); + } + + CloseHandle(hThread); + return true; +} diff --git a/sdk/injector.h b/sdk/injector.h index 67d33a5..e212a0e 100644 --- a/sdk/injector.h +++ b/sdk/injector.h @@ -5,3 +5,5 @@ HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase); bool EjectDll(HANDLE process, HMODULE dllBase); bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret); +bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, + DWORD *ret); diff --git a/sdk/sdk.cpp b/sdk/sdk.cpp index 3073711..b720a4d 100644 --- a/sdk/sdk.cpp +++ b/sdk/sdk.cpp @@ -1,10 +1,10 @@ #include "Shlwapi.h" #include "framework.h" +#include #include #include #include "injector.h" -#include "log.h" #include "sdk.h" #include "util.h" @@ -17,7 +17,6 @@ static WCHAR spyDllPath[MAX_PATH] = { 0 }; static int GetDllPath(bool debug, wchar_t *dllPath) { - InitLogger(); GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH); PathRemoveFileSpec(spyDllPath); if (debug) { @@ -27,7 +26,7 @@ static int GetDllPath(bool debug, wchar_t *dllPath) } if (!PathFileExists(spyDllPath)) { - LOG_ERROR("DLL does not exists: {}.", Wstring2String(spyDllPath)); + MessageBox(NULL, spyDllPath, L"文件不存在", 0); return ERROR_FILE_NOT_FOUND; } @@ -46,26 +45,30 @@ int WxInitSDK(bool debug, int port) status = OpenWeChat(&wcPid); if (status != 0) { - LOG_ERROR("OpenWeChat failed: {}.", status); + MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); return status; } Sleep(2000); // 等待微信打开 wcProcess = InjectDll(wcPid, spyDllPath, &spyBase); if (wcProcess == NULL) { - LOG_ERROR("Failed to Inject DLL into WeChat."); + MessageBox(NULL, L"注入失败", L"WxInitSDK", 0); return -1; } - if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)port, NULL)) { - LOG_ERROR("Failed to InitSpy."); + PortPath_t pp = { 0 }; + pp.port = port; + sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); + + if (!CallDllFuncEx(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { + MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0); return -1; } #ifdef WCF FILE *fd = fopen(WCF_LOCK, "wb"); if (fd == NULL) { - LOG_ERROR("Failed to open {}.", WCF_LOCK); + MessageBox(NULL, L"无法打开lock文件", L"WxInitSDK", 0); return -2; } fwrite((uint8_t *)&debug, sizeof(debug), 1, fd); @@ -83,19 +86,19 @@ int WxDestroySDK() bool debug; DWORD pid = GetWeChatPid(); if (pid == 0) { - LOG_ERROR("WeChat is not running."); + MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); return status; } wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (wcProcess == NULL) { - LOG_ERROR("WeChat is not running."); + MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); return -1; } FILE *fd = fopen(WCF_LOCK, "rb"); if (fd == NULL) { - LOG_ERROR("Failed to open {}.", WCF_LOCK); + MessageBox(NULL, L"无法打开lock文件", L"WxDestroySDK", 0); return -2; } fread((uint8_t *)&debug, sizeof(debug), 1, fd); @@ -111,14 +114,12 @@ int WxDestroySDK() } if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) { - LOG_ERROR("Failed to CleanupSpy."); return -1; } if (!EjectDll(wcProcess, spyBase)) { - LOG_ERROR("Failed to Eject DLL."); return -1; // TODO: Unify error codes } - LOG_INFO("WxDestroySDK done."); + return 0; } diff --git a/spy/log.cpp b/spy/log.cpp index 9b432ab..50e8d58 100644 --- a/spy/log.cpp +++ b/spy/log.cpp @@ -1,27 +1,34 @@ +#include + #include "log.h" +#include "util.h" #define LOGGER_NAME "WCF" -#define LOGGER_FILE_NAME "logs/wcf.txt" +#define LOGGER_FILE_NAME "/logs/wcf.txt" #define LOGGER_MAX_SIZE 1024 * 1024 * 10 // 10M #define LOGGER_MAX_FILES 10 // 10 files -void InitLogger() +void InitLogger(std::string path) { - static std::shared_ptr gLogger = nullptr; - if (gLogger != nullptr) { + static std::shared_ptr logger = nullptr; + if (logger != nullptr) { return; } - gLogger = spdlog::rotating_logger_mt(LOGGER_NAME, LOGGER_FILE_NAME, LOGGER_MAX_SIZE, LOGGER_MAX_FILES); - // gLogger = spdlog::stdout_color_mt("console"); + auto filename = std::filesystem::path(path + LOGGER_FILE_NAME).make_preferred().string(); + try { + logger = spdlog::rotating_logger_mt(LOGGER_NAME, filename, LOGGER_MAX_SIZE, LOGGER_MAX_FILES); + } catch (const spdlog::spdlog_ex &ex) { + MessageBox(NULL, String2Wstring(ex.what()).c_str(), L"Init LOGGER ERROR", 0); + } - spdlog::set_default_logger(gLogger); - gLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%s::%#::%!] %v"); + spdlog::set_default_logger(logger); + logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%s::%#::%!] %v"); #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG spdlog::set_level(spdlog::level::debug); - gLogger->flush_on(spdlog::level::debug); + logger->flush_on(spdlog::level::debug); #else - gLogger->flush_on(spdlog::level::info); + logger->flush_on(spdlog::level::info); #endif LOG_DEBUG("InitLogger with debug level"); } diff --git a/spy/log.h b/spy/log.h index c6a2926..dbc66d5 100644 --- a/spy/log.h +++ b/spy/log.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef ENABLE_DEBUG_LOG #include @@ -19,4 +21,4 @@ void log_buffer(uint8_t *buffer, size_t len); #define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__); #define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__); -void InitLogger(); +void InitLogger(std::string path); diff --git a/spy/spy.cpp b/spy/spy.cpp index 5f7d33e..55c98ba 100644 --- a/spy/spy.cpp +++ b/spy/spy.cpp @@ -1,16 +1,22 @@ -#include "spy.h" +#include + #include "load_calls.h" #include "log.h" #include "rpc_server.h" +#include "spy.h" #include "util.h" WxCalls_t g_WxCalls = { 0 }; DWORD g_WeChatWinDllAddr = 0; -void InitSpy(int port) +void InitSpy(LPVOID args) { wchar_t version[16] = { 0 }; - InitLogger(); + PortPath_t *pp = (PortPath_t *)args; + int port = pp->port; + std::string path(pp->path); + + InitLogger(path); g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址 if (g_WeChatWinDllAddr == 0) { LOG_ERROR("获取wechatWin.dll模块地址失败"); diff --git a/spy/util.h b/spy/util.h index 147f706..5d5344e 100644 --- a/spy/util.h +++ b/spy/util.h @@ -13,6 +13,11 @@ #define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr))) #define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +typedef struct PortPath { + int port; + char path[MAX_PATH]; +} PortPath_t; + DWORD GetWeChatPid(); int OpenWeChat(DWORD *pid); int GetWeChatVersion(wchar_t *version); diff --git a/wcf/main.cpp b/wcf/main.cpp index 98ff667..43d797b 100644 --- a/wcf/main.cpp +++ b/wcf/main.cpp @@ -2,14 +2,11 @@ #include #include -#include "framework.h" - -#include "log.h" #include "sdk.h" void help() { - LOG_INFO("\nUsage: \n启动: wcf.exe start port [debug]\n关闭: wcf.exe stop\nport: 命令端口, 消息端口为命令端口+1\n"); + printf("\nUsage: \n启动: wcf.exe start port [debug]\n关闭: wcf.exe stop\nport: 命令端口, 消息端口为命令端口+1\n"); } int main(int argc, char *argv[]) @@ -34,4 +31,4 @@ int main(int argc, char *argv[]) } return ret; -} \ No newline at end of file +} From 1c65ec90ada63c90abfa33eff2ec69d0edd79e15 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 22 May 2023 14:47:26 +0800 Subject: [PATCH 02/35] Impl is_login --- spy/load_calls.cpp | 4 ++-- spy/rpc_server.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index b0c0bc5..6da3af7 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -3,9 +3,9 @@ #include "load_calls.h" -#define SUPPORT_VERSION L"3.7.0.30" +#define SUPPORT_VERSION L"3.9.2.23" WxCalls_t wxCalls = { - 0x2366538, // Login Status + 0x2FFD638, // Login Status { 0x236607C, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home 0x521D30, // Send Message /* Receive Message: diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index fd8790f..814efbe 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -549,6 +549,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_is_login(out, out_len); break; } +#if 0 case Functions_FUNC_GET_SELF_WXID: { LOG_DEBUG("[Functions_FUNC_GET_SELF_WXID]"); ret = func_get_self_wxid(out, out_len); @@ -639,6 +640,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); break; } +#endif default: { LOG_ERROR("[UNKNOW FUNCTION]"); break; From 5701a50bd5342c7b6a3c8e098e7b3269b42026d9 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 23 May 2023 19:57:04 +0800 Subject: [PATCH 03/35] Impl Functions_FUNC_GET_SELF_WXID --- spy/load_calls.cpp | 2 +- spy/rpc_server.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 6da3af7..b23a544 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -6,7 +6,7 @@ #define SUPPORT_VERSION L"3.9.2.23" WxCalls_t wxCalls = { 0x2FFD638, // Login Status - { 0x236607C, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home + { 0x2FFD4E8, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home 0x521D30, // Send Message /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 814efbe..4413654 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -549,12 +549,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_is_login(out, out_len); break; } -#if 0 case Functions_FUNC_GET_SELF_WXID: { LOG_DEBUG("[Functions_FUNC_GET_SELF_WXID]"); ret = func_get_self_wxid(out, out_len); break; } +#if 0 case Functions_FUNC_GET_MSG_TYPES: { LOG_DEBUG("[Functions_FUNC_GET_MSG_TYPES]"); ret = func_get_msg_types(out, out_len); From 9cdfb66bd4ce587c55e46c622f69abebf51a1716 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 24 May 2023 22:01:31 +0800 Subject: [PATCH 04/35] Impl Functions_FUNC_GET_MSG_TYPES --- spy/receive_msg.cpp | 52 +++++++++++++++++++++++++++++---------------- spy/rpc_server.cpp | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/spy/receive_msg.cpp b/spy/receive_msg.cpp index 77f666e..9e58ee9 100644 --- a/spy/receive_msg.cpp +++ b/spy/receive_msg.cpp @@ -28,24 +28,40 @@ static CHAR recvMsgBackupCode[5] = { 0 }; MsgTypes_t GetMsgTypes() { - const MsgTypes_t m = { { 0x01, "文字" }, - { 0x03, "图片" }, - { 0x22, "语音" }, - { 0x25, "好友确认" }, - { 0x28, "POSSIBLEFRIEND_MSG" }, - { 0x2A, "名片" }, - { 0x2B, "视频" }, - { 0x2F, "石头剪刀布 | 表情图片" }, - { 0x30, "位置" }, - { 0x31, "共享实时位置、文件、转账、链接" }, - { 0x32, "VOIPMSG" }, - { 0x33, "微信初始化" }, - { 0x34, "VOIPNOTIFY" }, - { 0x35, "VOIPINVITE" }, - { 0x3E, "小视频" }, - { 0x270F, "SYSNOTICE" }, - { 0x2710, "红包、系统消息" }, - { 0x2712, "撤回消息" } }; + const MsgTypes_t m = { + { 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; } diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 4413654..b86aaaf 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -554,12 +554,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_self_wxid(out, out_len); break; } -#if 0 case Functions_FUNC_GET_MSG_TYPES: { LOG_DEBUG("[Functions_FUNC_GET_MSG_TYPES]"); ret = func_get_msg_types(out, out_len); break; } +#if 0 case Functions_FUNC_GET_CONTACTS: { LOG_DEBUG("[Functions_FUNC_GET_CONTACTS]"); ret = func_get_contacts(out, out_len); From b34cdfd38e5d3a5cddcfb927164343383ea33ec6 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 25 May 2023 00:18:10 +0800 Subject: [PATCH 05/35] Impl Functions_FUNC_GET_CONTACTS --- spy/get_contacts.cpp | 88 +++++++++++++++++++++++++++++++++++++------- spy/load_calls.cpp | 4 +- spy/rpc_server.cpp | 2 +- spy/util.cpp | 25 +++++++++++++ spy/util.h | 10 +++-- 5 files changed, 108 insertions(+), 21 deletions(-) diff --git a/spy/get_contacts.cpp b/spy/get_contacts.cpp index 0fbd5ce..68fd6a5 100644 --- a/spy/get_contacts.cpp +++ b/spy/get_contacts.cpp @@ -7,26 +7,86 @@ extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; +#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 DWORD FindMem(DWORD start, DWORD end, const void *target, size_t len) +{ + uint8_t *p = (uint8_t *)start; + while ((DWORD)p < end) { + if (memcmp((void *)p, target, len) == 0) { + return (DWORD)p; + } + p++; + } + + return 0; +} + +static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t len) +{ + DWORD pfeat = FindMem(start, end, feat, len); + if (pfeat == 0) { + return ""; + } + + DWORD lfeat = GET_DWORD(pfeat + len); + if (lfeat <= 2) { + return ""; + } + + // DbgMsg("pfeat: %08X, lfeat: %d", pfeat, lfeat); + return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat)); +} + vector GetContacts() { vector contacts; - DWORD baseAddr = g_WeChatWinDllAddr + g_WxCalls.contact.base; - DWORD tempAddr = GET_DWORD(baseAddr); - DWORD head = GET_DWORD(tempAddr + g_WxCalls.contact.head); - DWORD node = GET_DWORD(head); + DWORD call1 = g_WeChatWinDllAddr + g_WxCalls.contact.base; + DWORD call2 = g_WeChatWinDllAddr + g_WxCalls.contact.head; - while (node != head) { + int success = 0; + DWORD *addr[3] = { 0, 0, 0 }; + __asm { + pushad + call call1 + lea ecx,addr + push ecx + mov ecx,eax + call call2 + mov success,eax + popad + } + + DWORD pstart = (DWORD)addr[0]; + DWORD pend = (DWORD)addr[2]; + + while (pstart < pend) { RpcContact_t cnt; - cnt.wxid = GetStringByAddress(node + g_WxCalls.contact.wxId); - cnt.code = GetStringByAddress(node + g_WxCalls.contact.wxCode); - cnt.remark = GetStringByAddress(node + g_WxCalls.contact.wxRemark); - cnt.name = GetStringByAddress(node + g_WxCalls.contact.wxName); - cnt.country = GetStringByAddress(node + g_WxCalls.contact.wxCountry); - cnt.province = GetStringByAddress(node + g_WxCalls.contact.wxProvince); - cnt.city = GetStringByAddress(node + g_WxCalls.contact.wxCity); - cnt.gender = GET_DWORD(node + g_WxCalls.contact.wxGender); + DWORD pbin = GET_DWORD(pstart + 0x150); + DWORD lenbin = GET_DWORD(pstart + 0x154); + // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d", pstart, pbin, lenbin); + + cnt.wxid = GetStringByAddress(pstart + g_WxCalls.contact.wxId); + cnt.code = GetStringByAddress(pstart + g_WxCalls.contact.wxCode); + cnt.remark = GetStringByAddress(pstart + g_WxCalls.contact.wxRemark); + cnt.name = GetStringByAddress(pstart + g_WxCalls.contact.wxName); + + 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); + + if (pbin == 0) { + cnt.gender = 0; + } else { + cnt.gender = (DWORD) * (uint8_t *)(pbin + g_WxCalls.contact.wxGender); + } + // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d, cnt.gender: %08X", pstart, pbin, lenbin, cnt.gender); + contacts.push_back(cnt); - node = GET_DWORD(node); + pstart += 0x438; } return contacts; diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index b23a544..07747a8 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -16,8 +16,8 @@ WxCalls_t wxCalls = { { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message /* Get Contacts: - Base, head, wxId, Code, Remark,Name, Gender, Country, Province, City*/ - { 0x23668F4, 0x4C, 0x30, 0x44, 0x78, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 }, + call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ + { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, /* Exec Sql: Exec, base, start, end, slot, name*/ { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index b86aaaf..0c4d635 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -559,12 +559,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_msg_types(out, out_len); break; } -#if 0 case Functions_FUNC_GET_CONTACTS: { LOG_DEBUG("[Functions_FUNC_GET_CONTACTS]"); ret = func_get_contacts(out, out_len); break; } +#if 0 case Functions_FUNC_GET_DB_NAMES: { LOG_DEBUG("[Functions_FUNC_GET_DB_NAMES]"); ret = func_get_db_names(out, out_len); diff --git a/spy/util.cpp b/spy/util.cpp index 5604b34..66a831e 100644 --- a/spy/util.cpp +++ b/spy/util.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "util.h" @@ -244,3 +245,27 @@ wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address) return value; } + +void DbgMsg(const char *zcFormat, ...) +{ + // initialize use of the variable argument array + va_list vaArgs; + va_start(vaArgs, zcFormat); + + // 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); + + // 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); + + OutputDebugStringA(strText.c_str()); +} diff --git a/spy/util.h b/spy/util.h index 5d5344e..b33c685 100644 --- a/spy/util.h +++ b/spy/util.h @@ -8,10 +8,11 @@ #define WECHATINJECTDLL L"spy.dll" #define WECHATINJECTDLL_DEBUG L"spy_debug.dll" -#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr)) -#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr))) -#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr))) -#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr)) +#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr))) +#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr))) +#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +#define GET_WSTRING_FROM_P(addr) ((WCHAR *)(addr)) typedef struct PortPath { int port; @@ -27,3 +28,4 @@ std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); std::wstring String2Wstring(std::string s); std::string Wstring2String(std::wstring ws); std::string GetStringByAddress(DWORD address); +void DbgMsg(const char *zcFormat, ...); From eab38b09a6cf57367405fa09dd5a355d8230f34a Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 26 May 2023 00:19:08 +0800 Subject: [PATCH 06/35] Remove debug message --- spy/get_contacts.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/spy/get_contacts.cpp b/spy/get_contacts.cpp index 68fd6a5..039a89e 100644 --- a/spy/get_contacts.cpp +++ b/spy/get_contacts.cpp @@ -37,7 +37,6 @@ static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t l return ""; } - // DbgMsg("pfeat: %08X, lfeat: %d", pfeat, lfeat); return Wstring2String(wstring(GET_WSTRING_FROM_P(pfeat + FEAT_LEN + 4), lfeat)); } @@ -67,7 +66,6 @@ vector GetContacts() RpcContact_t cnt; DWORD pbin = GET_DWORD(pstart + 0x150); DWORD lenbin = GET_DWORD(pstart + 0x154); - // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d", pstart, pbin, lenbin); cnt.wxid = GetStringByAddress(pstart + g_WxCalls.contact.wxId); cnt.code = GetStringByAddress(pstart + g_WxCalls.contact.wxCode); @@ -83,7 +81,6 @@ vector GetContacts() } else { cnt.gender = (DWORD) * (uint8_t *)(pbin + g_WxCalls.contact.wxGender); } - // DbgMsg("pstart: %08X, pbin: %08X, lenbin: %d, cnt.gender: %08X", pstart, pbin, lenbin, cnt.gender); contacts.push_back(cnt); pstart += 0x438; From ca57fc64aa7794945829fea3edf112f3fcfc9da2 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 27 May 2023 15:38:31 +0800 Subject: [PATCH 07/35] Impl Functions_FUNC_GET_DB_NAMES --- spy/Spy.vcxproj | 1 + spy/Spy.vcxproj.filters | 3 + spy/exec_sql.cpp | 79 ++++++----------- spy/rpc_server.cpp | 2 +- spy/sqlite3.h | 192 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 53 deletions(-) create mode 100644 spy/sqlite3.h diff --git a/spy/Spy.vcxproj b/spy/Spy.vcxproj index 1b4f3e5..f2caedd 100644 --- a/spy/Spy.vcxproj +++ b/spy/Spy.vcxproj @@ -241,6 +241,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto + diff --git a/spy/Spy.vcxproj.filters b/spy/Spy.vcxproj.filters index 2e558b4..d8614de 100644 --- a/spy/Spy.vcxproj.filters +++ b/spy/Spy.vcxproj.filters @@ -90,6 +90,9 @@ 头文件 + + 头文件 + diff --git a/spy/exec_sql.cpp b/spy/exec_sql.cpp index 145c23d..faedd1c 100644 --- a/spy/exec_sql.cpp +++ b/spy/exec_sql.cpp @@ -2,45 +2,18 @@ #include "exec_sql.h" #include "load_calls.h" +#include "sqlite3.h" #include "util.h" -#define SQLITE_OK 0 /* Successful result */ -#define SQLITE_ERROR 1 /* Generic error */ -#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* The database file is locked */ -#define SQLITE_LOCKED 6 /* A table in the database is locked */ -#define SQLITE_NOMEM 7 /* A malloc() failed */ -#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ -#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ -#define SQLITE_FULL 13 /* Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* Internal use only */ -#define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ -#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Data type mismatch */ -#define SQLITE_MISUSE 21 /* Library used incorrectly */ -#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_FORMAT 24 /* Not used */ -#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ -#define SQLITE_NOTADB 26 /* File opened that is not a database file */ -#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ -#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ - -#define SQLITE_INTEGER 1 -#define SQLITE_FLOAT 2 -#define SQLITE_TEXT 3 -#define SQLITE_BLOB 4 -#define SQLITE_NULL 5 +#define OFFSET_DB_INSTANCE 0x2FFDDC8 +#define OFFSET_DB_MICROMSG 0x68 +#define OFFSET_DB_CHAT_MSG 0x1C0 +#define OFFSET_DB_MISC 0x3D8 +#define OFFSET_DB_EMOTION 0x558 +#define OFFSET_DB_MEDIA 0x9B8 +#define OFFSET_DB_BIZCHAT_MSG 0x1120 +#define OFFSET_DB_FUNCTION_MSG 0x11B0 +#define OFFSET_DB_NAME 0x14 extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; @@ -67,25 +40,27 @@ typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int); typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int); typedef int(__cdecl *Sqlite3_finalize)(DWORD *); +static void GetDbHandle(DWORD base, DWORD offset) +{ + wchar_t *wsp; + wsp = (wchar_t *)(*(DWORD *)(base + offset + OFFSET_DB_NAME)); + string dbname = Wstring2String(wstring(wsp)); + dbMap[dbname] = *(DWORD *)(base + offset); +} + dbMap_t GetDbHandles() { - if (!dbMap.empty()) - return dbMap; + dbMap.clear(); - g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); - DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base); - DWORD sqlHandleBeginAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.start); - DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end); - while (sqlHandleBeginAddr < sqlHandleEndAddr) { - DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr; - string dbName = Wstring2String(wstring((wchar_t *)(*(DWORD *)(dwHandle + g_WxCalls.sql.name)))); - DWORD handle = *(DWORD *)(dwHandle + g_WxCalls.sql.slot); - if (handle) { - dbMap[dbName] = handle; - } + DWORD dbInstanceAddr = *(DWORD *)(g_WeChatWinDllAddr + OFFSET_DB_INSTANCE); + + 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 - sqlHandleBeginAddr += 0x04; - } return dbMap; } diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 0c4d635..469864c 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -564,12 +564,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_contacts(out, out_len); break; } -#if 0 case Functions_FUNC_GET_DB_NAMES: { LOG_DEBUG("[Functions_FUNC_GET_DB_NAMES]"); ret = func_get_db_names(out, out_len); break; } +#if 0 case Functions_FUNC_GET_DB_TABLES: { LOG_DEBUG("[Functions_FUNC_GET_DB_TABLES]"); ret = func_get_db_tables(req.msg.str, out, out_len); diff --git a/spy/sqlite3.h b/spy/sqlite3.h new file mode 100644 index 0000000..ac3d2e8 --- /dev/null +++ b/spy/sqlite3.h @@ -0,0 +1,192 @@ +#pragma once + +#include "Windows.h" + +#define SQLITE_OK 0 /* Successful result */ + +/* beginning-of-error-codes */ +#define SQLITE_ERROR 1 /* Generic error */ +#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ +#define SQLITE_FULL 13 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ +#define SQLITE_EMPTY 16 /* Internal use only */ +#define SQLITE_SCHEMA 17 /* The database schema changed */ +#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ +#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Not used */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* File opened that is not a database file */ +#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ +#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ +#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +/* end-of-error-codes */ + +/* +** CAPI3REF: Extended Result Codes +** KEYWORDS: {extended result code definitions} +** +** In its default configuration, SQLite API routines return one of 30 integer +** [result codes]. However, experience has shown that many of +** these result codes are too coarse-grained. They do not provide as +** much information about problems as programmers might like. In an effort to +** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8] +** and later) include +** support for additional result codes that provide more detailed information +** about errors. These [extended result codes] are enabled or disabled +** on a per database connection basis using the +** [sqlite3_extended_result_codes()] API. Or, the extended code for +** the most recent error can be obtained using +** [sqlite3_extended_errcode()]. +*/ +#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8)) +#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8)) +#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8)) +#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8)) +#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8)) +#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8)) +#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8)) +#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8)) +#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8)) +#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8)) +#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8)) +#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8)) +#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8)) +#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8)) +#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8)) +#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8)) +#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8)) +#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8)) +#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8)) +#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8)) +#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8)) +#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8)) +#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8)) +#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8)) +#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8)) +#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8)) +#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8)) +#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8)) +#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8)) +#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8)) +#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8)) +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8)) +#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8)) +#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8)) +#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8)) +#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8)) +#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8)) +#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8)) +#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8)) +#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8)) +#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8)) +#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */ +#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8)) +#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8)) +#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8)) +#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8)) +#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8)) +#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8)) +#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8)) +#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8)) +#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8)) +#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8)) +#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8)) +#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8)) +#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8)) +#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8)) +#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8)) +#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8)) +#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8)) +#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8)) +#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8)) +#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8)) +#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8)) +#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8)) +#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8)) +#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8)) +#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8)) +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */ + +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 +#define SQLITE_TEXT 3 + +#define SQLITE3_EXEC_OFFSET 0x1E24F70 +#define SQLITE3_BACKUP_INIT_OFFSET 0x1DEA900 +#define SQLITE3_PREPARE_OFFSET 0x1E2B8C0 +#define SQLITE3_OPEN_OFFSET 0x1E598B0 +#define SQLITE3_BACKUP_STEP_OFFSET 0x1DEAD00 +#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1DEB440 +#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1DEB450 +#define SQLITE3_BACKUP_FINISH_OFFSET 0x1DEB340 +#define SQLITE3_SLEEP_OFFSET 0x1E5A0F0 +#define SQLITE3_ERRCODE_OFFSET 0x1E58550 +#define SQLITE3_CLOSE_OFFSET 0x1E56CD0 +#define SQLITE3_STEP_OFFSET 0x1DF3770 +#define SQLITE3_COLUMN_COUNT_OFFSET 0x1DF3C80 +#define SQLITE3_COLUMN_NAME_OFFSET 0x1DF4570 +#define SQLITE3_COLUMN_TYPE_OFFSET 0x1DF4410 +#define SQLITE3_COLUMN_BLOB_OFFSET 0x1DF3CC0 +#define SQLITE3_COLUMN_BYTES_OFFSET 0x1DF3DA0 +#define SQLITE3_FINALIZE_OFFSET 0x1DF2740 + +typedef int (*Sqlite3_callback)(void *, int, char **, char **); + +typedef int(__cdecl *Sqlite3_exec)(DWORD, /* An open database */ + const char *sql, /* SQL to be evaluated */ + Sqlite3_callback, /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ +); +typedef DWORD(__cdecl *Sqlite3_backup_init)(DWORD *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + DWORD *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ +); +typedef int(__cdecl *Sqlite3_prepare)(DWORD db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + DWORD **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +typedef int(__cdecl *Sqlite3_open)(const char *filename, DWORD **ppDb); +typedef int(__cdecl *Sqlite3_backup_step)(DWORD *p, int nPage); +typedef int(__cdecl *Sqlite3_backup_remaining)(DWORD *p); +typedef int(__cdecl *Sqlite3_backup_pagecount)(DWORD *p); +typedef int(__cdecl *Sqlite3_backup_finish)(DWORD *p); +typedef int(__cdecl *Sqlite3_sleep)(int); +typedef int(__cdecl *Sqlite3_errcode)(DWORD *db); +typedef int(__cdecl *Sqlite3_close)(DWORD *); + +typedef int(__cdecl *Sqlite3_step)(DWORD *); +typedef int(__cdecl *Sqlite3_column_count)(DWORD *pStmt); +typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int N); +typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int iCol); +typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int iCol); +typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int iCol); +typedef int(__cdecl *Sqlite3_finalize)(DWORD *pStmt); From 99b65fe2f91b0ee1815dd6b6a9d90f80d4373861 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 31 May 2023 15:40:22 +0800 Subject: [PATCH 08/35] Impl Functions_FUNC_GET_DB_TABLES --- spy/rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 469864c..5ba518e 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -569,12 +569,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_db_names(out, out_len); break; } -#if 0 case Functions_FUNC_GET_DB_TABLES: { LOG_DEBUG("[Functions_FUNC_GET_DB_TABLES]"); ret = func_get_db_tables(req.msg.str, out, out_len); break; } +#if 0 case Functions_FUNC_GET_USER_INFO: { LOG_DEBUG("[Functions_FUNC_GET_USER_INFO]"); ret = func_get_user_info(out, out_len); From 4ef478a5bb6f37cc68247db3ed939a1656efc810 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 1 Jun 2023 15:44:05 +0800 Subject: [PATCH 09/35] Impl Functions_FUNC_GET_USER_INFO --- spy/rpc_server.cpp | 2 +- spy/user_info.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 5ba518e..f58af3c 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -574,12 +574,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_db_tables(req.msg.str, out, out_len); break; } -#if 0 case Functions_FUNC_GET_USER_INFO: { LOG_DEBUG("[Functions_FUNC_GET_USER_INFO]"); ret = func_get_user_info(out, out_len); break; } +#if 0 case Functions_FUNC_SEND_TXT: { LOG_DEBUG("[Functions_FUNC_SEND_TXT]"); ret = func_send_txt(req.msg.txt, out, out_len); diff --git a/spy/user_info.cpp b/spy/user_info.cpp index 3797e45..166c743 100644 --- a/spy/user_info.cpp +++ b/spy/user_info.cpp @@ -33,7 +33,7 @@ UserInfo_t GetUserInfo() ui.wxid = GetSelfWxid(); ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName); ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.mobile); - ui.home = GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.home); + ui.home = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)); return ui; } From b7c71152e13482322aeaf5f0fa8e099d1e6d04ae Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 2 Jun 2023 17:35:52 +0800 Subject: [PATCH 10/35] Impl Functions_FUNC_SEND_TXT --- spy/load_calls.cpp | 2 +- spy/rpc_server.cpp | 2 +- spy/send_msg.cpp | 28 ++++++++++++++++++++-------- spy/spy_types.h | 8 +++++++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 07747a8..1164c98 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -7,7 +7,7 @@ WxCalls_t wxCalls = { 0x2FFD638, // Login Status { 0x2FFD4E8, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home - 0x521D30, // Send Message + { 0x768140, 0xCE6C80, 0x756960 }, // Send Message /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ { 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70, 0x198, 0x1AC }, diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index f58af3c..3d76804 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -579,12 +579,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_get_user_info(out, out_len); break; } -#if 0 case Functions_FUNC_SEND_TXT: { LOG_DEBUG("[Functions_FUNC_SEND_TXT]"); ret = func_send_txt(req.msg.txt, out, out_len); break; } +#if 0 case Functions_FUNC_SEND_IMG: { LOG_DEBUG("[Functions_FUNC_SEND_IMG]"); ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); diff --git a/spy/send_msg.cpp b/spy/send_msg.cpp index 7c93e5e..d26ca62 100644 --- a/spy/send_msg.cpp +++ b/spy/send_msg.cpp @@ -13,12 +13,15 @@ extern string GetSelfWxid(); // Defined in spy.cpp void SendTextMessage(string wxid, string msg, string atWxids) { - char buffer[0x3B0] = { 0 }; + int success = 0; + char buffer[0x2D8] = { 0 }; WxString_t wxMsg = { 0 }; WxString_t wxWxid = { 0 }; // 发送消息Call地址 = 微信基址 + 偏移 - DWORD sendCallAddress = g_WeChatWinDllAddr + g_WxCalls.sendTextMsg; + DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendText.call1; + DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendText.call2; + DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendText.call3; wstring wsWxid = String2Wstring(wxid); wstring wsMsg = String2Wstring(msg); @@ -49,15 +52,24 @@ void SendTextMessage(string wxid, string msg, string atWxids) __asm { + pushad; + call sendCall1; + push 0x0; + push 0x0; + push 0x0; + push 0x1; lea eax, vTxtAtWxids; - push 0x01; push eax; - lea edi, wxMsg; - push edi; + lea eax, wxMsg; + push eax; lea edx, wxWxid; lea ecx, buffer; - call sendCallAddress; - add esp, 0xC; + call sendCall2; + mov success, eax; + add esp, 0x18; + lea ecx, buffer; + call sendCall3; + popad; } } @@ -260,7 +272,7 @@ void SendEmotionMessage(string wxid, string path) return; } - char buffer[0x1C] = { 0 }; + char buffer[0x1C] = { 0 }; WxString_t emoWxid = { 0 }; WxString_t emoPath = { 0 }; WxString_t nullbuffer = { 0 }; diff --git a/spy/spy_types.h b/spy/spy_types.h index e11860e..baf71bc 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -23,6 +23,12 @@ typedef struct RecvMsg { DWORD extra; // 附加数据 } RecvMsg_t; +typedef struct SendText { + DWORD call1; + DWORD call2; + DWORD call3; +} SendText_t; + typedef struct Sendfile { DWORD call1; DWORD call2; @@ -79,7 +85,7 @@ typedef struct TF { typedef struct WxCalls { DWORD login; // 登录状态 UserInfoCall_t ui; // 用户信息 - DWORD sendTextMsg; // 发送消息 + SendText_t sendText; // 发送消息 RecvMsg_t recvMsg; // 接收消息 Sendfile_t sendImg; // 发送图片 Sendfile_t sendFile; // 发送文件 From 479827789da0def4d171af9e90bb1d5d960ce258 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 3 Jun 2023 18:13:18 +0800 Subject: [PATCH 11/35] Impl Functions_FUNC_SEND_IMG --- spy/load_calls.cpp | 2 +- spy/rpc_server.cpp | 2 +- spy/send_msg.cpp | 45 +++++++++++++++++++++++++-------------------- spy/spy_types.h | 1 + 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 1164c98..606811d 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -11,7 +11,7 @@ WxCalls_t wxCalls = { /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ { 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70, 0x198, 0x1AC }, - { 0xBD780, 0x771980, 0x521640 }, // Send Image Message + { 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message { 0xC3B70, 0x771980, 0x3ED8C0 }, // Send File Message { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 3d76804..5aa0c48 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -584,12 +584,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_send_txt(req.msg.txt, out, out_len); break; } -#if 0 case Functions_FUNC_SEND_IMG: { LOG_DEBUG("[Functions_FUNC_SEND_IMG]"); ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); break; } +#if 0 case Functions_FUNC_SEND_FILE: { LOG_DEBUG("[Functions_FUNC_SEND_FILE]"); ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); diff --git a/spy/send_msg.cpp b/spy/send_msg.cpp index d26ca62..737280b 100644 --- a/spy/send_msg.cpp +++ b/spy/send_msg.cpp @@ -13,7 +13,7 @@ extern string GetSelfWxid(); // Defined in spy.cpp void SendTextMessage(string wxid, string msg, string atWxids) { - int success = 0; + int success = 0; char buffer[0x2D8] = { 0 }; WxString_t wxMsg = { 0 }; WxString_t wxWxid = { 0 }; @@ -78,11 +78,12 @@ void SendImageMessage(string wxid, string path) if (g_WeChatWinDllAddr == 0) { return; } + int success = 0; DWORD tmpEAX = 0; - char buf1[0x48] = { 0 }; - char buf2[0x3B0] = { 0 }; + char buf[0x2D8] = { 0 }; WxString_t imgWxid = { 0 }; WxString_t imgPath = { 0 }; + WxString_t unkObj = { 0 }; wstring wsWxid = String2Wstring(wxid); wstring wspath = String2Wstring(path); @@ -99,25 +100,29 @@ void SendImageMessage(string wxid, string path) DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1; DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2; DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3; + DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call4; __asm { - pushad - call sendCall1 - sub esp, 0x14 - mov tmpEAX, eax - lea eax, buf1 - mov ecx, esp - lea edi, imgPath - push eax - call sendCall2 - mov ecx, dword ptr[tmpEAX] - lea eax, imgWxid - push edi - push eax - lea eax, buf2 - push eax - call sendCall3 - popad + pushad; + call sendCall1; + sub esp,0x14; + mov tmpEAX,eax; + lea eax,unkObj; + mov ecx,esp; + lea edi,imgPath; + push eax; + call sendCall2; + mov ecx,dword ptr [tmpEAX]; + lea eax,imgWxid; + push edi; + push eax; + lea eax,buf; + push eax; + call sendCall3; + mov success,eax; + lea ecx,buf; + call sendCall4; + popad; } } diff --git a/spy/spy_types.h b/spy/spy_types.h index baf71bc..d4ed35b 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -33,6 +33,7 @@ typedef struct Sendfile { DWORD call1; DWORD call2; DWORD call3; + DWORD call4; } Sendfile_t; typedef struct Contact { From 19c8a055e1cee24cd4cae6163bc3e257d9b3a0be Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 4 Jun 2023 18:37:36 +0800 Subject: [PATCH 12/35] Impl Functions_FUNC_SEND_FILE --- spy/load_calls.cpp | 2 +- spy/rpc_server.cpp | 2 +- spy/send_msg.cpp | 92 ++++++++++++++++++++++++---------------------- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 606811d..c0ebe7d 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -12,7 +12,7 @@ WxCalls_t wxCalls = { Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ { 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70, 0x198, 0x1AC }, { 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message - { 0xC3B70, 0x771980, 0x3ED8C0 }, // Send File Message + { 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message /* Get Contacts: diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 5aa0c48..c297bf9 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -589,12 +589,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); break; } -#if 0 case Functions_FUNC_SEND_FILE: { LOG_DEBUG("[Functions_FUNC_SEND_FILE]"); ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); break; } +#if 0 case Functions_FUNC_SEND_XML: { LOG_DEBUG("[Functions_FUNC_SEND_XML]"); ret = func_send_xml(req.msg.xml, out, out_len); diff --git a/spy/send_msg.cpp b/spy/send_msg.cpp index 737280b..a53e306 100644 --- a/spy/send_msg.cpp +++ b/spy/send_msg.cpp @@ -78,12 +78,12 @@ void SendImageMessage(string wxid, string path) if (g_WeChatWinDllAddr == 0) { return; } - int success = 0; - DWORD tmpEAX = 0; - char buf[0x2D8] = { 0 }; - WxString_t imgWxid = { 0 }; - WxString_t imgPath = { 0 }; - WxString_t unkObj = { 0 }; + int success = 0; + DWORD tmpEAX = 0; + char buf[0x2D8] = { 0 }; + WxString_t imgWxid = { 0 }; + WxString_t imgPath = { 0 }; + WxString_t nullbuffer = { 0 }; wstring wsWxid = String2Wstring(wxid); wstring wspath = String2Wstring(path); @@ -107,7 +107,7 @@ void SendImageMessage(string wxid, string path) call sendCall1; sub esp,0x14; mov tmpEAX,eax; - lea eax,unkObj; + lea eax,nullbuffer; mov ecx,esp; lea edi,imgPath; push eax; @@ -131,8 +131,9 @@ void SendFileMessage(string wxid, string path) if (g_WeChatWinDllAddr == 0) { return; } + int success = 0; DWORD tmpEAX = 0; - char buffer[0x3B0] = { 0 }; + char buffer[0x2D8] = { 0 }; WxString_t fileWxid = { 0 }; WxString_t filePath = { 0 }; WxString_t nullbuffer = { 0 }; @@ -152,46 +153,49 @@ void SendFileMessage(string wxid, string path) DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call1; DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call2; DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call3; + DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call4; __asm { - pushad; - pushfd; - call sendCall1; - sub esp, 0x14; - mov tmpEAX, eax; - lea eax, nullbuffer; - mov ecx, esp; - push eax; - call sendCall2; - push 0x00DBE200; - sub esp, 0x14; - mov edi, esp; - mov dword ptr ds : [edi] , 0x0; - mov dword ptr ds : [edi + 0x4] , 0x0; - mov dword ptr ds : [edi + 0x8] , 0x0; - mov dword ptr ds : [edi + 0xC] , 0x0; - mov dword ptr ds : [edi + 0x10] , 0x0; - sub esp, 0x14; - lea eax, filePath; - mov ecx, esp; - push eax; - call sendCall2; - sub esp, 0x14; - lea eax, fileWxid; - mov ecx, esp; - push eax; - call sendCall2; - mov ecx, dword ptr [tmpEAX]; - lea eax, buffer; - push eax; - call sendCall3; - mov al,byte ptr [eax + 0x38]; - movzx eax,al; - popfd; - popad; + pushad; + pushfd; + call sendCall1; + sub esp, 0x14; + mov tmpEAX, eax; + lea eax, nullbuffer; + mov ecx, esp; + push eax; + call sendCall2; + push 0x0; + sub esp, 0x14; + mov edi, esp; + mov dword ptr[edi], 0; + mov dword ptr[edi + 0x4], 0; + mov dword ptr[edi + 0x8], 0; + mov dword ptr[edi + 0xc], 0; + mov dword ptr[edi + 0x10], 0; + sub esp, 0x14; + lea eax, filePath; + mov ecx, esp; + push eax; + call sendCall2; + sub esp, 0x14; + lea eax, fileWxid; + mov ecx, esp; + push eax; + call sendCall2; + mov ecx, dword ptr[tmpEAX]; + lea eax, buffer; + push eax; + call sendCall3; + mov al, byte ptr[eax + 0x38]; + movzx eax, al; + mov success, eax; + lea ecx, buffer; + call sendCall4; + popfd; + popad; } } - void SendXmlMessage(string receiver, string xml, string path, int type) { if (g_WeChatWinDllAddr == 0) { From 14a7def6f4cfee1986143b51074d24da98384e88 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 5 Jun 2023 19:26:07 +0800 Subject: [PATCH 13/35] Impl Functions_FUNC_DECRYPT_IMAGE --- spy/rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index c297bf9..b2b2451 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -635,12 +635,12 @@ 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.tid, out, out_len); break; } +#endif case Functions_FUNC_DECRYPT_IMAGE: { LOG_DEBUG("[FUNCTIONS_FUNC_DECRYPT_IMAGE]"); ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); break; } -#endif default: { LOG_ERROR("[UNKNOW FUNCTION]"); break; From e70fa39ad8f52aa0abacc7724cb0ab89b9b5f59b Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 7 Jun 2023 15:50:12 +0800 Subject: [PATCH 14/35] Fix Functions_FUNC_GET_USER_INFO --- spy/load_calls.cpp | 2 +- spy/user_info.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index c0ebe7d..8218767 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -6,7 +6,7 @@ #define SUPPORT_VERSION L"3.9.2.23" WxCalls_t wxCalls = { 0x2FFD638, // Login Status - { 0x2FFD4E8, 0x23660F4, 0x2366128, 0x2386F7C }, // User Info: wxid, nickname, mobile, home + { 0x2FFD4E8, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home { 0x768140, 0xCE6C80, 0x756960 }, // Send Message /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ diff --git a/spy/user_info.cpp b/spy/user_info.cpp index 166c743..a7e6760 100644 --- a/spy/user_info.cpp +++ b/spy/user_info.cpp @@ -6,14 +6,23 @@ extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; -string GetHomePath() { return GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.home); } +static char home[MAX_PATH] = { 0 }; + +string GetHomePath() +{ + if (home[0] == 0) { + string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)); + strncpy_s(home, path.c_str(), path.size()); + } + + return string(home); +} string GetSelfWxid() { DWORD wxidType = 0; try { wxidType = GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.ui.wxid + 0x14); - LOG_DEBUG("WeChatWinDll: {:#x}, wxid type: {:#x}", g_WeChatWinDllAddr, wxidType); if (wxidType == 0xF) { return GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.wxid); } else { @@ -33,7 +42,7 @@ UserInfo_t GetUserInfo() ui.wxid = GetSelfWxid(); ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName); ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.mobile); - ui.home = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)); + ui.home = GetHomePath(); return ui; } From 29e260e3451f5744b40dfeb2a5abc55623a0ced3 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 8 Jun 2023 16:23:21 +0800 Subject: [PATCH 15/35] Impl Functions_FUNC_ENABLE_RECV_TXT --- spy/load_calls.cpp | 2 +- spy/receive_msg.cpp | 39 ++++++++++++++++++++------------------- spy/rpc_server.cpp | 2 ++ spy/util.cpp | 12 ++++++++++++ spy/util.h | 2 ++ 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 8218767..492cb18 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -10,7 +10,7 @@ WxCalls_t wxCalls = { { 0x768140, 0xCE6C80, 0x756960 }, // Send Message /* Receive Message: Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ - { 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70, 0x198, 0x1AC }, + { 0xD19A0B, 0x756960, 0x38, 0x3C, 0x194, 0x1FC, 0x48, 0x180, 0x70, 0x1A8, 0x1BC }, { 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message { 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message diff --git a/spy/receive_msg.cpp b/spy/receive_msg.cpp index 9e58ee9..6be0b1e 100644 --- a/spy/receive_msg.cpp +++ b/spy/receive_msg.cpp @@ -89,21 +89,20 @@ void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5]) void DispatchMsg(DWORD reg) { WxMsg_t wxMsg; - DWORD *p = (DWORD *)reg; // 消息结构基址 - wxMsg.type = GET_DWORD(*p + g_WxCalls.recvMsg.type); - wxMsg.is_self = GET_DWORD(*p + g_WxCalls.recvMsg.isSelf); - wxMsg.id = GetStringByAddress(*p + g_WxCalls.recvMsg.msgId); - wxMsg.xml = GetStringByAddress(*p + g_WxCalls.recvMsg.msgXml); + wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type); + wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf); + wxMsg.id = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgId); + wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml); - string roomid = GetStringByAddress(*p + g_WxCalls.recvMsg.roomId); + 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 = GetStringByAddress(*p + g_WxCalls.recvMsg.wxId); + wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxId); } } else { wxMsg.is_group = false; @@ -114,15 +113,16 @@ void DispatchMsg(DWORD reg) } } - wxMsg.content = GetStringByAddress(*p + g_WxCalls.recvMsg.content); - wxMsg.thumb = GetStringByAddress(*p + g_WxCalls.recvMsg.thumb); + wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content); + + wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb); if (!wxMsg.thumb.empty()) { - wxMsg.thumb = GetHomePath() + "\\WeChat Files\\" + wxMsg.thumb; + wxMsg.thumb = GetHomePath() + wxMsg.thumb; } - wxMsg.extra = GetStringByAddress(*p + g_WxCalls.recvMsg.extra); + wxMsg.extra = GetStringByStrAddr(reg + g_WxCalls.recvMsg.extra); if (!wxMsg.extra.empty()) { - wxMsg.extra = GetHomePath() + "\\WeChat Files\\" + wxMsg.extra; + wxMsg.extra = GetHomePath() + wxMsg.extra; } { @@ -136,13 +136,13 @@ void DispatchMsg(DWORD reg) __declspec(naked) void RecieveMsgFunc() { __asm { - mov reg_buffer, edi // 把值复制出来 - } - - DispatchMsg(reg_buffer); - - __asm - { + pushad + pushfd + push ecx + call DispatchMsg + add esp, 0x4 + popfd + popad call recvMsgCallAddr // 这个为被覆盖的call jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令 } @@ -150,6 +150,7 @@ __declspec(naked) void RecieveMsgFunc() void ListenMessage() { + // DbgMsg("ListenMessage"); // OutputDebugString(L"ListenMessage\n"); // MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0); if (gIsListening || (g_WeChatWinDllAddr == 0)) { diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index b2b2451..e48536a 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -605,11 +605,13 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len); break; } +#endif case Functions_FUNC_ENABLE_RECV_TXT: { LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]"); ret = func_enable_recv_txt(out, out_len); break; } +#if 0 case Functions_FUNC_DISABLE_RECV_TXT: { LOG_DEBUG("[Functions_FUNC_DISABLE_RECV_TXT]"); ret = func_disable_recv_txt(out, out_len); diff --git a/spy/util.cpp b/spy/util.cpp index 66a831e..7b22be5 100644 --- a/spy/util.cpp +++ b/spy/util.cpp @@ -213,6 +213,18 @@ string GetStringByAddress(DWORD address) return Wstring2String(wstring(GET_WSTRING(address), strLength)); } +string GetStringByStrAddr(DWORD addr) +{ + DWORD strLength = GET_DWORD(addr + 4); + return strLength ? string(GET_STRING(addr), strLength) : string(); +} + +string GetStringByWstrAddr(DWORD addr) +{ + DWORD strLength = GET_DWORD(addr + 4); + return strLength ? Wstring2String(wstring(GET_WSTRING(addr), strLength)) : string(); +} + DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address) { DWORD value = 0; diff --git a/spy/util.h b/spy/util.h index b33c685..5cf305f 100644 --- a/spy/util.h +++ b/spy/util.h @@ -28,4 +28,6 @@ std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); std::wstring String2Wstring(std::string s); std::string Wstring2String(std::wstring ws); std::string GetStringByAddress(DWORD address); +std::string GetStringByStrAddr(DWORD addr); +std::string GetStringByWstrAddr(DWORD addr); void DbgMsg(const char *zcFormat, ...); From 5e75f1c633fd7000b99b6b1964754eb89aee657c Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 9 Jun 2023 16:49:44 +0800 Subject: [PATCH 16/35] Impl Functions_FUNC_DISABLE_RECV_TXT --- spy/rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index e48536a..b33e9cc 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -611,12 +611,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_enable_recv_txt(out, out_len); break; } -#if 0 case Functions_FUNC_DISABLE_RECV_TXT: { LOG_DEBUG("[Functions_FUNC_DISABLE_RECV_TXT]"); ret = func_disable_recv_txt(out, out_len); break; } +#if 0 case Functions_FUNC_EXEC_DB_QUERY: { LOG_DEBUG("[Functions_FUNC_EXEC_DB_QUERY]"); ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); From 573d430457e69c66d2381e0880c088364bb80c3e Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 10 Jun 2023 16:57:54 +0800 Subject: [PATCH 17/35] Impl Functions_FUNC_EXEC_DB_QUERY --- spy/exec_sql.cpp | 40 ++++++++++------------------------------ spy/rpc_server.cpp | 2 +- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/spy/exec_sql.cpp b/spy/exec_sql.cpp index faedd1c..6fc3e3a 100644 --- a/spy/exec_sql.cpp +++ b/spy/exec_sql.cpp @@ -15,31 +15,11 @@ #define OFFSET_DB_FUNCTION_MSG 0x11B0 #define OFFSET_DB_NAME 0x14 -extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; typedef map dbMap_t; static dbMap_t dbMap; -// 回调函数指针 -typedef int (*sqlite3_callback)(void *, int, char **, char **); - -// sqlite3_exec函数指针 -typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which the SQL executes */ - const char *, /* The SQL to be executed */ - sqlite3_callback, /* Invoke this callback routine */ - void *, /* First argument to xCallback() */ - char ** /* Write error messages here */ -); -typedef int(__cdecl *Sqlite3_prepare)(DWORD, const char *, int, DWORD **, int); -typedef int(__cdecl *Sqlite3_step)(DWORD *); -typedef int(__cdecl *Sqlite3_column_count)(DWORD *); -typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int); -typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int); -typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int); -typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int); -typedef int(__cdecl *Sqlite3_finalize)(DWORD *); - static void GetDbHandle(DWORD base, DWORD offset) { wchar_t *wsp; @@ -108,9 +88,9 @@ DbTables_t GetDbTables(const string db) } const char *sql = "select name, sql from sqlite_master where type=\"table\";"; - Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec); + Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + SQLITE3_EXEC_OFFSET); - p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, (void *)&tables, 0); + p_Sqlite3_exec(it->second, sql, (Sqlite3_callback)cbGetTables, (void *)&tables, 0); return tables; } @@ -118,14 +98,14 @@ DbTables_t GetDbTables(const string db) DbRows_t ExecDbQuery(const string db, const string sql) { DbRows_t rows; - Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + 0x14227F0); - Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + 0x13EA780); - Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + 0x13EACD0); - Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + 0x13EB630); - Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + 0x13EB470); - Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + 0x13EAD10); - Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + 0x13EADD0); - Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730); + 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(); diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index b33e9cc..1419c27 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -616,12 +616,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_disable_recv_txt(out, out_len); break; } -#if 0 case Functions_FUNC_EXEC_DB_QUERY: { LOG_DEBUG("[Functions_FUNC_EXEC_DB_QUERY]"); ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); break; } +#if 0 case Functions_FUNC_ACCEPT_FRIEND: { LOG_DEBUG("[Functions_FUNC_ACCEPT_FRIEND]"); ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); From 591a958f859296069f3d85c2f28f512540aa7e0f Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 11 Jun 2023 17:56:54 +0800 Subject: [PATCH 18/35] Fix GetHomePath --- spy/user_info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spy/user_info.cpp b/spy/user_info.cpp index a7e6760..79e800d 100644 --- a/spy/user_info.cpp +++ b/spy/user_info.cpp @@ -11,7 +11,7 @@ static char home[MAX_PATH] = { 0 }; string GetHomePath() { if (home[0] == 0) { - string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)); + string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + g_WxCalls.ui.home)) + "\\WeChat Files\\"; strncpy_s(home, path.c_str(), path.size()); } From 18078f31712baf8e3a9ce32b9e75377e01d22d9b Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 12 Jun 2023 23:41:51 +0800 Subject: [PATCH 19/35] Impl Functions_FUNC_ACCEPT_FRIEND --- spy/accept_new_friend.cpp | 53 ++++++++++++++++----------------------- spy/load_calls.cpp | 6 ++--- spy/rpc_server.cpp | 2 +- spy/spy_types.h | 3 ++- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/spy/accept_new_friend.cpp b/spy/accept_new_friend.cpp index 938cf72..97f6ccc 100644 --- a/spy/accept_new_friend.cpp +++ b/spy/accept_new_friend.cpp @@ -5,36 +5,22 @@ #include "log.h" #include "util.h" -typedef struct NewFriendParam { - DWORD handle; - DWORD *status; - DWORD statusEnd1; - DWORD statusEnd2; - char buffer[0x3C]; -} NewFriendParam_t; - extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; int AcceptNewFriend(std::string v3, std::string v4, int scene) { - int isSucceeded = 0; + int success = 0; - DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1; - DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2; - DWORD acceptNewFriendHandle = g_WeChatWinDllAddr + g_WxCalls.anf.handle; + 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; - char buffer[0x94] = { 0 }; - NewFriendParam_t param = { 0 }; - DWORD status[9] = { 0xB2, (DWORD)¶m, 0xB5, (DWORD)¶m, 0xB0, (DWORD)¶m, 0xB1, (DWORD)¶m, 0x00 }; + char buffer[0x40] = { 0 }; + char nullbuffer[0x3CC] = { 0 }; - param.handle = acceptNewFriendHandle; - param.status = status; - param.statusEnd1 = (DWORD)status + 0x20; - param.statusEnd2 = (DWORD)status + 0x20; - NewFriendParam_t *pParam = ¶m; - - LOG_DEBUG("v3: {}\nv4: {}", v3, v4); + LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene); WxString_t wxV3 = { 0 }; WxString_t wxV4 = { 0 }; std::wstring wsV3 = String2Wstring(v3); @@ -51,26 +37,31 @@ int AcceptNewFriend(std::string v3, std::string v4, int scene) __asm { pushad; pushfd; - push 0x0; - mov eax, scene; - push eax; + lea ecx, buffer; + call acceptNewFriendCall1; + mov esi, 0x0; + mov edi, scene; + push esi; + push edi; sub esp, 0x14; mov ecx, esp; lea eax, wxV4; push eax; - call acceptNewFriendCall1; + call acceptNewFriendCall2; sub esp, 0x8; push 0x0; - lea eax, buffer; + lea eax, nullbuffer; push eax; lea eax, wxV3; push eax; - mov ecx, pParam; - call acceptNewFriendCall2; - mov isSucceeded, eax; + lea ecx, buffer; + call acceptNewFriendCall3; + mov success, eax; + lea ecx, buffer; + call acceptNewFriendCall4; popfd; popad; } - return isSucceeded; // 成功返回 1 + return success; // 成功返回 1 } diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 492cb18..b25c339 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -21,9 +21,9 @@ WxCalls_t wxCalls = { /* Exec Sql: Exec, base, start, end, slot, name*/ { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, - { 0x771980, 0x2AE8D0, 0x1EE40E0 }, // Accept New Friend application - { 0xE29F0, 0x771980, 0x43D8D0 }, // Add chatroom members - { 0x771980, 0xCD2A90 } // Receive transfer + { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application + { 0xE29F0, 0x771980, 0x43D8D0 }, // Add chatroom members + { 0x771980, 0xCD2A90 } // Receive transfer }; int LoadCalls(const wchar_t *version, WxCalls_t *calls) diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 1419c27..6ca982d 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -621,12 +621,12 @@ 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; } -#if 0 case Functions_FUNC_ACCEPT_FRIEND: { LOG_DEBUG("[Functions_FUNC_ACCEPT_FRIEND]"); ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); break; } +#if 0 case Functions_FUNC_ADD_ROOM_MEMBERS: { LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]"); ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); diff --git a/spy/spy_types.h b/spy/spy_types.h index d4ed35b..22a8c81 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -61,7 +61,8 @@ typedef struct Sql { typedef struct NewFriend { DWORD call1; DWORD call2; - DWORD handle; + DWORD call3; + DWORD call4; } NewFriend_t; typedef struct RoomMember { From e0f8edb647f5b906962c5b92eeeef33f03fe9173 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 13 Jun 2023 07:40:38 +0800 Subject: [PATCH 20/35] Rename files --- spy/Spy.vcxproj | 4 ++-- spy/Spy.vcxproj.filters | 4 ++-- spy/{add_chatroom_member.cpp => chatroom_mgmt.cpp} | 2 +- spy/{add_chatroom_member.h => chatroom_mgmt.h} | 0 spy/rpc_server.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename spy/{add_chatroom_member.cpp => chatroom_mgmt.cpp} (98%) rename spy/{add_chatroom_member.h => chatroom_mgmt.h} (100%) diff --git a/spy/Spy.vcxproj b/spy/Spy.vcxproj index f2caedd..471d676 100644 --- a/spy/Spy.vcxproj +++ b/spy/Spy.vcxproj @@ -227,7 +227,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - + @@ -252,7 +252,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - + diff --git a/spy/Spy.vcxproj.filters b/spy/Spy.vcxproj.filters index d8614de..1f814de 100644 --- a/spy/Spy.vcxproj.filters +++ b/spy/Spy.vcxproj.filters @@ -75,7 +75,7 @@ nnrpc - + 头文件 @@ -143,7 +143,7 @@ nnrpc - + 源文件 diff --git a/spy/add_chatroom_member.cpp b/spy/chatroom_mgmt.cpp similarity index 98% rename from spy/add_chatroom_member.cpp rename to spy/chatroom_mgmt.cpp index 2341cc3..0600431 100644 --- a/spy/add_chatroom_member.cpp +++ b/spy/chatroom_mgmt.cpp @@ -1,7 +1,7 @@ #include "framework.h" #include -#include "add_chatroom_member.h" +#include "chatroom_mgmt.h" #include "load_calls.h" #include "log.h" #include "util.h" diff --git a/spy/add_chatroom_member.h b/spy/chatroom_mgmt.h similarity index 100% rename from spy/add_chatroom_member.h rename to spy/chatroom_mgmt.h diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 6ca982d..6bb21fa 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -17,7 +17,7 @@ #include "wcf.pb.h" #include "accept_new_friend.h" -#include "add_chatroom_member.h" +#include "chatroom_mgmt.h" #include "decrypt_image.h" #include "exec_sql.h" #include "get_contacts.h" From a77e2513ce5e04d1220a152e55a13353c00ba470 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 20 Jun 2023 08:10:24 +0800 Subject: [PATCH 21/35] Rename files --- spy/Spy.vcxproj | 6 +- spy/Spy.vcxproj.filters | 10 +-- spy/accept_new_friend.cpp | 67 --------------------- spy/{get_contacts.cpp => contact_mgmt.cpp} | 61 ++++++++++++++++++- spy/{accept_new_friend.h => contact_mgmt.h} | 4 ++ spy/get_contacts.h | 7 --- spy/rpc_server.cpp | 3 +- 7 files changed, 69 insertions(+), 89 deletions(-) delete mode 100644 spy/accept_new_friend.cpp rename spy/{get_contacts.cpp => contact_mgmt.cpp} (61%) rename spy/{accept_new_friend.h => contact_mgmt.h} (56%) delete mode 100644 spy/get_contacts.h diff --git a/spy/Spy.vcxproj b/spy/Spy.vcxproj index 471d676..88117cd 100644 --- a/spy/Spy.vcxproj +++ b/spy/Spy.vcxproj @@ -226,12 +226,11 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - - + @@ -251,12 +250,11 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - - + diff --git a/spy/Spy.vcxproj.filters b/spy/Spy.vcxproj.filters index 1f814de..a7ce58b 100644 --- a/spy/Spy.vcxproj.filters +++ b/spy/Spy.vcxproj.filters @@ -27,13 +27,10 @@ 头文件 - - 头文件 - 头文件 - + 头文件 @@ -104,13 +101,10 @@ 源文件 - - 源文件 - 源文件 - + 源文件 diff --git a/spy/accept_new_friend.cpp b/spy/accept_new_friend.cpp deleted file mode 100644 index 97f6ccc..0000000 --- a/spy/accept_new_friend.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "framework.h" - -#include "accept_new_friend.h" -#include "load_calls.h" -#include "log.h" -#include "util.h" - -extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; - -int AcceptNewFriend(std::string v3, std::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; - - char buffer[0x40] = { 0 }; - char nullbuffer[0x3CC] = { 0 }; - - LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene); - WxString_t wxV3 = { 0 }; - WxString_t wxV4 = { 0 }; - std::wstring wsV3 = String2Wstring(v3); - std::wstring wsV4 = String2Wstring(v4); - - wxV3.text = (wchar_t *)wsV3.c_str(); - wxV3.size = wsV3.size(); - wxV3.capacity = wsV3.capacity(); - - wxV4.text = (wchar_t *)wsV4.c_str(); - wxV4.size = wsV4.size(); - wxV4.capacity = wsV4.capacity(); - - __asm { - pushad; - pushfd; - lea ecx, buffer; - call acceptNewFriendCall1; - mov esi, 0x0; - mov edi, scene; - push esi; - push edi; - sub esp, 0x14; - mov ecx, esp; - lea eax, wxV4; - push eax; - call acceptNewFriendCall2; - sub esp, 0x8; - push 0x0; - lea eax, nullbuffer; - push eax; - lea eax, wxV3; - push eax; - lea ecx, buffer; - call acceptNewFriendCall3; - mov success, eax; - lea ecx, buffer; - call acceptNewFriendCall4; - popfd; - popad; - } - - return success; // 成功返回 1 -} diff --git a/spy/get_contacts.cpp b/spy/contact_mgmt.cpp similarity index 61% rename from spy/get_contacts.cpp rename to spy/contact_mgmt.cpp index 039a89e..bb9780b 100644 --- a/spy/get_contacts.cpp +++ b/spy/contact_mgmt.cpp @@ -1,7 +1,8 @@ #pragma execution_character_set("utf-8") -#include "get_contacts.h" +#include "contact_mgmt.h" #include "load_calls.h" +#include "log.h" #include "util.h" extern WxCalls_t g_WxCalls; @@ -88,3 +89,61 @@ vector GetContacts() return contacts; } + +int AcceptNewFriend(std::string v3, std::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; + + char buffer[0x40] = { 0 }; + char nullbuffer[0x3CC] = { 0 }; + + LOG_DEBUG("\nv3: {}\nv4: {}\nscene: {}", v3, v4, scene); + WxString_t wxV3 = { 0 }; + WxString_t wxV4 = { 0 }; + std::wstring wsV3 = String2Wstring(v3); + std::wstring wsV4 = String2Wstring(v4); + + wxV3.text = (wchar_t *)wsV3.c_str(); + wxV3.size = wsV3.size(); + wxV3.capacity = wsV3.capacity(); + + wxV4.text = (wchar_t *)wsV4.c_str(); + wxV4.size = wsV4.size(); + wxV4.capacity = wsV4.capacity(); + + __asm { + pushad; + pushfd; + lea ecx, buffer; + call acceptNewFriendCall1; + mov esi, 0x0; + mov edi, scene; + push esi; + push edi; + sub esp, 0x14; + mov ecx, esp; + lea eax, wxV4; + push eax; + call acceptNewFriendCall2; + sub esp, 0x8; + push 0x0; + lea eax, nullbuffer; + push eax; + lea eax, wxV3; + push eax; + lea ecx, buffer; + call acceptNewFriendCall3; + mov success, eax; + lea ecx, buffer; + call acceptNewFriendCall4; + popfd; + popad; + } + + return success; // 成功返回 1 +} diff --git a/spy/accept_new_friend.h b/spy/contact_mgmt.h similarity index 56% rename from spy/accept_new_friend.h rename to spy/contact_mgmt.h index b6b7d70..b045b64 100644 --- a/spy/accept_new_friend.h +++ b/spy/contact_mgmt.h @@ -1,5 +1,9 @@ #pragma once #include "string" +#include +#include "pb_types.h" + +vector GetContacts(); int AcceptNewFriend(std::string v3, std::string v4, int scene); diff --git a/spy/get_contacts.h b/spy/get_contacts.h deleted file mode 100644 index a0ff70d..0000000 --- a/spy/get_contacts.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -#include "pb_types.h" - -vector GetContacts(); diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 6bb21fa..266f046 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -16,11 +16,10 @@ #include "wcf.pb.h" -#include "accept_new_friend.h" #include "chatroom_mgmt.h" #include "decrypt_image.h" #include "exec_sql.h" -#include "get_contacts.h" +#include "contact_mgmt.h" #include "log.h" #include "pb_types.h" #include "pb_util.h" From 9b1215d62e3e48cca5421cb7d0aef4a28dda0de8 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 21 Jun 2023 08:13:48 +0800 Subject: [PATCH 22/35] Disable warning C4244 --- spy/decrypt_image.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spy/decrypt_image.cpp b/spy/decrypt_image.cpp index 73b812f..8be811d 100644 --- a/spy/decrypt_image.cpp +++ b/spy/decrypt_image.cpp @@ -1,3 +1,5 @@ +#pragma warning( disable: 4244 ) + #include #include "decrypt_image.h" From 76df58d1554a124812644e5bcc84e06b8eb1129b Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 22 Jun 2023 08:16:26 +0800 Subject: [PATCH 23/35] Disable warning C4731 --- spy/Spy.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spy/Spy.vcxproj b/spy/Spy.vcxproj index 88117cd..2c78b33 100644 --- a/spy/Spy.vcxproj +++ b/spy/Spy.vcxproj @@ -107,7 +107,7 @@ $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - 4251;4819 + 4251;4731;4819 MultiThreaded stdcpp17 /EHa %(AdditionalOptions) @@ -153,7 +153,7 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - 4251;4819 + 4251;4731;4819 MultiThreaded stdcpp17 From 1dfb4a841626a44f1ef819111934b5e3470c3a6e Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 23 Jun 2023 09:08:25 +0800 Subject: [PATCH 24/35] Impl Functions_FUNC_ADD_ROOM_MEMBERS --- spy/chatroom_mgmt.cpp | 39 ++++++++++++++++++++++----------------- spy/load_calls.cpp | 2 +- spy/rpc_server.cpp | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/spy/chatroom_mgmt.cpp b/spy/chatroom_mgmt.cpp index 0600431..a9c68d6 100644 --- a/spy/chatroom_mgmt.cpp +++ b/spy/chatroom_mgmt.cpp @@ -23,6 +23,7 @@ int AddChatroomMember(string roomid, string wxids) DWORD addRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.arm.call2; DWORD addRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.arm.call3; + DWORD temp = 0; WxString_t txtRoomid = { 0 }; wstring wsRoomid = String2Wstring(roomid); txtRoomid.text = (wchar_t *)wsRoomid.c_str(); @@ -45,23 +46,27 @@ int AddChatroomMember(string roomid, string wxids) LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str()); __asm { - pushad; - pushfd; - call addRoomMemberCall1; - sub esp, 0x14; - mov esi, eax; - mov ecx, esp; - lea eax, txtRoomid; - push eax; - call addRoomMemberCall2; - lea edi, vTxtMembers - push edi; - mov ecx, esi; - call addRoomMemberCall3; - mov rv, eax; - popfd; - popad; + pushad; + pushfd; + call addRoomMemberCall1; + sub esp, 0x8; + mov temp, eax; + mov ecx, esp; + mov dword ptr[ecx], 0x0; + mov dword ptr[ecx + 4], 0x0; + test esi, esi; + sub esp, 0x14; + mov ecx, esp; + lea eax, txtRoomid; + push eax; + call addRoomMemberCall2; + mov ecx, temp; + lea eax, vTxtMembers; + push eax; + call addRoomMemberCall3; + mov rv, eax; + popfd; + popad; } - return rv; } diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index b25c339..fab2a89 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -22,7 +22,7 @@ WxCalls_t wxCalls = { Exec, base, start, end, slot, name*/ { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application - { 0xE29F0, 0x771980, 0x43D8D0 }, // Add chatroom members + { 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members { 0x771980, 0xCD2A90 } // Receive transfer }; diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index 266f046..f1898d1 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -625,12 +625,12 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); break; } -#if 0 case Functions_FUNC_ADD_ROOM_MEMBERS: { LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]"); ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); break; } +#if 0 case Functions_FUNC_RECV_TRANSFER: { LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]"); ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tid, out, out_len); From 2851ab4f50d2122330eda5e29162a1053eceb16f Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 24 Jun 2023 10:25:22 +0800 Subject: [PATCH 25/35] Impl Functions_FUNC_RECV_TRANSFER --- rpc/proto/wcf.proto | 3 +- spy/load_calls.cpp | 2 +- spy/receive_transfer.cpp | 66 ++++++++++++++++++++++++++++------------ spy/receive_transfer.h | 2 +- spy/rpc_server.cpp | 8 ++--- spy/spy_types.h | 1 + 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/rpc/proto/wcf.proto b/rpc/proto/wcf.proto index 34d1d83..b0d05bc 100644 --- a/rpc/proto/wcf.proto +++ b/rpc/proto/wcf.proto @@ -167,5 +167,6 @@ message DecPath message Transfer { string wxid = 1; // 转账人 - string tid = 2; // 转账id transferid + string tfid = 2; // 转账id transferid + string taid = 3; // Transaction id } diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index fab2a89..31680f1 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -23,7 +23,7 @@ WxCalls_t wxCalls = { { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application { 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members - { 0x771980, 0xCD2A90 } // Receive transfer + { 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer }; int LoadCalls(const wchar_t *version, WxCalls_t *calls) diff --git a/spy/receive_transfer.cpp b/spy/receive_transfer.cpp index 80346c2..6e1f006 100644 --- a/spy/receive_transfer.cpp +++ b/spy/receive_transfer.cpp @@ -1,4 +1,4 @@ -#include "receive_transfer.h" +#include "receive_transfer.h" #include "load_calls.h" #include "log.h" #include "util.h" @@ -8,31 +8,57 @@ using namespace std; extern WxCalls_t g_WxCalls; extern DWORD g_WeChatWinDllAddr; -int ReceiveTransfer(string wxid, string transferid) +int ReceiveTransfer(string wxid, string transferid, string transactionid) { int rv = 0; - DWORD recvTransferCall = g_WeChatWinDllAddr + g_WxCalls.tf.call1; + DWORD recvTransferCall1 = g_WeChatWinDllAddr + g_WxCalls.tf.call1; DWORD recvTransferCall2 = g_WeChatWinDllAddr + g_WxCalls.tf.call2; + DWORD recvTransferCall3 = g_WeChatWinDllAddr + g_WxCalls.tf.call3; - wstring wsWxid = String2Wstring(wxid); - wstring wsTid = String2Wstring(transferid); + char payInfo[0x134] = { 0 }; + wstring wsWxid = String2Wstring(wxid); + WxString_t wxWxid = { 0 }; + wxWxid.text = (wchar_t *)wsWxid.c_str(); + wxWxid.size = wsWxid.size(); + wxWxid.capacity = wsWxid.capacity(); - LOG_DEBUG("Receiving transfer, from: {}, transferid: {}", wxid, transferid); + wstring wsTfid = String2Wstring(transferid); + WxString_t wxTfid = { 0 }; + wxTfid.text = (wchar_t *)wsTfid.c_str(); + wxTfid.size = wsTfid.size(); + wxTfid.capacity = wsTfid.capacity(); + + wstring wsTaid = String2Wstring(transactionid); + WxString_t wxTaid = { 0 }; + wxTaid.text = (wchar_t *)wsTaid.c_str(); + wxTaid.size = wsTaid.size(); + wxTaid.capacity = wsTaid.capacity(); + + LOG_DEBUG("Receiving transfer, from: {}, transferid: {}, transactionid: {}", wxid, transferid, transactionid); __asm { - pushad - sub esp, 0x30 - mov ecx, esp - lea eax, wsTid - push eax - call recvTransferCall - lea ecx, dword ptr ds:[esp+0x14] - lea eax, wsWxid - push eax - call recvTransferCall - call recvTransferCall2 - add esp, 0x30 - mov rv, eax - popad + pushad; + lea ecx, payInfo; + call recvTransferCall1; + mov dword ptr[payInfo + 0x4], 0x1; + mov dword ptr[payInfo + 0x4C], 0x1; + popad; + } + memcpy(&payInfo[0x1C], &wxTaid, sizeof(wxTaid)); + memcpy(&payInfo[0x38], &wxTfid, sizeof(wxTfid)); + + __asm { + pushad; + push 0x1; + sub esp, 0x8; + lea edx, wxWxid; + lea ecx, payInfo; + call recvTransferCall2; + mov rv, eax; + add esp, 0xC; + push 0x0; + lea ecx, payInfo; + call recvTransferCall3; + popad; } return rv; diff --git a/spy/receive_transfer.h b/spy/receive_transfer.h index 82fd0aa..1942fb1 100644 --- a/spy/receive_transfer.h +++ b/spy/receive_transfer.h @@ -2,4 +2,4 @@ #include -int ReceiveTransfer(std::string wxid, std::string transferid); +int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid); diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index f1898d1..ffed0f7 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -486,14 +486,14 @@ bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) return true; } -bool func_receive_transfer(char *wxid, char *transferid, uint8_t *out, size_t *len) +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; rsp.msg.status = 0; - rsp.msg.status = ReceiveTransfer(wxid, transferid); + rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); if (rsp.msg.status != 1) { LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); } @@ -630,13 +630,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); break; } -#if 0 case Functions_FUNC_RECV_TRANSFER: { LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]"); - ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tid, out, out_len); + ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); break; } -#endif case Functions_FUNC_DECRYPT_IMAGE: { LOG_DEBUG("[FUNCTIONS_FUNC_DECRYPT_IMAGE]"); ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); diff --git a/spy/spy_types.h b/spy/spy_types.h index 22a8c81..e34cd67 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -82,6 +82,7 @@ typedef struct Xml { typedef struct TF { DWORD call1; DWORD call2; + DWORD call3; } TF_t; typedef struct WxCalls { From d6d85aa66f3eff1497d28124946e0af4df53b92a Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 24 Jun 2023 10:26:15 +0800 Subject: [PATCH 26/35] Update README --- python/README.MD | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/README.MD b/python/README.MD index d714730..ae52b5b 100644 --- a/python/README.MD +++ b/python/README.MD @@ -110,10 +110,11 @@ pip install grpcio-tools pynng ### 重新生成 PB 文件 ```sh -cd python\wcferry # CMD +cd python\wcferry python -m grpc_tools.protoc --python_out=. --proto_path=..\..\rpc\proto\ wcf.proto # GitBash +cd python/wcferry python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.proto ``` From 3b93184599d07236972ca3d9f684fba406b25adb Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 25 Jun 2023 10:29:03 +0800 Subject: [PATCH 27/35] Fix gender --- python/wcferry/client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/wcferry/client.py b/python/wcferry/client.py index 09fa128..1072eb1 100644 --- a/python/wcferry/client.py +++ b/python/wcferry/client.py @@ -180,6 +180,8 @@ class Wcf(): gender = "男" elif gender == 2: gender = "女" + else: + gender = "" contact = { "wxid": cnt.get("wxid", ""), "code": cnt.get("code", ""), From 39da9aaa5568f8950dd35fac6e6f0b6ed5c4520c Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 26 Jun 2023 10:30:08 +0800 Subject: [PATCH 28/35] Update receive_transfer --- python/wcferry/client.py | 6 ++++-- python/wcferry/wcf_pb2.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/python/wcferry/client.py b/python/wcferry/client.py index 1072eb1..8e33902 100644 --- a/python/wcferry/client.py +++ b/python/wcferry/client.py @@ -521,12 +521,13 @@ class Wcf(): rsp = self._send_request(req) return rsp.status - def receive_transfer(self, wxid: str, transferid: str) -> int: + def receive_transfer(self, wxid: str, transferid: str, transactionid: str) -> int: """接收转账 Args: wxid (str): 转账消息里的发送人 wxid transferid (str): 转账消息里的 transferid + transactionid (str): 转账消息里的 transactionid Returns: int: 1 为成功,其他失败 @@ -534,7 +535,8 @@ class Wcf(): req = wcf_pb2.Request() req.func = wcf_pb2.FUNC_RECV_TRANSFER # FUNC_RECV_TRANSFER req.tf.wxid = wxid - req.tf.tid = transferid + req.tf.tfid = transferid + req.tf.taid = transactionid rsp = self._send_request(req) return rsp.status diff --git a/python/wcferry/wcf_pb2.py b/python/wcferry/wcf_pb2.py index ea59a4e..fdffd3e 100644 --- a/python/wcferry/wcf_pb2.py +++ b/python/wcferry/wcf_pb2.py @@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xc8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xa0\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0b\n\x03xml\x18\x05 \x01(\t\x12\x0e\n\x06sender\x18\x06 \x01(\t\x12\x0e\n\x06roomid\x18\x07 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\t\x12\r\n\x05thumb\x18\t \x01(\t\x12\r\n\x05\x65xtra\x18\n \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"%\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0b\n\x03tid\x18\x02 \x01(\t*\xd3\x03\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10R\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10S\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`B\r\n\x0b\x63om.iamteerb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xc8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xa0\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0b\n\x03xml\x18\x05 \x01(\t\x12\x0e\n\x06sender\x18\x06 \x01(\t\x12\x0e\n\x06roomid\x18\x07 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\t\x12\r\n\x05thumb\x18\t \x01(\t\x12\r\n\x05\x65xtra\x18\n \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t*\xd3\x03\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10R\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10S\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`B\r\n\x0b\x63om.iamteerb\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wcf_pb2', globals()) @@ -23,8 +23,8 @@ if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._serialized_options = b'\n\013com.iamteer' _MSGTYPES_TYPESENTRY._options = None _MSGTYPES_TYPESENTRY._serialized_options = b'8\001' - _FUNCTIONS._serialized_start=1805 - _FUNCTIONS._serialized_end=2272 + _FUNCTIONS._serialized_start=1820 + _FUNCTIONS._serialized_end=2287 _REQUEST._serialized_start=19 _REQUEST._serialized_end=347 _RESPONSE._serialized_start=350 @@ -70,5 +70,5 @@ if _descriptor._USE_C_DESCRIPTORS == False: _DECPATH._serialized_start=1728 _DECPATH._serialized_end=1763 _TRANSFER._serialized_start=1765 - _TRANSFER._serialized_end=1802 + _TRANSFER._serialized_end=1817 # @@protoc_insertion_point(module_scope) From 7247636234e48ddaf2966a2e295ba4d3bb5466a5 Mon Sep 17 00:00:00 2001 From: Changhua Date: Tue, 27 Jun 2023 09:57:42 +0800 Subject: [PATCH 29/35] Update README --- python/README.MD | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/python/README.MD b/python/README.MD index ae52b5b..95b92f7 100644 --- a/python/README.MD +++ b/python/README.MD @@ -37,7 +37,6 @@ def process_msg(wcf: Wcf): def main(): LOG.info("Start demo...") wcf = Wcf(debug=True) # 默认连接本地服务 - # wcf = Wcf("tcp://127.0.0.1:10086") # 连接远端服务 sleep(5) # 等微信加载好,以免信息显示异常 LOG.info(f"已经登录: {True if wcf.is_login() else False}") @@ -118,3 +117,41 @@ python -m grpc_tools.protoc --python_out=. --proto_path=..\..\rpc\proto\ wcf.pro cd python/wcferry python -m grpc_tools.protoc --python_out=. --proto_path=../../rpc/proto/ wcf.proto ``` + +## 版本更新 +版本号:`w.x.y.z`。 + +其中: +* `w` 是微信的大版本号,如 `37` (3.7.a.a), `38` (3.8.a.a), `39` (3.9.a.a) +* `x` 是适配的微信的小版本号,从 0 开始 +* `y` 是 `WeChatFerry` 的版本,从 0 开始 +* `z` 是各客户端的版本,从 0 开始 + +### 37.1.25.5 (2023.05.19) +支持 `3.7.0.30` 的最后一个版本。 + +功能: + +* 检查登录状态 +* 获取登录账号的 wxid +* 获取消息类型 +* 获取所有联系人 +* 获取所有好友 +* 获取数据库 +* 获取某数据库下的表 +* 发送文本消息(可 @) +* 发送图片(Python 客户端支持网络路径) +* 发送文件 +* 发送 XML +* 发送表情 +* 允许接收消息 +* 停止接收消息 +* 执行 SQL 查询 +* 接受好友申请 +* 添加群成员 +* 解密图片 +* 某功能 + +
历史更新 + +
From 7bad831fe797e9ca3475c1df6a11092451ec41a2 Mon Sep 17 00:00:00 2001 From: Changhua Date: Wed, 28 Jun 2023 10:05:32 +0800 Subject: [PATCH 30/35] Update README --- python/README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/README.MD b/python/README.MD index 95b92f7..43bea9c 100644 --- a/python/README.MD +++ b/python/README.MD @@ -1,6 +1,8 @@ # WeChatFerry Python 客户端 [![PyPi](https://img.shields.io/pypi/v/wcferry.svg)](https://pypi.python.org/pypi/wcferry) [![Downloads](https://static.pepy.tech/badge/wcferry)](https://pypi.python.org/pypi/wcferry) [![Documentation Status](https://readthedocs.org/projects/wechatferry/badge/?version=latest)](https://wechatferry.readthedocs.io/zh/latest/?badge=latest) +|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/XTJ9H-FsCPCscixAts8i_A)| +|:-:|:-:|:-:| 🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。 ## 快速开始 From 0d847622a44e7bbcbc729f88adf104917c043fe4 Mon Sep 17 00:00:00 2001 From: Changhua Date: Thu, 29 Jun 2023 11:00:05 +0800 Subject: [PATCH 31/35] Impl Functions_FUNC_DEL_ROOM_MEMBERS --- rpc/proto/wcf.proto | 5 +-- spy/chatroom_mgmt.cpp | 56 +++++++++++++++++++++++++++++ spy/chatroom_mgmt.h | 2 +- spy/load_calls.cpp | 1 + spy/rpc_server.cpp | 83 ++++++++++++++++++++++++++++--------------- spy/spy_types.h | 1 + 6 files changed, 117 insertions(+), 31 deletions(-) diff --git a/rpc/proto/wcf.proto b/rpc/proto/wcf.proto index b0d05bc..caf79f6 100644 --- a/rpc/proto/wcf.proto +++ b/rpc/proto/wcf.proto @@ -21,9 +21,10 @@ enum Functions { FUNC_DISABLE_RECV_TXT = 0x40; FUNC_EXEC_DB_QUERY = 0x50; FUNC_ACCEPT_FRIEND = 0x51; - FUNC_ADD_ROOM_MEMBERS = 0x52; - FUNC_RECV_TRANSFER = 0x53; + FUNC_RECV_TRANSFER = 0x52; FUNC_DECRYPT_IMAGE = 0x60; + FUNC_ADD_ROOM_MEMBERS = 0x70; + FUNC_DEL_ROOM_MEMBERS = 0x71; } message Request diff --git a/spy/chatroom_mgmt.cpp b/spy/chatroom_mgmt.cpp index a9c68d6..e064178 100644 --- a/spy/chatroom_mgmt.cpp +++ b/spy/chatroom_mgmt.cpp @@ -1,5 +1,6 @@ #include "framework.h" #include +#include #include "chatroom_mgmt.h" #include "load_calls.h" @@ -70,3 +71,58 @@ int AddChatroomMember(string roomid, string wxids) } return rv; } + +int DelChatroomMember(string roomid, string wxids) +{ + if (roomid.empty() || wxids.empty()) { + LOG_ERROR("Empty roomid or wxids."); + return -1; + } + + int rv = 0; + DWORD delRoomMemberCall1 = g_WeChatWinDllAddr + g_WxCalls.drm.call1; + DWORD delRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.drm.call2; + DWORD delRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.drm.call3; + + DWORD temp = 0; + WxString_t txtRoomid = { 0 }; + wstring wsRoomid = String2Wstring(roomid); + txtRoomid.text = (wchar_t *)wsRoomid.c_str(); + txtRoomid.size = wsRoomid.size(); + txtRoomid.capacity = wsRoomid.capacity(); + + vector vMembers; + vector vTxtMembers; + wstringstream wss(String2Wstring(wxids)); + while (wss.good()) { + wstring wstr; + getline(wss, wstr, L','); + vMembers.push_back(wstr); + WxString_t txtMember = { 0 }; + txtMember.text = (wchar_t *)vMembers.back().c_str(); + txtMember.size = vMembers.back().size(); + txtMember.capacity = vMembers.back().capacity(); + vTxtMembers.push_back(txtMember); + } + + LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str()); + __asm { + pushad; + pushfd; + call delRoomMemberCall1; + sub esp, 0x14; + mov esi, eax; + mov ecx, esp; + lea edi, txtRoomid; + push edi; + call delRoomMemberCall2; + mov ecx, esi; + lea eax, vTxtMembers; + push eax; + call delRoomMemberCall3; + mov rv, eax; + popfd; + popad; + } + return rv; +} diff --git a/spy/chatroom_mgmt.h b/spy/chatroom_mgmt.h index eacb825..a53b55b 100644 --- a/spy/chatroom_mgmt.h +++ b/spy/chatroom_mgmt.h @@ -1,6 +1,6 @@ #pragma once #include -#include int AddChatroomMember(std::string roomid, std::string wxids); +int DelChatroomMember(std::string roomid, std::string wxids); diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp index 31680f1..a989338 100644 --- a/spy/load_calls.cpp +++ b/spy/load_calls.cpp @@ -23,6 +23,7 @@ WxCalls_t wxCalls = { { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application { 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members + { 0x78CF20, 0xF59E40, 0xBD22A0 }, // Delete chatroom members { 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer }; diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp index ffed0f7..bbc56a6 100644 --- a/spy/rpc_server.cpp +++ b/spy/rpc_server.cpp @@ -17,9 +17,9 @@ #include "wcf.pb.h" #include "chatroom_mgmt.h" +#include "contact_mgmt.h" #include "decrypt_image.h" #include "exec_sql.h" -#include "contact_mgmt.h" #include "log.h" #include "pb_types.h" #include "pb_util.h" @@ -464,28 +464,6 @@ bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t return true; } -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; - - rsp.msg.status = AddChatroomMember(roomid, wxids); - if (rsp.msg.status != 1) { - LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); - } - - 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; @@ -530,6 +508,50 @@ bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len) return true; } +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; + + rsp.msg.status = AddChatroomMember(roomid, wxids); + if (rsp.msg.status != 1) { + LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); + } + + 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_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; + + rsp.msg.status = DelChatroomMember(roomid, wxids); + if (rsp.msg.status != 1) { + LOG_ERROR("DelChatroomMember failed: {}", rsp.msg.status); + } + + 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 dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { bool ret = false; @@ -625,11 +647,6 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); break; } - case Functions_FUNC_ADD_ROOM_MEMBERS: { - LOG_DEBUG("[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_RECV_TRANSFER: { LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]"); ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); @@ -640,6 +657,16 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); break; } + case Functions_FUNC_ADD_ROOM_MEMBERS: { + LOG_DEBUG("[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: { + LOG_DEBUG("[Functions_FUNC_DEL_ROOM_MEMBERS]"); + ret = func_del_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); + break; + } default: { LOG_ERROR("[UNKNOW FUNCTION]"); break; diff --git a/spy/spy_types.h b/spy/spy_types.h index e34cd67..89287af 100644 --- a/spy/spy_types.h +++ b/spy/spy_types.h @@ -98,6 +98,7 @@ typedef struct WxCalls { Sql_t sql; // 执行 SQL NewFriend_t anf; // 通过好友申请 RoomMember_t arm; // 添加群成员 + RoomMember_t drm; // 删除群成员 TF_t tf; // 接收转账 } WxCalls_t; From 131778f3018e79de9a76ec5a558a35b1ce0f467e Mon Sep 17 00:00:00 2001 From: Changhua Date: Fri, 30 Jun 2023 12:01:36 +0800 Subject: [PATCH 32/35] Impl FUNC_DEL_ROOM_MEMBERS --- python/wcferry/client.py | 51 ++++++++++++++++++++++++++------------- python/wcferry/wcf_pb2.py | 4 +-- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/python/wcferry/client.py b/python/wcferry/client.py index 8e33902..3c981c2 100644 --- a/python/wcferry/client.py +++ b/python/wcferry/client.py @@ -504,23 +504,6 @@ class Wcf(): return friends - def add_chatroom_members(self, roomid: str, wxids: str) -> int: - """添加群成员 - - Args: - roomid (str): 待加群的 id - wxids (str): 要加到群里的 wxid,多个用逗号分隔 - - Returns: - int: 1 为成功,其他失败 - """ - req = wcf_pb2.Request() - req.func = wcf_pb2.FUNC_ADD_ROOM_MEMBERS # FUNC_ADD_ROOM_MEMBERS - req.m.roomid = roomid - req.m.wxids = wxids - rsp = self._send_request(req) - return rsp.status - def receive_transfer(self, wxid: str, transferid: str, transactionid: str) -> int: """接收转账 @@ -556,3 +539,37 @@ class Wcf(): req.dec.dst = dst rsp = self._send_request(req) return rsp.status == 1 + + def add_chatroom_members(self, roomid: str, wxids: str) -> int: + """添加群成员 + + Args: + roomid (str): 待加群的 id + wxids (str): 要加到群里的 wxid,多个用逗号分隔 + + Returns: + int: 1 为成功,其他失败 + """ + req = wcf_pb2.Request() + req.func = wcf_pb2.FUNC_ADD_ROOM_MEMBERS # FUNC_ADD_ROOM_MEMBERS + req.m.roomid = roomid + req.m.wxids = wxids + rsp = self._send_request(req) + return rsp.status + + def del_chatroom_members(self, roomid: str, wxids: str) -> int: + """删除群成员 + + Args: + roomid (str): 群的 id + wxids (str): 要删除成员的 wxid,多个用逗号分隔 + + Returns: + int: 1 为成功,其他失败 + """ + req = wcf_pb2.Request() + req.func = wcf_pb2.FUNC_DEL_ROOM_MEMBERS # FUNC_DEL_ROOM_MEMBERS + req.m.roomid = roomid + req.m.wxids = wxids.replace(" ", "") + rsp = self._send_request(req) + return rsp.status diff --git a/python/wcferry/wcf_pb2.py b/python/wcferry/wcf_pb2.py index fdffd3e..94b36fc 100644 --- a/python/wcferry/wcf_pb2.py +++ b/python/wcferry/wcf_pb2.py @@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xc8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xa0\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0b\n\x03xml\x18\x05 \x01(\t\x12\x0e\n\x06sender\x18\x06 \x01(\t\x12\x0e\n\x06roomid\x18\x07 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\t\x12\r\n\x05thumb\x18\t \x01(\t\x12\r\n\x05\x65xtra\x18\n \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t*\xd3\x03\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10R\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10S\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`B\r\n\x0b\x63om.iamteerb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xc8\x02\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.AddMembersH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x42\x05\n\x03msg\"\xab\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xa0\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0c\n\x04type\x18\x03 \x01(\x05\x12\n\n\x02id\x18\x04 \x01(\t\x12\x0b\n\x03xml\x18\x05 \x01(\t\x12\x0e\n\x06sender\x18\x06 \x01(\t\x12\x0e\n\x06roomid\x18\x07 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\t\x12\r\n\x05thumb\x18\t \x01(\t\x12\r\n\x05\x65xtra\x18\n \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x05\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nAddMembers\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t*\xee\x03\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10R\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10p\x12\x19\n\x15\x46UNC_DEL_ROOM_MEMBERS\x10qB\r\n\x0b\x63om.iamteerb\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'wcf_pb2', globals()) @@ -24,7 +24,7 @@ if _descriptor._USE_C_DESCRIPTORS == False: _MSGTYPES_TYPESENTRY._options = None _MSGTYPES_TYPESENTRY._serialized_options = b'8\001' _FUNCTIONS._serialized_start=1820 - _FUNCTIONS._serialized_end=2287 + _FUNCTIONS._serialized_end=2314 _REQUEST._serialized_start=19 _REQUEST._serialized_end=347 _RESPONSE._serialized_start=350 From 253154ed24a9dcec65f6fb30361b5b1e86bd7669 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sat, 1 Jul 2023 12:07:53 +0800 Subject: [PATCH 33/35] Update README --- README.MD | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.MD b/README.MD index 3f6c0e0..f3bb2a8 100644 --- a/README.MD +++ b/README.MD @@ -1,6 +1,9 @@ # WeChatFerry 一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/s/CGLfSaNDy8MyuyPWGjGJ7w)。 +|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/XTJ9H-FsCPCscixAts8i_A)| +|:-:|:-:|:-:| + 👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。
点击查看功能清单 From 090dea1d8a3896486919d0d35902c5eba23dda96 Mon Sep 17 00:00:00 2001 From: Changhua Date: Sun, 2 Jul 2023 06:37:33 +0800 Subject: [PATCH 34/35] v39.0.0 --- spy/spy.aps | Bin 2504 -> 2504 bytes spy/spy.rc | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spy/spy.aps b/spy/spy.aps index dd243d5bfdec6bc1dd1f9b0c4dcc149929343591..e053b40df7c6d93e48d0225c4f6fe8f7fb5aaa07 100644 GIT binary patch delta 73 zcmX>hd_s7`6jpu)26YAy;ACKC5NBYTyqNVOvk?R5D1_L-|*u0cYoRJ$O OXavT_n~$?IG64YQtPE!W delta 73 zcmX>hd_s7`6jpvl22}{}InE>(p47C6N diff --git a/spy/spy.rc b/spy/spy.rc index b52930f..abf36e5 100644 --- a/spy/spy.rc +++ b/spy/spy.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 37,1,25,0 - PRODUCTVERSION 3,7,0,30 + FILEVERSION 39,0,0,0 + PRODUCTVERSION 3,9,2,23 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "WeChatFerry" VALUE "FileDescription", "WeChatFerry" - VALUE "FileVersion", "37.1.25.0" + VALUE "FileVersion", "39.0.0.0" VALUE "InternalName", "spy.dll" VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "OriginalFilename", "spy.dll" VALUE "ProductName", "WeChatFerry" - VALUE "ProductVersion", "3.7.0.30" + VALUE "ProductVersion", "3.9.2.23" END END BLOCK "VarFileInfo" From 6ecc477366f24d48f15afd43085f4d7dd8117e13 Mon Sep 17 00:00:00 2001 From: Changhua Date: Mon, 3 Jul 2023 06:39:00 +0800 Subject: [PATCH 35/35] v39.0.0.0 --- python/wcferry/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/wcferry/client.py b/python/wcferry/client.py index 3c981c2..ffff015 100644 --- a/python/wcferry/client.py +++ b/python/wcferry/client.py @@ -1,7 +1,7 @@ #! /usr/bin/env python3 # -*- coding: utf-8 -*- -__version__ = "37.1.25.5" +__version__ = "39.0.0.0" import atexit import base64