Merge pull request #167 from lich0821/3.9.10.19

3.9.10.19
This commit is contained in:
Changhua 2024-07-02 22:33:23 +08:00 committed by GitHub
commit 1ae4c4b30c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 610 additions and 692 deletions

233
README.MD
View File

@ -1,7 +1,8 @@
# WeChatFerry
一个玩微信的工具。更多介绍见:[WeChatFerry: 一个玩微信的工具](https://mp.weixin.qq.com/s/CGLfSaNDy8MyuyPWGjGJ7w)。
<details><summary><font color="#FF0000" size="5">免责声明【必读】</font></summary>
<details><summary><font color="red" size="12">免责声明【必读】</font></summary>
本工具仅供学习和技术研究使用,不得用于任何商业或非法行为,否则后果自负。
@ -15,101 +16,22 @@
</details>
|[📖 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 机器人框架。
<details><summary>点击查看功能清单</summary>
* 检查登录状态
* 获取登录账号的 wxid
* 获取消息类型
* 获取所有联系人
* 获取所有好友
* 获取数据库
* 获取某数据库下的表
* 获取用户信息
* 发送文本消息(可 @
* 发送图片
* 发送文件
* 允许接收消息
* 停止接收消息
* 执行 SQL 查询
* 接受好友申请
* 添加群成员
* 删除群成员
* 解密图片
* 获取朋友圈消息
* 保存图片
* 保存语音
* 发送卡片消息
* 拍一拍群友
* 邀请群成员
* 图片 OCR
* 转发消息
* 撤回消息
* 获取登录二维码
</details>
<details><summary>点击查看支持的客户端</summary>
* Go
* HTTP (Go, Rust)
* Java
* Node.js
* Python
* Rust
</details>
|![碲矿](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)
## 一起开发
> 🚫 非开发用户不需要往下看。
### 安装开发环境
<details><summary>点击查看</summary>
#### 安装 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,16 @@ 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 install minhook:x64-windows-static
vcpkg integrate install
```
@ -134,32 +58,56 @@ vcpkg integrate install
#### 安装 Python3
通过微软商店或者 python.org 自行下载均可,注意配置好环境变量,确保 `python3` 在命令行下可用
通过微软商店或者 python.org 自行下载均可,注意配置好环境变量,确保 `python3` 在命令行下可用。
安装依赖:
```sh
pip install grpcio-tools==1.48.2
```
</details>
### 编译
使用 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 进程
```
### 调试日志
```c
DbgMsg("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 # 注入及启动模块
│   ├── spy # 核心功能实现模块
│   └── wcf # 命令行版启动器
│   ├── smc # Silk-Mp3 转换模块
│   └── spy # 核心功能实现模块
├── assets
│   ├── QR.jpeg # 二维码,测试用图
│   ├── TEQuant.jpg # 二维码,测试用图
@ -177,47 +125,13 @@ WeChatFerry
```
<details><summary>点击查看</summary>
### 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`。一般情况不需要显式运行,各客户端自动调用。
</details>
## 版本更新
### v39.0.14 (2024.02.18)
* 修复获取登录二维码问题
### v39.1.0 (2024.04.19)
* 适配 x64 环境
* 重构项目
* 开始适配 `3.9.10.19`
<details><summary>点击查看更多</summary>
@ -229,21 +143,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 +173,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 +214,7 @@ Rust 客户端。
* HTTP 客户端 `wcfhttp` 的 `v3.7.0.30.25` 应该调整为 `v37.1.25.0`
### v3.7.0.30.25 (2023.05.05)
* 修复群消息判断错误
* 修复名片添加好友问题
* 修复获取数据库多余字符问题
@ -290,105 +222,136 @@ Rust 客户端。
* Python 客户端发送图片支持网络路径
### v3.7.0.30.24 (2023.04.19)
实现了一个功能。
### v3.7.0.30.23 (2023.04.13)
* 解密图片
* 获取登录账号信息
* 获取联系人备注
### v3.7.0.30.222023.04.09
将监听端口调整为可配置。
### v3.7.0.30.212023.03.15
* 发送表情
### v3.7.0.30.202023.03.12
修复 wxid 获取问题。
### v3.7.0.30.192023.03.06
修复重复消息问题。
### v3.7.0.30.182023.03.05
修复添加好友问题。
### v3.7.0.30.172023.03.05
修复获取登录账号 wxid 问题。
### v3.7.0.30.162023.03.04
将错误码改成错误消息,方便调试。
### v3.7.0.30.152023.03.01
* 发送 xml
### v3.7.0.30.142023.02.28
* 添加群成员
### v3.7.0.30.132023.02.27
去除 gRPC 框架,自定义更轻量的 RPC 轮子 `nnprc`。
### v3.7.0.30.122023.01.20
* 更新 Python 客户端
* 修改监听地址为 `0.0.0.0:10086`
* 增加 `Launcher`,直接注入 `spy`
### v3.7.0.30.112022.10.19
更新 Python 客户端。
### v3.7.0.30-gRPC-22022.10.18
增加 Java 客户端。
### v3.7.0.30-gRPC-12022.10.16
将 RPC 框架切换为 gRPC
### v3.7.0.30-82022.09.25
* 获取登录账号微信 ID
### v3.7.0.30-72022.09.24
修复群聊有系统消息时会崩溃 bug。后续考虑把消息来源交还给客户端自己区别。
### v3.7.0.30-62022.08.21
* 通过好友验证
### v3.7.0.30-52022.08.20
* 执行 SQL 语句
### v3.7.0.30-42022.08.20
修复群消息 @人 功能。有几点注意事项:
1. `vAtWxids` 是要 `@` 的 `wxid` 清单,以 `,` 分隔。
2. 只有群主才能 `@所有人`,非群主硬发 `@所有人` 会导致消息发不出去;`@所有人` 对应 `vAtWxids` 为 `"notify@all"`。
3. 消息体里 `@` 的数量必须与 `vAtWxids` 里的数量一致,否则消息能发出但 `@` 功能失效。
### v3.7.0.30-32022.08.20
修复可重入 bug。
### v3.7.0.30-22022.08.14
优化 Hook 和 Inject 代码,实现可重入。
### v3.7.0.30-12022.08.12
适配微信 `3.7.0.30`。
### v3.7.0.29-32022.08.7
* 查询数据库,获取库、表。
### v3.7.0.29-22022.08.7
优化 RPC。
### v3.7.0.29-12022.08.7
适配微信 `3.7.0.29`。
### v3.3.0.115-32021.08.28
适配微信 `3.3.0.115`,新增功能:
* 获取所有联系人
### v3.3.0.115-22021.08.22
适配微信 `3.3.0.115`,新增功能:
* 发送图片消息
### v3.3.0.115-12021.08.22
适配微信 `3.3.0.115`。
### v3.0.0.57-12021.02.12
适配微信 `3.0.0.57`,支持功能:
* 登录状态判断
* 接收文本消息

View File

@ -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

View File

@ -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) {

View File

@ -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);
@ -208,44 +208,44 @@ int OpenWeChat(DWORD *pid)
return ERROR_SUCCESS;
}
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
size_t GetWstringByAddress(UINT64 addr, wchar_t *buffer, UINT64 buffer_size)
{
DWORD strLength = GET_DWORD(address + 4);
size_t strLength = GET_DWORD(addr + 8);
if (strLength == 0) {
return 0;
} else if (strLength > buffer_size) {
strLength = buffer_size - 1;
}
wmemcpy_s(buffer, strLength + 1, GET_WSTRING(address), strLength + 1);
wmemcpy_s(buffer, strLength + 1, GET_WSTRING(addr), strLength + 1);
return strLength;
}
string GetStringByAddress(DWORD address)
string GetStringByAddress(UINT64 addr)
{
DWORD strLength = GET_DWORD(address + 4);
return Wstring2String(wstring(GET_WSTRING(address), strLength));
size_t strLength = GET_DWORD(addr + 8);
return Wstring2String(wstring(GET_WSTRING(addr), strLength));
}
string GetStringByStrAddr(DWORD addr)
string GetStringByStrAddr(UINT64 addr)
{
DWORD strLength = GET_DWORD(addr + 4);
size_t strLength = GET_DWORD(addr + 8);
return strLength ? string(GET_STRING(addr), strLength) : string();
}
string GetStringByWstrAddr(DWORD addr)
string GetStringByWstrAddr(UINT64 addr)
{
DWORD strLength = GET_DWORD(addr + 4);
size_t strLength = GET_DWORD(addr + 8);
return strLength ? Wstring2String(wstring(GET_WSTRING(addr), strLength)) : string();
}
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
UINT32 GetMemoryIntByAddress(HANDLE hProcess, UINT64 addr)
{
DWORD value = 0;
UINT32 value = 0;
unsigned char data[4] = { 0 };
if (ReadProcessMemory(hProcess, (LPVOID)address, data, 4, 0)) {
if (ReadProcessMemory(hProcess, (LPVOID)addr, data, 4, 0)) {
value = data[0] & 0xFF;
value |= ((data[1] << 8) & 0xFF00);
value |= ((data[2] << 16) & 0xFF0000);
@ -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;

36
WeChatFerry/com/util.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <string>
#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_DWORD(addr) ((DWORD) * (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;
DWORD GetWeChatPid();
int OpenWeChat(DWORD *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, ...);

View File

@ -86,6 +86,10 @@
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x64-windows-static</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@ -154,30 +158,43 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)com;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include</AdditionalIncludeDirectories>
<PrecompiledHeaderOutputFile />
<SupportJustMyCode>true</SupportJustMyCode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
<PostBuildEvent>
<Command>xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy files</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\spy\log.h" />
<ClInclude Include="..\spy\util.h" />
<ClInclude Include="..\com\log.h" />
<ClInclude Include="..\com\util.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="injector.h" />
<ClInclude Include="sdk.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\spy\log.cpp" />
<ClCompile Include="..\spy\util.cpp" />
<ClCompile Include="..\com\log.cpp" />
<ClCompile Include="..\com\util.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="injector.cpp" />
<ClCompile Include="sdk.cpp" />

View File

@ -21,32 +21,32 @@
<ClInclude Include="sdk.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\spy\util.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\spy\log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="injector.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\com\log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\com\util.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="sdk.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="injector.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\com\log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\com\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="sdk.def">

View File

@ -1,26 +1,44 @@
#include "injector.h"
#include "framework.h"
#include "psapi.h"
#include <filesystem>
#include <string>
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;
}

View File

@ -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);

View File

@ -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;

View File

@ -83,6 +83,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<TargetName>$(ProjectName)_debug</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@ -94,6 +95,12 @@
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgConfiguration>Release</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@ -191,10 +198,20 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)com;$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include</AdditionalIncludeDirectories>
<IntrinsicFunctions>true</IntrinsicFunctions>
<OmitFramePointers>false</OmitFramePointers>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile />
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -202,7 +219,28 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
<AdditionalOptions> /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<AdditionalLibraryDirectories>$(SolutionDir)smc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>cd $(SolutionDir)rpc\proto
$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Generating PB files</Message>
</PreBuildEvent>
<PostBuildEvent>
<Command>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</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -210,21 +248,48 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)com;$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include</AdditionalIncludeDirectories>
<OmitFramePointers>false</OmitFramePointers>
<PrecompiledHeaderOutputFile />
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(SolutionDir)smc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions> /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
<PreBuildEvent>
<Message>Generating PB files</Message>
<Command>cd $(SolutionDir)rpc\proto
$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
</PreBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
<Command>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</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\com\log.h" />
<ClInclude Include="..\com\util.h" />
<ClInclude Include="..\rpc\nanopb\pb.h" />
<ClInclude Include="..\rpc\nanopb\pb_common.h" />
<ClInclude Include="..\rpc\nanopb\pb_decode.h" />
@ -239,7 +304,6 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<ClInclude Include="framework.h" />
<ClInclude Include="contact_mgmt.h" />
<ClInclude Include="load_calls.h" />
<ClInclude Include="log.h" />
<ClInclude Include="receive_msg.h" />
<ClInclude Include="receive_transfer.h" />
<ClInclude Include="resource.h" />
@ -249,9 +313,10 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<ClInclude Include="spy_types.h" />
<ClInclude Include="sqlite3.h" />
<ClInclude Include="user_info.h" />
<ClInclude Include="util.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\com\log.cpp" />
<ClCompile Include="..\com\util.cpp" />
<ClCompile Include="..\rpc\nanopb\pb_common.c" />
<ClCompile Include="..\rpc\nanopb\pb_decode.c" />
<ClCompile Include="..\rpc\nanopb\pb_encode.c" />
@ -263,14 +328,12 @@ $(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
<ClCompile Include="exec_sql.cpp" />
<ClCompile Include="contact_mgmt.cpp" />
<ClCompile Include="load_calls.cpp" />
<ClCompile Include="log.cpp" />
<ClCompile Include="receive_msg.cpp" />
<ClCompile Include="receive_transfer.cpp" />
<ClCompile Include="rpc_server.cpp" />
<ClCompile Include="send_msg.cpp" />
<ClCompile Include="spy.cpp" />
<ClCompile Include="user_info.cpp" />
<ClCompile Include="util.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\rpc\proto\wcf.proto" />

View File

@ -24,9 +24,6 @@
<ClInclude Include="rpc_server.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="exec_sql.h">
<Filter>头文件</Filter>
</ClInclude>
@ -48,9 +45,6 @@
<ClInclude Include="spy_types.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="util.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\rpc\nanopb\pb.h">
<Filter>nnrpc</Filter>
</ClInclude>
@ -93,6 +87,12 @@
<ClInclude Include="..\smc\codec.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\com\log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\com\util.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@ -101,9 +101,6 @@
<ClCompile Include="rpc_server.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="exec_sql.cpp">
<Filter>源文件</Filter>
</ClCompile>
@ -122,9 +119,6 @@
<ClCompile Include="spy.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\rpc\nanopb\pb_common.c">
<Filter>nnrpc</Filter>
</ClCompile>
@ -152,6 +146,12 @@
<ClCompile Include="receive_transfer.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\com\log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\com\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="spy.def">

View File

@ -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

View File

@ -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

View File

@ -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<string, DWORD> dbMap_t;
static dbMap_t dbMap;
#if 0
static void GetDbHandle(DWORD base, DWORD offset)
{
wchar_t *wsp;
@ -225,3 +225,4 @@ vector<uint8_t> GetAudioData(uint64_t id)
return vector<uint8_t>();
}
#endif

View File

@ -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

View File

@ -3,6 +3,7 @@
#include "stdint.h"
#include <string>
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);

View File

@ -3,14 +3,15 @@
#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
{ 0x2FFD484, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home
0x5AB9184, // Login Status
{ 0x5AB8FC8, 0x5AB90A8, 0x5AB8FE8, 0x5A7F170 }, // User Info: wxid, nickname, mobile, home
{ 0x768140, 0xCE6C80, 0x756960 }, // Send Message
/* Receive Message:
Hook, call, msgId, type, isSelf, ts, roomId, content, wxid, sign, thumb, extra, msgXml */
{ 0xD19A0B, 0x756960, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x70, 0x180, 0x194, 0x1A8, 0x1BC, 0x1FC },
{ 0x00, 0x2206570, 0x30, 0x38, 0x3C, 0x44, 0x48, 0x88, 0x240, 0x260, 0x280, 0x2A0, 0x308 },
{ 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message
{ 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message
{ 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message

View File

@ -1,5 +1,6 @@
#pragma execution_character_set("utf-8")
#include "MinHook.h"
#include "framework.h"
#include <condition_variable>
#include <mutex>
@ -19,18 +20,11 @@ extern queue<WxMsg_t> 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;
static DWORD recvMsgCallAddr = 0;
static DWORD recvMsgJumpBackAddr = 0;
static CHAR recvMsgBackupCode[5] = { 0 };
static DWORD recvPyqHookAddr = 0;
static DWORD recvPyqCallAddr = 0;
static DWORD recvPyqJumpBackAddr = 0;
static CHAR recvPyqBackupCode[5] = { 0 };
typedef UINT64 (*funcRecvMsg_t)(UINT64, UINT64);
static funcRecvMsg_t funcRecvMsg = nullptr;
static funcRecvMsg_t realRecvMsg = nullptr;
MsgTypes_t GetMsgTypes()
{
@ -73,6 +67,130 @@ MsgTypes_t GetMsgTypes()
return m;
}
static UINT64 DispatchMsg(UINT64 arg1, UINT64 arg2)
{
WxMsg_t wxMsg = { 0 };
try {
wxMsg.id = GET_QWORD(arg2 + g_WxCalls.recvMsg.msgId);
wxMsg.type = GET_DWORD(arg2 + g_WxCalls.recvMsg.type);
wxMsg.is_self = GET_DWORD(arg2 + g_WxCalls.recvMsg.isSelf);
wxMsg.ts = GET_DWORD(arg2 + g_WxCalls.recvMsg.ts);
wxMsg.content = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.content);
wxMsg.sign = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.sign);
wxMsg.xml = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.msgXml);
string roomid = GetStringByWstrAddr(arg2 + 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 = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.wxid);
}
} else {
wxMsg.is_group = false;
if (wxMsg.is_self) {
wxMsg.sender = GetSelfWxid();
} else {
wxMsg.sender = roomid;
}
}
wxMsg.thumb = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.thumb);
if (!wxMsg.thumb.empty()) {
wxMsg.thumb = GetHomePath() + wxMsg.thumb;
replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/');
}
wxMsg.extra = GetStringByWstrAddr(arg2 + g_WxCalls.recvMsg.extra);
if (!wxMsg.extra.empty()) {
wxMsg.extra = GetHomePath() + wxMsg.extra;
replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/');
}
} catch (const std::exception &e) {
LOG_ERROR(GB2312ToUtf8(e.what()));
} catch (...) {
LOG_ERROR("Unknow exception.");
}
{
unique_lock<mutex> lock(gMutex);
gMsgQueue.push(wxMsg); // 推送到队列
}
gCV.notify_all(); // 通知各方消息就绪
return realRecvMsg(arg1, arg2);
}
void ListenMessage()
{
MH_STATUS status = MH_UNKNOWN;
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
LOG_WARN("gIsListening || (g_WeChatWinDllAddr == 0)");
return;
}
funcRecvMsg = (funcRecvMsg_t)(g_WeChatWinDllAddr + g_WxCalls.recvMsg.call);
status = MH_Initialize();
if (status != MH_OK) {
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
return;
}
status = MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast<LPVOID *>(&realRecvMsg));
if (status != MH_OK) {
LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
return;
}
status = MH_EnableHook(funcRecvMsg);
if (status != MH_OK) {
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
return;
}
gIsListening = true;
}
void UnListenMessage()
{
MH_STATUS status = MH_UNKNOWN;
if (!gIsListening) {
return;
}
status = MH_DisableHook(funcRecvMsg);
if (status != MH_OK) {
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
return;
}
status = MH_Uninitialize();
if (status != MH_OK) {
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
return;
}
gIsListening = false;
}
void ListenPyq() { }
void UnListenPyq() { }
#if 0
// static DWORD reg_buffer = 0;
// static DWORD recvMsgHookAddr = 0;
// static DWORD recvMsgCallAddr = 0;
// static DWORD recvMsgJumpBackAddr = 0;
// static CHAR recvMsgBackupCode[5] = { 0 };
// static DWORD recvPyqHookAddr = 0;
// static DWORD recvPyqCallAddr = 0;
// static DWORD recvPyqJumpBackAddr = 0;
// static CHAR recvPyqBackupCode[5] = { 0 };
void HookAddress(DWORD hookAddr, LPVOID funcAddr, CHAR recvMsgBackupCode[5])
{
// 组装跳转数据
@ -259,3 +377,4 @@ void UnListenPyq()
UnHookAddress(recvPyqHookAddr, recvPyqBackupCode);
gIsListeningPyq = false;
}
#endif

View File

@ -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

View File

@ -40,8 +40,6 @@
namespace fs = std::filesystem;
extern int IsLogin(void); // Defined in spy.cpp
bool gIsListening = false;
bool gIsListeningPyq = false;
mutex gMutex;
@ -90,6 +88,28 @@ bool func_get_self_wxid(uint8_t *out, size_t *len)
return true;
}
bool func_get_user_info(uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_GET_USER_INFO;
rsp.which_msg = Response_ui_tag;
UserInfo_t ui = GetUserInfo();
rsp.msg.ui.wxid = (char *)ui.wxid.c_str();
rsp.msg.ui.name = (char *)ui.name.c_str();
rsp.msg.ui.mobile = (char *)ui.mobile.c_str();
rsp.msg.ui.home = (char *)ui.home.c_str();
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_get_msg_types(uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
@ -109,7 +129,7 @@ bool func_get_msg_types(uint8_t *out, size_t *len)
return true;
}
#if 0
bool func_get_contacts(uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
@ -170,28 +190,6 @@ bool func_get_db_tables(char *db, uint8_t *out, size_t *len)
return true;
}
bool func_get_user_info(uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_GET_USER_INFO;
rsp.which_msg = Response_ui_tag;
UserInfo_t ui = GetUserInfo();
rsp.msg.ui.wxid = (char *)ui.wxid.c_str();
rsp.msg.ui.name = (char *)ui.name.c_str();
rsp.msg.ui.mobile = (char *)ui.mobile.c_str();
rsp.msg.ui.home = (char *)ui.home.c_str();
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_get_audio_msg(uint64_t id, char *dir, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
@ -428,7 +426,7 @@ bool func_forward_msg(uint64_t id, char *receiver, uint8_t *out, size_t *len)
return true;
}
#endif
static void PushMessage()
{
static uint8_t buffer[G_BUF_SIZE] = { 0 };
@ -545,6 +543,7 @@ bool func_disable_recv_txt(uint8_t *out, size_t *len)
return true;
}
#if 0
bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
@ -837,7 +836,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,6 +849,7 @@ 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);
@ -859,10 +859,15 @@ 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;
}
case Functions_FUNC_GET_USER_INFO: {
ret = func_get_user_info(out, out_len);
break;
}
case Functions_FUNC_GET_MSG_TYPES: {
ret = func_get_msg_types(out, out_len);
break;
}
#if 0
case Functions_FUNC_GET_CONTACTS: {
ret = func_get_contacts(out, out_len);
break;
@ -875,10 +880,6 @@ 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;
}
case Functions_FUNC_GET_USER_INFO: {
ret = func_get_user_info(out, out_len);
break;
}
case Functions_FUNC_GET_AUDIO_MSG: {
ret = func_get_audio_msg(req.msg.am.id, req.msg.am.dir, out, out_len);
break;
@ -907,7 +908,6 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_forward_msg(req.msg.fm.id, req.msg.fm.receiver, out, out_len);
break;
}
#if 0
case Functions_FUNC_SEND_XML: {
ret = func_send_xml(req.msg.xml, out, out_len);
break;
@ -925,6 +925,7 @@ 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: {
ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len);
break;
@ -977,11 +978,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 +1068,7 @@ int RpcStopServer()
if (lIsRunning) {
nng_close(cmdSock);
nng_close(msgSock);
UnListenMessage();
// UnListenMessage();
lIsRunning = false;
Sleep(1000);
LOG_INFO("Server stoped.");

View File

@ -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

Binary file not shown.

View File

@ -7,17 +7,16 @@
#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 模块地址失败");
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();
}

View File

@ -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"

View File

@ -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;
}

View File

@ -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 + 0x18);
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 + 0x18);
if (nameType == 0xF) {
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + g_WxCalls.ui.nickName);
} else { // 0x1F

View File

@ -1,35 +0,0 @@
#pragma once
#include <string>
#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, ...);

View File

@ -1,34 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -1,173 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{02747ce0-ad9f-4812-b019-fcf9867f7514}</ProjectGuid>
<RootNamespace>wcf</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;WCF;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)sdk;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy files</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\sdk\framework.h" />
<ClInclude Include="..\sdk\injector.h" />
<ClInclude Include="..\sdk\sdk.h" />
<ClInclude Include="..\spy\log.h" />
<ClInclude Include="..\spy\util.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\sdk\injector.cpp" />
<ClCompile Include="..\sdk\sdk.cpp" />
<ClCompile Include="..\spy\log.cpp" />
<ClCompile Include="..\spy\util.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\sdk\framework.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\sdk\injector.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\spy\log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\sdk\sdk.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\spy\util.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\sdk\injector.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\sdk\sdk.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@ -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:
if self._local_mode and self.sdk and self.sdk.WxDestroySDK() != 0:
self.LOG.error("退出失败!")
return
self._is_running = False
def keep_running(self):