diff --git a/WeChatFerry/.editorconfig b/.editorconfig
similarity index 72%
rename from WeChatFerry/.editorconfig
rename to .editorconfig
index 46da929..8fcd9de 100644
--- a/WeChatFerry/.editorconfig
+++ b/.editorconfig
@@ -4,4 +4,7 @@ charset = utf-8-bom
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
-indent_size = 4
\ No newline at end of file
+indent_size = 4
+
+[*.{yml,yaml}]
+indent_size = 2
\ No newline at end of file
diff --git a/.github/workflows/Build-WeChatFerry.yml b/.github/workflows/Build-WeChatFerry.yml
deleted file mode 100644
index 1305750..0000000
--- a/.github/workflows/Build-WeChatFerry.yml
+++ /dev/null
@@ -1,114 +0,0 @@
-name: Build-WeChatFerry
-
-on:
- push:
- tags:
- - "v[0-9]+.[0-9]+.[0-9]+"
-
-jobs:
- build:
- runs-on: windows-latest
-
- steps:
- - name: 检出代码
- uses: actions/checkout@v4
-
- - name: 获取版本号和微信版本号
- run: |
- $version_full = (Select-String -Path "WeChatFerry/spy/spy.rc" -Pattern 'VALUE "FileVersion", "(.*)"').Matches.Groups[1].Value.Trim()
- $wechat_version = (Select-String -Path "WeChatFerry/spy/spy.rc" -Pattern 'VALUE "ProductVersion", "(.*)"').Matches.Groups[1].Value.Trim()
- $version = $version_full -replace '(\d+\.\d+\.\d+)\.\d+', '$1'
- echo "version=$version" >> $env:GITHUB_ENV
- echo "wechat_version=$wechat_version" >> $env:GITHUB_ENV
- echo "Program Version: $version"
- echo "WeChat Version: $wechat_version"
- shell: pwsh
-
- - name: 设置 Visual Studio 2019
- uses: microsoft/setup-msbuild@v2
- with:
- vs-version: "16.0" # 16.x 对应 Visual Studio 2019
-
- - name: 设置 Python 3
- uses: actions/setup-python@v5
- with:
- python-version: "3.9"
-
- - name: 安装 Python 依赖项
- run: |
- python -m pip install --upgrade pip
- pip install grpcio-tools==1.48.2
-
- - name: 设置缓存
- id: cache-vcpkg
- uses: actions/cache@v4
- with:
- path: |
- C:/Tools/vcpkg
- ${{ github.workspace }}/WeChatFerry/vcpkg_installed
- key: vcpkg-${{ hashFiles('WeChatFerry/vcpkg.json') }}
- restore-keys: |
- vcpkg-
-
- - name: 安装 vcpkg 并初始化依赖项
- run: |
- # 设置 vcpkg 目录
- if (!(Test-Path -Path 'C:/Tools')) {
- New-Item -ItemType Directory -Force -Path 'C:/Tools'
- }
- cd C:/Tools
-
- # 克隆并引导 vcpkg
- if (!(Test-Path -Path 'C:/Tools/vcpkg')) {
- git clone https://github.com/microsoft/vcpkg
- }
- .\vcpkg\bootstrap-vcpkg.bat
-
- # 设置 VCPKG_ROOT 环境变量
- echo "VCPKG_ROOT=C:/Tools/vcpkg" >> $GITHUB_ENV
- $env:VCPKG_ROOT = 'C:/Tools/vcpkg'
-
- # 返回到项目目录并安装依赖
- cd ${{ github.workspace }}/WeChatFerry
- C:/Tools/vcpkg/vcpkg install --triplet x64-windows-static
-
- # 将 vcpkg 与 Visual Studio 集成
- C:/Tools/vcpkg/vcpkg integrate install
-
- - name: 解析并构建配置
- run: |
- $configurations = "Release,Debug".Split(',')
- foreach ($config in $configurations) {
- Write-Host "Building configuration: $config"
- msbuild WeChatFerry/WeChatFerry.sln `
- /p:Configuration=$config `
- /p:Platform="x64" `
- /p:VcpkgTriplet="x64-windows-static" `
- /p:VcpkgEnableManifest=true `
- /verbosity:minimal
- }
- shell: pwsh
-
- - name: 打包输出文件及下载 WeChat 安装包
- run: |
- New-Item -ItemType Directory -Force -Path "WeChatFerry/tmp"
- Compress-Archive -Path "WeChatFerry/Out/sdk.dll", "WeChatFerry/Out/spy.dll", "WeChatFerry/Out/spy_debug.dll", "WeChatFerry/Out/DISCLAIMER.md" -DestinationPath "WeChatFerry/tmp/v${{ env.version }}.zip"
- Invoke-WebRequest -Uri "https://github.com/tom-snow/wechat-windows-versions/releases/download/v${{ env.wechat_version }}/WeChatSetup-${{ env.wechat_version }}.exe" -OutFile "WeChatFerry/tmp/WeChatSetup-${{ env.wechat_version }}.exe"
- shell: pwsh
-
- - name: 列出预发布文件
- run: |
- Get-ChildItem -Path "WeChatFerry/tmp" -Recurse
-
- - name: 发布固件到 Github Releases
- uses: ncipollo/release-action@main
- with:
- name: v${{ env.version }}
- tag: v${{ env.version }}
- token: ${{ secrets.REPO_TOKEN }}
- allowUpdates: true
- artifacts: "WeChatFerry/tmp/*"
- body: |
- 程序版本:`v${{ env.version }}`
- 配套微信版本:`${{ env.wechat_version }}`
- [📖 Python 文档](https://wechatferry.readthedocs.io/)
diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml
new file mode 100644
index 0000000..972c09a
--- /dev/null
+++ b/.github/workflows/build-ci.yml
@@ -0,0 +1,86 @@
+name: Build CI
+
+on:
+ workflow_call:
+
+jobs:
+ build:
+ name: 编译校验
+ runs-on: windows-latest
+ steps:
+ - name: 检出代码
+ uses: actions/checkout@v4
+
+ - name: 设置 Visual Studio 2019
+ uses: microsoft/setup-msbuild@v2
+ with:
+ vs-version: "16.0"
+
+ - name: 设置 Python 3
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.9"
+
+ - name: 安装 Python 依赖项
+ run: |
+ python -m pip install --upgrade pip
+ pip install grpcio-tools==1.48.2
+ shell: pwsh
+
+ - name: 设置 vcpkg 缓存
+ id: cache-vcpkg
+ uses: actions/cache@v4
+ with:
+ path: |
+ C:/Tools/vcpkg
+ ${{ github.workspace }}/WeChatFerry/vcpkg_installed
+ key: vcpkg-${{ hashFiles('WeChatFerry/vcpkg.json') }}
+ restore-keys: |
+ vcpkg-
+
+ - name: Clone & bootstrap vcpkg (首次或缓存失效时)
+ if: steps.cache-vcpkg.outputs.cache-hit != 'true'
+ shell: pwsh
+ run: |
+ if (!(Test-Path 'C:/Tools')) { New-Item -ItemType Directory -Force -Path 'C:/Tools' | Out-Null }
+ cd C:/Tools
+ git clone --single-branch https://github.com/microsoft/vcpkg vcpkg
+ $retry = 0
+ while ($retry -lt 3) {
+ try { .\vcpkg\bootstrap-vcpkg.bat -disableMetrics ; break }
+ catch { $retry++; if ($retry -ge 3) { throw }; Write-Host "bootstrap 失败,重试第 $retry 次..." ; Start-Sleep 15 }
+ }
+
+ - name: 设置 VCPKG_ROOT
+ shell: pwsh
+ run: |
+ "VCPKG_ROOT=C:/Tools/vcpkg" | Out-File $Env:GITHUB_ENV -Encoding utf8 -Append
+
+ - name: 安装/更新第三方依赖
+ shell: pwsh
+ run: |
+ cd ${{ github.workspace }}/WeChatFerry
+ C:/Tools/vcpkg/vcpkg install --triplet x64-windows-static
+ C:/Tools/vcpkg/vcpkg integrate install
+
+ - name: 解析并构建 Release/Debug
+ run: |
+ $configs = "Release","Debug"
+ foreach ($cfg in $configs) {
+ Write-Host "Building $cfg"
+ msbuild WeChatFerry/WeChatFerry.sln `
+ /p:Configuration=$cfg `
+ /p:Platform="x64" `
+ /p:VcpkgTriplet="x64-windows-static" `
+ /p:VcpkgEnableManifest=true `
+ /verbosity:minimal
+ }
+ shell: pwsh
+
+ - name: 上传
+ uses: actions/upload-artifact@v4
+ with:
+ name: wechatferry-binaries
+ path: |
+ WeChatFerry/Out/*.dll
+ WeChatFerry/Out/*.md
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..e90dd0c
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,14 @@
+name: CI
+
+on:
+ pull_request:
+ branches:
+ - master
+
+permissions:
+ contents: read
+ actions: write
+
+jobs:
+ build:
+ uses: ./.github/workflows/build-ci.yml
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..30be5f6
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,65 @@
+name: Release
+
+on:
+ push:
+ tags:
+ - "v[0-9]+.[0-9]+.[0-9]+"
+
+permissions:
+ contents: write
+ actions: write
+
+jobs:
+ build:
+ uses: ./.github/workflows/build-ci.yml
+
+ release:
+ name: 打包 & 发布
+ needs: build
+ runs-on: windows-latest
+ if: ${{ github.event_name == 'push' }}
+ steps:
+ - name: 检出代码
+ uses: actions/checkout@v4
+
+ - name: 下载编译产物
+ uses: actions/download-artifact@v4
+ with:
+ name: wechatferry-binaries
+ path: tmp
+
+ - name: 获取版本号和微信版本号
+ shell: pwsh
+ run: |
+ $version_full = (Select-String -Path "WeChatFerry/spy/spy.rc" -Pattern 'VALUE "FileVersion", "(.*)"').Matches.Groups[1].Value.Trim()
+ $wechat_version = (Select-String -Path "WeChatFerry/spy/spy.rc" -Pattern 'VALUE "ProductVersion", "(.*)"').Matches.Groups[1].Value.Trim()
+ $version = $version_full -replace '(\d+\.\d+\.\d+)\.\d+', '$1'
+ echo "version=$version" >> $env:GITHUB_ENV
+ echo "wechat_version=$wechat_version" >> $env:GITHUB_ENV
+ echo "Program Version: $version"
+ echo "WeChat Version: $wechat_version"
+
+ - name: 打包输出文件及下载 WeChat 安装包
+ shell: pwsh
+ run: |
+ Compress-Archive `
+ -Path "tmp/*" `
+ -DestinationPath "tmp/v${{ env.version }}.zip"
+
+ # 下载对应版本微信安装包
+ Invoke-WebRequest `
+ -Uri "https://github.com/tom-snow/wechat-windows-versions/releases/download/v${{ env.wechat_version }}/WeChatSetup-${{ env.wechat_version }}.exe" `
+ -OutFile "tmp/WeChatSetup-${{ env.wechat_version }}.exe"
+
+ - name: 发布到 GitHub Releases
+ uses: ncipollo/release-action@main
+ with:
+ name: v${{ env.version }}
+ tag: v${{ env.version }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+ allowUpdates: true
+ artifacts: "tmp/*"
+ body: |
+ 程序版本:`v${{ env.version }}`
+ 配套微信版本:`${{ env.wechat_version }}`
+ [📖 Python 文档](https://wechatferry.readthedocs.io/)
diff --git a/README.MD b/README.MD
index 7956df7..25aa748 100644
--- a/README.MD
+++ b/README.MD
@@ -9,7 +9,7 @@
-|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/UbzPuw3-2xZLEzUABXMEdw)|
+|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/c2JggTBlOP8fP9j-MlMAvg)|
|:-:|:-:|:-:|
👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人示例。
@@ -32,7 +32,7 @@
* 发送图片消息
* 发送文件消息
* 发送卡片消息
-* 发送 XML
+* 发送 XML 消息
* 发送 GIF 消息
* 拍一拍群友
* 转发消息
@@ -59,7 +59,7 @@
## 感谢大佬们贡献代码
-
+
## 快速开始
### Python
@@ -207,9 +207,8 @@ WeChatFerry
## 版本更新
-### v39.4.4
-
-* 实现通发送 XML 功能。
+### v39.5.2
+* 没有新功能
点击查看更多
@@ -221,6 +220,22 @@ WeChatFerry
* `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
* 实现通过好友申请功能。
diff --git a/WeChatFerry/CMakeLists.txt b/WeChatFerry/CMakeLists.txt
new file mode 100644
index 0000000..0abeef3
--- /dev/null
+++ b/WeChatFerry/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.15)
+
+# Common compiler flags
+# 设置 C 语言标准为 C17
+set(CMAKE_C_STANDARD 17)
+# 确保要求该标准为必须
+# set(CMAKE_C_STANDARD_REQUIRED ON)
+# 默认情况下禁用 GNU 扩展
+set(CMAKE_C_EXTENSIONS OFF)
+# 设置 C++ 语言标准为 C++17
+set(CMAKE_CXX_STANDARD 17)
+# set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+# 集成vcpkg
+set(VCPKG_TARGET_TRIPLET "x64-mingw-static" CACHE STRING "Vcpkg target triplet")
+set(VCPKG_HOST_TRIPLET "x64-mingw-static" CACHE STRING "Vcpkg host triplet")
+set(VCPKG_MANIFEST_MODE ON CACHE BOOL "Enable manifest mode")
+
+if(DEFINED ENV{VCPKG_ROOT})
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file")
+else()
+ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file")
+endif()
+
+# include(FetchContent)
+# include(ExternalProject)
+
+project(WeChatFerry LANGUAGES C CXX)
+
+add_compile_options(
+ -Wall
+ -Wextra
+ -fPIC
+)
+
+add_link_options(
+ -static
+)
+
+# Include directories
+include_directories(
+ ${CMAKE_SOURCE_DIR}/com
+ ${CMAKE_SOURCE_DIR}/rpc
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb
+ ${CMAKE_SOURCE_DIR}/rpc/proto
+ ${CMAKE_SOURCE_DIR}/sdk
+ ${CMAKE_SOURCE_DIR}/spy
+ ${CMAKE_SOURCE_DIR}/smc
+)
+
+# Add subdirectories
+
+add_subdirectory(sdk)
+add_subdirectory(spy)
+
diff --git a/WeChatFerry/sdk/framework.h b/WeChatFerry/com/framework.h
similarity index 100%
rename from WeChatFerry/sdk/framework.h
rename to WeChatFerry/com/framework.h
diff --git a/WeChatFerry/com/log.hpp b/WeChatFerry/com/log.hpp
index 4a08c8b..a8fa8f8 100644
--- a/WeChatFerry/com/log.hpp
+++ b/WeChatFerry/com/log.hpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include "framework.h"
#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__)
diff --git a/WeChatFerry/com/util.cpp b/WeChatFerry/com/util.cpp
index b82e82f..f5a8376 100644
--- a/WeChatFerry/com/util.cpp
+++ b/WeChatFerry/com/util.cpp
@@ -7,7 +7,6 @@
#include
#include
-#include "framework.h"
#include
#include
@@ -64,8 +63,8 @@ static DWORD get_wechat_pid()
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) return 0;
- PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
- while (Process32Next(hSnapshot, &pe32)) {
+ PROCESSENTRY32W pe32 = { sizeof(PROCESSENTRY32W) };
+ while (Process32NextW(hSnapshot, &pe32)) {
if (pe32.szExeFile == s2w(WECHATEXE)) {
pid = pe32.th32ProcessID;
break;
diff --git a/WeChatFerry/com/util.h b/WeChatFerry/com/util.h
index 1998fbb..6e83b01 100644
--- a/WeChatFerry/com/util.h
+++ b/WeChatFerry/com/util.h
@@ -14,7 +14,7 @@ struct PortPath {
char path[MAX_PATH];
};
-DWORD get_wechat_pid();
+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);
diff --git a/WeChatFerry/rpc/proto/wcf.proto b/WeChatFerry/rpc/proto/wcf.proto
index e965576..ad44e9e 100644
--- a/WeChatFerry/rpc/proto/wcf.proto
+++ b/WeChatFerry/rpc/proto/wcf.proto
@@ -36,6 +36,7 @@ enum Functions {
FUNC_ADD_ROOM_MEMBERS = 0x70;
FUNC_DEL_ROOM_MEMBERS = 0x71;
FUNC_INV_ROOM_MEMBERS = 0x72;
+ FUNC_SHUTDOWN = 0xFF;
}
message Request
diff --git a/WeChatFerry/rpc/tool/proto/nanopb_pb2.py b/WeChatFerry/rpc/tool/proto/nanopb_pb2.py
index eea6b3e..5db3058 100644
--- a/WeChatFerry/rpc/tool/proto/nanopb_pb2.py
+++ b/WeChatFerry/rpc/tool/proto/nanopb_pb2.py
@@ -2,9 +2,11 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: nanopb.proto
"""Generated protocol buffer code."""
-from google.protobuf.internal import builder as _builder
+from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
@@ -16,8 +18,52 @@ from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\xa4\x07\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x12\n\nmax_length\x18\x0e \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x15\n\x06proto3\x18\x0c \x01(\x08:\x05\x66\x61lse\x12#\n\x14proto3_singular_msgs\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x0e\x65num_to_string\x18\r \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x66ixed_length\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x66ixed_count\x18\x10 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0fsubmsg_callback\x18\x16 \x01(\x08:\x05\x66\x61lse\x12/\n\x0cmangle_names\x18\x11 \x01(\x0e\x32\x11.TypenameMangling:\x06M_NONE\x12(\n\x11\x63\x61llback_datatype\x18\x12 \x01(\t:\rpb_callback_t\x12\x34\n\x11\x63\x61llback_function\x18\x13 \x01(\t:\x19pb_default_field_callback\x12\x30\n\x0e\x64\x65scriptorsize\x18\x14 \x01(\x0e\x32\x0f.DescriptorSize:\x07\x44S_AUTO\x12\x1a\n\x0b\x64\x65\x66\x61ult_has\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x0f\n\x07include\x18\x18 \x03(\t\x12\x0f\n\x07\x65xclude\x18\x1a \x03(\t\x12\x0f\n\x07package\x18\x19 \x01(\t\x12\x41\n\rtype_override\x18\x1b \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x19\n\x0bsort_by_tag\x18\x1c \x01(\x08:\x04true\x12.\n\rfallback_type\x18\x1d \x01(\x0e\x32\n.FieldType:\x0b\x46T_CALLBACK*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@*Z\n\x10TypenameMangling\x12\n\n\x06M_NONE\x10\x00\x12\x13\n\x0fM_STRIP_PACKAGE\x10\x01\x12\r\n\tM_FLATTEN\x10\x02\x12\x16\n\x12M_PACKAGE_INITIALS\x10\x03*E\n\x0e\x44\x65scriptorSize\x12\x0b\n\x07\x44S_AUTO\x10\x00\x12\x08\n\x04\x44S_1\x10\x01\x12\x08\n\x04\x44S_2\x10\x02\x12\x08\n\x04\x44S_4\x10\x04\x12\x08\n\x04\x44S_8\x10\x08:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB\x1a\n\x18\x66i.kapsi.koti.jpa.nanopb')
-_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'nanopb_pb2', globals())
+_FIELDTYPE = DESCRIPTOR.enum_types_by_name['FieldType']
+FieldType = enum_type_wrapper.EnumTypeWrapper(_FIELDTYPE)
+_INTSIZE = DESCRIPTOR.enum_types_by_name['IntSize']
+IntSize = enum_type_wrapper.EnumTypeWrapper(_INTSIZE)
+_TYPENAMEMANGLING = DESCRIPTOR.enum_types_by_name['TypenameMangling']
+TypenameMangling = enum_type_wrapper.EnumTypeWrapper(_TYPENAMEMANGLING)
+_DESCRIPTORSIZE = DESCRIPTOR.enum_types_by_name['DescriptorSize']
+DescriptorSize = enum_type_wrapper.EnumTypeWrapper(_DESCRIPTORSIZE)
+FT_DEFAULT = 0
+FT_CALLBACK = 1
+FT_POINTER = 4
+FT_STATIC = 2
+FT_IGNORE = 3
+FT_INLINE = 5
+IS_DEFAULT = 0
+IS_8 = 8
+IS_16 = 16
+IS_32 = 32
+IS_64 = 64
+M_NONE = 0
+M_STRIP_PACKAGE = 1
+M_FLATTEN = 2
+M_PACKAGE_INITIALS = 3
+DS_AUTO = 0
+DS_1 = 1
+DS_2 = 2
+DS_4 = 4
+DS_8 = 8
+
+NANOPB_FILEOPT_FIELD_NUMBER = 1010
+nanopb_fileopt = DESCRIPTOR.extensions_by_name['nanopb_fileopt']
+NANOPB_MSGOPT_FIELD_NUMBER = 1010
+nanopb_msgopt = DESCRIPTOR.extensions_by_name['nanopb_msgopt']
+NANOPB_ENUMOPT_FIELD_NUMBER = 1010
+nanopb_enumopt = DESCRIPTOR.extensions_by_name['nanopb_enumopt']
+NANOPB_FIELD_NUMBER = 1010
+nanopb = DESCRIPTOR.extensions_by_name['nanopb']
+
+_NANOPBOPTIONS = DESCRIPTOR.message_types_by_name['NanoPBOptions']
+NanoPBOptions = _reflection.GeneratedProtocolMessageType('NanoPBOptions', (_message.Message,), {
+ 'DESCRIPTOR' : _NANOPBOPTIONS,
+ '__module__' : 'nanopb_pb2'
+ # @@protoc_insertion_point(class_scope:NanoPBOptions)
+ })
+_sym_db.RegisterMessage(NanoPBOptions)
+
if _descriptor._USE_C_DESCRIPTORS == False:
google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt)
google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
diff --git a/WeChatFerry/sdk/CMakeLists.txt b/WeChatFerry/sdk/CMakeLists.txt
new file mode 100644
index 0000000..158a441
--- /dev/null
+++ b/WeChatFerry/sdk/CMakeLists.txt
@@ -0,0 +1,57 @@
+# SDK project - dynamic library
+project(SDK LANGUAGES C CXX)
+
+find_package(spdlog REQUIRED)
+
+add_library(sdk SHARED
+ dllmain.cpp
+ injector.cpp
+ injector.h
+ sdk.cpp
+ sdk.h
+ sdk.def
+
+ # Common files
+ ${CMAKE_SOURCE_DIR}/com/util.cpp
+ ${CMAKE_SOURCE_DIR}/com/util.h
+)
+
+target_link_libraries(sdk PRIVATE
+ version
+ shlwapi
+ spdlog::spdlog
+ c++
+)
+
+# Set compiler definitions
+target_compile_definitions(sdk PRIVATE
+ SDK_EXPORTS
+ _WINDOWS
+ _USRDLL
+)
+
+# add_compile_options(
+# # -Wall
+# -fPIC
+# # -fms-extensions
+# )
+# Set output name for debug builds
+set_target_properties(sdk PROPERTIES
+ DEBUG_POSTFIX "d"
+)
+
+# # Post-build copy commands
+# add_custom_command(TARGET sdk POST_BUILD
+# COMMAND ${CMAKE_COMMAND} -E copy
+# $
+# ${CMAKE_SOURCE_DIR}/Out
+# COMMAND ${CMAKE_COMMAND} -E copy
+# $
+# ${CMAKE_SOURCE_DIR}/../clients/python/wcferry
+# COMMAND ${CMAKE_COMMAND} -E copy
+# ${CMAKE_SOURCE_DIR}/DISCLAIMER.md
+# ${CMAKE_SOURCE_DIR}/Out
+# COMMAND ${CMAKE_COMMAND} -E copy
+# ${CMAKE_SOURCE_DIR}/DISCLAIMER.md
+# ${CMAKE_SOURCE_DIR}/../clients/python/wcferry
+# )
diff --git a/WeChatFerry/sdk/SDK.vcxproj b/WeChatFerry/sdk/SDK.vcxproj
index cb0fd9d..054ecc1 100644
--- a/WeChatFerry/sdk/SDK.vcxproj
+++ b/WeChatFerry/sdk/SDK.vcxproj
@@ -86,7 +86,8 @@
Windows
true
false
- sdk.def
+
+
@@ -103,7 +104,8 @@
Windows
true
false
- sdk.def
+
+
@@ -130,7 +132,8 @@
true
false
false
- sdk.def
+
+
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
@@ -142,7 +145,7 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry
-
+
@@ -152,9 +155,6 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry
-
-
-
diff --git a/WeChatFerry/sdk/SDK.vcxproj.filters b/WeChatFerry/sdk/SDK.vcxproj.filters
index 5adfeab..9c2e881 100644
--- a/WeChatFerry/sdk/SDK.vcxproj.filters
+++ b/WeChatFerry/sdk/SDK.vcxproj.filters
@@ -15,7 +15,7 @@
-
+
头文件
@@ -42,9 +42,4 @@
源文件
-
-
- 源文件
-
-
\ No newline at end of file
diff --git a/WeChatFerry/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp
index 913ba87..6eb935e 100644
--- a/WeChatFerry/sdk/injector.cpp
+++ b/WeChatFerry/sdk/injector.cpp
@@ -122,7 +122,7 @@ static uint64_t get_func_offset(const string &dll_path, const string &func_name)
return 0;
}
- LPVOID absAddr = GetProcAddress(dll, func_name.c_str());
+ LPVOID absAddr = reinterpret_cast(GetProcAddress(dll, func_name.c_str()));
uint64_t offset = reinterpret_cast(absAddr) - reinterpret_cast(dll);
FreeLibrary(dll);
diff --git a/WeChatFerry/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp
index 8363414..831a855 100644
--- a/WeChatFerry/sdk/sdk.cpp
+++ b/WeChatFerry/sdk/sdk.cpp
@@ -21,9 +21,16 @@ static HANDLE wcProcess = NULL;
static HMODULE spyBase = NULL;
static std::string spyDllPath;
+//区分MSVC和MinGW
+#ifdef _MSC_VER
constexpr char WCFSDKDLL[] = "sdk.dll";
constexpr char WCFSPYDLL[] = "spy.dll";
constexpr char WCFSPYDLL_DEBUG[] = "spy_debug.dll";
+#else
+constexpr char WCFSDKDLL[] = "libsdk.dll";
+constexpr char WCFSPYDLL[] = "libspy.dll";
+constexpr char WCFSPYDLL_DEBUG[] = "libspyd.dll";
+#endif
constexpr std::string_view DISCLAIMER_FLAG = ".license_accepted.flag";
constexpr std::string_view DISCLAIMER_TEXT_FILE = "DISCLAIMER.md";
@@ -91,8 +98,8 @@ static std::string get_dll_path(bool debug)
return path.string();
}
-
-int WxInitSDK(bool debug, int port)
+extern "C" {
+__declspec(dllexport) int WxInitSDK(bool debug, int port)
{
if (!show_disclaimer()) {
exit(-1); // 用户拒绝协议,退出程序
@@ -134,7 +141,7 @@ int WxInitSDK(bool debug, int port)
return status;
}
-int WxDestroySDK()
+__declspec(dllexport) int WxDestroySDK()
{
if (!injected) {
return 1; // 未注入
@@ -151,3 +158,4 @@ int WxDestroySDK()
return 0;
}
+}
\ No newline at end of file
diff --git a/WeChatFerry/sdk/sdk.def b/WeChatFerry/sdk/sdk.def
deleted file mode 100644
index d8c9be9..0000000
--- a/WeChatFerry/sdk/sdk.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- WxInitSDK
- WxDestroySDK
diff --git a/WeChatFerry/sdk/sdk.h b/WeChatFerry/sdk/sdk.h
index 0ebec29..2002d03 100644
--- a/WeChatFerry/sdk/sdk.h
+++ b/WeChatFerry/sdk/sdk.h
@@ -1,4 +1,6 @@
#pragma once
-int WxInitSDK(bool debug, int port);
-int WxDestroySDK();
+extern "C" {
+__declspec(dllexport) int WxInitSDK(bool debug, int port);
+__declspec(dllexport) int WxDestroySDK();
+}
\ No newline at end of file
diff --git a/WeChatFerry/smc/libCodec.a b/WeChatFerry/smc/libCodec.a
new file mode 100644
index 0000000..1370505
Binary files /dev/null and b/WeChatFerry/smc/libCodec.a differ
diff --git a/WeChatFerry/smc/libmp3lame.a b/WeChatFerry/smc/libmp3lame.a
new file mode 100644
index 0000000..96e03ae
Binary files /dev/null and b/WeChatFerry/smc/libmp3lame.a differ
diff --git a/WeChatFerry/spy/CMakeLists.txt b/WeChatFerry/spy/CMakeLists.txt
new file mode 100644
index 0000000..986c53b
--- /dev/null
+++ b/WeChatFerry/spy/CMakeLists.txt
@@ -0,0 +1,108 @@
+# Spy project - dynamic library
+project(Spy LANGUAGES C CXX)
+
+find_package(spdlog REQUIRED)
+find_package(magic_enum REQUIRED)
+find_package(minhook CONFIG REQUIRED)
+find_package(nng REQUIRED)
+
+add_library(spy SHARED
+ chatroom_manager.cpp
+ chatroom_manager.h
+ misc_manager.cpp
+ misc_manager.h
+ database_executor.cpp
+ database_executor.h
+ contact_manager.cpp
+ contact_manager.h
+ message_handler.cpp
+ message_handler.h
+ rpc_server.cpp
+ rpc_server.h
+ message_sender.cpp
+ message_sender.h
+ spy.cpp
+ spy.h
+ spy_types.h
+ account_manager.cpp
+ account_manager.h
+ resource.h
+ rpc_helper.h
+ sqlite3.h
+ dllmain.cpp
+ spy.def
+
+ # Common files
+ ${CMAKE_SOURCE_DIR}/com/util.cpp
+ ${CMAKE_SOURCE_DIR}/com/util.h
+ ${CMAKE_SOURCE_DIR}/com/log.hpp
+
+ # RPC files
+ ${CMAKE_SOURCE_DIR}/rpc/pb_util.cpp
+ ${CMAKE_SOURCE_DIR}/rpc/pb_util.h
+ ${CMAKE_SOURCE_DIR}/rpc/pb_types.h
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb.h
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_common.h
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_decode.h
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_encode.h
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_common.c
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_decode.c
+ ${CMAKE_SOURCE_DIR}/rpc/nanopb/pb_encode.c
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.c
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.h
+)
+
+# link directories
+target_link_directories(spy PRIVATE
+ ${CMAKE_SOURCE_DIR}/smc
+)
+
+# Link dependencies
+target_link_libraries(spy PRIVATE
+ Codec
+ mp3lame
+ version
+ shlwapi
+ iphlpapi
+ wsock32
+ ws2_32
+ crypt32
+ magic_enum::magic_enum
+ nng::nng
+ spdlog::spdlog
+ minhook::minhook
+ c++
+)
+
+add_custom_command(
+ OUTPUT
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.c
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.h
+ COMMAND ${CMAKE_SOURCE_DIR}/rpc/tool/protoc --nanopb_out=${CMAKE_SOURCE_DIR}/rpc/proto wcf.proto
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/rpc/proto
+ DEPENDS ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.proto
+ COMMENT "Generated protobuf files"
+)
+
+# Add generated files as dependencies
+add_custom_target(protobuf_generation
+ DEPENDS
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.c
+ ${CMAKE_SOURCE_DIR}/rpc/proto/wcf.pb.h
+)
+add_dependencies(spy protobuf_generation)
+
+# Set output name for debug builds
+set_target_properties(spy PROPERTIES
+ DEBUG_POSTFIX "d"
+)
+
+# Post-build copy commands
+# add_custom_command(TARGET spy POST_BUILD
+# COMMAND ${CMAKE_COMMAND} -E copy
+# $
+# ${CMAKE_SOURCE_DIR}/Out
+# COMMAND ${CMAKE_COMMAND} -E copy
+# $
+# ${CMAKE_SOURCE_DIR}/../clients/python/wcferry
+# )
diff --git a/WeChatFerry/spy/Spy.vcxproj b/WeChatFerry/spy/Spy.vcxproj
index 0854bf5..ca8ea82 100644
--- a/WeChatFerry/spy/Spy.vcxproj
+++ b/WeChatFerry/spy/Spy.vcxproj
@@ -105,7 +105,8 @@
Windows
true
false
- spy.def
+
+
/ignore:4099 %(AdditionalOptions)
$(SolutionDir)smc;%(AdditionalLibraryDirectories)
iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)
@@ -158,7 +159,8 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferryWindows
true
false
- spy.def
+
+
/ignore:4099 %(AdditionalOptions)
$(SolutionDir)smc;%(AdditionalLibraryDirectories)
iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)
@@ -212,7 +214,8 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferrytrue
false
false
- spy.def
+
+
$(SolutionDir)smc;%(AdditionalLibraryDirectories)
iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)
/ignore:4099 %(AdditionalOptions)
@@ -250,7 +253,7 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry
-
+
@@ -282,7 +285,6 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry
-
diff --git a/WeChatFerry/spy/Spy.vcxproj.filters b/WeChatFerry/spy/Spy.vcxproj.filters
index a2a537b..dafe11c 100644
--- a/WeChatFerry/spy/Spy.vcxproj.filters
+++ b/WeChatFerry/spy/Spy.vcxproj.filters
@@ -18,7 +18,7 @@
-
+
头文件
@@ -142,9 +142,6 @@
-
- 源文件
-
nnrpc
diff --git a/WeChatFerry/spy/account_manager.cpp b/WeChatFerry/spy/account_manager.cpp
index d0353af..232fe85 100644
--- a/WeChatFerry/spy/account_manager.cpp
+++ b/WeChatFerry/spy/account_manager.cpp
@@ -17,14 +17,6 @@ namespace OsAcc = Offsets::Account;
using get_account_service_t = QWORD (*)();
using get_data_path_t = QWORD (*)(QWORD);
-// 缓存避免重复查询
-static std::optional cachedWxid;
-static std::optional cachedHomePath;
-
-// 清除缓存
-static void clear_cached_wxid() { cachedWxid.reset(); }
-static void clear_cached_home_path() { cachedHomePath.reset(); }
-
static uint64_t get_account_service()
{
static auto GetService = Spy::getFunction(OsAcc::SERVICE);
@@ -39,37 +31,44 @@ static std::string get_string_value(uint64_t base_addr, uint64_t offset)
bool is_logged_in()
{
- clear_cached_wxid();
- clear_cached_home_path();
uint64_t service_addr = get_account_service();
return service_addr && util::get_qword(service_addr + OsAcc::LOGIN) != 0;
}
fs::path get_home_path()
{
- if (cachedHomePath) {
- return *cachedHomePath;
- }
- WxString home;
- auto GetDataPath = Spy::getFunction(OsAcc::PATH);
- int64_t service_addr = get_account_service();
- GetDataPath((QWORD)&home);
- if (home.wptr) {
- cachedHomePath = util::w2s(std::wstring(home.wptr, home.size));
- }
- return *cachedHomePath;
+ static fs::path home_path;
+ static std::once_flag home_once;
+
+ std::call_once(home_once, []() {
+ WxString home {};
+ if (auto getDataPath = Spy::getFunction(OsAcc::PATH)) {
+ getDataPath(reinterpret_cast(&home));
+ if (home.wptr) {
+ std::wstring wstr(home.wptr, home.size);
+ home_path = util::w2s(std::move(wstr));
+ }
+ }
+ });
+
+ return home_path;
}
std::string get_self_wxid()
{
- if (cachedWxid) {
- return *cachedWxid;
- }
- uint64_t service_addr = get_account_service();
- if (!service_addr) return "";
+ static std::string cached_wxid;
+ static std::once_flag wxid_once;
- cachedWxid = get_string_value(service_addr, OsAcc::WXID);
- return *cachedWxid;
+ std::call_once(wxid_once, []() {
+ if (uint64_t svc = get_account_service(); svc) {
+ cached_wxid = get_string_value(svc, OsAcc::WXID);
+ if (cached_wxid.empty()) {
+ cached_wxid = get_string_value(svc, OsAcc::ALIAS);
+ }
+ }
+ });
+
+ return cached_wxid;
}
UserInfo_t get_user_info()
diff --git a/WeChatFerry/spy/chatroom_manager.cpp b/WeChatFerry/spy/chatroom_manager.cpp
index 912bda2..5763283 100644
--- a/WeChatFerry/spy/chatroom_manager.cpp
+++ b/WeChatFerry/spy/chatroom_manager.cpp
@@ -12,10 +12,11 @@ namespace chatroom
{
namespace OsRoom = Offsets::Chatroom;
+using new_t = QWORD (*)(QWORD, WxString *);
using get_mgr_t = QWORD (*)();
using add_member_t = QWORD (*)(QWORD, QWORD, WxString *, QWORD);
using delete_member_t = QWORD (*)(QWORD, QWORD, WxString *);
-using invite_members_t = QWORD (*)(const wchar_t *, QWORD, WxString *, QWORD);
+using invite_members_t = QWORD (*)(const wchar_t *, QWORD, QWORD, QWORD);
template
bool rpc_chatroom_common(const MemberMgmt &m, uint8_t *out, size_t *len, Func func)
@@ -36,9 +37,11 @@ int add_chatroom_member(const string &roomid, const string &wxids)
WxString *wx_roomid = util::CreateWxString(roomid);
- QWORD tmp[2] = { 0 };
- auto wx_members = util::parse_wxids(wxids).wxWxids;
- QWORD p_members = reinterpret_cast(&wx_members);
+ QWORD tmp[2] = { 0 };
+
+ auto split = util::parse_wxids(wxids);
+ auto &wx_members = split.wxWxids;
+ QWORD p_members = reinterpret_cast(&wx_members);
return static_cast(add_members(get_chatroom_mgr(), p_members, wx_roomid, reinterpret_cast(tmp)));
}
@@ -49,24 +52,32 @@ int del_chatroom_member(const string &roomid, const string &wxids)
auto del_members = Spy::getFunction(OsRoom::DEL);
WxString *wx_roomid = util::CreateWxString(roomid);
- auto wx_members = util::parse_wxids(wxids).wxWxids;
- QWORD p_members = reinterpret_cast(&wx_members);
+
+ auto split = util::parse_wxids(wxids);
+ auto &wx_members = split.wxWxids;
+ QWORD p_members = reinterpret_cast(&wx_members);
return static_cast(del_members(get_chatroom_mgr(), p_members, wx_roomid));
}
int invite_chatroom_member(const string &roomid, const string &wxids)
{
+ auto init_roomid = Spy::getFunction(OsRoom::NEW);
auto invite_members = Spy::getFunction(OsRoom::INV);
- wstring ws_roomid = util::s2w(roomid);
- WxString *wx_roomid = util::CreateWxString(roomid);
+ wstring ws_roomid = util::s2w(roomid);
+ WxString wx_roomid(ws_roomid);
- QWORD tmp[2] = { 0 };
- auto wx_members = util::parse_wxids(wxids).wxWxids;
- QWORD p_members = reinterpret_cast(&wx_members);
+ QWORD tmp[2] = { 0 };
+ QWORD array[4] = { 0 };
- return static_cast(invite_members(ws_roomid.c_str(), p_members, wx_roomid, reinterpret_cast(tmp)));
+ auto split = util::parse_wxids(wxids);
+ auto &wx_members = split.wxWxids;
+ QWORD p_members = reinterpret_cast(&wx_members);
+ QWORD p_roomid = init_roomid(reinterpret_cast(&array), &wx_roomid);
+ LOG_BUFFER((uint8_t *)*(QWORD *)(*(QWORD *)p_members), 40);
+
+ return static_cast(invite_members(ws_roomid.c_str(), p_members, p_roomid, reinterpret_cast(tmp)));
}
bool rpc_add_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len)
diff --git a/WeChatFerry/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp
deleted file mode 100644
index ce36eac..0000000
--- a/WeChatFerry/spy/chatroom_mgmt.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "framework.h"
-#include
-#include
-
-#include "chatroom_mgmt.h"
-#include "log.h"
-#include "util.h"
-
-using namespace std;
-extern QWORD g_WeChatWinDllAddr;
-
-#define OS_GET_CHATROOM_MGR 0x1B894E0
-#define OS_ADD_MEMBERS 0x215A820
-#define OS_DELETE_MEMBERS 0x215AE60
-#define OS_INVITE_MEMBERS 0x215A200
-
-typedef QWORD (*GetChatRoomMgr_t)();
-typedef QWORD (*AddMemberToChatRoom_t)(QWORD, QWORD, QWORD, QWORD);
-typedef QWORD (*DelMemberFromChatRoom_t)(QWORD, QWORD, QWORD);
-typedef QWORD (*InviteMemberToChatRoom_t)(QWORD, QWORD, QWORD, QWORD);
-
-int AddChatroomMember(string roomid, string wxids)
-{
- int status = -1;
-
- if (roomid.empty() || wxids.empty()) {
- LOG_ERROR("Empty roomid or wxids.");
- return status;
- }
-
- GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR);
- AddMemberToChatRoom_t AddMembers = (AddMemberToChatRoom_t)(g_WeChatWinDllAddr + OS_ADD_MEMBERS);
-
- vector vMembers;
- vector vWxMembers;
- wstringstream wss(String2Wstring(wxids));
- while (wss.good()) {
- wstring wstr;
- getline(wss, wstr, L',');
- vMembers.push_back(wstr);
- WxString wxMember(vMembers.back());
- vWxMembers.push_back(wxMember);
- }
-
- QWORD temp[2] = { 0 };
- WxString *pWxRoomid = NewWxStringFromStr(roomid);
- QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start;
-
- QWORD mgr = GetChatRoomMgr();
- status = (int)AddMembers(mgr, pMembers, (QWORD)pWxRoomid, (QWORD)temp);
- return status;
-}
-
-int DelChatroomMember(string roomid, string wxids)
-{
- int status = -1;
-
- if (roomid.empty() || wxids.empty()) {
- LOG_ERROR("Empty roomid or wxids.");
- return status;
- }
-
- GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR);
- DelMemberFromChatRoom_t DelMembers = (DelMemberFromChatRoom_t)(g_WeChatWinDllAddr + OS_DELETE_MEMBERS);
-
- vector vMembers;
- vector vWxMembers;
- wstringstream wss(String2Wstring(wxids));
- while (wss.good()) {
- wstring wstr;
- getline(wss, wstr, L',');
- vMembers.push_back(wstr);
- WxString wxMember(vMembers.back());
- vWxMembers.push_back(wxMember);
- }
-
- WxString *pWxRoomid = NewWxStringFromStr(roomid);
- QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start;
-
- QWORD mgr = GetChatRoomMgr();
- status = (int)DelMembers(mgr, pMembers, (QWORD)pWxRoomid);
- return status;
-}
-
-int InviteChatroomMember(string roomid, string wxids)
-{
- int status = -1;
-
- if (roomid.empty() || wxids.empty()) {
- LOG_ERROR("Empty roomid or wxids.");
- return status;
- }
-
- InviteMemberToChatRoom_t InviteMembers = (InviteMemberToChatRoom_t)(g_WeChatWinDllAddr + OS_INVITE_MEMBERS);
-
- vector vMembers;
- vector vWxMembers;
- wstringstream wss(String2Wstring(wxids));
- while (wss.good()) {
- wstring wstr;
- getline(wss, wstr, L',');
- vMembers.push_back(wstr);
- WxString wxMember(vMembers.back());
- vWxMembers.push_back(wxMember);
- }
- QWORD temp[2] = { 0 };
- wstring wsRoomid = String2Wstring(roomid);
- WxString *pWxRoomid = NewWxStringFromWstr(wsRoomid);
- QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start;
-
- status = (int)InviteMembers((QWORD)wsRoomid.c_str(), pMembers, (QWORD)pWxRoomid, (QWORD)temp);
- return status;
-}
-
diff --git a/WeChatFerry/spy/contact_manager.cpp b/WeChatFerry/spy/contact_manager.cpp
index 57ff600..2863aed 100644
--- a/WeChatFerry/spy/contact_manager.cpp
+++ b/WeChatFerry/spy/contact_manager.cpp
@@ -18,7 +18,7 @@ namespace OsCon = Offsets::Contact;
using get_contact_mgr_t = QWORD (*)();
using get_contact_list_t = QWORD (*)(QWORD, QWORD);
using func_verify_new_t = QWORD (*)(QWORD, WxString *);
-using func_verify_ok_t = QWORD (*)(QWORD, WxString *, QWORD *, QWORD, QWORD, QWORD *, WxString *, QWORD *, WxString *);
+using func_verify_ok_t = QWORD (*)(QWORD, WxString *, QWORD *, QWORD, QWORD, QWORD, QWORD, QWORD, WxString *);
#define FEAT_LEN 5
static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 };
@@ -92,26 +92,24 @@ vector get_contacts()
int accept_new_friend(const std::string &v3, const std::string &v4, int scene)
{
- // TODO: 处理来源、备注、标签等
+ // TODO: 备注、标签等
auto func_new = Spy::getFunction(OsCon::VERIFY_NEW);
auto func_verify = Spy::getFunction(OsCon::VERIFY_OK);
QWORD helper = util::get_qword(Spy::WeChatDll.load() + OsCon::ADD_FRIEND_HELPER);
QWORD fvdf = util::get_qword(Spy::WeChatDll.load() + OsCon::FVDF);
- QWORD mgr = util::get_qword(Spy::WeChatDll.load() + OsCon::VERIFY_MGR);
- QWORD a8 = util::get_qword(Spy::WeChatDll.load() + OsCon::VERIFY_A8);
auto pV3 = util::CreateWxString(v3);
auto pV4 = util::CreateWxString(v4);
QWORD v4Array[4] = { 0 };
- QWORD p_v4Buff = func_new(reinterpret_cast(&v4Array), pV4);
+ QWORD pV4Buff = func_new(reinterpret_cast(&v4Array), pV4);
char buff[0x100] = { 0 };
memcpy(buff, &helper, sizeof(&helper));
QWORD a1 = reinterpret_cast(&buff);
- QWORD ret = func_verify(a1, pV3, &fvdf, 0x3A08A4, p_v4Buff, &mgr, pV4, &a8, pV4);
+ QWORD ret = func_verify(a1, pV3, &fvdf, 0x1D08B4, pV4Buff, 0x1, pV4Buff, scene, 0x0);
util::FreeWxString(pV3);
util::FreeWxString(pV4);
diff --git a/WeChatFerry/spy/framework.h b/WeChatFerry/spy/framework.h
deleted file mode 100644
index 80cbbc9..0000000
--- a/WeChatFerry/spy/framework.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
-// Windows 头文件
-#include
diff --git a/WeChatFerry/spy/message_handler.cpp b/WeChatFerry/spy/message_handler.cpp
index 9537bf1..851584f 100644
--- a/WeChatFerry/spy/message_handler.cpp
+++ b/WeChatFerry/spy/message_handler.cpp
@@ -5,8 +5,6 @@
#include
#include
-#include "framework.h"
-
#include "account_manager.h"
#include "log.hpp"
#include "offsets.h"
@@ -192,8 +190,8 @@ int Handler::EnableLog()
funcWxLog = Spy::getFunction(OsLog::CALL);
if (InitializeHook() != MH_OK) return -1;
- if (MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast(&realWxLog)) != MH_OK) return -2;
- if (MH_EnableHook(funcWxLog) != MH_OK) return -3;
+ if (MH_CreateHook(reinterpret_cast(funcWxLog), reinterpret_cast(&PrintWxLog), reinterpret_cast(&realWxLog)) != MH_OK) return -2;
+ if (MH_EnableHook(reinterpret_cast(funcWxLog)) != MH_OK) return -3;
*pLogLevel = 0;
isLogging = true;
@@ -203,8 +201,9 @@ int Handler::EnableLog()
int Handler::DisableLog()
{
if (!isLogging) return 1;
- if (MH_DisableHook(funcWxLog) != MH_OK) return -1;
- if (UninitializeHook() != MH_OK) return -2;
+ if (MH_DisableHook(reinterpret_cast(funcWxLog)) != MH_OK) return -1;
+ if (MH_RemoveHook(reinterpret_cast(funcWxLog)) != MH_OK) return -2;
+ if (UninitializeHook() != MH_OK) return -3;
*pLogLevel = 6;
isLogging = false;
return 0;
@@ -216,8 +215,8 @@ int Handler::ListenMsg()
funcRecvMsg = Spy::getFunction(OsRecv::CALL);
if (InitializeHook() != MH_OK) return -1;
- if (MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast(&realRecvMsg)) != MH_OK) return -1;
- if (MH_EnableHook(funcRecvMsg) != MH_OK) return -1;
+ if (MH_CreateHook(reinterpret_cast(funcRecvMsg), reinterpret_cast(&DispatchMsg), reinterpret_cast(&realRecvMsg)) != MH_OK) return -2;
+ if (MH_EnableHook(reinterpret_cast(funcRecvMsg)) != MH_OK) return -3;
isListeningMsg = true;
return 0;
@@ -226,8 +225,9 @@ int Handler::ListenMsg()
int Handler::UnListenMsg()
{
if (!isListeningMsg) return 1;
- if (MH_DisableHook(funcRecvMsg) != MH_OK) return -1;
- if (UninitializeHook() != MH_OK) return -1;
+ if (MH_DisableHook(reinterpret_cast(funcRecvMsg)) != MH_OK) return -1;
+ if (MH_RemoveHook(reinterpret_cast(funcRecvMsg)) != MH_OK) return -2;
+ if (UninitializeHook() != MH_OK) return -3;
isListeningMsg = false;
return 0;
}
@@ -238,8 +238,8 @@ int Handler::ListenPyq()
funcRecvPyq = Spy::getFunction(OsRecv::PYQ_CALL);
if (InitializeHook() != MH_OK) return -1;
- if (MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast(&realRecvPyq)) != MH_OK) return -1;
- if (MH_EnableHook(funcRecvPyq) != MH_OK) return -1;
+ if (MH_CreateHook(reinterpret_cast(funcRecvPyq), reinterpret_cast(&DispatchPyq), reinterpret_cast(&realRecvPyq)) != MH_OK) return -1;
+ if (MH_EnableHook(reinterpret_cast(funcRecvPyq)) != MH_OK) return -1;
isListeningPyq = true;
return 0;
@@ -248,8 +248,9 @@ int Handler::ListenPyq()
int Handler::UnListenPyq()
{
if (!isListeningPyq) return 1;
- if (MH_DisableHook(funcRecvPyq) != MH_OK) return -1;
- if (UninitializeHook() != MH_OK) return -1;
+ if (MH_DisableHook(reinterpret_cast(funcRecvPyq)) != MH_OK) return -1;
+ if (MH_RemoveHook(reinterpret_cast(funcRecvPyq)) != MH_OK) return -2;
+ if (UninitializeHook() != MH_OK) return -3;
isListeningPyq = false;
return 0;
}
diff --git a/WeChatFerry/spy/message_sender.cpp b/WeChatFerry/spy/message_sender.cpp
index e565ae4..544c747 100644
--- a/WeChatFerry/spy/message_sender.cpp
+++ b/WeChatFerry/spy/message_sender.cpp
@@ -313,8 +313,8 @@ bool Sender::rpc_send_xml(const XmlMsg &xml, uint8_t *out, size_t *len)
LOG_ERROR("Empty content or receiver.");
rsp.msg.status = -1;
} else {
- // send_xml(xml.receiver, xml.content, xml.path, xml.type);
- rsp.msg.status = -1;
+ send_xml(xml.receiver, xml.content, xml.path, xml.type);
+ rsp.msg.status = 0;
}
});
}
diff --git a/WeChatFerry/spy/misc_manager.cpp b/WeChatFerry/spy/misc_manager.cpp
index 5db4fbc..7a7f445 100644
--- a/WeChatFerry/spy/misc_manager.cpp
+++ b/WeChatFerry/spy/misc_manager.cpp
@@ -4,14 +4,13 @@
#include
#include
-#include "framework.h"
-
#include "codec.h"
#include "database_executor.h"
#include "log.hpp"
#include "message_handler.h"
#include "offsets.h"
#include "rpc_helper.h"
+#include "rpc_server.h"
#include "spy.h"
#include "spy_types.h"
#include "util.h"
@@ -418,4 +417,17 @@ bool rpc_receive_transfer(const Transfer &tf, uint8_t *out, size_t *len)
return fill_response(
out, len, [&](Response &rsp) { rsp.msg.status = receive_transfer(tf.wxid, tf.tfid, tf.taid); });
}
+
+bool rpc_shutdown(uint8_t *out, size_t *len)
+{
+ return fill_response(out, len, [&](Response &rsp) {
+ rsp.msg.status = 0;
+ std::thread([]() {
+ Sleep(100);
+ RpcServer::destroyInstance();
+ Spy::Cleanup();
+ }).detach();
+ return true;
+ });
+}
} // namespace misc
diff --git a/WeChatFerry/spy/misc_manager.h b/WeChatFerry/spy/misc_manager.h
index 0792c3f..1351438 100644
--- a/WeChatFerry/spy/misc_manager.h
+++ b/WeChatFerry/spy/misc_manager.h
@@ -36,5 +36,6 @@ bool rpc_download_attachment(const AttachMsg &att, uint8_t *out, size_t *len);
bool rpc_revoke_message(uint64_t id, uint8_t *out, size_t *len);
bool rpc_get_ocr_result(const std::filesystem::path &path, uint8_t *out, size_t *len);
bool rpc_receive_transfer(const Transfer &tf, uint8_t *out, size_t *len);
+bool rpc_shutdown(uint8_t *out, size_t *len);
// clang-format on
} // namespace misc
diff --git a/WeChatFerry/spy/offsets.h b/WeChatFerry/spy/offsets.h
index 5066766..a29370e 100644
--- a/WeChatFerry/spy/offsets.h
+++ b/WeChatFerry/spy/offsets.h
@@ -7,8 +7,8 @@ namespace Offsets
namespace Account
{
- constexpr uint64_t SERVICE = 0x1B58B50; // 账户服务
- constexpr uint64_t PATH = 0x25E9090; // 数据路径
+ constexpr uint64_t SERVICE = 0x1B5CA40; // 账户服务
+ constexpr uint64_t PATH = 0x25F4A40; // 数据路径
constexpr uint64_t WXID = 0x80; // WXID
constexpr uint64_t NAME = 0x1E8; // 昵称
constexpr uint64_t MOBILE = 0x128; // 手机号
@@ -18,16 +18,17 @@ namespace Account
namespace Chatroom
{
- constexpr uint64_t MGR = 0x1B86F60;
- constexpr uint64_t DEL = 0x2158830;
- constexpr uint64_t ADD = 0x21581F0;
- constexpr uint64_t INV = 0x2157BD0;
+ constexpr uint64_t MGR = 0x1B8AE40;
+ constexpr uint64_t NEW = 0x262D800;
+ constexpr uint64_t DEL = 0x2163070;
+ constexpr uint64_t ADD = 0x2162A30;
+ constexpr uint64_t INV = 0x2162410;
}
namespace Contact
{
- constexpr uint64_t MGR = 0x1B44B20;
- constexpr uint64_t LIST = 0x21A1E00;
+ constexpr uint64_t MGR = 0x1B489D0;
+ constexpr uint64_t LIST = 0x21ACBE0;
constexpr uint64_t BIN = 0x200;
constexpr uint64_t BIN_LEN = 0x208;
constexpr uint64_t WXID = 0x10;
@@ -37,18 +38,16 @@ namespace Contact
constexpr uint64_t GENDER = 0x0E;
constexpr uint64_t STEP = 0x6A8;
- constexpr uint64_t VERIFY_NEW = 0x2621B00;
- constexpr uint64_t VERIFY_OK = 0x1F421E0;
- constexpr uint64_t VERIFY_MGR = 0x4F022A8;
- constexpr uint64_t VERIFY_A8 = 0x2621B91;
- constexpr uint64_t ADD_FRIEND_HELPER = 0x4EE4A20;
- constexpr uint64_t FVDF = 0x4F02768; // FriendVeriyDialogFragment
+ constexpr uint64_t VERIFY_NEW = Chatroom::NEW;
+ constexpr uint64_t VERIFY_OK = 0x1F48850;
+ constexpr uint64_t ADD_FRIEND_HELPER = 0x4F7FB18; // a1
+ constexpr uint64_t FVDF = 0x4F9DE28; // FriendVeriyDialogFragment
}
namespace Db
{
- constexpr uint64_t INSTANCE = 0x59226C8; // 数据库实例地址
- constexpr uint64_t MSG_I = 0x5980420; // MSGi.db & MediaMsgi.db
+ constexpr uint64_t INSTANCE = 0x59D2008; // 数据库实例地址
+ constexpr uint64_t MSG_I = 0x5A30158; // MSGi.db & MediaMsgi.db
constexpr uint64_t MICROMSG = 0xB8;
constexpr uint64_t CHAT_MSG = 0x2C8;
constexpr uint64_t MISC = 0x5F0;
@@ -59,7 +58,7 @@ namespace Db
constexpr uint64_t NAME = 0x28;
// SQLITE3
- constexpr uint64_t EXEC = 0x3A76430;
+ constexpr uint64_t EXEC = 0x3A820A0;
// constexpr uint64_t BACKUP_INIT = EXEC - 0x1D113E0;
constexpr uint64_t PREPARE = EXEC + 0x7CB0;
// constexpr uint64_t OPEN = EXEC - 0x1CA2430;
@@ -83,13 +82,13 @@ namespace Message
{
namespace Log
{
- constexpr uint64_t LEVEL = 0x56E4244; // 日志级别
- constexpr uint64_t CALL = 0x261B890; // 日志函数
+ constexpr uint64_t LEVEL = 0x578DF28; // 日志级别
+ constexpr uint64_t CALL = 0x2627590; // 日志函数
}
namespace Receive
{
- constexpr uint64_t CALL = 0x2141E80; // 接收消息 Call
+ constexpr uint64_t CALL = 0x214C6C0; // 接收消息 Call
constexpr uint64_t ID = 0x30; // 消息 ID
constexpr uint64_t TYPE = 0x38; // 消息类型
constexpr uint64_t SELF = 0x3C; // 消息是否来自自己
@@ -102,7 +101,7 @@ namespace Message
constexpr uint64_t EXTRA = 0x2A0; // 原图路径
constexpr uint64_t XML = 0x308; // 消息 XML
- constexpr uint64_t PYQ_CALL = 0x2E56080; // 接收朋友圈 Call
+ constexpr uint64_t PYQ_CALL = 0x2E621D0; // 接收朋友圈 Call
constexpr uint64_t PYQ_START = 0x30; // 开始地址
constexpr uint64_t PYQ_END = 0x38; // 结束地址
constexpr uint64_t PYQ_SENDER = 0x18; // 发布者
@@ -113,45 +112,45 @@ namespace Message
namespace Send
{
- constexpr uint64_t MGR = 0x1B57350;
- constexpr uint64_t INSTANCE = 0x1B614C0;
- constexpr uint64_t FREE = 0x1B58BD0;
- constexpr uint64_t TEXT = 0x22C9CA0;
- constexpr uint64_t IMAGE = 0x22BF430;
- constexpr uint64_t APP_MGR = 0x1B5C2F0;
- constexpr uint64_t FILE = 0x20D30E0;
- constexpr uint64_t XML = 0x20D2210;
- constexpr uint64_t XML_BUF_SIGN = 0x24F95C0;
- constexpr uint64_t EMOTION_MGR = 0x1BD2310;
- constexpr uint64_t EMOTION = 0x21B8100;
+ constexpr uint64_t MGR = 0x1B5B210;
+ constexpr uint64_t INSTANCE = 0x1B653B0;
+ constexpr uint64_t FREE = 0x1B5CAC0;
+ constexpr uint64_t TEXT = 0x22D4A90;
+ constexpr uint64_t IMAGE = 0x22CA2A0;
+ constexpr uint64_t APP_MGR = 0x1B601E0;
+ constexpr uint64_t FILE = 0x20DE200;
+ constexpr uint64_t XML = 0x20DD330;
+ constexpr uint64_t XML_BUF_SIGN = 0x2503760;
+ constexpr uint64_t EMOTION_MGR = 0x1BD6300;
+ constexpr uint64_t EMOTION = 0x21C2EE0;
- constexpr uint64_t NEW_MM_READER = 0x1B60A10;
- constexpr uint64_t FREE_MM_READER = 0x1B5FDE0;
- constexpr uint64_t RICH_TEXT = 0x20DD0C0;
+ constexpr uint64_t NEW_MM_READER = 0x1B64900;
+ constexpr uint64_t FREE_MM_READER = 0x1B63CD0;
+ constexpr uint64_t RICH_TEXT = 0x20E81E0;
- constexpr uint64_t PAT = 0x2CC1E90;
+ constexpr uint64_t PAT = 0x2CCDDC0;
- constexpr uint64_t FORWARD = 0x22C9220;
+ constexpr uint64_t FORWARD = 0x22D4010;
}
}
namespace Misc
{
- constexpr uint64_t QR_CODE = 0x2025A80;
+ constexpr uint64_t QR_CODE = 0x202D3C0;
constexpr uint64_t INSATNCE = Message::Send::INSTANCE;
constexpr uint64_t FREE = Message::Send::FREE;
- constexpr uint64_t CHAT_MGR = 0x1B8AA50;
- constexpr uint64_t PRE_LOCAL_ID_MGR = 0x2142BF0;
- constexpr uint64_t PRE_DOWNLOAD_MGR = 0x1C12260;
- constexpr uint64_t PUSH_ATTACH_TASK = 0x1CE3050;
+ constexpr uint64_t CHAT_MGR = 0x1B8E930;
+ constexpr uint64_t PRE_LOCAL_ID_MGR = 0x214D430;
+ constexpr uint64_t PRE_DOWNLOAD_MGR = 0x1C17660;
+ constexpr uint64_t PUSH_ATTACH_TASK = 0x1CE8500;
namespace Sns
{
- constexpr uint64_t DATA_MGR = 0x21E52F0;
- constexpr uint64_t TIMELINE = 0x2DC6180;
- constexpr uint64_t FIRST = 0x2E346C0;
- constexpr uint64_t NEXT = 0x2E5A270;
+ constexpr uint64_t DATA_MGR = 0x21F00D0;
+ constexpr uint64_t TIMELINE = 0x2DD2320;
+ constexpr uint64_t FIRST = 0x2E40810;
+ constexpr uint64_t NEXT = 0x2E663C0;
}
}
}
diff --git a/WeChatFerry/spy/rpc_helper.h b/WeChatFerry/spy/rpc_helper.h
index feeb081..0ecbdcb 100644
--- a/WeChatFerry/spy/rpc_helper.h
+++ b/WeChatFerry/spy/rpc_helper.h
@@ -2,6 +2,8 @@
#include
+#define MAGIC_ENUM_RANGE_MIN 0
+#define MAGIC_ENUM_RANGE_MAX 256
#include
#include "wcf.pb.h"
@@ -41,7 +43,8 @@ static const std::unordered_map rpc_tag_map
{ Functions_FUNC_EXEC_OCR, Response_ocr_tag },
{ Functions_FUNC_ADD_ROOM_MEMBERS, Response_status_tag },
{ Functions_FUNC_DEL_ROOM_MEMBERS, Response_status_tag },
- { Functions_FUNC_INV_ROOM_MEMBERS, Response_status_tag } };
+ { Functions_FUNC_INV_ROOM_MEMBERS, Response_status_tag },
+ { Functions_FUNC_SHUTDOWN, Response_status_tag } };
template bool fill_response(uint8_t *out, size_t *len, AssignFunc assign)
{
diff --git a/WeChatFerry/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp
index 094420b..354f7da 100644
--- a/WeChatFerry/spy/rpc_server.cpp
+++ b/WeChatFerry/spy/rpc_server.cpp
@@ -13,7 +13,6 @@
#include
#include
-#include
#include
#include
@@ -214,7 +213,7 @@ bool RpcServer::start_message_listener(bool pyq, uint8_t *out, size_t *len)
{
return fill_response(out, len, [&](Response &rsp) {
rsp.msg.status = handler_.ListenMsg();
- if (rsp.msg.status == 0) {
+ if (rsp.msg.status >= 0) {
if (pyq) {
handler_.ListenPyq();
}
@@ -227,7 +226,7 @@ bool RpcServer::stop_message_listener(uint8_t *out, size_t *len)
{
return fill_response(out, len, [&](Response &rsp) {
rsp.msg.status = handler_.UnListenMsg();
- if (rsp.msg.status == 0) {
+ if (rsp.msg.status >= 0) {
handler_.UnListenPyq();
if (msgThread_.joinable()) {
msgThread_.join();
@@ -269,6 +268,7 @@ const std::unordered_map RpcServer::rpcFu
{ Functions_FUNC_ADD_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_add_chatroom_member(r.msg.m, out, len); } },
{ Functions_FUNC_DEL_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_delete_chatroom_member(r.msg.m, out, len); } },
{ Functions_FUNC_INV_ROOM_MEMBERS, [](const Request &r, uint8_t *out, size_t *len) { return chatroom::rpc_invite_chatroom_member(r.msg.m, out, len); } },
+ { Functions_FUNC_SHUTDOWN, [](const Request &r, uint8_t *out, size_t *len) { return misc::rpc_shutdown(out, len); }}
// clang-format on
};
diff --git a/WeChatFerry/spy/spy.cpp b/WeChatFerry/spy/spy.cpp
index dc6a700..cc7e6b0 100644
--- a/WeChatFerry/spy/spy.cpp
+++ b/WeChatFerry/spy/spy.cpp
@@ -14,7 +14,7 @@ int Init(void *args)
auto *pp = static_cast(args);
Log::InitLogger(pp->path);
- if (auto dll_addr = GetModuleHandle(L"WeChatWin.dll")) {
+ if (auto dll_addr = GetModuleHandleW(L"WeChatWin.dll")) {
WeChatDll.store(reinterpret_cast(dll_addr));
} else {
LOG_ERROR("获取 WeChatWin.dll 模块地址失败");
@@ -44,5 +44,5 @@ void Cleanup()
extern "C" {
__declspec(dllexport) int InitSpy(void *args) { return Spy::Init(args); }
-__declspec(dllexport) void CleanupSpy() { Spy::Cleanup(); }
+__declspec(dllexport) int CleanupSpy() { Spy::Cleanup(); return 0;}
}
diff --git a/WeChatFerry/spy/spy.def b/WeChatFerry/spy/spy.def
deleted file mode 100644
index 7632d5c..0000000
--- a/WeChatFerry/spy/spy.def
+++ /dev/null
@@ -1,3 +0,0 @@
-EXPORTS
- InitSpy
- CleanupSpy
diff --git a/WeChatFerry/spy/spy.h b/WeChatFerry/spy/spy.h
index ae8f402..e460bc9 100644
--- a/WeChatFerry/spy/spy.h
+++ b/WeChatFerry/spy/spy.h
@@ -6,7 +6,7 @@
namespace Spy
{
-constexpr std::string_view SUPPORT_VERSION = "3.9.12.17";
+constexpr std::string_view SUPPORT_VERSION = "3.9.12.51";
inline std::atomic WeChatDll { 0 };
template inline T getFunction(std::uintptr_t offset) { return reinterpret_cast(WeChatDll + offset); }
diff --git a/WeChatFerry/spy/spy.rc b/WeChatFerry/spy/spy.rc
index 1153695..346545c 100644
--- a/WeChatFerry/spy/spy.rc
+++ b/WeChatFerry/spy/spy.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 39,4,4,0
- PRODUCTVERSION 3,9,12,17
+ FILEVERSION 39,5,2,0
+ PRODUCTVERSION 3,9,12,51
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -69,12 +69,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "WeChatFerry"
VALUE "FileDescription", "WeChatFerry"
- VALUE "FileVersion", "39.4.4.0"
+ VALUE "FileVersion", "39.5.2.0"
VALUE "InternalName", "spy.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "spy.dll"
VALUE "ProductName", "WeChatFerry"
- VALUE "ProductVersion", "3.9.12.17"
+ VALUE "ProductVersion", "3.9.12.51"
END
END
BLOCK "VarFileInfo"
diff --git a/WeChatFerry/vcpkg.json b/WeChatFerry/vcpkg.json
index d735952..5f077e0 100644
--- a/WeChatFerry/vcpkg.json
+++ b/WeChatFerry/vcpkg.json
@@ -2,14 +2,10 @@
"name": "wcf",
"version-string": "1.0.0",
"dependencies": [
- {
- "name": "protobuf",
- "features": [ "zlib" ]
- },
"spdlog",
"nng",
"magic-enum",
"minhook"
],
- "builtin-baseline": "80d54ff62d528339c626a6fbc3489a7f25956ade"
+ "builtin-baseline": "d6995a0cf3cafda5e9e52749fad075dd62bfd90c"
}
diff --git a/clients/python/README.MD b/clients/python/README.MD
index bd80fa3..258d184 100644
--- a/clients/python/README.MD
+++ b/clients/python/README.MD
@@ -1,7 +1,7 @@
# WeChatFerry Python 客户端
[](https://pypi.python.org/pypi/wcferry) [](https://pypi.python.org/pypi/wcferry) [](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
-|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/YvgFFhF6D-79kXDzRqtg6w)|
+|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/c2JggTBlOP8fP9j-MlMAvg)|
|:-:|:-:|:-:|
🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。
@@ -44,8 +44,8 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc
## 版本更新
-### v39.4.4.0
-* 实现发送 XML 功能
+### v39.5.2.0
+* 没有新功能
点击查看更多
@@ -71,7 +71,7 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc
* 发送图片消息
* 发送文件消息
* 发送卡片消息
-* 发送 XML
+* 发送 XML 消息
* 发送 GIF 消息
* 拍一拍群友
* 转发消息
diff --git a/clients/python/wcferry/client.py b/clients/python/wcferry/client.py
index af70b4e..71675ae 100644
--- a/clients/python/wcferry/client.py
+++ b/clients/python/wcferry/client.py
@@ -1,11 +1,13 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
-__version__ = "39.4.4.0"
+__version__ = "39.5.2.0"
import atexit
import base64
import ctypes
+import ctypes.wintypes
+import gc
import logging
import mimetypes
import os
@@ -80,10 +82,7 @@ class Wcf():
if host is None:
self._local_mode = True
self.host = "127.0.0.1"
- self.sdk = ctypes.cdll.LoadLibrary(f"{self._wcf_root}/sdk.dll")
- if self.sdk.WxInitSDK(debug, port) != 0:
- self.LOG.error("初始化失败!")
- os._exit(-1)
+ self._sdk_init(debug, port)
self.cmd_url = f"tcp://{self.host}:{self.port}"
@@ -125,15 +124,42 @@ class Wcf():
except subprocess.CalledProcessError as e:
self.LOG.error(f"修改控制台代码页失败: {e}")
+ def _sdk_init(self, debug, port):
+ sdk = ctypes.cdll.LoadLibrary(f"{self._wcf_root}/sdk.dll")
+ if sdk.WxInitSDK(debug, port) != 0:
+ self.LOG.error("初始化失败!")
+ os._exit(-1)
+
+ # 主动卸载
+ ctypes.windll.kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE]
+ ctypes.windll.kernel32.FreeLibrary(sdk._handle)
+ del sdk # 删除 Python 对象、触发垃圾回收
+ gc.collect()
+
+ def _sdk_destroy(self):
+ sdk = ctypes.cdll.LoadLibrary(f"{self._wcf_root}/sdk.dll")
+ sdk.WxDestroySDK()
+ # 主动卸载
+ ctypes.windll.kernel32.FreeLibrary.argtypes = [ctypes.wintypes.HMODULE]
+ ctypes.windll.kernel32.FreeLibrary(sdk._handle)
+ del sdk # 删除 Python 对象、触发垃圾回收
+ gc.collect()
+
def cleanup(self) -> None:
"""关闭连接,回收资源"""
if not self._is_running:
return
self.disable_recv_msg()
- self.cmd_socket.close()
- if self._local_mode and self.sdk and self.sdk.WxDestroySDK() != 0:
+ req = wcf_pb2.Request()
+ req.func = wcf_pb2.FUNC_SHUTDOWN
+ _ = self._send_request(req)
+
+ self.cmd_socket.close()
+ self.msg_socket.close()
+
+ if self._local_mode and self.sdk and self._sdk_destroy() != 0:
self.LOG.error("退出失败!")
self._is_running = False
@@ -537,9 +563,6 @@ class Wcf():
else:
self.msgQ.put(WxMsg(rsp.wxmsg))
- # 退出前关闭通信通道
- self.msg_socket.close()
-
if self._is_receiving_msg:
return True
@@ -574,8 +597,6 @@ class Wcf():
pass
else:
callback(WxMsg(rsp.wxmsg))
- # 退出前关闭通信通道
- self.msg_socket.close()
if self._is_receiving_msg:
return True
@@ -666,9 +687,9 @@ class Wcf():
friends = []
for cnt in self.get_contacts():
if (cnt["wxid"].endswith("@chatroom") or # 群聊
- cnt["wxid"].startswith("gh_") or # 公众号
- cnt["wxid"] in not_friends.keys() # 其他杂号
- ):
+ cnt["wxid"].startswith("gh_") or # 公众号
+ cnt["wxid"] in not_friends.keys() # 其他杂号
+ ):
continue
friends.append(cnt)
@@ -843,7 +864,7 @@ class Wcf():
Returns:
str: 成功返回存储路径;空字符串为失败,原因见日志。
"""
- sleep(1) # 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
+ sleep(1) # 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
if (not os.path.exists(extra)) and (self.download_attach(id, "", extra) != 0):
self.LOG.error(f"下载失败")
return ""
@@ -870,7 +891,7 @@ class Wcf():
Returns:
str: 成功返回存储路径;空字符串为失败,原因见日志。
"""
- sleep(1) # 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
+ sleep(1) # 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
base, _ = os.path.splitext(thumb)
file_path = base + ".mp4"
file_name = os.path.basename(file_path)
diff --git a/clients/python/wcferry/wcf_pb2.py b/clients/python/wcferry/wcf_pb2.py
index acb1981..36cf857 100644
--- a/clients/python/wcferry/wcf_pb2.py
+++ b/clients/python/wcferry/wcf_pb2.py
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xff\x03\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.MemberMgmtH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x12\x12\n\x04ui64\x18\x0c \x01(\x04\x42\x02\x30\x01H\x00\x12\x0e\n\x04\x66lag\x18\r \x01(\x08H\x00\x12\x1d\n\x03\x61tt\x18\x0e \x01(\x0b\x32\x0e.wcf.AttachMsgH\x00\x12\x1b\n\x02\x61m\x18\x0f \x01(\x0b\x32\r.wcf.AudioMsgH\x00\x12\x1b\n\x02rt\x18\x10 \x01(\x0b\x32\r.wcf.RichTextH\x00\x12\x19\n\x02pm\x18\x11 \x01(\x0b\x32\x0b.wcf.PatMsgH\x00\x12\x1d\n\x02\x66m\x18\x12 \x01(\x0b\x32\x0f.wcf.ForwardMsgH\x00\x42\x05\n\x03msg\"\xc7\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x12\x1a\n\x03ocr\x18\x0b \x01(\x0b\x32\x0b.wcf.OcrMsgH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xbe\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0e\n\x02id\x18\x03 \x01(\x04\x42\x02\x30\x01\x12\x0c\n\x04type\x18\x04 \x01(\r\x12\n\n\x02ts\x18\x05 \x01(\r\x12\x0e\n\x06roomid\x18\x06 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x07 \x01(\t\x12\x0e\n\x06sender\x18\x08 \x01(\t\x12\x0c\n\x04sign\x18\t \x01(\t\x12\r\n\x05thumb\x18\n \x01(\t\x12\r\n\x05\x65xtra\x18\x0b \x01(\t\x12\x0b\n\x03xml\x18\x0c \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x04\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nMemberMgmt\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"D\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t\"9\n\tAttachMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05thumb\x18\x02 \x01(\t\x12\r\n\x05\x65xtra\x18\x03 \x01(\t\"\'\n\x08\x41udioMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x0b\n\x03\x64ir\x18\x02 \x01(\t\"y\n\x08RichText\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\t\x12\r\n\x05title\x18\x03 \x01(\t\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\x10\n\x08thumburl\x18\x06 \x01(\t\x12\x10\n\x08receiver\x18\x07 \x01(\t\"&\n\x06PatMsg\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\x0c\n\x04wxid\x18\x02 \x01(\t\"(\n\x06OcrMsg\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0e\n\x06result\x18\x02 \x01(\t\".\n\nForwardMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x10\n\x08receiver\x18\x02 \x01(\t\"\xb7\x02\n\x08RoomData\x12)\n\x07members\x18\x01 \x03(\x0b\x32\x18.wcf.RoomData.RoomMember\x12\x14\n\x07\x66ield_2\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x0f\n\x07\x66ield_3\x18\x03 \x01(\x05\x12\x14\n\x07\x66ield_4\x18\x04 \x01(\x05H\x01\x88\x01\x01\x12\x10\n\x08\x63\x61pacity\x18\x05 \x01(\x05\x12\x14\n\x07\x66ield_6\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x0f\n\x07\x66ield_7\x18\x07 \x01(\x05\x12\x0f\n\x07\x66ield_8\x18\x08 \x01(\x05\x12\x0e\n\x06\x61\x64mins\x18\t \x03(\t\x1a\x45\n\nRoomMember\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05state\x18\x03 \x01(\x05\x42\x07\n\x05_nameB\n\n\x08_field_2B\n\n\x08_field_4B\n\n\x08_field_6*\xf2\x05\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x16\n\x12\x46UNC_GET_AUDIO_MSG\x10\x16\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x16\n\x12\x46UNC_SEND_RICH_TXT\x10%\x12\x15\n\x11\x46UNC_SEND_PAT_MSG\x10&\x12\x14\n\x10\x46UNC_FORWARD_MSG\x10\'\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10R\x12\x14\n\x10\x46UNC_REFRESH_PYQ\x10S\x12\x18\n\x14\x46UNC_DOWNLOAD_ATTACH\x10T\x12\x19\n\x15\x46UNC_GET_CONTACT_INFO\x10U\x12\x13\n\x0f\x46UNC_REVOKE_MSG\x10V\x12\x17\n\x13\x46UNC_REFRESH_QRCODE\x10W\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`\x12\x11\n\rFUNC_EXEC_OCR\x10\x61\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10p\x12\x19\n\x15\x46UNC_DEL_ROOM_MEMBERS\x10q\x12\x19\n\x15\x46UNC_INV_ROOM_MEMBERS\x10rB\r\n\x0b\x63om.iamteerb\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\twcf.proto\x12\x03wcf\"\xff\x03\n\x07Request\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x1b\n\x05\x65mpty\x18\x02 \x01(\x0b\x32\n.wcf.EmptyH\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x03txt\x18\x04 \x01(\x0b\x32\x0c.wcf.TextMsgH\x00\x12\x1c\n\x04\x66ile\x18\x05 \x01(\x0b\x32\x0c.wcf.PathMsgH\x00\x12\x1d\n\x05query\x18\x06 \x01(\x0b\x32\x0c.wcf.DbQueryH\x00\x12\x1e\n\x01v\x18\x07 \x01(\x0b\x32\x11.wcf.VerificationH\x00\x12\x1c\n\x01m\x18\x08 \x01(\x0b\x32\x0f.wcf.MemberMgmtH\x00\x12\x1a\n\x03xml\x18\t \x01(\x0b\x32\x0b.wcf.XmlMsgH\x00\x12\x1b\n\x03\x64\x65\x63\x18\n \x01(\x0b\x32\x0c.wcf.DecPathH\x00\x12\x1b\n\x02tf\x18\x0b \x01(\x0b\x32\r.wcf.TransferH\x00\x12\x12\n\x04ui64\x18\x0c \x01(\x04\x42\x02\x30\x01H\x00\x12\x0e\n\x04\x66lag\x18\r \x01(\x08H\x00\x12\x1d\n\x03\x61tt\x18\x0e \x01(\x0b\x32\x0e.wcf.AttachMsgH\x00\x12\x1b\n\x02\x61m\x18\x0f \x01(\x0b\x32\r.wcf.AudioMsgH\x00\x12\x1b\n\x02rt\x18\x10 \x01(\x0b\x32\r.wcf.RichTextH\x00\x12\x19\n\x02pm\x18\x11 \x01(\x0b\x32\x0b.wcf.PatMsgH\x00\x12\x1d\n\x02\x66m\x18\x12 \x01(\x0b\x32\x0f.wcf.ForwardMsgH\x00\x42\x05\n\x03msg\"\xc7\x02\n\x08Response\x12\x1c\n\x04\x66unc\x18\x01 \x01(\x0e\x32\x0e.wcf.Functions\x12\x10\n\x06status\x18\x02 \x01(\x05H\x00\x12\r\n\x03str\x18\x03 \x01(\tH\x00\x12\x1b\n\x05wxmsg\x18\x04 \x01(\x0b\x32\n.wcf.WxMsgH\x00\x12\x1e\n\x05types\x18\x05 \x01(\x0b\x32\r.wcf.MsgTypesH\x00\x12$\n\x08\x63ontacts\x18\x06 \x01(\x0b\x32\x10.wcf.RpcContactsH\x00\x12\x1b\n\x03\x64\x62s\x18\x07 \x01(\x0b\x32\x0c.wcf.DbNamesH\x00\x12\x1f\n\x06tables\x18\x08 \x01(\x0b\x32\r.wcf.DbTablesH\x00\x12\x1b\n\x04rows\x18\t \x01(\x0b\x32\x0b.wcf.DbRowsH\x00\x12\x1b\n\x02ui\x18\n \x01(\x0b\x32\r.wcf.UserInfoH\x00\x12\x1a\n\x03ocr\x18\x0b \x01(\x0b\x32\x0b.wcf.OcrMsgH\x00\x42\x05\n\x03msg\"\x07\n\x05\x45mpty\"\xbe\x01\n\x05WxMsg\x12\x0f\n\x07is_self\x18\x01 \x01(\x08\x12\x10\n\x08is_group\x18\x02 \x01(\x08\x12\x0e\n\x02id\x18\x03 \x01(\x04\x42\x02\x30\x01\x12\x0c\n\x04type\x18\x04 \x01(\r\x12\n\n\x02ts\x18\x05 \x01(\r\x12\x0e\n\x06roomid\x18\x06 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x07 \x01(\t\x12\x0e\n\x06sender\x18\x08 \x01(\t\x12\x0c\n\x04sign\x18\t \x01(\t\x12\r\n\x05thumb\x18\n \x01(\t\x12\r\n\x05\x65xtra\x18\x0b \x01(\t\x12\x0b\n\x03xml\x18\x0c \x01(\t\"7\n\x07TextMsg\x12\x0b\n\x03msg\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\x12\r\n\x05\x61ters\x18\x03 \x01(\t\")\n\x07PathMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x10\n\x08receiver\x18\x02 \x01(\t\"G\n\x06XmlMsg\x12\x10\n\x08receiver\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\x04\"a\n\x08MsgTypes\x12\'\n\x05types\x18\x01 \x03(\x0b\x32\x18.wcf.MsgTypes.TypesEntry\x1a,\n\nTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x01\n\nRpcContact\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0e\n\x06remark\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x05 \x01(\t\x12\x10\n\x08province\x18\x06 \x01(\t\x12\x0c\n\x04\x63ity\x18\x07 \x01(\t\x12\x0e\n\x06gender\x18\x08 \x01(\x05\"0\n\x0bRpcContacts\x12!\n\x08\x63ontacts\x18\x01 \x03(\x0b\x32\x0f.wcf.RpcContact\"\x18\n\x07\x44\x62Names\x12\r\n\x05names\x18\x01 \x03(\t\"$\n\x07\x44\x62Table\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"(\n\x08\x44\x62Tables\x12\x1c\n\x06tables\x18\x01 \x03(\x0b\x32\x0c.wcf.DbTable\"\"\n\x07\x44\x62Query\x12\n\n\x02\x64\x62\x18\x01 \x01(\t\x12\x0b\n\x03sql\x18\x02 \x01(\t\"8\n\x07\x44\x62\x46ield\x12\x0c\n\x04type\x18\x01 \x01(\x05\x12\x0e\n\x06\x63olumn\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"%\n\x05\x44\x62Row\x12\x1c\n\x06\x66ields\x18\x01 \x03(\x0b\x32\x0c.wcf.DbField\"\"\n\x06\x44\x62Rows\x12\x18\n\x04rows\x18\x01 \x03(\x0b\x32\n.wcf.DbRow\"5\n\x0cVerification\x12\n\n\x02v3\x18\x01 \x01(\t\x12\n\n\x02v4\x18\x02 \x01(\t\x12\r\n\x05scene\x18\x03 \x01(\x05\"+\n\nMemberMgmt\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\r\n\x05wxids\x18\x02 \x01(\t\"S\n\x08UserInfo\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06mobile\x18\x03 \x01(\t\x12\x0c\n\x04home\x18\x04 \x01(\t\x12\r\n\x05\x61lias\x18\x05 \x01(\t\"#\n\x07\x44\x65\x63Path\x12\x0b\n\x03src\x18\x01 \x01(\t\x12\x0b\n\x03\x64st\x18\x02 \x01(\t\"4\n\x08Transfer\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x0c\n\x04tfid\x18\x02 \x01(\t\x12\x0c\n\x04taid\x18\x03 \x01(\t\"9\n\tAttachMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05thumb\x18\x02 \x01(\t\x12\r\n\x05\x65xtra\x18\x03 \x01(\t\"\'\n\x08\x41udioMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x0b\n\x03\x64ir\x18\x02 \x01(\t\"y\n\x08RichText\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\t\x12\r\n\x05title\x18\x03 \x01(\t\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12\x0b\n\x03url\x18\x05 \x01(\t\x12\x10\n\x08thumburl\x18\x06 \x01(\t\x12\x10\n\x08receiver\x18\x07 \x01(\t\"&\n\x06PatMsg\x12\x0e\n\x06roomid\x18\x01 \x01(\t\x12\x0c\n\x04wxid\x18\x02 \x01(\t\"(\n\x06OcrMsg\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0e\n\x06result\x18\x02 \x01(\t\".\n\nForwardMsg\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x10\n\x08receiver\x18\x02 \x01(\t\"\xb7\x02\n\x08RoomData\x12)\n\x07members\x18\x01 \x03(\x0b\x32\x18.wcf.RoomData.RoomMember\x12\x14\n\x07\x66ield_2\x18\x02 \x01(\x05H\x00\x88\x01\x01\x12\x0f\n\x07\x66ield_3\x18\x03 \x01(\x05\x12\x14\n\x07\x66ield_4\x18\x04 \x01(\x05H\x01\x88\x01\x01\x12\x10\n\x08\x63\x61pacity\x18\x05 \x01(\x05\x12\x14\n\x07\x66ield_6\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x0f\n\x07\x66ield_7\x18\x07 \x01(\x05\x12\x0f\n\x07\x66ield_8\x18\x08 \x01(\x05\x12\x0e\n\x06\x61\x64mins\x18\t \x03(\t\x1a\x45\n\nRoomMember\x12\x0c\n\x04wxid\x18\x01 \x01(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05state\x18\x03 \x01(\x05\x42\x07\n\x05_nameB\n\n\x08_field_2B\n\n\x08_field_4B\n\n\x08_field_6*\x86\x06\n\tFunctions\x12\x11\n\rFUNC_RESERVED\x10\x00\x12\x11\n\rFUNC_IS_LOGIN\x10\x01\x12\x16\n\x12\x46UNC_GET_SELF_WXID\x10\x10\x12\x16\n\x12\x46UNC_GET_MSG_TYPES\x10\x11\x12\x15\n\x11\x46UNC_GET_CONTACTS\x10\x12\x12\x15\n\x11\x46UNC_GET_DB_NAMES\x10\x13\x12\x16\n\x12\x46UNC_GET_DB_TABLES\x10\x14\x12\x16\n\x12\x46UNC_GET_USER_INFO\x10\x15\x12\x16\n\x12\x46UNC_GET_AUDIO_MSG\x10\x16\x12\x11\n\rFUNC_SEND_TXT\x10 \x12\x11\n\rFUNC_SEND_IMG\x10!\x12\x12\n\x0e\x46UNC_SEND_FILE\x10\"\x12\x11\n\rFUNC_SEND_XML\x10#\x12\x15\n\x11\x46UNC_SEND_EMOTION\x10$\x12\x16\n\x12\x46UNC_SEND_RICH_TXT\x10%\x12\x15\n\x11\x46UNC_SEND_PAT_MSG\x10&\x12\x14\n\x10\x46UNC_FORWARD_MSG\x10\'\x12\x18\n\x14\x46UNC_ENABLE_RECV_TXT\x10\x30\x12\x19\n\x15\x46UNC_DISABLE_RECV_TXT\x10@\x12\x16\n\x12\x46UNC_EXEC_DB_QUERY\x10P\x12\x16\n\x12\x46UNC_ACCEPT_FRIEND\x10Q\x12\x16\n\x12\x46UNC_RECV_TRANSFER\x10R\x12\x14\n\x10\x46UNC_REFRESH_PYQ\x10S\x12\x18\n\x14\x46UNC_DOWNLOAD_ATTACH\x10T\x12\x19\n\x15\x46UNC_GET_CONTACT_INFO\x10U\x12\x13\n\x0f\x46UNC_REVOKE_MSG\x10V\x12\x17\n\x13\x46UNC_REFRESH_QRCODE\x10W\x12\x16\n\x12\x46UNC_DECRYPT_IMAGE\x10`\x12\x11\n\rFUNC_EXEC_OCR\x10\x61\x12\x19\n\x15\x46UNC_ADD_ROOM_MEMBERS\x10p\x12\x19\n\x15\x46UNC_DEL_ROOM_MEMBERS\x10q\x12\x19\n\x15\x46UNC_INV_ROOM_MEMBERS\x10r\x12\x12\n\rFUNC_SHUTDOWN\x10\xff\x01\x42\r\n\x0b\x63om.iamteerb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -44,8 +44,8 @@ if not _descriptor._USE_C_DESCRIPTORS:
_globals['_AUDIOMSG'].fields_by_name['id']._serialized_options = b'0\001'
_globals['_FORWARDMSG'].fields_by_name['id']._loaded_options = None
_globals['_FORWARDMSG'].fields_by_name['id']._serialized_options = b'0\001'
- _globals['_FUNCTIONS']._serialized_start=2728
- _globals['_FUNCTIONS']._serialized_end=3482
+ _globals['_FUNCTIONS']._serialized_start=2743
+ _globals['_FUNCTIONS']._serialized_end=3517
_globals['_REQUEST']._serialized_start=19
_globals['_REQUEST']._serialized_end=530
_globals['_RESPONSE']._serialized_start=533
@@ -87,25 +87,25 @@ if not _descriptor._USE_C_DESCRIPTORS:
_globals['_MEMBERMGMT']._serialized_start=1854
_globals['_MEMBERMGMT']._serialized_end=1897
_globals['_USERINFO']._serialized_start=1899
- _globals['_USERINFO']._serialized_end=1967
- _globals['_DECPATH']._serialized_start=1969
- _globals['_DECPATH']._serialized_end=2004
- _globals['_TRANSFER']._serialized_start=2006
- _globals['_TRANSFER']._serialized_end=2058
- _globals['_ATTACHMSG']._serialized_start=2060
- _globals['_ATTACHMSG']._serialized_end=2117
- _globals['_AUDIOMSG']._serialized_start=2119
- _globals['_AUDIOMSG']._serialized_end=2158
- _globals['_RICHTEXT']._serialized_start=2160
- _globals['_RICHTEXT']._serialized_end=2281
- _globals['_PATMSG']._serialized_start=2283
- _globals['_PATMSG']._serialized_end=2321
- _globals['_OCRMSG']._serialized_start=2323
- _globals['_OCRMSG']._serialized_end=2363
- _globals['_FORWARDMSG']._serialized_start=2365
- _globals['_FORWARDMSG']._serialized_end=2411
- _globals['_ROOMDATA']._serialized_start=2414
- _globals['_ROOMDATA']._serialized_end=2725
- _globals['_ROOMDATA_ROOMMEMBER']._serialized_start=2620
- _globals['_ROOMDATA_ROOMMEMBER']._serialized_end=2689
+ _globals['_USERINFO']._serialized_end=1982
+ _globals['_DECPATH']._serialized_start=1984
+ _globals['_DECPATH']._serialized_end=2019
+ _globals['_TRANSFER']._serialized_start=2021
+ _globals['_TRANSFER']._serialized_end=2073
+ _globals['_ATTACHMSG']._serialized_start=2075
+ _globals['_ATTACHMSG']._serialized_end=2132
+ _globals['_AUDIOMSG']._serialized_start=2134
+ _globals['_AUDIOMSG']._serialized_end=2173
+ _globals['_RICHTEXT']._serialized_start=2175
+ _globals['_RICHTEXT']._serialized_end=2296
+ _globals['_PATMSG']._serialized_start=2298
+ _globals['_PATMSG']._serialized_end=2336
+ _globals['_OCRMSG']._serialized_start=2338
+ _globals['_OCRMSG']._serialized_end=2378
+ _globals['_FORWARDMSG']._serialized_start=2380
+ _globals['_FORWARDMSG']._serialized_end=2426
+ _globals['_ROOMDATA']._serialized_start=2429
+ _globals['_ROOMDATA']._serialized_end=2740
+ _globals['_ROOMDATA_ROOMMEMBER']._serialized_start=2635
+ _globals['_ROOMDATA_ROOMMEMBER']._serialized_end=2704
# @@protoc_insertion_point(module_scope)