Merge branch 'lich0821:master' into master
This commit is contained in:
commit
79b7629b3e
@ -4,4 +4,7 @@ charset = utf-8-bom
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 4
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
114
.github/workflows/Build-WeChatFerry.yml
vendored
114
.github/workflows/Build-WeChatFerry.yml
vendored
@ -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/)
|
86
.github/workflows/build-ci.yml
vendored
Normal file
86
.github/workflows/build-ci.yml
vendored
Normal file
@ -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
|
14
.github/workflows/ci.yml
vendored
Normal file
14
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/build-ci.yml
|
65
.github/workflows/release.yml
vendored
Normal file
65
.github/workflows/release.yml
vendored
Normal file
@ -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/)
|
27
README.MD
27
README.MD
@ -9,7 +9,7 @@
|
||||
|
||||
</details>
|
||||
|
||||
|[📖 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 @@
|
||||
|
||||
## 感谢大佬们贡献代码
|
||||
|
||||
<a href="https://github.com/lich0821/WeChatFerry/graphs/contributors"></a>
|
||||
<a href="https://github.com/lich0821/WeChatFerry/graphs/contributors"></a>
|
||||
|
||||
## 快速开始
|
||||
### Python
|
||||
@ -207,9 +207,8 @@ WeChatFerry
|
||||
|
||||
## 版本更新
|
||||
|
||||
### v39.4.4
|
||||
|
||||
* 实现通发送 XML 功能。
|
||||
### v39.5.2
|
||||
* 没有新功能
|
||||
|
||||
<details><summary>点击查看更多</summary>
|
||||
|
||||
@ -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
|
||||
|
||||
* 实现通过好友申请功能。
|
||||
|
56
WeChatFerry/CMakeLists.txt
Normal file
56
WeChatFerry/CMakeLists.txt
Normal file
@ -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)
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "framework.h"
|
||||
|
||||
#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
|
||||
#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__)
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <strsafe.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "framework.h"
|
||||
#include <Shlwapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
57
WeChatFerry/sdk/CMakeLists.txt
Normal file
57
WeChatFerry/sdk/CMakeLists.txt
Normal file
@ -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
|
||||
# $<TARGET_FILE:sdk>
|
||||
# ${CMAKE_SOURCE_DIR}/Out
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy
|
||||
# $<TARGET_FILE:sdk>
|
||||
# ${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
|
||||
# )
|
@ -86,7 +86,8 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'">
|
||||
@ -103,7 +104,8 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@ -130,7 +132,8 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</ModuleDefinitionFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
|
||||
@ -142,7 +145,7 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Com
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\com\util.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="..\com\framework.h" />
|
||||
<ClInclude Include="injector.h" />
|
||||
<ClInclude Include="sdk.h" />
|
||||
</ItemGroup>
|
||||
@ -152,9 +155,6 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Com
|
||||
<ClCompile Include="injector.cpp" />
|
||||
<ClCompile Include="sdk.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="sdk.def" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -15,7 +15,7 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<ClInclude Include="..\com\framework.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sdk.h">
|
||||
@ -42,9 +42,4 @@
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="sdk.def">
|
||||
<Filter>源文件</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -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<LPVOID>(GetProcAddress(dll, func_name.c_str()));
|
||||
uint64_t offset = reinterpret_cast<uint64_t>(absAddr) - reinterpret_cast<uint64_t>(dll);
|
||||
FreeLibrary(dll);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
EXPORTS
|
||||
WxInitSDK
|
||||
WxDestroySDK
|
@ -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();
|
||||
}
|
BIN
WeChatFerry/smc/libCodec.a
Normal file
BIN
WeChatFerry/smc/libCodec.a
Normal file
Binary file not shown.
BIN
WeChatFerry/smc/libmp3lame.a
Normal file
BIN
WeChatFerry/smc/libmp3lame.a
Normal file
Binary file not shown.
108
WeChatFerry/spy/CMakeLists.txt
Normal file
108
WeChatFerry/spy/CMakeLists.txt
Normal file
@ -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
|
||||
# $<TARGET_FILE:spy>
|
||||
# ${CMAKE_SOURCE_DIR}/Out
|
||||
# COMMAND ${CMAKE_COMMAND} -E copy
|
||||
# $<TARGET_FILE:spy>
|
||||
# ${CMAKE_SOURCE_DIR}/../clients/python/wcferry
|
||||
# )
|
@ -105,7 +105,8 @@
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</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>
|
||||
@ -158,7 +159,8 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry</Co
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</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>
|
||||
@ -212,7 +214,8 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry</Co
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
|
||||
<ModuleDefinitionFile>
|
||||
</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>
|
||||
@ -250,7 +253,7 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry</Co
|
||||
<ClInclude Include="chatroom_manager.h" />
|
||||
<ClInclude Include="misc_manager.h" />
|
||||
<ClInclude Include="database_executor.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="..\com\framework.h" />
|
||||
<ClInclude Include="contact_manager.h" />
|
||||
<ClInclude Include="message_handler.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
@ -282,7 +285,6 @@ xcopy /y $(SolutionDir)DISCLAIMER.md $(SolutionDir)..\clients\python\wcferry</Co
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\rpc\proto\wcf.proto" />
|
||||
<None Include="spy.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="spy.rc" />
|
||||
|
@ -18,7 +18,7 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<ClInclude Include="..\com\framework.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rpc_server.h">
|
||||
@ -142,9 +142,6 @@
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="spy.def">
|
||||
<Filter>源文件</Filter>
|
||||
</None>
|
||||
<None Include="..\rpc\proto\wcf.proto">
|
||||
<Filter>nnrpc</Filter>
|
||||
</None>
|
||||
|
@ -17,14 +17,6 @@ namespace OsAcc = Offsets::Account;
|
||||
using get_account_service_t = QWORD (*)();
|
||||
using get_data_path_t = QWORD (*)(QWORD);
|
||||
|
||||
// 缓存避免重复查询
|
||||
static std::optional<std::string> cachedWxid;
|
||||
static std::optional<fs::path> 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<get_account_service_t>(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<get_data_path_t>(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<get_data_path_t>(OsAcc::PATH)) {
|
||||
getDataPath(reinterpret_cast<QWORD>(&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()
|
||||
|
@ -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 <auto FillFunc, typename Func>
|
||||
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<QWORD>(&wx_members);
|
||||
QWORD tmp[2] = { 0 };
|
||||
|
||||
auto split = util::parse_wxids(wxids);
|
||||
auto &wx_members = split.wxWxids;
|
||||
QWORD p_members = reinterpret_cast<QWORD>(&wx_members);
|
||||
|
||||
return static_cast<int>(add_members(get_chatroom_mgr(), p_members, wx_roomid, reinterpret_cast<QWORD>(tmp)));
|
||||
}
|
||||
@ -49,24 +52,32 @@ int del_chatroom_member(const string &roomid, const string &wxids)
|
||||
auto del_members = Spy::getFunction<delete_member_t>(OsRoom::DEL);
|
||||
|
||||
WxString *wx_roomid = util::CreateWxString(roomid);
|
||||
auto wx_members = util::parse_wxids(wxids).wxWxids;
|
||||
QWORD p_members = reinterpret_cast<QWORD>(&wx_members);
|
||||
|
||||
auto split = util::parse_wxids(wxids);
|
||||
auto &wx_members = split.wxWxids;
|
||||
QWORD p_members = reinterpret_cast<QWORD>(&wx_members);
|
||||
|
||||
return static_cast<int>(del_members(get_chatroom_mgr(), p_members, wx_roomid));
|
||||
}
|
||||
|
||||
int invite_chatroom_member(const string &roomid, const string &wxids)
|
||||
{
|
||||
auto init_roomid = Spy::getFunction<new_t>(OsRoom::NEW);
|
||||
auto invite_members = Spy::getFunction<invite_members_t>(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<QWORD>(&wx_members);
|
||||
QWORD tmp[2] = { 0 };
|
||||
QWORD array[4] = { 0 };
|
||||
|
||||
return static_cast<int>(invite_members(ws_roomid.c_str(), p_members, wx_roomid, reinterpret_cast<QWORD>(tmp)));
|
||||
auto split = util::parse_wxids(wxids);
|
||||
auto &wx_members = split.wxWxids;
|
||||
QWORD p_members = reinterpret_cast<QWORD>(&wx_members);
|
||||
QWORD p_roomid = init_roomid(reinterpret_cast<QWORD>(&array), &wx_roomid);
|
||||
LOG_BUFFER((uint8_t *)*(QWORD *)(*(QWORD *)p_members), 40);
|
||||
|
||||
return static_cast<int>(invite_members(ws_roomid.c_str(), p_members, p_roomid, reinterpret_cast<QWORD>(tmp)));
|
||||
}
|
||||
|
||||
bool rpc_add_chatroom_member(const MemberMgmt &m, uint8_t *out, size_t *len)
|
||||
|
@ -1,114 +0,0 @@
|
||||
#include "framework.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#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<wstring> vMembers;
|
||||
vector<WxString> 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<wstring> vMembers;
|
||||
vector<WxString> 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<wstring> vMembers;
|
||||
vector<WxString> 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;
|
||||
}
|
||||
|
@ -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<RpcContact_t> get_contacts()
|
||||
|
||||
int accept_new_friend(const std::string &v3, const std::string &v4, int scene)
|
||||
{
|
||||
// TODO: 处理来源、备注、标签等
|
||||
// TODO: 备注、标签等
|
||||
auto func_new = Spy::getFunction<func_verify_new_t>(OsCon::VERIFY_NEW);
|
||||
auto func_verify = Spy::getFunction<func_verify_ok_t>(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<QWORD>(&v4Array), pV4);
|
||||
QWORD pV4Buff = func_new(reinterpret_cast<QWORD>(&v4Array), pV4);
|
||||
|
||||
char buff[0x100] = { 0 };
|
||||
memcpy(buff, &helper, sizeof(&helper));
|
||||
QWORD a1 = reinterpret_cast<QWORD>(&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);
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
|
||||
// Windows 头文件
|
||||
#include <windows.h>
|
@ -5,8 +5,6 @@
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "framework.h"
|
||||
|
||||
#include "account_manager.h"
|
||||
#include "log.hpp"
|
||||
#include "offsets.h"
|
||||
@ -192,8 +190,8 @@ int Handler::EnableLog()
|
||||
funcWxLog = Spy::getFunction<funcWxLog_t>(OsLog::CALL);
|
||||
|
||||
if (InitializeHook() != MH_OK) return -1;
|
||||
if (MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast<LPVOID *>(&realWxLog)) != MH_OK) return -2;
|
||||
if (MH_EnableHook(funcWxLog) != MH_OK) return -3;
|
||||
if (MH_CreateHook(reinterpret_cast<LPVOID>(funcWxLog), reinterpret_cast<LPVOID>(&PrintWxLog), reinterpret_cast<LPVOID *>(&realWxLog)) != MH_OK) return -2;
|
||||
if (MH_EnableHook(reinterpret_cast<LPVOID>(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<LPVOID>(funcWxLog)) != MH_OK) return -1;
|
||||
if (MH_RemoveHook(reinterpret_cast<LPVOID>(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<funcRecvMsg_t>(OsRecv::CALL);
|
||||
if (InitializeHook() != MH_OK) return -1;
|
||||
if (MH_CreateHook(funcRecvMsg, &DispatchMsg, reinterpret_cast<LPVOID *>(&realRecvMsg)) != MH_OK) return -1;
|
||||
if (MH_EnableHook(funcRecvMsg) != MH_OK) return -1;
|
||||
if (MH_CreateHook(reinterpret_cast<LPVOID>(funcRecvMsg), reinterpret_cast<LPVOID>(&DispatchMsg), reinterpret_cast<LPVOID *>(&realRecvMsg)) != MH_OK) return -2;
|
||||
if (MH_EnableHook(reinterpret_cast<LPVOID>(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<LPVOID>(funcRecvMsg)) != MH_OK) return -1;
|
||||
if (MH_RemoveHook(reinterpret_cast<LPVOID>(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<funcRecvPyq_t>(OsRecv::PYQ_CALL);
|
||||
if (InitializeHook() != MH_OK) return -1;
|
||||
if (MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast<LPVOID *>(&realRecvPyq)) != MH_OK) return -1;
|
||||
if (MH_EnableHook(funcRecvPyq) != MH_OK) return -1;
|
||||
if (MH_CreateHook(reinterpret_cast<LPVOID>(funcRecvPyq), reinterpret_cast<LPVOID>(&DispatchPyq), reinterpret_cast<LPVOID *>(&realRecvPyq)) != MH_OK) return -1;
|
||||
if (MH_EnableHook(reinterpret_cast<LPVOID>(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<LPVOID>(funcRecvPyq)) != MH_OK) return -1;
|
||||
if (MH_RemoveHook(reinterpret_cast<LPVOID>(funcRecvPyq)) != MH_OK) return -2;
|
||||
if (UninitializeHook() != MH_OK) return -3;
|
||||
isListeningPyq = false;
|
||||
return 0;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -4,14 +4,13 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#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<Functions_FUNC_RECV_TRANSFER>(
|
||||
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<Functions_FUNC_SHUTDOWN>(out, len, [&](Response &rsp) {
|
||||
rsp.msg.status = 0;
|
||||
std::thread([]() {
|
||||
Sleep(100);
|
||||
RpcServer::destroyInstance();
|
||||
Spy::Cleanup();
|
||||
}).detach();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
} // namespace misc
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#define MAGIC_ENUM_RANGE_MIN 0
|
||||
#define MAGIC_ENUM_RANGE_MAX 256
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "wcf.pb.h"
|
||||
@ -41,7 +43,8 @@ static const std::unordered_map<Functions, int> 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 <Functions FuncType, typename AssignFunc> bool fill_response(uint8_t *out, size_t *len, AssignFunc assign)
|
||||
{
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <nng/protocol/pair1/pair.h>
|
||||
#include <nng/supplemental/util/platform.h>
|
||||
|
||||
@ -214,7 +213,7 @@ bool RpcServer::start_message_listener(bool pyq, uint8_t *out, size_t *len)
|
||||
{
|
||||
return fill_response<Functions_FUNC_ENABLE_RECV_TXT>(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<Functions_FUNC_DISABLE_RECV_TXT>(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<Functions, RpcServer::FunctionHandler> 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
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,7 @@ int Init(void *args)
|
||||
auto *pp = static_cast<util::PortPath *>(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<uint64_t>(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;}
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
EXPORTS
|
||||
InitSpy
|
||||
CleanupSpy
|
@ -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<std::uintptr_t> WeChatDll { 0 };
|
||||
|
||||
template <typename T> inline T getFunction(std::uintptr_t offset) { return reinterpret_cast<T>(WeChatDll + offset); }
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
}
|
||||
|
8
clients/python/README.MD
vendored
8
clients/python/README.MD
vendored
@ -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
|
||||
* 没有新功能
|
||||
|
||||
<details><summary>点击查看更多</summary>
|
||||
|
||||
@ -71,7 +71,7 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc
|
||||
* 发送图片消息
|
||||
* 发送文件消息
|
||||
* 发送卡片消息
|
||||
* 发送 XML
|
||||
* 发送 XML 消息
|
||||
* 发送 GIF 消息
|
||||
* 拍一拍群友
|
||||
* 转发消息
|
||||
|
55
clients/python/wcferry/client.py
vendored
55
clients/python/wcferry/client.py
vendored
@ -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)
|
||||
|
48
clients/python/wcferry/wcf_pb2.py
vendored
48
clients/python/wcferry/wcf_pb2.py
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user