diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml
index 972c09af..1af3bbe7 100644
--- a/.github/workflows/build-ci.yml
+++ b/.github/workflows/build-ci.yml
@@ -60,7 +60,7 @@ jobs:
shell: pwsh
run: |
cd ${{ github.workspace }}/WeChatFerry
- C:/Tools/vcpkg/vcpkg install --triplet x64-windows-static
+ C:/Tools/vcpkg/vcpkg install --triplet x86-windows-static
C:/Tools/vcpkg/vcpkg integrate install
- name: 解析并构建 Release/Debug
@@ -70,9 +70,10 @@ jobs:
Write-Host "Building $cfg"
msbuild WeChatFerry/WeChatFerry.sln `
/p:Configuration=$cfg `
- /p:Platform="x64" `
- /p:VcpkgTriplet="x64-windows-static" `
+ /p:Platform="x86" `
/p:VcpkgEnableManifest=true `
+ /p:VcpkgManifestInstall=false `
+ /p:VcpkgInstalledDir="${{ github.workspace }}/WeChatFerry/vcpkg_installed" `
/verbosity:minimal
}
shell: pwsh
@@ -83,4 +84,5 @@ jobs:
name: wechatferry-binaries
path: |
WeChatFerry/Out/*.dll
+ WeChatFerry/Out/*.exe
WeChatFerry/Out/*.md
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d7bbc55b..52301c09 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -46,7 +46,7 @@ jobs:
-Path "tmp/*" `
-DestinationPath "tmp/v${{ env.version }}.zip"
- Remove-Item -Path "tmp/*.dll", "tmp/*.md"
+ Remove-Item -Path "tmp/*.dll", "tmp/*.md", "tmp/*.exe"
# 下载对应版本微信安装包
Invoke-WebRequest `
diff --git a/.gitignore b/.gitignore
index b9a68490..c73d340b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ Debug/
Release/
x64/
Out/
+_build/
# Generated files
*.pb.h
diff --git a/README.MD b/README.MD
index d94b1369..3d546204 100644
--- a/README.MD
+++ b/README.MD
@@ -1,304 +1,332 @@
-# WeChatFerry
-
-一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/)。
-
-
-⚠️ 免责声明【必读】⚠️
-
-请阅读完整的免责声明:[点击查看](WeChatFerry/DISCLAIMER.md)
-
-
-
-|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/)|[🙋 FAQ](https://mp.weixin.qq.com/)|
-|:-:|:-:|:-:|
-
-👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人示例。
-
-点击查看功能清单
-
-* 获取登录二维码
-* 查询登录状态
-* 获取登录账号信息
-* 获取消息类型
-* 获取联系人
-* 获取可查询数据库
-* 获取数据库所有表
-* 获取语音消息
-* 发送文本消息(可 @)
-* 发送图片消息
-* 发送文件消息
-* 发送卡片消息
-* 发送 XML 消息
-* 发送 GIF 消息
-* 拍一拍群友
-* 转发消息
-* 开启接收消息
-* 关闭接收消息
-* 查询数据库
-* 获取朋友圈消息
-* 下载图片、视频、文件
-* 解密图片
-* 通过好友申请
-* 添加群成员
-* 删除群成员
-* 邀请群成员
-
-
-
-点击查看支持的客户端
-
-* Python
-* HTTP
-* NodeJS
-
-
-
-## 感谢大佬们贡献代码
-
-
-
-## 快速开始
-### Python
-[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](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)
-* [go_wcf_http](clients/go_wcf_http/README.MD)(基于 Go)
-* [wrest-chat](https://github.com/opentdp/wrest-chat)(基于 Go)
-* [wcf-http](https://github.com/yuxiaoli/wcf-http)(基于 Python)
-
-### Java
-* [java](clients/java/wcferry/README.MD)
-
-### NodeJS
-* [wcferry-node](https://github.com/dr-forget/wcferry-node)
-* [node-wcferry](https://github.com/stkevintan/node-wcferry)
-* [wechatferry](https://github.com/wechatferry/wechatferry)
-
-### C#
-* [WeChatFerry.Net](https://github.com/SilkageNet/WeChatFerry.Net) Install using Nuget
-* [WeChatFerry-CSharp](https://github.com/send010/WeChatFerry-CSharp)
-
-### Rust
-* [wechat-bot](https://github.com/CliffHan/wechat-bot)
-
-### Docker
-* [docker_wechat](https://github.com/Saroth/docker_wechat)
-* [wechatbot-provider-windows](https://github.com/danni-cool/wechatbot-provider-windows)
-
-## 一起开发
-
-> 🚫 非开发用户不需要往下看。
->
-> **开发用户**:可以根据文档和错误提示,自行解决编译错误的人员。
-
-### 安装开发环境
-
-点击查看
-
-#### 安装 vcpkg
-
-* 安装,参考[Vcpkg: 总览](https://github.com/microsoft/vcpkg/blob/master/README_zh_CN.md)。
-
-```sh
-cd C:\Tools
-git clone https://github.com/microsoft/vcpkg
-.\vcpkg\bootstrap-vcpkg.bat
-```
-
-* 添加全局配置:
-环境变量增加 `vcpkg` 所在路径(本文为:`C:\Tools\vcpkg`):
-```sh
-setx VCPKG_ROOT "C:/Tools/vcpkg" /M
-```
-
-* 与 Visual Studio 集成
-```sh
-vcpkg integrate install # 失败则说明未正确安装或者未正确配置环境变量
-```
-
-#### 安装相关组件
-
-编译时会自动安装。但如果需要使用 `protoc.exe`,则需要配置一下 `protoc.exe` 环境变量:`\x64-windows-static\x64-windows-static\tools\protobuf`。
-
-(本文为:`C:\Projs\WeChatFerry\WeChatFerry\vcpkg_installed\x64-windows-static\x64-windows-static\tools\protobuf`)
-
-#### 安装 VS2019
-
-#### 安装 Python3
-
-通过微软商店或者 python.org 自行下载均可(注意 `python` 版本不能太高,否则需要自行编译依赖,建议使用 python 3.10),然后配置好环境变量,确保 `python` 在命令行下可用。
-
-安装依赖:
-```sh
-pip install grpcio-tools==1.48.2
-```
-
-
-
-### 编译
-
-使用 VS2019 打开工程,编译即可。编译成功后,在 `WeChatFerry\WeChatFerry\Out` 目录中会看到相应的 DLL 文件。
-
-**注**:如果遇到执行 `protoc` 时的 9009 错误,检查是否是 python3 环境有问题,或者 protoc 命令的环境变量配置不正确。
-
-### 运行
-```py
-import ctypes
-# 加载 sdk.dll (需要绝对路径)
-sdk = ctypes.cdll.LoadLibrary("C:/Projs/WeChatFerry/WeChatFerry/Out/sdk.dll")
-
-# 初始化
-sdk.WxInitSDK(False, 10086)
-
-# 退出 SDK
-sdk.WxDestroySDK()
-
-# 注意关闭 Python 进程
-```
-
-### 调试日志
-```c
- util::dbg_msg("ListenMessage"); // 封装的 OutputDebugString
- OutputDebugString(L"ListenMessage\n");
- MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
-```
-
-## 项目结构
-
-```sh
-WeChatFerry
-├── LICENSE # LICENSE
-├── README.MD # 说明
-├── WeChatFerry
-│ ├── WeChatFerry.sln # VS2019 工程文件
-│ ├── com # 公共模块
-│ ├── rpc # RPC 模块
-│ ├── sdk # 注入及启动模块
-│ ├── smc # Silk-Mp3 转换模块
-│ └── spy # 核心功能实现模块
-├── assets
-│ ├── QR.jpeg # 二维码,测试用图
-│ ├── TEQuant.jpg # 二维码,测试用图
-│ └── demo.gif # 示例动图
-├── clients
-│ ├── go # Go 客户端
-│ ├── gohttp # HTTP 客户端
-│ ├── http # HTTP 客户端
-│ ├── java # Java 客户端
-│ ├── node # Node.js 客户端
-│ ├── pyauto # 群友封装的客户端
-│ ├── python # Python 客户端
-│ └── rust # Rust 客户端
-└── docs # 文档
-
-```
-
-## 版本更新
-
-### v39.5.2
-* 没有新功能
-
-点击查看更多
-
-客户端越来越多了,版本号开始混乱,所以重新定义了版本号:`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 开始
-
-### v39.5.1
-* 修复邀请进群偶发失败
-* 修复获取 wxid 失败
-
-### v39.5.0
-
-* 适配 `3.9.12.51`。
-
-### v39.4.5
-
-* 修复发送 XML 功能。
-
-### v39.4.4
-
-* 实现发送 XML 功能。
-
-### v39.4.3
-
-* 实现通过好友申请功能。
-
-### v39.4.2
-
-* 修复附件下载类型错误。
-
-### v39.4.1
-
-* 修复乱码问题。
-
-### v39.4.0
-
-* 重构代码,适配 `3.9.12.17`。
-
-### v39.3.5
-
-* 代码优化
-
-### v39.3.4
-
-* 实现获取登录二维码
-
-### v39.3.3
-
-* 修复发送文件 / 图片中文路径问题
-
-### v39.3.2
-
-* 修复接收消息问题
-
-### v39.3.0
-
-* 适配 `3.9.11.25`
-
-### v39.2.4
-
-* 修复 wxid 问题
-
-### v39.2.3
-
-* 实现发送 GIF
-
-### v39.2.2
-
-* 修复开启、停止接收消息失败问题
-
-### v39.2.1
-
-* 实现了好多功能(见功能清单)
-
-### v39.2.0
-
-* 开始适配 `3.9.10.27`
-* 实现检查登录状态
-* 实现获取登录账号信息(wxid、昵称、手机号、数据目录)
-* 实现获取消息类型
-* 实现开启接收消息
-* 实现停止接收消息
-* 实现发送文本消息(可 @)
-* 实现发送图片消息
-
-### v39.1.0 (2024.04.19)
-
-* 适配 x64 环境
-* 重构项目
-* 开始适配 `3.9.10.19`
-
-
+# WeChatFerry
+
+一个让微信封号的工具,千万不要使用。更多介绍见:[~~WeChatFerry: 一个玩微信的工具~~]()。
+
+
+⚠️ 免责声明【必读】⚠️
+
+请阅读完整的免责声明:[点击查看](WeChatFerry/DISCLAIMER.md)
+
+
+
+|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 ~~Python 视频教程~~]()|[🙋 ~~FAQ~~]()|
+|:-:|:-:|:-:|
+
+👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人示例。
+
+点击查看功能清单
+
+* 获取登录二维码
+* 查询登录状态
+* 获取登录账号信息
+* 获取消息类型
+* 获取联系人
+* 获取可查询数据库
+* 获取数据库所有表
+* 获取数据库密钥
+* 获取语音消息
+* 发送文本消息(可 @)
+* 发送图片消息
+* 发送文件消息
+* 发送卡片消息
+* 发送 XML 消息
+* 发送 GIF 消息
+* 拍一拍群友
+* 转发消息
+* 开启接收消息
+* 关闭接收消息
+* 查询数据库
+* 获取朋友圈消息
+* 下载图片、视频、文件
+* 解密图片
+* 图片 OCR 识别
+* 通过好友申请
+* 领取转账
+* 添加群成员
+* 删除群成员
+* 邀请群成员
+
+
+
+点击查看支持的客户端
+
+* Python
+* HTTP
+* NodeJS
+* Go
+* Java
+* Rust
+
+
+
+## 感谢大佬们贡献代码
+
+
+
+## 快速开始
+### Python
+[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](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)
+* [go_wcf_http](clients/go_wcf_http/README.MD)(基于 Go)
+* [wrest-chat](https://github.com/opentdp/wrest-chat)(基于 Go)
+* [wcf-http](https://github.com/yuxiaoli/wcf-http)(基于 Python)
+
+### Java
+* [java](clients/java/wcferry/README.MD)
+
+### NodeJS
+* [wcferry-node](https://github.com/dr-forget/wcferry-node)
+* [node-wcferry](https://github.com/stkevintan/node-wcferry)
+* [wechatferry](https://github.com/wechatferry/wechatferry)
+
+### C#
+* [WeChatFerry.Net](https://github.com/SilkageNet/WeChatFerry.Net) Install using Nuget
+* [WeChatFerry-CSharp](https://github.com/send010/WeChatFerry-CSharp)
+
+### Rust
+* [wechat-bot](https://github.com/CliffHan/wechat-bot)
+
+### Docker
+* [docker_wechat](https://github.com/Saroth/docker_wechat)
+* [wechatbot-provider-windows](https://github.com/danni-cool/wechatbot-provider-windows)
+
+## 一起开发
+
+> 🚫 非开发用户不需要往下看。
+>
+> **开发用户**:可以根据文档和错误提示,自行解决编译错误的人员。
+
+### 安装开发环境
+
+点击查看
+
+#### 安装 vcpkg
+
+* 安装,参考[Vcpkg: 总览](https://github.com/microsoft/vcpkg/blob/master/README_zh_CN.md)。
+
+```sh
+cd C:\Tools
+git clone https://github.com/microsoft/vcpkg
+.\vcpkg\bootstrap-vcpkg.bat
+```
+
+* 添加全局配置:
+环境变量增加 `vcpkg` 所在路径(本文为:`C:\Tools\vcpkg`):
+```sh
+setx VCPKG_ROOT "C:/Tools/vcpkg" /M
+```
+
+* 与 Visual Studio 集成
+```sh
+vcpkg integrate install # 失败则说明未正确安装或者未正确配置环境变量
+```
+
+#### 安装相关组件
+
+编译时会自动安装。但如果需要使用 `protoc.exe`,则需要配置一下 `protoc.exe` 环境变量:`\x86-windows-static\x86-windows-static\tools\protobuf`。
+
+(本文为:`C:\Projs\WeChatFerry\WeChatFerry\vcpkg_installed\x86-windows-static\x86-windows-static\tools\protobuf`)
+
+#### 安装 VS2019
+
+#### 安装 Python3
+
+通过微软商店或者 python.org 自行下载均可(注意 `python` 版本不能太高,否则需要自行编译依赖,建议使用 python 3.10),然后配置好环境变量,确保 `python` 在命令行下可用。
+
+安装依赖:
+```sh
+pip install grpcio-tools==1.48.2
+```
+
+
+
+### 编译
+
+使用 VS2019 打开工程(解决方案只有 `x86` 平台),编译即可。编译成功后,在 `WeChatFerry\WeChatFerry\Out` 目录中会看到相应的 DLL 及命令行工具 `wcf.exe`。
+
+**注**:如果遇到执行 `protoc` 时的 9009 错误,检查是否是 python3 环境有问题,或者 protoc 命令的环境变量配置不正确。
+
+### 运行
+
+有两种驱动方式:
+
+**方式一:`wcf.exe` 命令行(推荐,适合子进程编排 / 64 位客户端)**
+
+```sh
+wcf.exe start 10086 # 注入并在命令端口 10086 启动 RPC(消息端口为 10087)
+wcf.exe start 10086 debug # 注入 debug 版 spy
+wcf.exe stop # 卸载 spy
+wcf.exe start 10086 --gui # 出错时弹模态框(默认写 stderr,返回语义化退出码,便于自动化)
+```
+
+因 spy 为 32 位,64 位客户端无法直接 `LoadLibrary` 加载 `sdk.dll`,改由子进程调用 `wcf.exe` 驱动注入。语义化退出码:`0` 成功、`2` 参数错误、`3` spy DLL 不存在、`4` 打开/启动微信失败、`5` 注入失败、`6` 初始化 RPC 失败、`7` `.wcf.lock` 读写失败、`8` 停止时微信未运行、`9` 卸载失败、`10` spy 已注入(重复 start)。
+
+**方式二:32 位进程内直接加载 `sdk.dll`(Python 需为 32 位)**
+
+```py
+import ctypes
+# 加载 sdk.dll (需要绝对路径)
+sdk = ctypes.cdll.LoadLibrary("C:/Projs/WeChatFerry/WeChatFerry/Out/sdk.dll")
+
+# 初始化
+sdk.WxInitSDK(False, 10086)
+
+# 退出 SDK
+sdk.WxDestroySDK()
+
+# 注意关闭 Python 进程
+```
+
+### 调试日志
+```c
+ util::dbg_msg("ListenMessage"); // 封装的 OutputDebugString
+ OutputDebugString(L"ListenMessage\n");
+ MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
+```
+
+## 项目结构
+
+```sh
+WeChatFerry
+├── LICENSE # LICENSE
+├── README.MD # 说明
+├── WeChatFerry
+│ ├── WeChatFerry.sln # VS2019 工程文件
+│ ├── com # 公共模块
+│ ├── rpc # RPC 模块
+│ ├── sdk # 注入及启动模块
+│ ├── smc # Silk-Mp3 转换模块
+│ ├── spy # 核心功能实现模块
+│ └── wcf # 命令行工具(wcf.exe)
+├── assets
+│ ├── QR.jpeg # 二维码,测试用图
+│ ├── TEQuant.jpg # 二维码,测试用图
+│ └── demo.gif # 示例动图
+├── clients
+│ ├── go # Go 客户端
+│ ├── go_wcf_http # Go HTTP 客户端
+│ ├── gohttp # HTTP 客户端
+│ ├── http # HTTP 客户端
+│ ├── java # Java 客户端
+│ ├── node # Node.js 客户端
+│ ├── pyauto # 群友封装的客户端
+│ ├── python # Python 客户端
+│ ├── rust # Rust 客户端
+│ └── wcferry-node # Node.js 客户端
+└── docs # 文档
+```
+
+## 版本更新
+
+### v39.6.0
+* 适配微信 `3.9.12.56`,核心 spy 由 x64 迁回 **x86**(32 位)。
+* `wcf.exe` 增强:语义化退出码、`--gui` 开关、重复注入防护、按需等待微信启动。
+
+点击查看更多
+
+客户端越来越多了,版本号开始混乱,所以重新定义了版本号:`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 开始
+
+### v39.5.2
+* 没有新功能
+
+### v39.5.1
+* 修复邀请进群偶发失败
+* 修复获取 wxid 失败
+
+### v39.5.0
+
+* 适配 `3.9.12.51`。
+
+### v39.4.5
+
+* 修复发送 XML 功能。
+
+### v39.4.4
+
+* 实现发送 XML 功能。
+
+### v39.4.3
+
+* 实现通过好友申请功能。
+
+### v39.4.2
+
+* 修复附件下载类型错误。
+
+### v39.4.1
+
+* 修复乱码问题。
+
+### v39.4.0
+
+* 重构代码,适配 `3.9.12.17`。
+
+### v39.3.5
+
+* 代码优化
+
+### v39.3.4
+
+* 实现获取登录二维码
+
+### v39.3.3
+
+* 修复发送文件 / 图片中文路径问题
+
+### v39.3.2
+
+* 修复接收消息问题
+
+### v39.3.0
+
+* 适配 `3.9.11.25`
+
+### v39.2.4
+
+* 修复 wxid 问题
+
+### v39.2.3
+
+* 实现发送 GIF
+
+### v39.2.2
+
+* 修复开启、停止接收消息失败问题
+
+### v39.2.1
+
+* 实现了好多功能(见功能清单)
+
+### v39.2.0
+
+* 开始适配 `3.9.10.27`
+* 实现检查登录状态
+* 实现获取登录账号信息(wxid、昵称、手机号、数据目录)
+* 实现获取消息类型
+* 实现开启接收消息
+* 实现停止接收消息
+* 实现发送文本消息(可 @)
+* 实现发送图片消息
+
+### v39.1.0 (2024.04.19)
+
+* 适配 x64 环境
+* 重构项目
+* 开始适配 `3.9.10.19`
+
+
diff --git a/WeChatFerry/.editorconfig b/WeChatFerry/.editorconfig
new file mode 100644
index 00000000..46da929a
--- /dev/null
+++ b/WeChatFerry/.editorconfig
@@ -0,0 +1,7 @@
+[*]
+end_of_line = lf
+charset = utf-8-bom
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 4
\ No newline at end of file
diff --git a/WeChatFerry/CMakeLists.txt b/WeChatFerry/CMakeLists.txt
index 0abeef38..738e2c4e 100644
--- a/WeChatFerry/CMakeLists.txt
+++ b/WeChatFerry/CMakeLists.txt
@@ -40,7 +40,7 @@ add_link_options(
# Include directories
include_directories(
- ${CMAKE_SOURCE_DIR}/com
+ ${CMAKE_SOURCE_DIR}/spy/com
${CMAKE_SOURCE_DIR}/rpc
${CMAKE_SOURCE_DIR}/rpc/nanopb
${CMAKE_SOURCE_DIR}/rpc/proto
diff --git a/WeChatFerry/WeChatFerry.sln b/WeChatFerry/WeChatFerry.sln
index 02ba879a..8e49373a 100644
--- a/WeChatFerry/WeChatFerry.sln
+++ b/WeChatFerry/WeChatFerry.sln
@@ -10,23 +10,27 @@ 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|x64 = Debug|x64
- Dev|x64 = Dev|x64
- Release|x64 = Release|x64
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {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}.Dev|x64.ActiveCfg = Dev|x64
- {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Dev|x64.Build.0 = Dev|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}.Dev|x64.ActiveCfg = Dev|x64
- {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.ActiveCfg = Release|x64
- {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.Build.0 = Release|x64
+ {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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/WeChatFerry/com/framework.h b/WeChatFerry/com/framework.h
index 80cbbc9b..8d8692c7 100644
--- a/WeChatFerry/com/framework.h
+++ b/WeChatFerry/com/framework.h
@@ -1,5 +1,3 @@
#pragma once
-#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
-// Windows 头文件
-#include
+#include "../spy/com/framework.h"
diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp
index a8fa8f80..03a18a1d 100644
--- a/WeChatFerry/com/log.hpp
+++ b/WeChatFerry/com/log.hpp
@@ -1,90 +1,3 @@
#pragma once
-#ifdef ENABLE_DEBUG_LOG
-#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include "framework.h"
-
-#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
-#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__)
-#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__)
-#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__)
-
-#ifdef ENABLE_DEBUG_LOG
-#define LOG_BUFFER(buf, len) Log::log_buffer((buf), (len))
-#else
-#define LOG_BUFFER(...) (void)0
-#endif
-
-namespace Log
-{
-inline constexpr char DEFAULT_LOGGER_NAME[] = "WCF";
-inline constexpr char DEFAULT_LOGGER_FILE[] = "logs/wcf.txt";
-inline constexpr size_t DEFAULT_LOGGER_MAX_SIZE = 1024 * 1024 * 10; // 10MB
-inline constexpr size_t DEFAULT_LOGGER_MAX_FILES = 10;
-
-inline void InitLogger(const std::string &path)
-{
- static std::shared_ptr logger = nullptr;
-
- if (logger != nullptr) {
- return; // 已初始化
- }
-
- std::filesystem::path filename = std::filesystem::path(path) / DEFAULT_LOGGER_FILE;
- std::filesystem::path logDir = filename.parent_path();
-
- if (!std::filesystem::exists(logDir)) {
- std::filesystem::create_directories(logDir);
- }
-
- try {
- logger = spdlog::rotating_logger_mt(DEFAULT_LOGGER_NAME, filename.string(), DEFAULT_LOGGER_MAX_SIZE,
- DEFAULT_LOGGER_MAX_FILES);
- } catch (const spdlog::spdlog_ex &ex) {
- MessageBoxA(NULL, ex.what(), "Init LOGGER ERROR", MB_ICONERROR);
- return;
- }
-
- 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);
- logger->flush_on(spdlog::level::debug);
-#else
- logger->flush_on(spdlog::level::info);
-#endif
-
- LOG_DEBUG("InitLogger with debug level");
-}
-
-#ifdef ENABLE_DEBUG_LOG
-inline void log_buffer(uint8_t *buffer, size_t len)
-{
- constexpr size_t BUF_SIZE = 1024 * 1024;
- std::ostringstream oss;
-
- oss << "BUF@" << static_cast(buffer) << "[" << len << "]: ";
- for (size_t i = 0; i < len; ++i) {
- oss << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(buffer[i]) << " ";
- if (oss.tellp() > BUF_SIZE - 3) {
- break; // 防止缓冲区溢出
- }
- }
-
- LOG_DEBUG(oss.str());
-}
-#endif
-
-} // namespace Log
+#include "../spy/com/log.hpp"
diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp
index f5a83763..6ec111f4 100644
--- a/WeChatFerry/com/util.cpp
+++ b/WeChatFerry/com/util.cpp
@@ -1,310 +1 @@
-#include "util.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "log.hpp"
-
-#pragma comment(lib, "shlwapi")
-#pragma comment(lib, "Version.lib")
-
-namespace fs = std::filesystem;
-
-namespace util
-{
-
-constexpr char WECHATEXE[] = "WeChat.exe";
-constexpr char WECHATWINDLL[] = "WeChatWin.dll";
-
-std::wstring s2w(const std::string &s)
-{
- if (s.empty()) return std::wstring();
- int size_needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast(s.size()), nullptr, 0);
- std::wstring ws(size_needed, 0);
- MultiByteToWideChar(CP_UTF8, 0, s.c_str(), static_cast(s.size()), &ws[0], size_needed);
- return ws;
-}
-
-std::string w2s(const std::wstring &ws)
-{
- if (ws.empty()) return std::string();
- int size_needed
- = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast(ws.size()), nullptr, 0, nullptr, nullptr);
- std::string s(size_needed, 0);
- WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), static_cast(ws.size()), &s[0], size_needed, nullptr, nullptr);
- return s;
-}
-
-std::string gb2312_to_utf8(const char *gb2312)
-{
- if (!gb2312) return "";
-
- int size_needed = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, nullptr, 0);
- std::wstring ws(size_needed, 0);
- MultiByteToWideChar(CP_ACP, 0, gb2312, -1, &ws[0], size_needed);
-
- size_needed = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, nullptr, 0, nullptr, nullptr);
- std::string s(size_needed, 0);
- WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, &s[0], size_needed, nullptr, nullptr);
-
- return s;
-}
-
-static DWORD get_wechat_pid()
-{
- DWORD pid = 0;
- HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
-
- PROCESSENTRY32W pe32 = { sizeof(PROCESSENTRY32W) };
- while (Process32NextW(hSnapshot, &pe32)) {
- if (pe32.szExeFile == s2w(WECHATEXE)) {
- pid = pe32.th32ProcessID;
- break;
- }
- }
- CloseHandle(hSnapshot);
- return pid;
-}
-
-static std::optional get_wechat_path()
-{
- HKEY hKey;
- if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Tencent\\WeChat", 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
- LOG_ERROR("无法打开注册表项");
- return std::nullopt;
- }
-
- char path[MAX_PATH] = { 0 };
- DWORD type = REG_SZ;
- DWORD size = sizeof(path);
- if (RegQueryValueExA(hKey, "InstallPath", nullptr, &type, reinterpret_cast(path), &size) != ERROR_SUCCESS) {
- RegCloseKey(hKey);
- LOG_ERROR("无法读取注册表中的 InstallPath");
- return std::nullopt;
- }
- RegCloseKey(hKey);
-
- PathAppendA(path, WECHATEXE);
- return std::string(path);
-}
-
-static std::optional get_wechat_win_dll_path()
-{
- auto wechat_path = get_wechat_path();
- if (!wechat_path) {
- return std::nullopt;
- }
-
- fs::path dll_path = *wechat_path;
- dll_path = dll_path.parent_path();
-
- fs::path wechat_dll_path = dll_path / WECHATWINDLL;
- if (fs::exists(wechat_dll_path)) { // 尝试直接查找 WeChatWin.dll
- return wechat_dll_path.string();
- }
-
- // 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29]
- std::optional found_path;
- for (const auto &entry : fs::directory_iterator(dll_path)) {
- if (entry.is_directory()) {
- fs::path possible_dll = entry.path() / WECHATWINDLL;
- if (fs::exists(possible_dll)) {
- found_path = possible_dll.string();
- break; // 取第一个找到的版本号文件夹
- }
- }
- }
-
- if (!found_path) {
- LOG_ERROR("未找到 WeChatWin.dll");
- }
-
- return found_path;
-}
-
-static std::optional get_file_version(const std::string &path)
-{
- if (!PathFileExistsA(path.c_str())) {
- LOG_ERROR("文件不存在: {}", path);
- return std::nullopt;
- }
-
- DWORD dummy = 0;
- DWORD size = GetFileVersionInfoSizeA(path.c_str(), &dummy);
- if (size == 0) {
- LOG_ERROR("无法获取文件版本信息大小: {}", path);
- return std::nullopt;
- }
-
- std::vector buffer(size);
- if (!GetFileVersionInfoA(path.c_str(), 0, size, buffer.data())) {
- LOG_ERROR("无法获取文件版本信息: {}", path);
- return std::nullopt;
- }
-
- VS_FIXEDFILEINFO *ver_info = nullptr;
- UINT ver_size = 0;
- if (!VerQueryValueA(buffer.data(), "\\", reinterpret_cast(&ver_info), &ver_size)) {
- LOG_ERROR("无法获取文件版本信息: {}", path);
- return std::nullopt;
- }
-
- return fmt::format("{}.{}.{}.{}", HIWORD(ver_info->dwFileVersionMS), LOWORD(ver_info->dwFileVersionMS),
- HIWORD(ver_info->dwFileVersionLS), LOWORD(ver_info->dwFileVersionLS));
-}
-
-std::string get_wechat_version()
-{
- auto dll_path = get_wechat_win_dll_path();
- if (!dll_path) {
- LOG_ERROR("无法获取 WeChatWin.dll 路径");
- return "";
- }
-
- auto version = get_file_version(*dll_path);
- if (!version) {
- LOG_ERROR("无法获取 WeChat 版本信息");
- return "";
- }
-
- return *version;
-}
-
-int open_wechat(DWORD &pid)
-{
- pid = get_wechat_pid();
- if (pid != 0) {
- return ERROR_SUCCESS;
- }
-
- auto wechat_path = util::get_wechat_path();
- if (!wechat_path) {
- LOG_ERROR("获取 WeChat 安装路径失败");
- return ERROR_FILE_NOT_FOUND;
- }
-
- STARTUPINFOA si = { sizeof(si) };
- PROCESS_INFORMATION pi = {};
-
- std::string command_line = *wechat_path;
- if (!CreateProcessA(nullptr, command_line.data(), nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, nullptr, nullptr,
- &si, &pi)) {
- return GetLastError();
- }
-
- CloseHandle(pi.hThread);
- CloseHandle(pi.hProcess);
-
- pid = pi.dwProcessId;
- return ERROR_SUCCESS;
-}
-
-uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr)
-{
- uint32_t value = 0;
- if (!addr || !hProcess) return value;
-
- ReadProcessMemory(hProcess, reinterpret_cast(addr), &value, sizeof(value), nullptr);
-
- return value;
-}
-
-std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t address)
-{
- if (!hProcess || !address) return L"";
-
- uint64_t str_address = get_memory_int_by_address(hProcess, address);
- uint64_t str_len = get_memory_int_by_address(hProcess, address + 0x4);
- if (str_len > 500) return L"";
-
- wchar_t cValue[500] = { 0 };
- if (ReadProcessMemory(hProcess, reinterpret_cast(str_address), cValue, (str_len + 1) * sizeof(wchar_t),
- nullptr)) {
- return std::wstring(cValue);
- }
-
- return L"";
-}
-
-void dbg_msg(const char *format, ...)
-{
- if (!format) return;
-
- va_list args;
- va_start(args, format);
-
- va_list args_copy;
- va_copy(args_copy, args);
- int len = vsnprintf(nullptr, 0, format, args_copy);
- va_end(args_copy);
-
- std::vector buffer(len + 1);
- vsnprintf(buffer.data(), buffer.size(), format, args);
- va_end(args);
-
- OutputDebugStringW(s2w(buffer.data()).c_str());
-}
-
-std::unique_ptr new_wx_string(const char *str)
-{
- return new_wx_string(str ? std::string(str) : std::string());
-}
-
-std::unique_ptr new_wx_string(const std::string &str) { return std::make_unique(s2w(str)); }
-
-std::unique_ptr new_wx_string(const wchar_t *wstr)
-{
- return new_wx_string(wstr ? std::wstring(wstr) : std::wstring());
-}
-
-std::unique_ptr new_wx_string(const std::wstring &wstr) { return std::make_unique(wstr); }
-
-AtWxidSplitResult<> parse_wxids(const std::string &atWxids)
-{
- AtWxidSplitResult<> result;
- if (!atWxids.empty()) {
- std::wstringstream wss(util::s2w(atWxids));
- for (std::wstring wxid; std::getline(wss, wxid, L',');) {
- result.wxids.push_back(wxid);
- result.wxWxids.emplace_back(result.wxids.back());
- }
- }
- return result;
-}
-
-WxString *CreateWxString(const std::string &s)
-{
- std::wstring ws = util::s2w(s);
- WxString *wxStr = reinterpret_cast(HeapAlloc(GetProcessHeap(), 8, sizeof(WxString)));
- if (!wxStr) return nullptr;
- size_t len = ws.length();
- wchar_t *ptr = reinterpret_cast(HeapAlloc(GetProcessHeap(), 8, (len + 1) * sizeof(wchar_t)));
- if (!ptr) {
- HeapFree(GetProcessHeap(), 8, wxStr);
- return nullptr;
- }
- wmemcpy(ptr, ws.c_str(), len + 1);
- wxStr->wptr = ptr;
- wxStr->size = static_cast(ws.size());
- wxStr->length = static_cast(ws.length());
- wxStr->clen = 0;
- wxStr->ptr = nullptr;
- return wxStr;
-}
-
-void FreeWxString(WxString *wxStr)
-{
- if (wxStr) {
- if (wxStr->wptr) HeapFree(GetProcessHeap(), 8, const_cast(wxStr->wptr));
- HeapFree(GetProcessHeap(), 8, wxStr);
- }
-}
-} // namespace util
+#include "../spy/com/util.cpp"
diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h
index 6e83b014..d43ff270 100644
--- a/WeChatFerry/com/util.h
+++ b/WeChatFerry/com/util.h
@@ -1,105 +1,3 @@
-#pragma once
+#pragma once
-#include
-#include
-#include
-#include
-
-#include "spy_types.h"
-
-namespace util
-{
-struct PortPath {
- int port;
- char path[MAX_PATH];
-};
-
-static DWORD get_wechat_pid();
-int open_wechat(DWORD &pid);
-std::string get_wechat_version();
-uint32_t get_memory_int_by_address(HANDLE hProcess, uint64_t addr);
-std::wstring get_unicode_info_by_address(HANDLE hProcess, uint64_t addr);
-std::wstring s2w(const std::string &s);
-std::string w2s(const std::wstring &ws);
-std::string gb2312_to_utf8(const char *gb2312);
-void dbg_msg(const char *format, ...);
-
-inline DWORD get_dword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; }
-inline QWORD get_qword(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; }
-inline uint64_t get_uint64(uint64_t addr) { return addr ? *reinterpret_cast(addr) : 0; }
-inline std::string get_p_string(uint64_t addr) { return addr ? std::string(reinterpret_cast(addr)) : ""; }
-inline std::string get_p_string(uint64_t addr, size_t len)
-{
- return addr ? std::string(reinterpret_cast(addr), len) : "";
-}
-inline std::wstring get_p_wstring(uint64_t addr)
-{
- return addr ? std::wstring(reinterpret_cast(addr)) : L"";
-}
-inline std::wstring get_p_wstring(uint64_t addr, size_t len)
-{
- return addr ? std::wstring(reinterpret_cast(addr), len) : L"";
-}
-inline std::string get_pp_string(uint64_t addr)
-{
- if (!addr) return "";
-
- const char *ptr = *reinterpret_cast(addr);
- return (ptr && *ptr) ? std::string(ptr) : "";
-}
-inline std::wstring get_pp_wstring(uint64_t addr)
-{
- if (!addr) return L"";
-
- const wchar_t *ptr = *reinterpret_cast(addr);
- return (ptr && *ptr) ? std::wstring(ptr) : L"";
-}
-inline std::string get_pp_len_string(uint64_t addr)
-{
- size_t len = get_dword(addr + 8);
- return (addr && len) ? std::string(*reinterpret_cast(addr), len) : "";
-}
-inline std::wstring get_pp_len_wstring(uint64_t addr)
-{
- size_t len = get_dword(addr + 8);
- return (addr && len) ? std::wstring(*reinterpret_cast(addr), len) : L"";
-}
-inline std::string get_str_by_wstr_addr(uint64_t addr) { return w2s(get_pp_len_wstring(addr)); }
-inline void *AllocFromHeap(size_t size) { return HeapAlloc(GetProcessHeap(), 8, size); }
-inline void FreeBuffer(void *buffer)
-{
- if (buffer) HeapFree(GetProcessHeap(), 8, buffer);
-}
-inline int MsgBox(HWND hWnd, const std::string &text, const std::string &caption = "WCF", UINT uType = MB_OK)
-{
- std::wstring wText = s2w(text);
- std::wstring wCaption = s2w(caption);
- return MessageBoxW(nullptr, wText.c_str(), wCaption.c_str(), uType);
-}
-
-template static T *AllocBuffer(size_t count)
-{
- return reinterpret_cast(HeapAlloc(GetProcessHeap(), 8, sizeof(T) * count));
-}
-
-template struct WxStringHolder {
- std::wstring ws;
- WxString wx;
- explicit WxStringHolder(const T &str) : ws(util::s2w(str)), wx(ws) { }
-};
-
-template struct AtWxidSplitResult {
- std::vector wxids;
- std::vector wxWxids;
-};
-
-WxString *CreateWxString(const std::string &s);
-void FreeWxString(WxString *wxStr);
-AtWxidSplitResult<> parse_wxids(const std::string &atWxids);
-
-std::unique_ptr new_wx_string(const char *str);
-std::unique_ptr new_wx_string(const wchar_t *wstr);
-std::unique_ptr new_wx_string(const std::string &str);
-std::unique_ptr new_wx_string(const std::wstring &wstr);
-
-} // namespace util
+#include "../spy/com/util.h"
diff --git a/WeChatFerry/rpc/pb_types.h b/WeChatFerry/rpc/pb_types.h
index 82f5459b..897b8af3 100644
--- a/WeChatFerry/rpc/pb_types.h
+++ b/WeChatFerry/rpc/pb_types.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#include