diff --git a/README.MD b/README.MD index d92c9e8..145d848 100644 --- a/README.MD +++ b/README.MD @@ -1,7 +1,8 @@ # WeChatFerry + 一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/s/CGLfSaNDy8MyuyPWGjGJ7w)。 -
免责声明【必读】 +
免责声明【必读】 本工具仅供学习和技术研究使用,不得用于任何商业或非法行为,否则后果自负。 @@ -15,101 +16,22 @@
-|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/WOw26mKJG8Nq55cT6iG-yA)| -|:-:|:-:|:-:| - -👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。 - -
点击查看功能清单 - -* 检查登录状态 -* 获取登录账号的 wxid -* 获取消息类型 -* 获取所有联系人 -* 获取所有好友 -* 获取数据库 -* 获取某数据库下的表 -* 获取用户信息 -* 发送文本消息(可 @) -* 发送图片 -* 发送文件 -* 允许接收消息 -* 停止接收消息 -* 执行 SQL 查询 -* 接受好友申请 -* 添加群成员 -* 删除群成员 -* 解密图片 -* 获取朋友圈消息 -* 保存图片 -* 保存语音 -* 发送卡片消息 -* 拍一拍群友 -* 邀请群成员 -* 图片 OCR -* 转发消息 -* 撤回消息 -* 获取登录二维码 - -
- -
点击查看支持的客户端 - -* Go -* HTTP (Go, Rust) -* Java -* Node.js -* Python -* Rust -
- |![碲矿](assets/TEQuant.jpg)|![赞赏](assets/QR.jpeg)| |:-:|:-:| |后台回复 `WCF` 加群交流|如果你觉得有用| -## 快速开始 -### 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) - -* 安装 -```sh -pip install --upgrade wcferry -``` - -* 参考框架:[🤖WeChatRobot](https://github.com/lich0821/WeChatRobot) - -### HTTP -#### [wcfrust](https://github.com/lich0821/wcf-client-rust)(基于 Rust) -开箱即用:[快速开始](https://github.com/lich0821/wcf-client-rust?tab=readme-ov-file#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B)。 - -#### GoHttp(基于 Go) -参考 [GoHttp README.MD](clients/gohttp/README.md) - -#### ~~wcfhttp(基于 Python)~~ -❗ **wcfhttp 不再维护,有需要可以使用 [WcfRust](https://github.com/lich0821/wcf-client-rust) 或者 [GoHttp](clients/gohttp/README.md)。** - -其余客户端,可下载 [最新发布的版本](https://github.com/lich0821/WeChatFerry/releases/latest),根据技术栈,选择客户端,将相应 `dll` 和 `exe` 文件放到对应位置。 - -### Go -参考 [Go README.MD](clients/go/README.md) - -### Java -参考 [Java README.MD](clients/java/README.MD) - -### Node.js -参考 [Node.js README.MD](https://github.com/stkevintan/node-wcferry/blob/main/README.md) - -### Rust -参考 [Rust README.MD](clients/rust/README.MD) - ## 一起开发 + > 🚫 非开发用户不需要往下看。 ### 安装开发环境 +
点击查看 #### 安装 vcpkg + * 安装,参考[Vcpkg: 总览](https://github.com/microsoft/vcpkg/blob/master/README_zh_CN.md)。 + ```sh cd C:\Tools git clone https://github.com/microsoft/vcpkg @@ -117,14 +39,15 @@ git clone https://github.com/microsoft/vcpkg ``` * 添加全局配置: -环境变量增加 `vcpkg` 所在路径(本文为:`C:\Tools\vcpkg`)。 +环境变量增加 `vcpkg` 所在路径(本项目为:`C:\Tools\vcpkg`)。 #### 安装相关组件 + ```sh -vcpkg install protobuf[zlib]:x86-windows-static -vcpkg install spdlog:x86-windows-static -vcpkg install nng:x86-windows-static -vcpkg install magic-enum:x86-windows-static +vcpkg install protobuf[zlib]:x64-windows-static +vcpkg install spdlog:x64-windows-static +vcpkg install nng:x64-windows-static +vcpkg install magic-enum:x64-windows-static vcpkg integrate install ``` @@ -139,27 +62,39 @@ vcpkg integrate install
### 编译 -使用 VS2019 打开工程,编译即可。 + +使用 VS2019 打开工程,编译即可。编译成功后,在 `WeChatFerry\WeChatFerry\Out` 目录中会看到相应的 DLL 文件。 **注**:如果遇到执行 `protoc` 时的 9009 错误,检查是否是 python3 环境有问题,或者 protoc 命令的环境变量配置不正确。 ### 运行 -运行 `wcf.exe` 启动 -```sh -wcf.exe --help +```py +import ctypes +# 加载 sdk.dll (需要绝对路径) +sdk = ctypes.cdll.LoadLibrary("C:/Projs/WeChatFerry/WeChatFerry/Out/sdk.dll") + +# 初始化 +sdk.WxInitSDK(False, 10086) + +# 退出 SDK +sdk.WxDestroySDK() + +# 注意关闭 Python 进程 ``` ## 项目结构 + ```sh WeChatFerry ├── LICENSE # LICENSE ├── README.MD # 说明 ├── WeChatFerry │   ├── WeChatFerry.sln # VS2019 工程文件 +│   ├── com # 公共模块 │   ├── rpc # RPC 模块 │   ├── sdk # 注入及启动模块 -│   ├── spy # 核心功能实现模块 -│   └── wcf # 命令行版启动器 +│   ├── smc # Silk-Mp3 转换模块 +│   └── spy # 核心功能实现模块 ├── assets │   ├── QR.jpeg # 二维码,测试用图 │   ├── TEQuant.jpg # 二维码,测试用图 @@ -169,7 +104,7 @@ WeChatFerry │   ├── gohttp # HTTP 客户端 │   ├── http # HTTP 客户端 │   ├── java # Java 客户端 -│   ├── node # Node.js 客户端 +│   ├── node # Node.js 客户端 │   ├── pyauto # 群友封装的客户端 │   ├── python # Python 客户端 │   └── rust # Rust 客户端 @@ -177,47 +112,13 @@ WeChatFerry ``` -
点击查看 - -### go -Go 客户端。 - -### gohttp -HTTP 客户端,二进制发布无依赖 - -### http -HTTP 客户端。 - -### node -Node.js 客户端. - -### java -Java 客户端。 - -### python -Python 客户端。 - -### rpc -RPC 的通信部分和序列化 / 反序列化部分。 - -### rust -Rust 客户端。 - -### sdk -负责将 `spy` 注入微信进程,并启动 RPC 服务。 - -### spy -间谍模块,注入到微信中,通过 RPC 做消息转发工作。 - -### wcf -命令行版启动器,调用 `sdk` 将 `spy` 注入微信。其他客户端可通过 RPC 连接到 `spy` 进行消息传递。默认监听的地址为 `tcp://0.0.0.0:10086` 和 `tcp://0.0.0.0:10087`。一般情况不需要显式运行,各客户端自动调用。 - -
- ## 版本更新 -### v39.0.14 (2024.02.18) -* 修复获取登录二维码问题 +### v39.1.0 (2024.04.19) + +* 适配 x64 环境 +* 重构项目 +* 开始适配 `3.9.10.19`
点击查看更多 @@ -229,21 +130,29 @@ Rust 客户端。 * `y` 是 `WeChatFerry` 的版本,从 0 开始 * `z` 是各客户端的版本,从 0 开始 +### v39.0.14 (2024.02.18) + +* 修复获取登录二维码问题 + ### v39.0.13 (2024.02.14) + * 修复若干问题 * 撤回消息 * 获取登录二维码 ### v39.0.12 (2023.12.20) + * 修复一个问题 * 消息转发 ### v39.0.11 (2023.12.16) + * 修复 PB 消息类型(可能会导致非 Python 客户端崩溃) * 修复日志错误 * 移除非必要依赖 ### v39.0.10 (2023.12.08) + * 代码优化 * 发送卡片消息 * 拍一拍群友 @@ -251,30 +160,39 @@ Rust 客户端。 * 图片 OCR ### v39.0.7 (2023.12.03) + * 保存语音 ### v39.0.6 (2023.11.26) + * 修复下载图片退出问题 ### v39.0.5 (2023.11.22) + * 修复收到某些文件崩溃问题 ### v39.0.4 (2023.11.21) + * 下载图片、文件和视频 ### v39.0.3 (2023.09.28) + * 修复登录账号昵称超长报错问题 ### v39.0.2 (2023.07.16) + * 修复朋友圈消息 `is_group` 为 `True` 问题 ### v39.0.1 (2023.07.16) + * 获取朋友圈消息 ### v39.0.0 (2023.07.14) + 升级到 `3.9.2.23`。 ### v37.1.25 (2023.05.07) + 更新版本编码。 根据新版本编码规则: @@ -283,6 +201,7 @@ Rust 客户端。 * HTTP 客户端 `wcfhttp` 的 `v3.7.0.30.25` 应该调整为 `v37.1.25.0` ### v3.7.0.30.25 (2023.05.05) + * 修复群消息判断错误 * 修复名片添加好友问题 * 修复获取数据库多余字符问题 @@ -290,105 +209,136 @@ Rust 客户端。 * Python 客户端发送图片支持网络路径 ### v3.7.0.30.24 (2023.04.19) + 实现了一个功能。 ### v3.7.0.30.23 (2023.04.13) + * 解密图片 * 获取登录账号信息 * 获取联系人备注 ### v3.7.0.30.22(2023.04.09) + 将监听端口调整为可配置。 ### v3.7.0.30.21(2023.03.15) + * 发送表情 ### v3.7.0.30.20(2023.03.12) + 修复 wxid 获取问题。 ### v3.7.0.30.19(2023.03.06) + 修复重复消息问题。 ### v3.7.0.30.18(2023.03.05) + 修复添加好友问题。 ### v3.7.0.30.17(2023.03.05) + 修复获取登录账号 wxid 问题。 ### v3.7.0.30.16(2023.03.04) + 将错误码改成错误消息,方便调试。 ### v3.7.0.30.15(2023.03.01) + * 发送 xml ### v3.7.0.30.14(2023.02.28) + * 添加群成员 ### v3.7.0.30.13(2023.02.27) + 去除 gRPC 框架,自定义更轻量的 RPC 轮子 `nnprc`。 ### v3.7.0.30.12(2023.01.20) + * 更新 Python 客户端 * 修改监听地址为 `0.0.0.0:10086` * 增加 `Launcher`,直接注入 `spy` ### v3.7.0.30.11(2022.10.19) + 更新 Python 客户端。 ### v3.7.0.30-gRPC-2(2022.10.18) + 增加 Java 客户端。 ### v3.7.0.30-gRPC-1(2022.10.16) + 将 RPC 框架切换为 gRPC! ### v3.7.0.30-8(2022.09.25) + * 获取登录账号微信 ID ### v3.7.0.30-7(2022.09.24) + 修复群聊有系统消息时会崩溃 bug。后续考虑把消息来源交还给客户端自己区别。 ### v3.7.0.30-6(2022.08.21) + * 通过好友验证 ### v3.7.0.30-5(2022.08.20) + * 执行 SQL 语句 ### v3.7.0.30-4(2022.08.20) + 修复群消息 @人 功能。有几点注意事项: 1. `vAtWxids` 是要 `@` 的 `wxid` 清单,以 `,` 分隔。 2. 只有群主才能 `@所有人`,非群主硬发 `@所有人` 会导致消息发不出去;`@所有人` 对应 `vAtWxids` 为 `"notify@all"`。 3. 消息体里 `@` 的数量必须与 `vAtWxids` 里的数量一致,否则消息能发出但 `@` 功能失效。 ### v3.7.0.30-3(2022.08.20) + 修复可重入 bug。 ### v3.7.0.30-2(2022.08.14) + 优化 Hook 和 Inject 代码,实现可重入。 ### v3.7.0.30-1(2022.08.12) + 适配微信 `3.7.0.30`。 ### v3.7.0.29-3(2022.08.7) + * 查询数据库,获取库、表。 ### v3.7.0.29-2(2022.08.7) + 优化 RPC。 ### v3.7.0.29-1(2022.08.7) + 适配微信 `3.7.0.29`。 ### v3.3.0.115-3(2021.08.28) + 适配微信 `3.3.0.115`,新增功能: * 获取所有联系人 ### v3.3.0.115-2(2021.08.22) + 适配微信 `3.3.0.115`,新增功能: * 发送图片消息 ### v3.3.0.115-1(2021.08.22) + 适配微信 `3.3.0.115`。 ### v3.0.0.57-1(2021.02.12) + 适配微信 `3.0.0.57`,支持功能: * 登录状态判断 * 接收文本消息 diff --git a/WeChatFerry/WeChatFerry.sln b/WeChatFerry/WeChatFerry.sln index 8e49373..2122ba1 100644 --- a/WeChatFerry/WeChatFerry.sln +++ b/WeChatFerry/WeChatFerry.sln @@ -10,27 +10,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk\sdk.vcxproj", "{ {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wcf", "wcf\wcf.vcxproj", "{02747CE0-AD9F-4812-B019-FCF9867F7514}" - ProjectSection(ProjectDependencies) = postProject - {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.ActiveCfg = Debug|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.Build.0 = Debug|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.ActiveCfg = Release|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.Build.0 = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x86.ActiveCfg = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.ActiveCfg = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.Build.0 = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Debug|x86.ActiveCfg = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.ActiveCfg = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.Build.0 = Release|Win32 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.ActiveCfg = Debug|x64 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.Build.0 = Debug|x64 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.ActiveCfg = Release|x64 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.Build.0 = Release|x64 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x64.ActiveCfg = Debug|x64 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.ActiveCfg = Release|x64 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/WeChatFerry/spy/log.cpp b/WeChatFerry/com/log.cpp similarity index 94% rename from WeChatFerry/spy/log.cpp rename to WeChatFerry/com/log.cpp index 6242800..e06c0e9 100644 --- a/WeChatFerry/spy/log.cpp +++ b/WeChatFerry/com/log.cpp @@ -40,7 +40,7 @@ static char buf[BUF_SIZE] = { 0 }; void log_buffer(uint8_t *buffer, size_t len) { - size_t j = sprintf_s(buf, BUF_SIZE, "BUF@%08X[%ld]: ", (uint32_t)buffer, len); + size_t j = sprintf_s(buf, BUF_SIZE, "BUF@%p[%zd]: ", buffer, len); for (size_t i = 0; i < len; i++) { j += sprintf_s(buf + j, BUF_SIZE, "%02X ", buffer[i]); if (j > BUF_SIZE - 3) { diff --git a/WeChatFerry/spy/log.h b/WeChatFerry/com/log.h similarity index 100% rename from WeChatFerry/spy/log.h rename to WeChatFerry/com/log.h diff --git a/WeChatFerry/spy/util.cpp b/WeChatFerry/com/util.cpp similarity index 86% rename from WeChatFerry/spy/util.cpp rename to WeChatFerry/com/util.cpp index ff324ac..aefcfe4 100644 --- a/WeChatFerry/spy/util.cpp +++ b/WeChatFerry/com/util.cpp @@ -133,12 +133,12 @@ static bool GetFileVersion(const wchar_t *filePath, wchar_t *version) return false; } - DWORD verMS = pVerInfo->dwFileVersionMS; - DWORD verLS = pVerInfo->dwFileVersionLS; - DWORD major = HIWORD(verMS); - DWORD minor = LOWORD(verMS); - DWORD build = HIWORD(verLS); - DWORD revision = LOWORD(verLS); + UINT64 verMS = pVerInfo->dwFileVersionMS; + UINT64 verLS = pVerInfo->dwFileVersionLS; + UINT64 major = HIWORD(verMS); + UINT64 minor = LOWORD(verMS); + UINT64 build = HIWORD(verLS); + UINT64 revision = LOWORD(verLS); delete[] pData; StringCbPrintf(version, 0x20, TEXT("%d.%d.%d.%d"), major, minor, build, revision); @@ -163,9 +163,9 @@ int GetWeChatVersion(wchar_t *version) return ret; } -DWORD GetWeChatPid() +UINT64 GetWeChatPid() { - DWORD pid = 0; + UINT64 pid = 0; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; while (Process32Next(hSnapshot, &pe32)) { @@ -179,7 +179,7 @@ DWORD GetWeChatPid() return pid; } -int OpenWeChat(DWORD *pid) +int OpenWeChat(UINT64 *pid) { *pid = GetWeChatPid(); if (*pid) { @@ -208,9 +208,9 @@ int OpenWeChat(DWORD *pid) return ERROR_SUCCESS; } -int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size) +size_t GetWstringByAddress(UINT64 address, wchar_t *buffer, UINT64 buffer_size) { - DWORD strLength = GET_DWORD(address + 4); + size_t strLength = GET_UINT64(address + 4); if (strLength == 0) { return 0; } else if (strLength > buffer_size) { @@ -222,27 +222,27 @@ int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size) return strLength; } -string GetStringByAddress(DWORD address) +string GetStringByAddress(UINT64 address) { - DWORD strLength = GET_DWORD(address + 4); + UINT64 strLength = GET_UINT64(address + 4); return Wstring2String(wstring(GET_WSTRING(address), strLength)); } -string GetStringByStrAddr(DWORD addr) +string GetStringByStrAddr(UINT64 addr) { - DWORD strLength = GET_DWORD(addr + 4); + UINT64 strLength = GET_UINT64(addr + 4); return strLength ? string(GET_STRING(addr), strLength) : string(); } -string GetStringByWstrAddr(DWORD addr) +string GetStringByWstrAddr(UINT64 addr) { - DWORD strLength = GET_DWORD(addr + 4); + UINT64 strLength = GET_UINT64(addr + 4); return strLength ? Wstring2String(wstring(GET_WSTRING(addr), strLength)) : string(); } -DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address) +UINT32 GetMemoryIntByAddress(HANDLE hProcess, UINT64 address) { - DWORD value = 0; + UINT32 value = 0; unsigned char data[4] = { 0 }; if (ReadProcessMemory(hProcess, (LPVOID)address, data, 4, 0)) { @@ -255,12 +255,12 @@ DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address) return value; } -wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address) +wstring GetUnicodeInfoByAddress(HANDLE hProcess, UINT64 address) { wstring value = L""; - DWORD strAddress = GetMemoryIntByAddress(hProcess, address); - DWORD strLen = GetMemoryIntByAddress(hProcess, address + 0x4); + UINT64 strAddress = GetMemoryIntByAddress(hProcess, address); + UINT64 strLen = GetMemoryIntByAddress(hProcess, address + 0x4); if (strLen > 500) return value; diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h new file mode 100644 index 0000000..5d369f8 --- /dev/null +++ b/WeChatFerry/com/util.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#define WECHAREXE L"WeChat.exe" +#define WECHATWINDLL L"WeChatWin.dll" +#define WCFSDKDLL L"sdk.dll" +#define WCFSPYDLL L"spy.dll" +#define WCFSPYDLL_DEBUG L"spy_debug.dll" + +#define GET_UINT64(addr) ((UINT64) * (UINT64 *)(addr)) +#define GET_QWORD(addr) ((UINT64) * (UINT64 *)(addr)) +#define GET_STRING(addr) ((CHAR *)(*(UINT64 *)(addr))) +#define GET_WSTRING(addr) ((WCHAR *)(*(UINT64 *)(addr))) +#define GET_STRING_FROM_P(addr) ((CHAR *)(addr)) +#define GET_WSTRING_FROM_P(addr) ((WCHAR *)(addr)) + +typedef struct PortPath { + int port; + char path[MAX_PATH]; +} PortPath_t; + +UINT64 GetWeChatPid(); +int OpenWeChat(UINT64 *pid); +int GetWeChatVersion(wchar_t *version); +size_t GetWstringByAddress(UINT64 address, wchar_t *buffer, UINT64 buffer_size); +UINT32 GetMemoryIntByAddress(HANDLE hProcess, UINT64 address); +std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, UINT64 address); +std::wstring String2Wstring(std::string s); +std::string Wstring2String(std::wstring ws); +std::string GB2312ToUtf8(const char *gb2312); +std::string GetStringByAddress(UINT64 address); +std::string GetStringByStrAddr(UINT64 addr); +std::string GetStringByWstrAddr(UINT64 addr); +void DbgMsg(const char *zcFormat, ...); diff --git a/WeChatFerry/sdk/SDK.vcxproj b/WeChatFerry/sdk/SDK.vcxproj index d781815..5c17179 100644 --- a/WeChatFerry/sdk/SDK.vcxproj +++ b/WeChatFerry/sdk/SDK.vcxproj @@ -86,6 +86,10 @@ true x86-windows-static + + true + x64-windows-static + Level3 @@ -154,30 +158,43 @@ true true true - NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true - Use - pch.h + NotUsing + + + stdcpp17 + $(SolutionDir)com;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include + + true + MultiThreaded Windows true true - true + false false sdk.def + + xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry + + + Copy files + - - + + - - + + diff --git a/WeChatFerry/sdk/SDK.vcxproj.filters b/WeChatFerry/sdk/SDK.vcxproj.filters index 8f8a4a5..f38f11a 100644 --- a/WeChatFerry/sdk/SDK.vcxproj.filters +++ b/WeChatFerry/sdk/SDK.vcxproj.filters @@ -21,32 +21,32 @@ 头文件 - - 头文件 - - - 头文件 - 头文件 + + 头文件 + + + 头文件 + 源文件 - - 源文件 - - - 源文件 - 源文件 源文件 + + 源文件 + + + 源文件 + diff --git a/WeChatFerry/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp index 9146f49..cc06298 100644 --- a/WeChatFerry/sdk/injector.cpp +++ b/WeChatFerry/sdk/injector.cpp @@ -1,26 +1,44 @@ -#include "injector.h" +#include "framework.h" +#include "psapi.h" +#include +#include -typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); +#include "injector.h" +#include "util.h" -static void ShowErrorMessage(DWORD dwError, HANDLE hProcess) +using namespace std; + +HMODULE GetTargetModuleBase(HANDLE process, string dll) { - BOOL bIsWow64 = FALSE; - WCHAR szErrorMessage[256] = { 0 }; - LPFN_ISWOW64PROCESS fnIsWow64Process - = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); - if (fnIsWow64Process != NULL && fnIsWow64Process(hProcess, &bIsWow64)) { - if (bIsWow64) { - wsprintf(szErrorMessage, L"LoadLibrary 调用失败,请检查应用版本/位数。错误码: %lu", dwError); + DWORD cbNeeded; + HMODULE moduleHandleList[512]; + BOOL ret = EnumProcessModulesEx(process, moduleHandleList, sizeof(moduleHandleList), &cbNeeded, LIST_MODULES_64BIT); + if (!ret) { + MessageBox(NULL, L"获取模块失败", L"GetTargetModuleBase", 0); + return NULL; + } + + if (cbNeeded > sizeof(moduleHandleList)) { + MessageBox(NULL, L"模块数量过多", L"GetTargetModuleBase", 0); + return NULL; + } + DWORD processCount = cbNeeded / sizeof(HMODULE); + + char moduleName[32]; + for (DWORD i = 0; i < processCount; i++) { + GetModuleBaseNameA(process, moduleHandleList[i], moduleName, 32); + if (!strncmp(dll.c_str(), moduleName, dll.size())) { + return moduleHandleList[i]; } } - wsprintf(szErrorMessage, L"LoadLibrary 调用失败。错误码: %lu", dwError); - MessageBox(NULL, szErrorMessage, L"InjectDll", 0); + return NULL; } HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) { HANDLE hThread; SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR); + // 1. 打开目标进程 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) { @@ -39,18 +57,31 @@ HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL); // 3. 创建一个远程线程,让目标进程调用 LoadLibrary - hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, 0, NULL); + HMODULE k32 = GetModuleHandle(L"kernel32.dll"); + if (k32 == NULL) { + MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); + return NULL; + } + + FARPROC libAddr = GetProcAddress(k32, "LoadLibraryW"); + if (!libAddr) { + MessageBox(NULL, L"获取 LoadLibrary 失败", L"InjectDll", 0); + return NULL; + } + + hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, pRemoteAddress, 0, NULL); if (hThread == NULL) { - ShowErrorMessage(GetLastError(), hProcess); VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); CloseHandle(hProcess); - + MessageBox(NULL, L"CreateRemoteThread 失败", L"InjectDll", 0); return NULL; } WaitForSingleObject(hThread, -1); - GetExitCodeThread(hThread, (LPDWORD)injectedBase); CloseHandle(hThread); + + *injectedBase = GetTargetModuleBase(hProcess, filesystem::path(Wstring2String(dllPath)).filename().string()); + VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); // CloseHandle(hProcess); // Close when exit @@ -62,7 +93,18 @@ bool EjectDll(HANDLE process, HMODULE dllBase) HANDLE hThread = NULL; // 使目标进程调用 FreeLibrary,卸载 DLL - hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dllBase, 0, NULL); + HMODULE k32 = GetModuleHandle(L"kernel32.dll"); + if (k32 == NULL) { + MessageBox(NULL, L"获取 kernel32 失败", L"InjectDll", 0); + return NULL; + } + + FARPROC libAddr = GetProcAddress(k32, "FreeLibraryAndExitThread"); + if (!libAddr) { + MessageBox(NULL, L"获取 FreeLibrary 失败", L"InjectDll", 0); + return NULL; + } + hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)libAddr, (LPVOID)dllBase, 0, NULL); if (hThread == NULL) { MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0); return false; @@ -74,29 +116,33 @@ bool EjectDll(HANDLE process, HMODULE dllBase) return true; } -static void *GetFuncAddr(LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName) +static UINT64 GetFuncOffset(LPCWSTR dllPath, LPCSTR funcName) { - HMODULE hLoaded = LoadLibrary(dllPath); - if (hLoaded == NULL) { - return NULL; + HMODULE dll = LoadLibrary(dllPath); + if (dll == NULL) { + MessageBox(NULL, L"获取 DLL 失败", L"GetFuncOffset", 0); + return 0; } - void *absAddr = GetProcAddress(hLoaded, funcName); - DWORD offset = (DWORD)absAddr - (DWORD)hLoaded; + LPVOID absAddr = GetProcAddress(dll, funcName); + UINT64 offset = (UINT64)absAddr - (UINT64)dll; + FreeLibrary(dll); - FreeLibrary(hLoaded); - - return (void *)((DWORD)dllBase + offset); + return offset; } -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret) +bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPDWORD ret) { - void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); - if (pFunc == NULL) { + UINT64 offset = GetFuncOffset(dllPath, funcName); + if (offset == 0) { + return false; + } + UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); + if (pFunc <= (UINT64)dllBase) { return false; } - HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, parameter, 0, NULL); + HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, NULL, 0, NULL); if (hThread == NULL) { return false; } @@ -110,10 +156,14 @@ bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcNa } bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - DWORD *ret) + LPDWORD ret) { - void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); - if (pFunc == NULL) { + UINT64 offset = GetFuncOffset(dllPath, funcName); + if (offset == 0) { + return false; + } + UINT64 pFunc = (UINT64)dllBase + GetFuncOffset(dllPath, funcName); + if (pFunc <= (UINT64)dllBase) { return false; } diff --git a/WeChatFerry/sdk/injector.h b/WeChatFerry/sdk/injector.h index e212a0e..07b4a28 100644 --- a/WeChatFerry/sdk/injector.h +++ b/WeChatFerry/sdk/injector.h @@ -4,6 +4,6 @@ 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 CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, DWORD *ret); bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, DWORD *ret); diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp index 0b996bc..ff754d5 100644 --- a/WeChatFerry/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -8,25 +8,23 @@ #include "sdk.h" #include "util.h" -#define WCF_LOCK ".wcf.lock" - -static bool debugMode = false; +static BOOL injected = false; static HANDLE wcProcess = NULL; static HMODULE spyBase = NULL; static WCHAR spyDllPath[MAX_PATH] = { 0 }; static int GetDllPath(bool debug, wchar_t *dllPath) { - GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH); - PathRemoveFileSpec(spyDllPath); + GetModuleFileName(GetModuleHandle(WCFSDKDLL), dllPath, MAX_PATH); + PathRemoveFileSpec(dllPath); if (debug) { - PathAppend(spyDllPath, WECHATINJECTDLL_DEBUG); + PathAppend(dllPath, WCFSPYDLL_DEBUG); } else { - PathAppend(spyDllPath, WECHATINJECTDLL); + PathAppend(dllPath, WCFSPYDLL); } - if (!PathFileExists(spyDllPath)) { - MessageBox(NULL, spyDllPath, L"文件不存在", 0); + if (!PathFileExists(dllPath)) { + MessageBox(NULL, dllPath, L"文件不存在", 0); return ERROR_FILE_NOT_FOUND; } @@ -65,60 +63,22 @@ int WxInitSDK(bool debug, int port) return -1; } -#ifdef WCF - FILE *fd = fopen(WCF_LOCK, "wb"); - if (fd == NULL) { - MessageBox(NULL, L"无法打开lock文件", L"WxInitSDK", 0); - return -2; - } - fwrite((uint8_t *)&debug, sizeof(debug), 1, fd); - fwrite((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); - fclose(fd); -#endif - debugMode = debug; + injected = true; return 0; } int WxDestroySDK() { - int status = 0; -#ifdef WCF - bool debug; - DWORD pid = GetWeChatPid(); - if (pid == 0) { - MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); - return status; - } - - wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (wcProcess == NULL) { - MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); + if (!injected) { return -1; } - FILE *fd = fopen(WCF_LOCK, "rb"); - if (fd == NULL) { - MessageBox(NULL, L"无法打开lock文件", L"WxDestroySDK", 0); + if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL)) { return -2; } - fread((uint8_t *)&debug, sizeof(debug), 1, fd); - fread((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); - fclose(fd); - status = GetDllPath(debug, spyDllPath); -#else - status = GetDllPath(debugMode, spyDllPath); -#endif - - if (status != 0) { - return status; - } - - if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) { - return -1; - } if (!EjectDll(wcProcess, spyBase)) { - return -1; // TODO: Unify error codes + return -3; // TODO: Unify error codes } return 0; diff --git a/WeChatFerry/spy/Spy.vcxproj b/WeChatFerry/spy/Spy.vcxproj index f3ca5a3..c81c7d0 100644 --- a/WeChatFerry/spy/Spy.vcxproj +++ b/WeChatFerry/spy/Spy.vcxproj @@ -83,6 +83,7 @@ true + $(ProjectName)_debug false @@ -94,6 +95,12 @@ true Release + + true + + + true + Level3 @@ -191,10 +198,20 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto Level3 true - _DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;%(PreprocessorDefinitions) true - Use - pch.h + NotUsing + + + stdcpp17 + $(SolutionDir)com;$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include + true + false + MultiThreadedDebug + true + + 4251;4731;4819 + /EHa %(AdditionalOptions) Windows @@ -202,7 +219,28 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto false spy.def /ignore:4099 %(AdditionalOptions) + $(SolutionDir)smc;%(AdditionalLibraryDirectories) + iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies) + true + + cd $(SolutionDir)rpc\proto +$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto + + + Generating PB files + + + if not exist $(SolutionDir)Out md $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry + + + Copy spy.dll + @@ -210,21 +248,48 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto true true true - NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true - Use - pch.h + NotUsing + + + stdcpp17 + $(SolutionDir)com;$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include + false + + 4251;4731;4819 + /EHa %(AdditionalOptions) + MultiThreaded Windows true true - true + false false spy.def + $(SolutionDir)smc;%(AdditionalLibraryDirectories) + iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) + + Generating PB files + cd $(SolutionDir)rpc\proto +$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto + + + Copy spy.dll + if not exist $(SolutionDir)Out md $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry + + + @@ -239,7 +304,6 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - @@ -249,9 +313,10 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - + + @@ -263,14 +328,12 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - - diff --git a/WeChatFerry/spy/Spy.vcxproj.filters b/WeChatFerry/spy/Spy.vcxproj.filters index 1574f30..8bd6b31 100644 --- a/WeChatFerry/spy/Spy.vcxproj.filters +++ b/WeChatFerry/spy/Spy.vcxproj.filters @@ -24,9 +24,6 @@ 头文件 - - 头文件 - 头文件 @@ -48,9 +45,6 @@ 头文件 - - 头文件 - nnrpc @@ -93,6 +87,12 @@ 头文件 + + 头文件 + + + 头文件 + @@ -101,9 +101,6 @@ 源文件 - - 源文件 - 源文件 @@ -122,9 +119,6 @@ 源文件 - - 源文件 - nnrpc @@ -152,6 +146,12 @@ 源文件 + + 源文件 + + + 源文件 + diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp index 5b32ffb..7a6e4b9 100644 --- a/WeChatFerry/spy/chatroom_mgmt.cpp +++ b/WeChatFerry/spy/chatroom_mgmt.cpp @@ -10,8 +10,8 @@ using namespace std; extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; - +extern UINT64 g_WeChatWinDllAddr; +#if 0 int AddChatroomMember(string roomid, string wxids) { if (roomid.empty() || wxids.empty()) { @@ -178,3 +178,4 @@ int InviteChatroomMember(string roomid, string wxids) } return 1; } +#endif diff --git a/WeChatFerry/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp index a88a178..2039a40 100644 --- a/WeChatFerry/spy/contact_mgmt.cpp +++ b/WeChatFerry/spy/contact_mgmt.cpp @@ -7,8 +7,8 @@ using namespace std; extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; - +extern UINT64 g_WeChatWinDllAddr; +#if 0 #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 }; @@ -183,3 +183,4 @@ RpcContact_t GetContactByWxid(string wxid) return contact; } +#endif diff --git a/WeChatFerry/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp index 65e886b..9065a35 100644 --- a/WeChatFerry/spy/exec_sql.cpp +++ b/WeChatFerry/spy/exec_sql.cpp @@ -16,11 +16,11 @@ #define OFFSET_DB_NAME 0x14 #define OFFSET_DB_MSG_MGR 0x30403B8 -extern DWORD g_WeChatWinDllAddr; +extern UINT64 g_WeChatWinDllAddr; typedef map dbMap_t; static dbMap_t dbMap; - +#if 0 static void GetDbHandle(DWORD base, DWORD offset) { wchar_t *wsp; @@ -225,3 +225,4 @@ vector GetAudioData(uint64_t id) return vector(); } +#endif diff --git a/WeChatFerry/spy/funcs.cpp b/WeChatFerry/spy/funcs.cpp index 322133c..b03bb51 100644 --- a/WeChatFerry/spy/funcs.cpp +++ b/WeChatFerry/spy/funcs.cpp @@ -23,8 +23,11 @@ namespace fs = std::filesystem; extern bool gIsListeningPyq; extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; +extern UINT64 g_WeChatWinDllAddr; +int IsLogin(void) { return (int)GET_UINT64(g_WeChatWinDllAddr + g_WxCalls.login); } + +#if 0 static string get_key(uint8_t header1, uint8_t header2, uint8_t *key) { // PNG? @@ -443,3 +446,4 @@ string GetLoginUrl() } return "http://weixin.qq.com/x/" + string(url); } +#endif diff --git a/WeChatFerry/spy/funcs.h b/WeChatFerry/spy/funcs.h index ec4e0f8..2b33509 100644 --- a/WeChatFerry/spy/funcs.h +++ b/WeChatFerry/spy/funcs.h @@ -3,6 +3,7 @@ #include "stdint.h" #include +int IsLogin(void); std::string GetAudio(uint64_t id, std::string dir); std::string DecryptImage(std::string src, std::string dst); int RefreshPyq(uint64_t id); diff --git a/WeChatFerry/spy/load_calls.cpp b/WeChatFerry/spy/load_calls.cpp index 4c0cbfe..f3a7dd2 100644 --- a/WeChatFerry/spy/load_calls.cpp +++ b/WeChatFerry/spy/load_calls.cpp @@ -3,9 +3,10 @@ #include "load_calls.h" -#define SUPPORT_VERSION L"3.9.2.23" +#define SUPPORT_VERSION L"3.9.10.19" + WxCalls_t wxCalls = { - 0x2FFD638, // Login Status + 0x5AB9184, // Login Status { 0x2FFD484, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home { 0x768140, 0xCE6C80, 0x756960 }, // Send Message /* Receive Message: diff --git a/WeChatFerry/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp index 91fa118..b8adf11 100644 --- a/WeChatFerry/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -19,7 +19,7 @@ extern queue gMsgQueue; // Defined in spy.cpp extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; +extern UINT64 g_WeChatWinDllAddr; static DWORD reg_buffer = 0; static DWORD recvMsgHookAddr = 0; @@ -31,7 +31,7 @@ static DWORD recvPyqHookAddr = 0; static DWORD recvPyqCallAddr = 0; static DWORD recvPyqJumpBackAddr = 0; static CHAR recvPyqBackupCode[5] = { 0 }; - +#if 0 MsgTypes_t GetMsgTypes() { const MsgTypes_t m = { @@ -259,3 +259,4 @@ void UnListenPyq() UnHookAddress(recvPyqHookAddr, recvPyqBackupCode); gIsListeningPyq = false; } +#endif diff --git a/WeChatFerry/spy/receive_transfer.cpp b/WeChatFerry/spy/receive_transfer.cpp index a31960d..019d220 100644 --- a/WeChatFerry/spy/receive_transfer.cpp +++ b/WeChatFerry/spy/receive_transfer.cpp @@ -6,8 +6,8 @@ using namespace std; extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; - +extern UINT64 g_WeChatWinDllAddr; +#if 0 int ReceiveTransfer(string wxid, string transferid, string transactionid) { int rv = 0; @@ -53,3 +53,4 @@ int ReceiveTransfer(string wxid, string transferid, string transactionid) return rv; } +#endif diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp index 72eb6fb..dd1b1e6 100644 --- a/WeChatFerry/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -40,8 +40,6 @@ namespace fs = std::filesystem; -extern int IsLogin(void); // Defined in spy.cpp - bool gIsListening = false; bool gIsListeningPyq = false; mutex gMutex; @@ -70,7 +68,7 @@ bool func_is_login(uint8_t *out, size_t *len) return true; } - +#if 0 bool func_get_self_wxid(uint8_t *out, size_t *len) { Response rsp = Response_init_default; @@ -837,7 +835,7 @@ bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, size_t *l return true; } - +#endif static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { bool ret = false; @@ -850,11 +848,13 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len } LOG_DEBUG("{:#04x}[{}] length: {}", (uint8_t)req.func, magic_enum::enum_name(req.func), in_len); + switch (req.func) { case Functions_FUNC_IS_LOGIN: { ret = func_is_login(out, out_len); break; } +#if 0 case Functions_FUNC_GET_SELF_WXID: { ret = func_get_self_wxid(out, out_len); break; @@ -977,11 +977,13 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len ret = func_invite_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); break; } +#endif default: { LOG_ERROR("[UNKNOW FUNCTION]"); break; } } + pb_release(Request_fields, &req); return ret; } @@ -1065,7 +1067,7 @@ int RpcStopServer() if (lIsRunning) { nng_close(cmdSock); nng_close(msgSock); - UnListenMessage(); + // UnListenMessage(); lIsRunning = false; Sleep(1000); LOG_INFO("Server stoped."); diff --git a/WeChatFerry/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp index ab45561..362150c 100644 --- a/WeChatFerry/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -10,9 +10,9 @@ extern HANDLE g_hEvent; extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; +extern UINT64 g_WeChatWinDllAddr; extern string GetSelfWxid(); // Defined in spy.cpp - +#if 0 void SendTextMessage(string wxid, string msg, string atWxids) { int success = 0; @@ -438,3 +438,4 @@ int ForwardMessage(uint64_t msgid, string receiver) return status; } +#endif diff --git a/WeChatFerry/spy/spy.aps b/WeChatFerry/spy/spy.aps index 5fd638a..d525acb 100644 Binary files a/WeChatFerry/spy/spy.aps and b/WeChatFerry/spy/spy.aps differ diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp index 55c98ba..ef711fe 100644 --- a/WeChatFerry/spy/spy.cpp +++ b/WeChatFerry/spy/spy.cpp @@ -7,19 +7,18 @@ #include "util.h" WxCalls_t g_WxCalls = { 0 }; -DWORD g_WeChatWinDllAddr = 0; +UINT64 g_WeChatWinDllAddr = 0; void InitSpy(LPVOID args) { + wchar_t version[16] = { 0 }; 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模块地址 + InitLogger(pp->path); + g_WeChatWinDllAddr = (UINT64)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址 if (g_WeChatWinDllAddr == 0) { - LOG_ERROR("获取wechatWin.dll模块地址失败"); + LOG_ERROR("获取 wechatWin.dll 模块地址失败"); return; } @@ -27,16 +26,18 @@ void InitSpy(LPVOID args) LOG_ERROR("获取微信版本失败"); return; } - LOG_DEBUG("WeChat version: {}", Wstring2String(version).c_str()); + LOG_INFO("WeChat version: {}", Wstring2String(version).c_str()); if (LoadCalls(version, &g_WxCalls) != 0) { // 加载微信版本对应的Call地址 LOG_ERROR("不支持当前版本"); MessageBox(NULL, L"不支持当前版本", L"错误", 0); return; } - RpcStartServer(port); + RpcStartServer(pp->port); } -void CleanupSpy() { RpcStopServer(); } - -int IsLogin(void) { return (int)GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.login); } +void CleanupSpy() +{ + LOG_DEBUG("CleanupSpy"); + RpcStopServer(); +} diff --git a/WeChatFerry/spy/spy.rc b/WeChatFerry/spy/spy.rc index f50e642..2aa2b4a 100644 --- a/WeChatFerry/spy/spy.rc +++ b/WeChatFerry/spy/spy.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 39,0,13,0 - PRODUCTVERSION 3,9,2,23 + FILEVERSION 39,1,0,0 + PRODUCTVERSION 3,9,10,19 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "WeChatFerry" VALUE "FileDescription", "WeChatFerry" - VALUE "FileVersion", "39.0.13.0" + VALUE "FileVersion", "39.1.0.0" VALUE "InternalName", "spy.dll" VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "OriginalFilename", "spy.dll" VALUE "ProductName", "WeChatFerry" - VALUE "ProductVersion", "3.9.2.23" + VALUE "ProductVersion", "3.9.10.19" END END BLOCK "VarFileInfo" diff --git a/WeChatFerry/spy/spy_types.h b/WeChatFerry/spy/spy_types.h index 08fa4ae..2bb396a 100644 --- a/WeChatFerry/spy/spy_types.h +++ b/WeChatFerry/spy/spy_types.h @@ -206,8 +206,8 @@ struct WxString { WxString(std::wstring &ws) { wptr = ws.c_str(); - size = ws.size(); - capacity = ws.capacity(); + size = (DWORD)ws.size(); + capacity = (DWORD)ws.capacity(); ptr = NULL; clen = 0; } diff --git a/WeChatFerry/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp index dddc108..75f7691 100644 --- a/WeChatFerry/spy/user_info.cpp +++ b/WeChatFerry/spy/user_info.cpp @@ -1,10 +1,10 @@ -#include "user_info.h" +#include "user_info.h" #include "load_calls.h" #include "log.h" #include "util.h" extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; +extern UINT64 g_WeChatWinDllAddr; static char home[MAX_PATH] = { 0 }; @@ -20,9 +20,9 @@ string GetHomePath() string GetSelfWxid() { - DWORD wxidType = 0; + UINT64 wxidType = 0; try { - wxidType = GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.ui.wxid + 0x14); + wxidType = GET_UINT64(g_WeChatWinDllAddr + g_WxCalls.ui.wxid + 0x14); if (wxidType == 0xF) { return GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.wxid); } else { @@ -41,7 +41,7 @@ UserInfo_t GetUserInfo() ui.wxid = GetSelfWxid(); - DWORD nameType = GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.ui.nickName + 0x14); + UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + g_WxCalls.ui.nickName + 0x14); if (nameType == 0xF) { ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName); } else { // 0x1F diff --git a/WeChatFerry/spy/util.h b/WeChatFerry/spy/util.h deleted file mode 100644 index 5d79b4a..0000000 --- a/WeChatFerry/spy/util.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#define WECHAREXE L"WeChat.exe" -#define WECHATWINDLL L"WeChatWin.dll" -#define WECHATSDKDLL L"sdk.dll" -#define WECHATINJECTDLL L"spy.dll" -#define WECHATINJECTDLL_DEBUG L"spy_debug.dll" - -#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr)) -#define GET_QWORD(addr) ((uint64_t) * (uint64_t *)(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; - char path[MAX_PATH]; -} PortPath_t; - -DWORD GetWeChatPid(); -int OpenWeChat(DWORD *pid); -int GetWeChatVersion(wchar_t *version); -int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size); -DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address); -std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); -std::wstring String2Wstring(std::string s); -std::string Wstring2String(std::wstring ws); -std::string GB2312ToUtf8(const char *gb2312); -std::string GetStringByAddress(DWORD address); -std::string GetStringByStrAddr(DWORD addr); -std::string GetStringByWstrAddr(DWORD addr); -void DbgMsg(const char *zcFormat, ...); diff --git a/WeChatFerry/wcf/main.cpp b/WeChatFerry/wcf/main.cpp deleted file mode 100644 index 43d797b..0000000 --- a/WeChatFerry/wcf/main.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -#include "sdk.h" - -void help() -{ - printf("\nUsage: \n启动: wcf.exe start port [debug]\n关闭: wcf.exe stop\nport: 命令端口, 消息端口为命令端口+1\n"); -} - -int main(int argc, char *argv[]) -{ - int ret = -1; - bool debug = false; - - if ((argc < 2) || (argc > 4)) { - help(); - } else if (argc == 4) { - debug = (strcmp(argv[3], "debug") == 0); - } - - if (strcmp(argv[1], "start") == 0) { - int port = strtol(argv[2], NULL, 10); - - ret = WxInitSDK(debug, port); - } else if (strcmp(argv[1], "stop") == 0) { - ret = WxDestroySDK(); - } else { - help(); - } - - return ret; -} diff --git a/WeChatFerry/wcf/wcf.vcxproj b/WeChatFerry/wcf/wcf.vcxproj deleted file mode 100644 index 1f9b67f..0000000 --- a/WeChatFerry/wcf/wcf.vcxproj +++ /dev/null @@ -1,173 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {02747ce0-ad9f-4812-b019-fcf9867f7514} - wcf - 10.0 - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - true - x86-windows-static - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;WCF;%(PreprocessorDefinitions) - true - $(SolutionDir)sdk;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - MultiThreaded - stdcpp17 - 4996 - - - Console - true - true - true - - - xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry - - - Copy files - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/WeChatFerry/wcf/wcf.vcxproj.filters b/WeChatFerry/wcf/wcf.vcxproj.filters deleted file mode 100644 index aee99f2..0000000 --- a/WeChatFerry/wcf/wcf.vcxproj.filters +++ /dev/null @@ -1,51 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - \ No newline at end of file diff --git a/WeChatFerry/wcf/wcf.vcxproj.user b/WeChatFerry/wcf/wcf.vcxproj.user deleted file mode 100644 index 88a5509..0000000 --- a/WeChatFerry/wcf/wcf.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/clients/python/wcferry/client.py b/clients/python/wcferry/client.py index 7452d67..ef1d9b9 100644 --- a/clients/python/wcferry/client.py +++ b/clients/python/wcferry/client.py @@ -1,10 +1,11 @@ #! /usr/bin/env python3 # -*- coding: utf-8 -*- -__version__ = "39.0.14.1" +__version__ = "39.1.0.0" import atexit import base64 +import ctypes import logging import mimetypes import os @@ -72,11 +73,12 @@ class Wcf(): self.LOG.info(f"wcferry version: {__version__}") self.port = port self.host = host + self.sdk = None if host is None: self._local_mode = True self.host = "127.0.0.1" - cmd = fr'"{self._wcf_root}\wcf.exe" start {self.port} {"debug" if debug else ""}' - if os.system(cmd) != 0: + self.sdk = ctypes.cdll.LoadLibrary(f"{self._wcf_root}/sdk.dll") + if self.sdk.WxInitSDK(debug, port) != 0: self.LOG.error("初始化失败!") os._exit(-1) @@ -121,11 +123,9 @@ class Wcf(): self.disable_recv_msg() self.cmd_socket.close() - if self._local_mode: - cmd = fr'"{self._wcf_root}\wcf.exe" stop' - if os.system(cmd) != 0: - self.LOG.error("退出失败!") - return + if self._local_mode and self.sdk and self.sdk.WxDestroySDK() != 0: + self.LOG.error("退出失败!") + self._is_running = False def keep_running(self): @@ -658,7 +658,7 @@ class Wcf(): if (cnt["wxid"].endswith("@chatroom") or # 群聊 cnt["wxid"].startswith("gh_") or # 公众号 cnt["wxid"] in not_friends.keys() # 其他杂号 - ): + ): continue friends.append(cnt)