Resolve merge conflict

This commit is contained in:
Changhua 2024-07-26 21:50:39 +08:00
commit 59a4c318ff
48 changed files with 13976 additions and 4150 deletions

97
.github/workflows/Build-WeChatFerry.yml vendored Normal file
View File

@ -0,0 +1,97 @@
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-dependencies
uses: actions/cache@v4
with:
path: |
C:/Tools/vcpkg
key: ${{ runner.os }}-dependencies-${{ hashFiles('**/WeChatFerry/spy/spy.rc') }}
restore-keys: |
${{ runner.os }}-dependencies-
- name: 安装 vcpkg 和依赖项
run: |
cd C:/Tools
git clone https://github.com/microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
.\vcpkg\vcpkg install protobuf[zlib]:x64-windows-static
.\vcpkg\vcpkg install spdlog:x64-windows-static
.\vcpkg\vcpkg install nng:x64-windows-static
.\vcpkg\vcpkg install magic-enum:x64-windows-static
.\vcpkg\vcpkg install minhook:x64-windows-static
.\vcpkg\vcpkg integrate install
echo "VCPKG_ROOT=C:/Tools/vcpkg" >> $GITHUB_ENV
- 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" /verbosity:detailed
}
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" -DestinationPath "WeChatFerry/tmp/v${{ env.version }}.zip"
# Compress-Archive -Path "WeChatFerry/Out/*" -DestinationPath "WeChatFerry/tmp/v${{ env.version }}-debug.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/)

3
.gitmodules vendored
View File

@ -2,3 +2,6 @@
path = clients/node path = clients/node
url = https://github.com/stkevintan/node-wcferry url = https://github.com/stkevintan/node-wcferry
branch = main branch = main
[submodule "clients/wcferry-node"]
path = clients/wcferry-node
url = https://github.com/dr-forget/wcferry-node.git

View File

@ -16,36 +16,72 @@
</details> </details>
|[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/eMQgP1TiEqAxmpxYljSgeg)| |[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/I6n_6fuQa60CrROWSgq0TA)|
|:-:|:-:|:-:| |:-:|:-:|:-:|
👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。 👉 [WeChatRobot🤖](https://github.com/lich0821/WeChatRobot),一个基于 WeChatFerry 的 Python 机器人框架。
|![碲矿](assets/TEQuant.jpg)|![赞赏](assets/QR.jpeg)|
|:-:|:-:|
|后台回复 `WCF` 加群交流|如果你觉得有用|
<details><summary>点击查看功能清单</summary> <details><summary>点击查看功能清单</summary>
* 检查登录状态 * 查登录状态
* 获取登录账号信息wxid、昵称、手机号、数据目录 * 获取登录账号信息
* 获取消息类型 * 获取消息类型
* 获取联系人
* 获取可查询数据库
* 获取数据库所有表
* 获取语音消息
* 发送文本消息(可 @ * 发送文本消息(可 @
* 发送图片 * 发送图片消息
* 允许接收消息 * 发送文件消息
* 停止接收消息 * 发送卡片消息
* 发送 GIF 消息
* 拍一拍群友
* 转发消息
* 开启接收消息
* 关闭接收消息
* 查询数据库
* 获取朋友圈消息
* 下载图片、视频、文件
* 解密图片
* 添加群成员
* 删除群成员
* 邀请群成员
</details> </details>
<details><summary>点击查看支持的客户端</summary> <details><summary>点击查看支持的客户端</summary>
* Python * Python
* HTTP
* NodeJS
</details> </details>
|![碲矿](assets/TEQuant.jpg)|![赞赏](assets/QR.jpeg)| ## 快速开始
|:-:|:-:| ### Python
|后台回复 `WCF` 加群交流|如果你觉得有用| [![PyPi](https://img.shields.io/pypi/v/wcferry.svg)](https://pypi.python.org/pypi/wcferry) [![Downloads](https://static.pepy.tech/badge/wcferry)](https://pypi.python.org/pypi/wcferry) [![Documentation Status](https://readthedocs.org/projects/wechatferry/badge/?version=latest)](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
* 安装
```sh
pip install --upgrade wcferry
```
* 参考框架:[🤖WeChatRobot](https://github.com/lich0821/WeChatRobot)
### HTTP
#### [wcfrust](https://github.com/lich0821/wcf-client-rust)(基于 Rust
#### [go_wcf_http](clients/go_wcf_http/README.MD)(基于 Go
### [NodeJS](clients/wcferry-node)
## 一起开发 ## 一起开发
> 🚫 非开发用户不需要往下看。 > 🚫 非开发用户不需要往下看。
> **开发用户**:可以根据文档和错误提示,自行解决编译错误的人员。
### 安装开发环境 ### 安装开发环境
@ -150,16 +186,9 @@ WeChatFerry
## 版本更新 ## 版本更新
### v39.2.0 ### v39.2.4
* 开始适配 `3.9.10.27` * 修复 wxid 问题
* 实现检查登录状态
* 实现获取登录账号信息wxid、昵称、手机号、数据目录
* 实现获取消息类型
* 实现开启接收消息
* 实现停止接收消息
* 实现发送文本消息(可 @
* 实现发送图片消息
<details><summary>点击查看更多</summary> <details><summary>点击查看更多</summary>
@ -171,6 +200,29 @@ WeChatFerry
* `y` 是 `WeChatFerry` 的版本,从 0 开始 * `y` 是 `WeChatFerry` 的版本,从 0 开始
* `z` 是各客户端的版本,从 0 开始 * `z` 是各客户端的版本,从 0 开始
### v39.2.3
* 实现发送 GIF
### v39.2.2
* 修复开启、停止接收消息失败问题
### v39.2.1
* 实现了好多功能(见功能清单)
### v39.2.0
* 开始适配 `3.9.10.27`
* 实现检查登录状态
* 实现获取登录账号信息wxid、昵称、手机号、数据目录
* 实现获取消息类型
* 实现开启接收消息
* 实现停止接收消息
* 实现发送文本消息(可 @
* 实现发送图片消息
### v39.1.0 (2024.04.19) ### v39.1.0 (2024.04.19)
* 适配 x64 环境 * 适配 x64 环境

View File

@ -13,14 +13,18 @@ EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
Dev|x64 = Dev|x64
Release|x64 = Release|x64 Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.ActiveCfg = Debug|x64 {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.ActiveCfg = Debug|x64
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.Build.0 = Debug|x64 {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x64.Build.0 = Debug|x64
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Dev|x64.ActiveCfg = Dev|x64
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Dev|x64.Build.0 = Dev|x64
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.ActiveCfg = Release|x64 {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.ActiveCfg = Release|x64
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.Build.0 = Release|x64 {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x64.Build.0 = Release|x64
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x64.ActiveCfg = Debug|x64 {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x64.ActiveCfg = Debug|x64
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Dev|x64.ActiveCfg = Dev|x64
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.ActiveCfg = Release|x64 {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.ActiveCfg = Release|x64
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.Build.0 = Release|x64 {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection

View File

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <wchar.h> #include <wchar.h>
#include "log.h"
#include "util.h" #include "util.h"
#pragma comment(lib, "shlwapi") #pragma comment(lib, "shlwapi")
@ -179,6 +180,34 @@ DWORD GetWeChatPid()
return pid; return pid;
} }
enum class WindowsArchiture { x32, x64 };
static WindowsArchiture GetWindowsArchitecture()
{
#ifdef _WIN64
return WindowsArchiture::x64;
#else
return WindowsArchiture::x32;
#endif
}
BOOL IsProcessX64(DWORD pid)
{
BOOL isWow64 = false;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid);
if (!hProcess)
return false;
BOOL result = IsWow64Process(hProcess, &isWow64);
CloseHandle(hProcess);
if (!result)
return false;
if (isWow64)
return false;
else if (GetWindowsArchitecture() == WindowsArchiture::x32)
return false;
else
return true;
}
int OpenWeChat(DWORD *pid) int OpenWeChat(DWORD *pid)
{ {
*pid = GetWeChatPid(); *pid = GetWeChatPid();
@ -296,3 +325,23 @@ void DbgMsg(const char *zcFormat, ...)
OutputDebugStringA(strText.c_str()); OutputDebugStringA(strText.c_str());
} }
WxString *NewWxStringFromStr(const string &str) { return NewWxStringFromWstr(String2Wstring(str)); }
WxString *NewWxStringFromWstr(const wstring &ws)
{
WxString *p = (WxString *)HeapAlloc(GetProcessHeap(), 0, sizeof(WxString));
wchar_t *pWstring = (wchar_t *)HeapAlloc(GetProcessHeap(), 0, (ws.size() + 1) * 2);
if (p == NULL || pWstring == NULL) {
LOG_ERROR("Out of Memory...");
return NULL;
}
wmemcpy(pWstring, ws.c_str(), ws.size() + 1);
p->wptr = pWstring;
p->size = (DWORD)ws.size();
p->capacity = (DWORD)ws.size();
p->ptr = 0;
p->clen = 0;
return p;
}

View File

@ -3,6 +3,8 @@
#include <string> #include <string>
#include <minwindef.h> #include <minwindef.h>
#include "spy_types.h"
#define WECHAREXE L"WeChat.exe" #define WECHAREXE L"WeChat.exe"
#define WECHATWINDLL L"WeChatWin.dll" #define WECHATWINDLL L"WeChatWin.dll"
#define WCFSDKDLL L"sdk.dll" #define WCFSDKDLL L"sdk.dll"
@ -23,6 +25,7 @@ typedef struct PortPath {
} PortPath_t; } PortPath_t;
DWORD GetWeChatPid(); DWORD GetWeChatPid();
BOOL IsProcessX64(DWORD pid);
int OpenWeChat(DWORD *pid); int OpenWeChat(DWORD *pid);
int GetWeChatVersion(wchar_t *version); int GetWeChatVersion(wchar_t *version);
size_t GetWstringByAddress(UINT64 address, wchar_t *buffer, UINT64 buffer_size); size_t GetWstringByAddress(UINT64 address, wchar_t *buffer, UINT64 buffer_size);
@ -35,3 +38,5 @@ std::string GetStringByAddress(UINT64 address);
std::string GetStringByStrAddr(UINT64 addr); std::string GetStringByStrAddr(UINT64 addr);
std::string GetStringByWstrAddr(UINT64 addr); std::string GetStringByWstrAddr(UINT64 addr);
void DbgMsg(const char *zcFormat, ...); void DbgMsg(const char *zcFormat, ...);
WxString *NewWxStringFromStr(const std::string &str);
WxString *NewWxStringFromWstr(const std::wstring &ws);

View File

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Dev|x64">
<Configuration>Dev</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
@ -26,12 +22,13 @@
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<<<<<<< HEAD
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
@ -40,6 +37,9 @@
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
=======
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'" Label="Configuration">
>>>>>>> master
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
@ -57,44 +57,34 @@
</ImportGroup> </ImportGroup>
<ImportGroup Label="Shared"> <ImportGroup Label="Shared">
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic> <VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x64-windows-static</VcpkgTriplet> <VcpkgTriplet>x64-windows-static</VcpkgTriplet>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
@ -106,37 +96,7 @@
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile> <ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
<PostBuildEvent>
<Command>xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy files</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>

View File

@ -47,6 +47,11 @@ int WxInitSDK(bool debug, int port)
return status; return status;
} }
if (!IsProcessX64(wcPid)) {
MessageBox(NULL, L"只支持 64 位微信", L"WxInitSDK", 0);
return -1;
}
Sleep(2000); // 等待微信打开 Sleep(2000); // 等待微信打开
wcProcess = InjectDll(wcPid, spyDllPath, &spyBase); wcProcess = InjectDll(wcPid, spyDllPath, &spyBase);
if (wcProcess == NULL) { if (wcProcess == NULL) {

View File

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Dev|x64">
<Configuration>Dev</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
@ -24,16 +20,16 @@
<ProjectGuid>{4de80b82-5f6a-4c4c-9d16-1574308110fa}</ProjectGuid> <ProjectGuid>{4de80b82-5f6a-4c4c-9d16-1574308110fa}</ProjectGuid>
<RootNamespace>spy</RootNamespace> <RootNamespace>spy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet> <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<<<<<<< HEAD
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
@ -42,6 +38,9 @@
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
=======
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'" Label="Configuration">
>>>>>>> master
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset> <PlatformToolset>v143</PlatformToolset>
@ -59,141 +58,37 @@
</ImportGroup> </ImportGroup>
<ImportGroup Label="Shared"> <ImportGroup Label="Shared">
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<TargetName>$(ProjectName)_debug</TargetName> <TargetName>$(ProjectName)_debug</TargetName>
<PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'">
<LinkIncremental>false</LinkIncremental>
<PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<TargetName>$(ProjectName)_debug</TargetName> <TargetName>$(ProjectName)_debug</TargetName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic> <VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgConfiguration>Release</VcpkgConfiguration> <VcpkgConfiguration>Release</VcpkgConfiguration>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'" Label="Vcpkg">
<VcpkgUseStatic>true</VcpkgUseStatic> <VcpkgUseStatic>true</VcpkgUseStatic>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgUseStatic>true</VcpkgUseStatic> <VcpkgUseStatic>true</VcpkgUseStatic>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
<PrecompiledHeaderOutputFile />
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(SolutionDir)smc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions> /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
<PostBuildEvent>
<Command>if not exist $(SolutionDir)Out md $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
</PostBuildEvent>
<PreBuildEvent>
<Command>cd $(SolutionDir)rpc\proto
$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Generating PB files</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
<PrecompiledHeaderOutputFile />
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
<AdditionalLibraryDirectories>$(SolutionDir)smc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions> /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
</Link>
<PostBuildEvent>
<Command>if not exist $(SolutionDir)Out md $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
</PostBuildEvent>
<PreBuildEvent>
<Command>cd $(SolutionDir)rpc\proto
$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Generating PB files</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
@ -236,6 +131,55 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;ENABLE_WX_LOG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)com;$(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)smc;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x64-windows-static\include</AdditionalIncludeDirectories>
<IntrinsicFunctions>true</IntrinsicFunctions>
<OmitFramePointers>false</OmitFramePointers>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<PrecompiledHeaderOutputFile>
</PrecompiledHeaderOutputFile>
<DisableSpecificWarnings>4251;4731;4819</DisableSpecificWarnings>
<AdditionalOptions>/EHa %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
<AdditionalOptions> /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
<AdditionalLibraryDirectories>$(SolutionDir)smc;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;Codec.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>cd $(SolutionDir)rpc\proto
$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>Generating PB files</Message>
</PreBuildEvent>
<PostBuildEvent>
<Command>if not exist $(SolutionDir)Out md $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out
xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command> xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Command>
</PostBuildEvent> </PostBuildEvent>
<PostBuildEvent> <PostBuildEvent>
@ -303,9 +247,7 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Com
<ClInclude Include="exec_sql.h" /> <ClInclude Include="exec_sql.h" />
<ClInclude Include="framework.h" /> <ClInclude Include="framework.h" />
<ClInclude Include="contact_mgmt.h" /> <ClInclude Include="contact_mgmt.h" />
<ClInclude Include="load_calls.h" />
<ClInclude Include="receive_msg.h" /> <ClInclude Include="receive_msg.h" />
<ClInclude Include="receive_transfer.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="rpc_server.h" /> <ClInclude Include="rpc_server.h" />
<ClInclude Include="send_msg.h" /> <ClInclude Include="send_msg.h" />
@ -328,9 +270,7 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry</Com
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="exec_sql.cpp" /> <ClCompile Include="exec_sql.cpp" />
<ClCompile Include="contact_mgmt.cpp" /> <ClCompile Include="contact_mgmt.cpp" />
<ClCompile Include="load_calls.cpp" />
<ClCompile Include="receive_msg.cpp" /> <ClCompile Include="receive_msg.cpp" />
<ClCompile Include="receive_transfer.cpp" />
<ClCompile Include="rpc_server.cpp" /> <ClCompile Include="rpc_server.cpp" />
<ClCompile Include="send_msg.cpp" /> <ClCompile Include="send_msg.cpp" />
<ClCompile Include="spy.cpp" /> <ClCompile Include="spy.cpp" />

View File

@ -30,9 +30,6 @@
<ClInclude Include="contact_mgmt.h"> <ClInclude Include="contact_mgmt.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="load_calls.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="receive_msg.h"> <ClInclude Include="receive_msg.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
@ -78,9 +75,6 @@
<ClInclude Include="funcs.h"> <ClInclude Include="funcs.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="receive_transfer.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="sqlite3.h"> <ClInclude Include="sqlite3.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
@ -110,9 +104,6 @@
<ClCompile Include="contact_mgmt.cpp"> <ClCompile Include="contact_mgmt.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="load_calls.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="receive_msg.cpp"> <ClCompile Include="receive_msg.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
@ -146,9 +137,6 @@
<ClCompile Include="funcs.cpp"> <ClCompile Include="funcs.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="receive_transfer.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\com\log.cpp"> <ClCompile Include="..\com\log.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>

View File

@ -3,122 +3,33 @@
#include <vector> #include <vector>
#include "chatroom_mgmt.h" #include "chatroom_mgmt.h"
#include "load_calls.h"
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
using namespace std; using namespace std;
extern QWORD g_WeChatWinDllAddr;
#define OS_GET_CHATROOM_MGR 0x1C4E200
#define OS_ADD_MEMBERS 0x221B8A0
#define OS_DELETE_MEMBERS 0x221BEE0
#define OS_INVITE_MEMBERS 0x221B280
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);
extern WxCalls_t g_WxCalls;
extern UINT64 g_WeChatWinDllAddr;
#if 0
int AddChatroomMember(string roomid, string wxids) int AddChatroomMember(string roomid, string wxids)
{ {
int status = -1;
if (roomid.empty() || wxids.empty()) { if (roomid.empty() || wxids.empty()) {
LOG_ERROR("Empty roomid or wxids."); LOG_ERROR("Empty roomid or wxids.");
return -1; return status;
} }
int rv = 0; GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR);
DWORD armCall1 = g_WeChatWinDllAddr + g_WxCalls.arm.call1; AddMemberToChatRoom_t AddMembers = (AddMemberToChatRoom_t)(g_WeChatWinDllAddr + OS_ADD_MEMBERS);
DWORD armCall2 = g_WeChatWinDllAddr + g_WxCalls.arm.call2;
DWORD armCall3 = g_WeChatWinDllAddr + g_WxCalls.arm.call3;
DWORD temp = 0;
wstring wsRoomid = String2Wstring(roomid);
WxString wxRoomid(wsRoomid);
vector<wstring> vMembers;
vector<WxString> vWxMembers;
wstringstream wss(String2Wstring(wxids));
while (wss.good()) {
wstring wstr;
getline(wss, wstr, L',');
vMembers.push_back(wstr);
WxString txtMember(vMembers.back());
vWxMembers.push_back(txtMember);
}
LOG_DEBUG("Adding {} members[{}] to {}", vWxMembers.size(), wxids.c_str(), roomid.c_str());
__asm {
pushad;
pushfd;
call armCall1;
sub esp, 0x8;
mov temp, eax;
mov ecx, esp;
mov dword ptr[ecx], 0x0;
mov dword ptr[ecx + 4], 0x0;
test esi, esi;
sub esp, 0x14;
mov ecx, esp;
lea eax, wxRoomid;
push eax;
call armCall2;
mov ecx, temp;
lea eax, vWxMembers;
push eax;
call armCall3;
mov rv, eax;
popfd;
popad;
}
return rv;
}
int DelChatroomMember(string roomid, string wxids)
{
if (roomid.empty() || wxids.empty()) {
LOG_ERROR("Empty roomid or wxids.");
return -1;
}
int rv = 0;
DWORD drmCall1 = g_WeChatWinDllAddr + g_WxCalls.drm.call1;
DWORD drmCall2 = g_WeChatWinDllAddr + g_WxCalls.drm.call2;
DWORD drmCall3 = g_WeChatWinDllAddr + g_WxCalls.drm.call3;
DWORD temp = 0;
wstring wsRoomid = String2Wstring(roomid);
WxString wxRoomid(wsRoomid);
vector<wstring> vMembers;
vector<WxString> vWxMembers;
wstringstream wss(String2Wstring(wxids));
while (wss.good()) {
wstring wstr;
getline(wss, wstr, L',');
vMembers.push_back(wstr);
WxString txtMember(vMembers.back());
vWxMembers.push_back(txtMember);
}
LOG_DEBUG("Deleting {} members[{}] from {}", vWxMembers.size(), wxids.c_str(), roomid.c_str());
__asm {
pushad;
pushfd;
call drmCall1;
sub esp, 0x14;
mov esi, eax;
mov ecx, esp;
lea edi, wxRoomid;
push edi;
call drmCall2;
mov ecx, esi;
lea eax, vWxMembers;
push eax;
call drmCall3;
mov rv, eax;
popfd;
popad;
}
return rv;
}
int InviteChatroomMember(string roomid, string wxids)
{
wstring wsRoomid = String2Wstring((roomid));
WxString wxRoomid(wsRoomid);
vector<wstring> vMembers; vector<wstring> vMembers;
vector<WxString> vWxMembers; vector<WxString> vWxMembers;
@ -131,51 +42,72 @@ int InviteChatroomMember(string roomid, string wxids)
vWxMembers.push_back(wxMember); vWxMembers.push_back(wxMember);
} }
LOG_DEBUG("Inviting {} members[{}] to {}", vWxMembers.size(), wxids.c_str(), roomid.c_str()); QWORD temp[2] = { 0 };
WxString *pWxRoomid = NewWxStringFromStr(roomid);
QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start;
DWORD irmCall1 = g_WeChatWinDllAddr + g_WxCalls.irm.call1; QWORD mgr = GetChatRoomMgr();
DWORD irmCall2 = g_WeChatWinDllAddr + g_WxCalls.irm.call2; status = (int)AddMembers(mgr, pMembers, (QWORD)pWxRoomid, (QWORD)temp);
DWORD irmCall3 = g_WeChatWinDllAddr + g_WxCalls.irm.call3; return status;
DWORD irmCall4 = g_WeChatWinDllAddr + g_WxCalls.irm.call4; }
DWORD irmCall5 = g_WeChatWinDllAddr + g_WxCalls.irm.call5;
DWORD irmCall6 = g_WeChatWinDllAddr + g_WxCalls.irm.call6; int DelChatroomMember(string roomid, string wxids)
DWORD irmCall7 = g_WeChatWinDllAddr + g_WxCalls.irm.call7; {
DWORD irmCall8 = g_WeChatWinDllAddr + g_WxCalls.irm.call8; int status = -1;
DWORD sys_addr = (DWORD)GetModuleHandleA("win32u.dll") + 0x116C; if (roomid.empty() || wxids.empty()) {
DWORD addr[2] = { sys_addr, 0 }; LOG_ERROR("Empty roomid or wxids.");
__asm { return status;
pushad; }
pushfd;
call irmCall1; GetChatRoomMgr_t GetChatRoomMgr = (GetChatRoomMgr_t)(g_WeChatWinDllAddr + OS_GET_CHATROOM_MGR);
lea ecx, addr; DelMemberFromChatRoom_t DelMembers = (DelMemberFromChatRoom_t)(g_WeChatWinDllAddr + OS_DELETE_MEMBERS);
push ecx;
mov ecx, eax; vector<wstring> vMembers;
call irmCall2; vector<WxString> vWxMembers;
call irmCall3; wstringstream wss(String2Wstring(wxids));
sub esp, 0x8; while (wss.good()) {
lea eax, addr; wstring wstr;
mov ecx, esp; getline(wss, wstr, L',');
push eax; vMembers.push_back(wstr);
call irmCall4; WxString wxMember(vMembers.back());
sub esp, 0x14; vWxMembers.push_back(wxMember);
mov ecx, esp; }
lea eax, wxRoomid;
push eax; WxString *pWxRoomid = NewWxStringFromStr(roomid);
call irmCall5; QWORD pMembers = (QWORD) & ((RawVector_t *)&vWxMembers)->start;
lea eax, vWxMembers;
push eax; QWORD mgr = GetChatRoomMgr();
call irmCall6; status = (int)DelMembers(mgr, pMembers, (QWORD)pWxRoomid);
call irmCall1; return status;
push 0x0; }
push 0x1;
mov ecx, eax; int InviteChatroomMember(string roomid, string wxids)
call irmCall7; {
lea ecx, addr; int status = -1;
call irmCall8;
popfd; if (roomid.empty() || wxids.empty()) {
popad; LOG_ERROR("Empty roomid or wxids.");
} return status;
return 1; }
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;
} }
#endif

View File

@ -1,25 +1,37 @@
#pragma execution_character_set("utf-8") #pragma execution_character_set("utf-8")
#include "contact_mgmt.h" #include "contact_mgmt.h"
#include "load_calls.h"
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
using namespace std; using namespace std;
extern WxCalls_t g_WxCalls; extern QWORD g_WeChatWinDllAddr;
extern UINT64 g_WeChatWinDllAddr;
#if 0 #define OS_GET_CONTACT_MGR 0x1C0BDE0
#define OS_GET_CONTACT_LIST 0x2265540
#define OS_CONTACT_BIN 0x200
#define OS_CONTACT_BIN_LEN 0x208
#define OS_CONTACT_WXID 0x10
#define OS_CONTACT_CODE 0x30
#define OS_CONTACT_REMARK 0x80
#define OS_CONTACT_NAME 0xA0
#define OS_CONTACT_GENDER 0x0E
#define OS_CONTACT_STEP 0x6A8
typedef QWORD (*GetContactMgr_t)();
typedef QWORD (*GetContactList_t)(QWORD, QWORD);
#define FEAT_LEN 5 #define FEAT_LEN 5
static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 }; static const uint8_t FEAT_COUNTRY[FEAT_LEN] = { 0xA4, 0xD9, 0x02, 0x4A, 0x18 };
static const uint8_t FEAT_PROVINCE[FEAT_LEN] = { 0xE2, 0xEA, 0xA8, 0xD1, 0x18 }; static const uint8_t FEAT_PROVINCE[FEAT_LEN] = { 0xE2, 0xEA, 0xA8, 0xD1, 0x18 };
static const uint8_t FEAT_CITY[FEAT_LEN] = { 0x1D, 0x02, 0x5B, 0xBF, 0x18 }; static const uint8_t FEAT_CITY[FEAT_LEN] = { 0x1D, 0x02, 0x5B, 0xBF, 0x18 };
static DWORD FindMem(DWORD start, DWORD end, const void *target, size_t len) static QWORD FindMem(QWORD start, QWORD end, const void *target, size_t len)
{ {
uint8_t *p = (uint8_t *)start; uint8_t *p = (uint8_t *)start;
while ((DWORD)p < end) { while ((QWORD)p < end) {
if (memcmp((void *)p, target, len) == 0) { if (memcmp((void *)p, target, len) == 0) {
return (DWORD)p; return (QWORD)p;
} }
p++; p++;
} }
@ -27,9 +39,9 @@ static DWORD FindMem(DWORD start, DWORD end, const void *target, size_t len)
return 0; return 0;
} }
static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t len) static string GetCntString(QWORD start, QWORD end, const uint8_t *feat, size_t len)
{ {
DWORD pfeat = FindMem(start, end, feat, len); QWORD pfeat = FindMem(start, end, feat, len);
if (pfeat == 0) { if (pfeat == 0) {
return ""; return "";
} }
@ -45,34 +57,27 @@ static string GetCntString(DWORD start, DWORD end, const uint8_t *feat, size_t l
vector<RpcContact_t> GetContacts() vector<RpcContact_t> GetContacts()
{ {
vector<RpcContact_t> contacts; vector<RpcContact_t> contacts;
DWORD call1 = g_WeChatWinDllAddr + g_WxCalls.contact.base; GetContactMgr_t funcGetContactMgr = (GetContactMgr_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_MGR);
DWORD call2 = g_WeChatWinDllAddr + g_WxCalls.contact.head; GetContactList_t funcGetContactList = (GetContactList_t)(g_WeChatWinDllAddr + OS_GET_CONTACT_LIST);
int success = 0; QWORD mgr = funcGetContactMgr();
DWORD *addr[3] = { 0, 0, 0 }; QWORD addr[3] = { 0 };
__asm { if (funcGetContactList(mgr, (QWORD)addr) != 1) {
pushad LOG_ERROR("GetContacts failed");
call call1 return contacts;
lea ecx,addr
push ecx
mov ecx,eax
call call2
mov success,eax
popad
} }
DWORD pstart = (DWORD)addr[0]; QWORD pstart = (QWORD)addr[0];
DWORD pend = (DWORD)addr[2]; QWORD pend = (QWORD)addr[2];
while (pstart < pend) { while (pstart < pend) {
RpcContact_t cnt; RpcContact_t cnt;
DWORD pbin = GET_DWORD(pstart + 0x150); QWORD pbin = GET_QWORD(pstart + OS_CONTACT_BIN);
DWORD lenbin = GET_DWORD(pstart + 0x154); QWORD lenbin = GET_DWORD(pstart + OS_CONTACT_BIN_LEN);
cnt.wxid = GetStringByAddress(pstart + g_WxCalls.contact.wxId); cnt.wxid = GetStringByWstrAddr(pstart + OS_CONTACT_WXID);
cnt.code = GetStringByAddress(pstart + g_WxCalls.contact.wxCode); cnt.code = GetStringByWstrAddr(pstart + OS_CONTACT_CODE);
cnt.remark = GetStringByAddress(pstart + g_WxCalls.contact.wxRemark); cnt.remark = GetStringByWstrAddr(pstart + OS_CONTACT_REMARK);
cnt.name = GetStringByAddress(pstart + g_WxCalls.contact.wxName); cnt.name = GetStringByWstrAddr(pstart + OS_CONTACT_NAME);
cnt.country = GetCntString(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN); cnt.country = GetCntString(pbin, pbin + lenbin, FEAT_COUNTRY, FEAT_LEN);
cnt.province = GetCntString(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN); cnt.province = GetCntString(pbin, pbin + lenbin, FEAT_PROVINCE, FEAT_LEN);
@ -81,16 +86,17 @@ vector<RpcContact_t> GetContacts()
if (pbin == 0) { if (pbin == 0) {
cnt.gender = 0; cnt.gender = 0;
} else { } else {
cnt.gender = (DWORD) * (uint8_t *)(pbin + g_WxCalls.contact.wxGender); cnt.gender = (DWORD) * (uint8_t *)(pbin + OS_CONTACT_GENDER);
} }
contacts.push_back(cnt); contacts.push_back(cnt);
pstart += 0x438; pstart += OS_CONTACT_STEP;
} }
return contacts; return contacts;
} }
#if 0
int AcceptNewFriend(string v3, string v4, int scene) int AcceptNewFriend(string v3, string v4, int scene)
{ {
int success = 0; int success = 0;

View File

@ -1,7 +1,11 @@
#include <iterator> #include <iterator>
#include "exec_sql.h" #include "exec_sql.h"
<<<<<<< HEAD
#include "load_calls.h" #include "load_calls.h"
=======
#include "log.h"
>>>>>>> master
#include "sqlite3.h" #include "sqlite3.h"
#include "util.h" #include "util.h"

View File

@ -12,6 +12,12 @@
#include "util.h" #include "util.h"
#include "wechat_function.h" #include "wechat_function.h"
using namespace std;
namespace fs = std::filesystem;
extern bool gIsListeningPyq;
extern QWORD g_WeChatWinDllAddr;
#define HEADER_PNG1 0x89 #define HEADER_PNG1 0x89
#define HEADER_PNG2 0x50 #define HEADER_PNG2 0x50
#define HEADER_JPG1 0xFF #define HEADER_JPG1 0xFF
@ -19,14 +25,36 @@
#define HEADER_GIF1 0x47 #define HEADER_GIF1 0x47
#define HEADER_GIF2 0x49 #define HEADER_GIF2 0x49
using namespace std; #define OS_LOGIN_STATUS 0x5AB86A8
namespace fs = std::filesystem; #define OS_GET_SNS_DATA_MGR 0x22A91C0
#define OS_GET_SNS_FIRST_PAGE 0x2ED9080
#define OS_GET_SNS_TIMELINE_MGR 0x2E6B110
#define OS_GET_SNS_NEXT_PAGE 0x2EFEC00
#define OS_NEW_CHAT_MSG 0x1C28800
#define OS_FREE_CHAT_MSG 0x1C1FF10
#define OS_GET_CHAT_MGR 0x1C51CF0
#define OS_GET_MGR_BY_PREFIX_LOCAL_ID 0x2206280
#define OS_GET_PRE_DOWNLOAD_MGR 0x1CD87E0
#define OS_PUSH_ATTACH_TASK 0x1DA69C0
extern bool gIsListeningPyq; typedef QWORD (*GetSNSDataMgr_t)();
extern WxCalls_t g_WxCalls; typedef QWORD (*GetSnsTimeLineMgr_t)();
extern UINT64 g_WeChatWinDllAddr; typedef QWORD (*GetSNSFirstPage_t)(QWORD, QWORD, QWORD);
typedef QWORD (*GetSNSNextPageScene_t)(QWORD, QWORD);
typedef QWORD (*GetChatMgr_t)();
typedef QWORD (*NewChatMsg_t)(QWORD);
typedef QWORD (*FreeChatMsg_t)(QWORD);
typedef QWORD (*GetPreDownLoadMgr_t)();
typedef QWORD (*GetMgrByPrefixLocalId_t)(QWORD, QWORD);
typedef QWORD (*PushAttachTask_t)(QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*GetOCRManager_t)();
typedef QWORD (*DoOCRTask_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
<<<<<<< HEAD
int IsLogin(void) { return (int)GET_UINT64(g_WeChatWinDllAddr + offset::wcf_kLoginStatu); } int IsLogin(void) { return (int)GET_UINT64(g_WeChatWinDllAddr + offset::wcf_kLoginStatu); }
=======
int IsLogin(void) { return (int)GET_QWORD(g_WeChatWinDllAddr + OS_LOGIN_STATUS); }
>>>>>>> master
#if 0 #if 0
static string get_key(uint8_t header1, uint8_t header2, uint8_t *key) static string get_key(uint8_t header1, uint8_t header2, uint8_t *key)
@ -117,53 +145,32 @@ string DecryptImage(string src, string dir)
static int GetFirstPage() static int GetFirstPage()
{ {
int rv = -1; int status = -1;
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
DWORD pyqCall2 = g_WeChatWinDllAddr + g_WxCalls.pyq.call2;
char buf[0xB44] = { 0 }; GetSNSDataMgr_t GetSNSDataMgr = (GetSNSDataMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_DATA_MGR);
__asm { GetSNSFirstPage_t GetSNSFirstPage = (GetSNSFirstPage_t)(g_WeChatWinDllAddr + OS_GET_SNS_FIRST_PAGE);
pushad;
call pyqCall1;
push 0x1;
lea ecx, buf;
push ecx;
mov ecx, eax;
call pyqCall2;
mov rv, eax;
popad;
}
return rv; QWORD buff[16] = { 0 };
QWORD mgr = GetSNSDataMgr();
status = (int)GetSNSFirstPage(mgr, (QWORD)buff, 1);
return status;
} }
static int GetNextPage(uint64_t id) static int GetNextPage(QWORD id)
{ {
int rv = -1; int status = -1;
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
DWORD pyqCall3 = g_WeChatWinDllAddr + g_WxCalls.pyq.call3;
RawVector_t tmp = { 0 }; GetSnsTimeLineMgr_t GetSnsTimeLineMgr = (GetSnsTimeLineMgr_t)(g_WeChatWinDllAddr + OS_GET_SNS_TIMELINE_MGR);
GetSNSNextPageScene_t GetSNSNextPageScene = (GetSNSNextPageScene_t)(g_WeChatWinDllAddr + OS_GET_SNS_NEXT_PAGE);
__asm { QWORD mgr = GetSnsTimeLineMgr();
pushad; status = (int)GetSNSNextPageScene(mgr, id);
call pyqCall1;
lea ecx, tmp;
push ecx;
mov ebx, dword ptr [id + 0x04];
push ebx;
mov edi, dword ptr [id]
push edi;
mov ecx, eax;
call pyqCall3;
mov rv, eax;
popad;
}
return rv; return status;
} }
int RefreshPyq(uint64_t id) int RefreshPyq(QWORD id)
{ {
if (!gIsListeningPyq) { if (!gIsListeningPyq) {
LOG_ERROR("没有启动朋友圈消息接收参考enable_receiving_msg"); LOG_ERROR("没有启动朋友圈消息接收参考enable_receiving_msg");
@ -177,13 +184,21 @@ int RefreshPyq(uint64_t id)
return GetNextPage(id); return GetNextPage(id);
} }
int DownloadAttach(uint64_t id, string thumb, string extra) /*******************************************************************************
*
*
*
* id id
* thumb mp4
* extra
*******************************************************************************/
int DownloadAttach(QWORD id, string thumb, string extra)
{ {
int status = -1; int status = -1;
uint64_t localId; QWORD localId;
uint32_t dbIdx; uint32_t dbIdx;
if (fs::exists(extra)) { // 第一道,不重复下载 if (fs::exists(extra)) { // 第一道,不重复下载。TODO: 通过文件大小来判断
return 0; return 0;
} }
@ -192,30 +207,29 @@ int DownloadAttach(uint64_t id, string thumb, string extra)
return status; return status;
} }
char buff[0x2D8] = { 0 }; NewChatMsg_t NewChatMsg = (NewChatMsg_t)(g_WeChatWinDllAddr + OS_NEW_CHAT_MSG);
DWORD dlCall1 = g_WeChatWinDllAddr + g_WxCalls.da.call1; FreeChatMsg_t FreeChatMsg = (FreeChatMsg_t)(g_WeChatWinDllAddr + OS_FREE_CHAT_MSG);
DWORD dlCall2 = g_WeChatWinDllAddr + g_WxCalls.da.call2; GetChatMgr_t GetChatMgr = (GetChatMgr_t)(g_WeChatWinDllAddr + OS_GET_CHAT_MGR);
DWORD dlCall3 = g_WeChatWinDllAddr + g_WxCalls.da.call3; GetPreDownLoadMgr_t GetPreDownLoadMgr = (GetPreDownLoadMgr_t)(g_WeChatWinDllAddr + OS_GET_PRE_DOWNLOAD_MGR);
DWORD dlCall4 = g_WeChatWinDllAddr + g_WxCalls.da.call4; PushAttachTask_t PushAttachTask = (PushAttachTask_t)(g_WeChatWinDllAddr + OS_PUSH_ATTACH_TASK);
DWORD dlCall5 = g_WeChatWinDllAddr + g_WxCalls.da.call5; GetMgrByPrefixLocalId_t GetMgrByPrefixLocalId
DWORD dlCall6 = g_WeChatWinDllAddr + g_WxCalls.da.call6; = (GetMgrByPrefixLocalId_t)(g_WeChatWinDllAddr + OS_GET_MGR_BY_PREFIX_LOCAL_ID);
__asm { LARGE_INTEGER l;
pushad; l.HighPart = dbIdx;
pushfd; l.LowPart = (DWORD)localId;
lea ecx, buff;
call dlCall1; char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, 0x460);
call dlCall2; if (buff == nullptr) {
push dword ptr [dbIdx]; LOG_ERROR("Failed to allocate memory.");
lea ecx, buff; return status;
push dword ptr [localId];
call dlCall3;
add esp, 0x8;
popfd;
popad;
} }
DWORD type = GET_DWORD(buff + 0x38); QWORD pChatMsg = NewChatMsg((QWORD)buff);
GetChatMgr();
GetMgrByPrefixLocalId(l.QuadPart, pChatMsg);
QWORD type = GET_QWORD(buff + 0x38);
string save_path = ""; string save_path = "";
string thumb_path = ""; string thumb_path = "";
@ -239,7 +253,7 @@ int DownloadAttach(uint64_t id, string thumb, string extra)
break; break;
} }
if (fs::exists(save_path)) { // 不重复下载 if (fs::exists(save_path)) { // 不重复下载。TODO: 通过文件大小来判断
return 0; return 0;
} }
@ -247,38 +261,22 @@ int DownloadAttach(uint64_t id, string thumb, string extra)
// 创建父目录,由于路径来源于微信,不做检查 // 创建父目录,由于路径来源于微信,不做检查
fs::create_directory(fs::path(save_path).parent_path().string()); fs::create_directory(fs::path(save_path).parent_path().string());
wstring wsSavePath = String2Wstring(save_path); int temp = 1;
wstring wsThumbPath = String2Wstring(thumb_path); WxString *pSavePath = NewWxStringFromStr(save_path);
WxString *pThumbPath = NewWxStringFromStr(thumb_path);
WxString wxSavePath(wsSavePath); memcpy(&buff[0x280], pThumbPath, sizeof(WxString));
WxString wxThumbPath(wsThumbPath); memcpy(&buff[0x2A0], pSavePath, sizeof(WxString));
memcpy(&buff[0x40C], &temp, sizeof(temp));
int temp = 1; QWORD mgr = GetPreDownLoadMgr();
memcpy(&buff[0x19C], &wxThumbPath, sizeof(wxThumbPath)); status = (int)PushAttachTask(mgr, pChatMsg, 0, 1);
memcpy(&buff[0x1B0], &wxSavePath, sizeof(wxSavePath)); FreeChatMsg(pChatMsg);
memcpy(&buff[0x29C], &temp, sizeof(temp));
__asm {
pushad;
pushfd;
call dlCall4;
push 0x1;
push 0x0;
lea ecx, buff;
push ecx;
mov ecx, eax;
call dlCall5;
mov status, eax;
lea ecx, buff;
push 0x0;
call dlCall6;
popfd;
popad;
}
return status; return status;
} }
<<<<<<< HEAD
int RevokeMsg(uint64_t id) int RevokeMsg(uint64_t id)
{ {
int status = -1; int status = -1;
@ -325,6 +323,9 @@ int RevokeMsg(uint64_t id)
} }
string GetAudio(uint64_t id, string dir) string GetAudio(uint64_t id, string dir)
=======
string GetAudio(QWORD id, string dir)
>>>>>>> master
{ {
string mp3path = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/"); string mp3path = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
mp3path += to_string(id) + ".mp3"; mp3path += to_string(id) + ".mp3";
@ -347,104 +348,66 @@ string GetAudio(uint64_t id, string dir)
OcrResult_t GetOcrResult(string path) OcrResult_t GetOcrResult(string path)
{ {
OcrResult_t ret = { -1, "" }; OcrResult_t ret = { -1, "" };
#if 0 // 参数没调好,会抛异常,看看有没有好心人来修复
if (!fs::exists(path)) { if (!fs::exists(path)) {
LOG_ERROR("Can not find: {}", path); LOG_ERROR("Can not find: {}", path);
return ret; return ret;
} }
GetOCRManager_t GetOCRManager = (GetOCRManager_t)(g_WeChatWinDllAddr + 0x1D6C3C0);
DoOCRTask_t DoOCRTask = (DoOCRTask_t)(g_WeChatWinDllAddr + 0x2D10BC0);
QWORD unk1 = 0, unk2 = 0, unused = 0;
QWORD *pUnk1 = &unk1;
QWORD *pUnk2 = &unk2;
// 路径分隔符有要求,必须为 `\` // 路径分隔符有要求,必须为 `\`
wstring wsPath = String2Wstring(fs::path(path).make_preferred().string()); wstring wsPath = String2Wstring(fs::path(path).make_preferred().string());
WxString wxPath(wsPath); WxString wxPath(wsPath);
WxString nullObj; vector<QWORD> *pv = (vector<QWORD> *)HeapAlloc(GetProcessHeap(), 0, 0x20);
WxString ocrBuffer; RawVector_t *pRv = (RawVector_t *)pv;
pRv->finish = pRv->start;
char buff[0x98] = { 0 };
memcpy(buff, &pRv->start, sizeof(QWORD));
DWORD ocrCall1 = g_WeChatWinDllAddr + g_WxCalls.ocr.call1; QWORD mgr = GetOCRManager();
DWORD ocrCall2 = g_WeChatWinDllAddr + g_WxCalls.ocr.call2; ret.status = (int)DoOCRTask(mgr, (QWORD)&wxPath, unused, (QWORD)buff, (QWORD)&pUnk1, (QWORD)&pUnk2);
DWORD ocrCall3 = g_WeChatWinDllAddr + g_WxCalls.ocr.call3;
DWORD tmp = 0; QWORD count = GET_QWORD(buff + 0x8);
int status = -1; if (count > 0) {
__asm { QWORD header = GET_QWORD(buff);
pushad; for (QWORD i = 0; i < count; i++) {
pushfd; QWORD content = GET_QWORD(header);
lea ecx, ocrBuffer; ret.result += Wstring2String(GET_WSTRING(content + 0x28));
call ocrCall1; ret.result += "\n";
call ocrCall2; header = content;
lea ecx, nullObj; }
push ecx;
lea ecx, tmp;
push ecx;
lea ecx, ocrBuffer;
push ecx;
push 0x0;
lea ecx, wxPath;
push ecx;
mov ecx, eax;
call ocrCall3;
mov status, eax;
popfd;
popad;
} }
#endif
if (status != 0)
{
LOG_ERROR("OCR status: {}", to_string(status));
return ret; // 识别出错
}
ret.status = status;
DWORD addr = (DWORD)&ocrBuffer;
DWORD header = GET_DWORD(addr);
DWORD num = GET_DWORD(addr + 0x4);
if (num <= 0) {
return ret; // 识别内容为空
}
for (uint32_t i = 0; i < num; i++) {
DWORD content = GET_DWORD(header);
ret.result += Wstring2String(GET_WSTRING(content + 0x14));
ret.result += "\n";
header = content;
}
return ret; return ret;
} }
int RevokeMsg(QWORD id)
{
int status = -1;
#if 0 // 这个挺鸡肋的,因为自己发的消息没法直接获得 msgid就这样吧
QWORD localId;
uint32_t dbIdx;
if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) {
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id));
return status;
}
#endif
return status;
}
string GetLoginUrl() string GetLoginUrl()
{ {
if (GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.login) == 1) { char url[] = "方法还没实现";
LOG_DEBUG("Already logined.");
return ""; // 已登录直接返回空字符
}
DWORD refreshLoginQrcodeCall1 = g_WeChatWinDllAddr + g_WxCalls.rlq.call1;
DWORD refreshLoginQrcodeCall2 = g_WeChatWinDllAddr + g_WxCalls.rlq.call2;
// 刷新二维码
__asm {
pushad;
pushfd;
call refreshLoginQrcodeCall1;
mov ecx, eax;
call refreshLoginQrcodeCall2;
popfd;
popad;
}
// 获取二维码链接
char *url = GET_STRING(g_WeChatWinDllAddr + g_WxCalls.rlq.url);
uint8_t cnt = 0;
while (url[0] == 0) { // 刷新需要时间,太快了会获取不到
if (cnt > 5) {
LOG_ERROR("Refresh QR Code timeout.");
return "";
}
Sleep(1000);
cnt++;
}
return "http://weixin.qq.com/x/" + string(url); return "http://weixin.qq.com/x/" + string(url);
} }
#endif
int ReceiveTransfer(string wxid, string transferid, string transactionid)
{
// 别想了,这个不实现了
return -1;
}

View File

@ -11,3 +11,4 @@ int DownloadAttach(uint64_t id, std::string thumb, std::string extra);
int RevokeMsg(uint64_t id); int RevokeMsg(uint64_t id);
OcrResult_t GetOcrResult(std::string path); OcrResult_t GetOcrResult(std::string path);
string GetLoginUrl(); string GetLoginUrl();
int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid);

View File

@ -1,5 +0,0 @@
#pragma once
#include "spy_types.h"
int LoadCalls(const wchar_t *version, WxCalls_t *calls);

View File

@ -6,7 +6,6 @@
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include "load_calls.h"
#include "log.h" #include "log.h"
#include "receive_msg.h" #include "receive_msg.h"
#include "user_info.h" #include "user_info.h"
@ -14,18 +13,46 @@
#include "wechat_function.h" #include "wechat_function.h"
// Defined in rpc_server.cpp // Defined in rpc_server.cpp
extern bool gIsListening, gIsListeningPyq; extern bool gIsLogging, gIsListening, gIsListeningPyq;
extern mutex gMutex; extern mutex gMutex;
extern condition_variable gCV; extern condition_variable gCV;
extern queue<WxMsg_t> gMsgQueue; extern queue<WxMsg_t> gMsgQueue;
// Defined in spy.cpp // Defined in spy.cpp
extern WxCalls_t g_WxCalls; extern QWORD g_WeChatWinDllAddr;
extern UINT64 g_WeChatWinDllAddr;
typedef UINT64 (*funcRecvMsg_t)(UINT64, UINT64); #define OS_RECV_MSG_ID 0x30
static funcRecvMsg_t funcRecvMsg = nullptr; #define OS_RECV_MSG_TYPE 0x38
static funcRecvMsg_t realRecvMsg = nullptr; #define OS_RECV_MSG_SELF 0x3C
#define OS_RECV_MSG_TS 0x44
#define OS_RECV_MSG_ROOMID 0x48
#define OS_RECV_MSG_CONTENT 0x88
#define OS_RECV_MSG_WXID 0x240
#define OS_RECV_MSG_SIGN 0x260
#define OS_RECV_MSG_THUMB 0x280
#define OS_RECV_MSG_EXTRA 0x2A0
#define OS_RECV_MSG_XML 0x308
#define OS_RECV_MSG_CALL 0x2205510
#define OS_PYQ_MSG_START 0x30
#define OS_PYQ_MSG_END 0x38
#define OS_PYQ_MSG_TS 0x38
#define OS_PYQ_MSG_XML 0x9B8
#define OS_PYQ_MSG_SENDER 0x18
#define OS_PYQ_MSG_CONTENT 0x48
#define OS_PYQ_MSG_CALL 0x2EFAA10
#define OS_WXLOG 0x26DA2D0
typedef QWORD (*RecvMsg_t)(QWORD, QWORD);
typedef QWORD (*WxLog_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*RecvPyq_t)(QWORD, QWORD, QWORD);
static RecvMsg_t funcRecvMsg = nullptr;
static RecvMsg_t realRecvMsg = nullptr;
static WxLog_t funcWxLog = nullptr;
static WxLog_t realWxLog = nullptr;
static RecvPyq_t funcRecvPyq = nullptr;
static RecvPyq_t realRecvPyq = nullptr;
static bool isMH_Initialized = false;
MsgTypes_t GetMsgTypes() MsgTypes_t GetMsgTypes()
{ {
@ -68,10 +95,11 @@ MsgTypes_t GetMsgTypes()
return m; return m;
} }
static UINT64 DispatchMsg(UINT64 arg1, UINT64 arg2) static QWORD DispatchMsg(QWORD arg1, QWORD arg2)
{ {
WxMsg_t wxMsg = { 0 }; WxMsg_t wxMsg = { 0 };
try { try {
<<<<<<< HEAD
wxMsg.id = GET_QWORD(arg2 + offset::wcf_msgId); wxMsg.id = GET_QWORD(arg2 + offset::wcf_msgId);
wxMsg.type = GET_DWORD(arg2 + offset::wcf_type); wxMsg.type = GET_DWORD(arg2 + offset::wcf_type);
wxMsg.is_self = GET_DWORD(arg2 + offset::wcf_isSelf); wxMsg.is_self = GET_DWORD(arg2 + offset::wcf_isSelf);
@ -81,13 +109,28 @@ static UINT64 DispatchMsg(UINT64 arg1, UINT64 arg2)
wxMsg.xml = GetStringByWstrAddr(arg2 + offset::wcf_msgXml); wxMsg.xml = GetStringByWstrAddr(arg2 + offset::wcf_msgXml);
string roomid = GetStringByWstrAddr(arg2 + offset::wcf_roomId); string roomid = GetStringByWstrAddr(arg2 + offset::wcf_roomId);
=======
wxMsg.id = GET_QWORD(arg2 + OS_RECV_MSG_ID);
wxMsg.type = GET_DWORD(arg2 + OS_RECV_MSG_TYPE);
wxMsg.is_self = GET_DWORD(arg2 + OS_RECV_MSG_SELF);
wxMsg.ts = GET_DWORD(arg2 + OS_RECV_MSG_TS);
wxMsg.content = GetStringByWstrAddr(arg2 + OS_RECV_MSG_CONTENT);
wxMsg.sign = GetStringByWstrAddr(arg2 + OS_RECV_MSG_SIGN);
wxMsg.xml = GetStringByWstrAddr(arg2 + OS_RECV_MSG_XML);
string roomid = GetStringByWstrAddr(arg2 + OS_RECV_MSG_ROOMID);
wxMsg.roomid = roomid;
>>>>>>> master
if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom
wxMsg.is_group = true; wxMsg.is_group = true;
wxMsg.roomid = roomid;
if (wxMsg.is_self) { if (wxMsg.is_self) {
wxMsg.sender = GetSelfWxid(); wxMsg.sender = GetSelfWxid();
} else { } else {
<<<<<<< HEAD
wxMsg.sender = GetStringByWstrAddr(arg2 + offset::wcf_wxid); wxMsg.sender = GetStringByWstrAddr(arg2 + offset::wcf_wxid);
=======
wxMsg.sender = GetStringByWstrAddr(arg2 + OS_RECV_MSG_WXID);
>>>>>>> master
} }
} else { } else {
wxMsg.is_group = false; wxMsg.is_group = false;
@ -98,13 +141,21 @@ static UINT64 DispatchMsg(UINT64 arg1, UINT64 arg2)
} }
} }
<<<<<<< HEAD
wxMsg.thumb = GetStringByWstrAddr(arg2 + offset::wcf_thumb); wxMsg.thumb = GetStringByWstrAddr(arg2 + offset::wcf_thumb);
=======
wxMsg.thumb = GetStringByWstrAddr(arg2 + OS_RECV_MSG_THUMB);
>>>>>>> master
if (!wxMsg.thumb.empty()) { if (!wxMsg.thumb.empty()) {
wxMsg.thumb = GetHomePath() + wxMsg.thumb; wxMsg.thumb = GetHomePath() + wxMsg.thumb;
replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/'); replace(wxMsg.thumb.begin(), wxMsg.thumb.end(), '\\', '/');
} }
<<<<<<< HEAD
wxMsg.extra = GetStringByWstrAddr(arg2 + offset::wcf_extra); wxMsg.extra = GetStringByWstrAddr(arg2 + offset::wcf_extra);
=======
wxMsg.extra = GetStringByWstrAddr(arg2 + OS_RECV_MSG_EXTRA);
>>>>>>> master
if (!wxMsg.extra.empty()) { if (!wxMsg.extra.empty()) {
wxMsg.extra = GetHomePath() + wxMsg.extra; wxMsg.extra = GetHomePath() + wxMsg.extra;
replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/'); replace(wxMsg.extra.begin(), wxMsg.extra.end(), '\\', '/');
@ -124,16 +175,143 @@ static UINT64 DispatchMsg(UINT64 arg1, UINT64 arg2)
return realRecvMsg(arg1, arg2); return realRecvMsg(arg1, arg2);
} }
static QWORD PrintWxLog(QWORD a1, QWORD a2, QWORD a3, QWORD a4, QWORD a5, QWORD a6, QWORD a7, QWORD a8, QWORD a9,
QWORD a10, QWORD a11, QWORD a12)
{
QWORD p = realWxLog(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
if (p == 0 || p == 1) {
return p;
}
LOG_INFO("【WX】\n{}", GB2312ToUtf8((char *)p));
return p;
}
static void DispatchPyq(QWORD arg1, QWORD arg2, QWORD arg3)
{
QWORD startAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_START);
QWORD endAddr = *(QWORD *)(arg2 + OS_PYQ_MSG_END);
if (startAddr == 0) {
return;
}
while (startAddr < endAddr) {
WxMsg_t wxMsg;
wxMsg.type = 0x00; // 朋友圈消息
wxMsg.is_self = false;
wxMsg.is_group = false;
wxMsg.id = GET_QWORD(startAddr);
wxMsg.ts = GET_DWORD(startAddr + OS_PYQ_MSG_TS);
wxMsg.xml = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_XML);
wxMsg.sender = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_SENDER);
wxMsg.content = GetStringByWstrAddr(startAddr + OS_PYQ_MSG_CONTENT);
{
unique_lock<mutex> lock(gMutex);
gMsgQueue.push(wxMsg); // 推送到队列
}
gCV.notify_all(); // 通知各方消息就绪
startAddr += 0x1618;
}
}
static MH_STATUS InitializeHook()
{
if (isMH_Initialized) {
return MH_OK;
}
MH_STATUS status = MH_Initialize();
if (status == MH_OK) {
isMH_Initialized = true;
}
return status;
}
static MH_STATUS UninitializeHook()
{
if (!isMH_Initialized) {
return MH_OK;
}
if (gIsLogging || gIsListening || gIsListeningPyq) {
return MH_OK;
}
MH_STATUS status = MH_Uninitialize();
if (status == MH_OK) {
isMH_Initialized = false;
}
return status;
}
void EnableLog()
{
MH_STATUS status = MH_UNKNOWN;
if (gIsLogging) {
LOG_WARN("gIsLogging");
return;
}
WxLog_t funcWxLog = (WxLog_t)(g_WeChatWinDllAddr + OS_WXLOG);
status = InitializeHook();
if (status != MH_OK) {
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
return;
}
status = MH_CreateHook(funcWxLog, &PrintWxLog, reinterpret_cast<LPVOID *>(&realWxLog));
if (status != MH_OK) {
LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
return;
}
status = MH_EnableHook(funcWxLog);
if (status != MH_OK) {
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
return;
}
gIsLogging = true;
}
void DisableLog()
{
MH_STATUS status = MH_UNKNOWN;
if (!gIsLogging) {
return;
}
status = MH_DisableHook(funcWxLog);
if (status != MH_OK) {
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
return;
}
gIsLogging = false;
status = UninitializeHook();
if (status != MH_OK) {
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
return;
}
}
void ListenMessage() void ListenMessage()
{ {
MH_STATUS status = MH_UNKNOWN; MH_STATUS status = MH_UNKNOWN;
if (gIsListening || (g_WeChatWinDllAddr == 0)) { if (gIsListening) {
LOG_WARN("gIsListening || (g_WeChatWinDllAddr == 0)"); LOG_WARN("gIsListening");
return; return;
} }
<<<<<<< HEAD
funcRecvMsg = (funcRecvMsg_t)(g_WeChatWinDllAddr + offset::wcf_HookCall); funcRecvMsg = (funcRecvMsg_t)(g_WeChatWinDllAddr + offset::wcf_HookCall);
=======
funcRecvMsg = (RecvMsg_t)(g_WeChatWinDllAddr + OS_RECV_MSG_CALL);
>>>>>>> master
status = MH_Initialize(); status = InitializeHook();
if (status != MH_OK) { if (status != MH_OK) {
LOG_ERROR("MH_Initialize failed: {}", to_string(status)); LOG_ERROR("MH_Initialize failed: {}", to_string(status));
return; return;
@ -167,11 +345,14 @@ void UnListenMessage()
return; return;
} }
status = MH_Uninitialize(); gIsListening = false;
status = UninitializeHook();
if (status != MH_OK) { if (status != MH_OK) {
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status)); LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
return; return;
} }
<<<<<<< HEAD
gIsListening = false; gIsListening = false;
} }
@ -353,29 +534,58 @@ __declspec(naked) void RecievePyqFunc()
call recvPyqCallAddr // 这个为被覆盖的call call recvPyqCallAddr // 这个为被覆盖的call
jmp recvPyqJumpBackAddr // 跳回被HOOK指令的下一条指令 jmp recvPyqJumpBackAddr // 跳回被HOOK指令的下一条指令
} }
=======
>>>>>>> master
} }
void ListenPyq() void ListenPyq()
{ {
if (gIsListeningPyq || (g_WeChatWinDllAddr == 0)) { MH_STATUS status = MH_UNKNOWN;
if (gIsListeningPyq) {
LOG_WARN("gIsListeningPyq");
return;
}
funcRecvPyq = (RecvPyq_t)(g_WeChatWinDllAddr + OS_PYQ_MSG_CALL);
status = InitializeHook();
if (status != MH_OK) {
LOG_ERROR("MH_Initialize failed: {}", to_string(status));
return; return;
} }
recvPyqHookAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.hook; status = MH_CreateHook(funcRecvPyq, &DispatchPyq, reinterpret_cast<LPVOID *>(&realRecvPyq));
recvPyqCallAddr = g_WeChatWinDllAddr + g_WxCalls.pyq.call; if (status != MH_OK) {
recvPyqJumpBackAddr = recvPyqHookAddr + 5; LOG_ERROR("MH_CreateHook failed: {}", to_string(status));
return;
}
status = MH_EnableHook(funcRecvPyq);
if (status != MH_OK) {
LOG_ERROR("MH_EnableHook failed: {}", to_string(status));
return;
}
HookAddress(recvPyqHookAddr, RecievePyqFunc, recvPyqBackupCode);
gIsListeningPyq = true; gIsListeningPyq = true;
} }
void UnListenPyq() void UnListenPyq()
{ {
MH_STATUS status = MH_UNKNOWN;
if (!gIsListeningPyq) { if (!gIsListeningPyq) {
return; return;
} }
UnHookAddress(recvPyqHookAddr, recvPyqBackupCode); status = MH_DisableHook(funcRecvPyq);
if (status != MH_OK) {
LOG_ERROR("MH_DisableHook failed: {}", to_string(status));
return;
}
gIsListeningPyq = false; gIsListeningPyq = false;
status = UninitializeHook();
if (status != MH_OK) {
LOG_ERROR("MH_Uninitialize failed: {}", to_string(status));
return;
}
} }
#endif

View File

@ -2,6 +2,8 @@
#include "pb_types.h" #include "pb_types.h"
void EnableLog();
void DisableLog();
void ListenPyq(); void ListenPyq();
void UnListenPyq(); void UnListenPyq();
void ListenMessage(); void ListenMessage();

View File

@ -1,56 +0,0 @@
#include "receive_transfer.h"
#include "load_calls.h"
#include "log.h"
#include "util.h"
using namespace std;
extern WxCalls_t g_WxCalls;
extern UINT64 g_WeChatWinDllAddr;
#if 0
int ReceiveTransfer(string wxid, string transferid, string transactionid)
{
int rv = 0;
DWORD recvTransferCall1 = g_WeChatWinDllAddr + g_WxCalls.tf.call1;
DWORD recvTransferCall2 = g_WeChatWinDllAddr + g_WxCalls.tf.call2;
DWORD recvTransferCall3 = g_WeChatWinDllAddr + g_WxCalls.tf.call3;
char payInfo[0x134] = { 0 };
wstring wsWxid = String2Wstring(wxid);
wstring wsTfid = String2Wstring(transferid);
wstring wsTaid = String2Wstring(transactionid);
WxString wxWxid(wsWxid);
WxString wxTfid(wsTfid);
WxString wxTaid(wsTaid);
LOG_DEBUG("Receiving transfer, from: {}, transferid: {}, transactionid: {}", wxid, transferid, transactionid);
__asm {
pushad;
lea ecx, payInfo;
call recvTransferCall1;
mov dword ptr[payInfo + 0x4], 0x1;
mov dword ptr[payInfo + 0x4C], 0x1;
popad;
}
memcpy(&payInfo[0x1C], &wxTaid, sizeof(wxTaid));
memcpy(&payInfo[0x38], &wxTfid, sizeof(wxTfid));
__asm {
pushad;
push 0x1;
sub esp, 0x8;
lea edx, wxWxid;
lea ecx, payInfo;
call recvTransferCall2;
mov rv, eax;
add esp, 0xC;
push 0x0;
lea ecx, payInfo;
call recvTransferCall3;
popad;
}
return rv;
}
#endif

View File

@ -1,5 +0,0 @@
#pragma once
#include <string>
int ReceiveTransfer(std::string wxid, std::string transferid, std::string transactionid);

View File

@ -26,7 +26,6 @@
#include "pb_types.h" #include "pb_types.h"
#include "pb_util.h" #include "pb_util.h"
#include "receive_msg.h" #include "receive_msg.h"
#include "receive_transfer.h"
#include "rpc_server.h" #include "rpc_server.h"
#include "send_msg.h" #include "send_msg.h"
#include "spy.h" #include "spy.h"
@ -40,6 +39,7 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
bool gIsLogging = false;
bool gIsListening = false; bool gIsListening = false;
bool gIsListeningPyq = false; bool gIsListeningPyq = false;
mutex gMutex; mutex gMutex;
@ -129,7 +129,7 @@ bool func_get_msg_types(uint8_t *out, size_t *len)
return true; return true;
} }
#if 0
bool func_get_contacts(uint8_t *out, size_t *len) bool func_get_contacts(uint8_t *out, size_t *len)
{ {
Response rsp = Response_init_default; Response rsp = Response_init_default;
@ -297,6 +297,30 @@ bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len)
return true; return true;
} }
bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_SEND_EMOTION;
rsp.which_msg = Response_status_tag;
if ((path == NULL) || (receiver == NULL)) {
LOG_ERROR("Empty path or receiver.");
rsp.msg.status = -1;
} else {
SendEmotionMessage(receiver, path);
rsp.msg.status = 0;
}
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
#if 0 #if 0
bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len)
{ {
@ -325,30 +349,6 @@ bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len)
return true; return true;
} }
bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_SEND_EMOTION;
rsp.which_msg = Response_status_tag;
if ((path == NULL) || (receiver == NULL)) {
LOG_ERROR("Empty path or receiver.");
rsp.msg.status = -1;
} else {
SendEmotionMessage(receiver, path);
rsp.msg.status = 0;
}
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
#endif #endif
bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len) bool func_send_rich_txt(RichText rt, uint8_t *out, size_t *len)
@ -573,6 +573,7 @@ bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len)
return true; return true;
} }
<<<<<<< HEAD
bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len)
{ {
Response rsp = Response_init_default; Response rsp = Response_init_default;
@ -619,6 +620,8 @@ bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, siz
return true; return true;
} }
=======
>>>>>>> master
bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len) bool func_refresh_pyq(uint64_t id, uint8_t *out, size_t *len)
{ {
Response rsp = Response_init_default; Response rsp = Response_init_default;
@ -659,29 +662,6 @@ bool func_download_attach(AttachMsg att, uint8_t *out, size_t *len)
return true; return true;
} }
bool func_get_contact_info(string wxid, uint8_t *out, size_t *len)
{
/*借用 Functions_FUNC_GET_CONTACTS */
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_GET_CONTACT_INFO;
rsp.which_msg = Response_contacts_tag;
vector<RpcContact_t> contacts;
contacts.push_back(GetContactByWxid(wxid));
rsp.msg.contacts.contacts.funcs.encode = encode_contacts;
rsp.msg.contacts.contacts.arg = &contacts;
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len) bool func_revoke_msg(uint64_t id, uint8_t *out, size_t *len)
{ {
Response rsp = Response_init_default; Response rsp = Response_init_default;
@ -717,6 +697,80 @@ bool func_refresh_qrcode(uint8_t *out, size_t *len)
return true; return true;
} }
<<<<<<< HEAD
=======
bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_RECV_TRANSFER;
rsp.which_msg = Response_status_tag;
if ((wxid == NULL) || (tfid == NULL) || (taid == NULL)) {
rsp.msg.status = -1;
LOG_ERROR("Empty wxid, tfid or taid.");
} else {
rsp.msg.status = ReceiveTransfer(wxid, tfid, taid);
}
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
#if 0
bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len)
{
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_ACCEPT_FRIEND;
rsp.which_msg = Response_status_tag;
if ((v3 == NULL) || (v4 == NULL)) {
rsp.msg.status = -1;
LOG_ERROR("Empty V3 or V4.");
} else {
rsp.msg.status = AcceptNewFriend(v3, v4, scene);
}
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
bool func_get_contact_info(string wxid, uint8_t *out, size_t *len)
{
/*借用 Functions_FUNC_GET_CONTACTS */
Response rsp = Response_init_default;
rsp.func = Functions_FUNC_GET_CONTACT_INFO;
rsp.which_msg = Response_contacts_tag;
vector<RpcContact_t> contacts;
contacts.push_back(GetContactByWxid(wxid));
rsp.msg.contacts.contacts.funcs.encode = encode_contacts;
rsp.msg.contacts.contacts.arg = &contacts;
pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
if (!pb_encode(&stream, Response_fields, &rsp)) {
LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
return false;
}
*len = stream.bytes_written;
return true;
}
#endif
>>>>>>> master
bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len) bool func_decrypt_image(DecPath dec, uint8_t *out, size_t *len)
{ {
@ -839,7 +893,11 @@ bool func_invite_room_members(char *roomid, char *wxids, uint8_t *out, size_t *l
return true; return true;
} }
<<<<<<< HEAD
#endif #endif
=======
>>>>>>> master
static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len)
{ {
bool ret = false; bool ret = false;
@ -870,7 +928,6 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_get_msg_types(out, out_len); ret = func_get_msg_types(out, out_len);
break; break;
} }
#if 0
case Functions_FUNC_GET_CONTACTS: { case Functions_FUNC_GET_CONTACTS: {
ret = func_get_contacts(out, out_len); ret = func_get_contacts(out, out_len);
break; break;
@ -913,14 +970,18 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_forward_msg(req.msg.fm.id, req.msg.fm.receiver, out, out_len); ret = func_forward_msg(req.msg.fm.id, req.msg.fm.receiver, out, out_len);
break; break;
} }
case Functions_FUNC_SEND_XML: { <<<<<<< HEAD
ret = func_send_xml(req.msg.xml, out, out_len); =======
break;
}
case Functions_FUNC_SEND_EMOTION: { case Functions_FUNC_SEND_EMOTION: {
ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len); ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len);
break; break;
} }
#if 0
>>>>>>> master
case Functions_FUNC_SEND_XML: {
ret = func_send_xml(req.msg.xml, out, out_len);
break;
}
#endif #endif
case Functions_FUNC_ENABLE_RECV_TXT: { case Functions_FUNC_ENABLE_RECV_TXT: {
ret = func_enable_recv_txt(req.msg.flag, out, out_len); ret = func_enable_recv_txt(req.msg.flag, out, out_len);
@ -935,6 +996,7 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len);
break; break;
} }
<<<<<<< HEAD
case Functions_FUNC_ACCEPT_FRIEND: { case Functions_FUNC_ACCEPT_FRIEND: {
ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len);
break; break;
@ -943,6 +1005,8 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len);
break; break;
} }
=======
>>>>>>> master
case Functions_FUNC_REFRESH_PYQ: { case Functions_FUNC_REFRESH_PYQ: {
ret = func_refresh_pyq(req.msg.ui64, out, out_len); ret = func_refresh_pyq(req.msg.ui64, out, out_len);
break; break;
@ -951,8 +1015,8 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_download_attach(req.msg.att, out, out_len); ret = func_download_attach(req.msg.att, out, out_len);
break; break;
} }
case Functions_FUNC_GET_CONTACT_INFO: { case Functions_FUNC_RECV_TRANSFER: {
ret = func_get_contact_info(req.msg.str, out, out_len); ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len);
break; break;
} }
case Functions_FUNC_REVOKE_MSG: { case Functions_FUNC_REVOKE_MSG: {
@ -963,6 +1027,19 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_refresh_qrcode(out, out_len); ret = func_refresh_qrcode(out, out_len);
break; break;
} }
<<<<<<< HEAD
=======
#if 0
case Functions_FUNC_ACCEPT_FRIEND: {
ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len);
break;
}
case Functions_FUNC_GET_CONTACT_INFO: {
ret = func_get_contact_info(req.msg.str, out, out_len);
break;
}
#endif
>>>>>>> master
case Functions_FUNC_DECRYPT_IMAGE: { case Functions_FUNC_DECRYPT_IMAGE: {
ret = func_decrypt_image(req.msg.dec, out, out_len); ret = func_decrypt_image(req.msg.dec, out, out_len);
break; break;
@ -983,7 +1060,6 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_invite_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); ret = func_invite_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len);
break; break;
} }
#endif
default: { default: {
LOG_ERROR("[UNKNOW FUNCTION]"); LOG_ERROR("[UNKNOW FUNCTION]");
break; break;
@ -1048,7 +1124,7 @@ static int RunServer()
} }
nng_free(in, in_len); nng_free(in, in_len);
} }
lIsRunning = false; RpcStopServer();
LOG_DEBUG("Leave RunServer"); LOG_DEBUG("Leave RunServer");
return rv; return rv;
} }
@ -1065,7 +1141,9 @@ int RpcStartServer(int port)
if (rpcThread != 0) { if (rpcThread != 0) {
CloseHandle(rpcThread); CloseHandle(rpcThread);
} }
#if ENABLE_WX_LOG
EnableLog();
#endif
return 0; return 0;
} }
@ -1079,5 +1157,8 @@ int RpcStopServer()
Sleep(1000); Sleep(1000);
LOG_INFO("Server stoped."); LOG_INFO("Server stoped.");
} }
#if ENABLE_WX_LOG
DisableLog();
#endif
return 0; return 0;
} }

View File

@ -10,20 +10,47 @@
#include "wechat_function.h" #include "wechat_function.h"
extern HANDLE g_hEvent; extern HANDLE g_hEvent;
extern WxCalls_t g_WxCalls;
extern QWORD g_WeChatWinDllAddr; extern QWORD g_WeChatWinDllAddr;
extern string GetSelfWxid(); // Defined in spy.cpp extern string GetSelfWxid(); // Defined in spy.cpp
typedef QWORD (*funcNew_t)(QWORD); #define SRTM_SIZE 0x3F0
typedef QWORD (*funcFree_t)(QWORD);
typedef QWORD (*funcSendMsgMgr_t)();
typedef QWORD (*funcGetAppMsgMgr_t)();
<<<<<<< HEAD
typedef QWORD (*funcSendTextMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD); typedef QWORD (*funcSendTextMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*funcSendImageMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD); typedef QWORD (*funcSendImageMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*funcSendFileMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD, typedef QWORD (*funcSendFileMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD,
QWORD); QWORD);
typedef QWORD (*funcSendRichTextMsg_t)(QWORD, QWORD, QWORD); typedef QWORD (*funcSendRichTextMsg_t)(QWORD, QWORD, QWORD);
=======
#define OS_NEW 0x1C28800
#define OS_FREE 0x1C1FF10
#define OS_SEND_MSG_MGR 0x1C1E690
#define OS_SEND_TEXT 0x238DDD0
#define OS_SEND_IMAGE 0x2383560
#define OS_GET_APP_MSG_MGR 0x1C23630
#define OS_SEND_FILE 0x21969E0
#define OS_RTM_NEW 0x1C27D50
#define OS_RTM_FREE 0x1C27120
#define OS_SEND_RICH_TEXT 0x21A09C0
#define OS_SEND_PAT_MSG 0x2D669B0
#define OS_FORWARD_MSG 0x238D350
#define OS_GET_EMOTION_MGR 0x1C988D0
#define OS_SEND_EMOTION 0x227B9E0
typedef QWORD (*New_t)(QWORD);
typedef QWORD (*Free_t)(QWORD);
typedef QWORD (*SendMsgMgr_t)();
typedef QWORD (*GetAppMsgMgr_t)();
typedef QWORD (*SendTextMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*SendImageMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*SendFileMsg_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD *, QWORD, QWORD *, QWORD, QWORD *, QWORD,
QWORD);
typedef QWORD (*SendRichTextMsg_t)(QWORD, QWORD, QWORD);
typedef QWORD (*SendPatMsg_t)(QWORD, QWORD);
typedef QWORD (*ForwardMsg_t)(QWORD, QWORD, QWORD, QWORD);
typedef QWORD (*GetEmotionMgr_t)();
typedef QWORD (*SendEmotion_t)(QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD, QWORD);
>>>>>>> master
void SendTextMessage(string wxid, string msg, string atWxids) void SendTextMessage(string wxid, string msg, string atWxids)
{ {
@ -51,10 +78,17 @@ void SendTextMessage(string wxid, string msg, string atWxids)
QWORD wxAters = (QWORD) & ((RawVector_t *)&vWxAtWxids)->start; QWORD wxAters = (QWORD) & ((RawVector_t *)&vWxAtWxids)->start;
<<<<<<< HEAD
char buffer[0x460] = { 0 }; char buffer[0x460] = { 0 };
funcSendMsgMgr_t funcSendMsgMgr = (funcSendMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetSendMessageMgr); funcSendMsgMgr_t funcSendMsgMgr = (funcSendMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetSendMessageMgr);
funcSendTextMsg_t funcSendTextMsg = (funcSendTextMsg_t)(g_WeChatWinDllAddr + offset::kSendTextMsg); funcSendTextMsg_t funcSendTextMsg = (funcSendTextMsg_t)(g_WeChatWinDllAddr + offset::kSendTextMsg);
funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg); funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg);
=======
char buffer[0x460] = { 0 };
SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR);
SendTextMsg_t funcSendTextMsg = (SendTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_TEXT);
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
>>>>>>> master
funcSendMsgMgr(); funcSendMsgMgr();
success = funcSendTextMsg((QWORD)(&buffer), (QWORD)(&wxWxid), (QWORD)(&wxMsg), wxAters, 1, 1, 0, 0); success = funcSendTextMsg((QWORD)(&buffer), (QWORD)(&wxWxid), (QWORD)(&wxMsg), wxAters, 1, 1, 0, 0);
funcFree((QWORD)(&buffer)); funcFree((QWORD)(&buffer));
@ -68,10 +102,17 @@ void SendImageMessage(string wxid, string path)
WxString wxWxid(wsWxid); WxString wxWxid(wsWxid);
WxString wxPath(wsPath); WxString wxPath(wsPath);
<<<<<<< HEAD
funcNew_t funcNew = (funcNew_t)(g_WeChatWinDllAddr + offset::kNewChatMsgByDownloadMgr); funcNew_t funcNew = (funcNew_t)(g_WeChatWinDllAddr + offset::kNewChatMsgByDownloadMgr);
funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg); funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg);
funcSendMsgMgr_t funcSendMsgMgr = (funcSendMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetSendMessageMgr); funcSendMsgMgr_t funcSendMsgMgr = (funcSendMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetSendMessageMgr);
funcSendImageMsg_t funcSendImage = (funcSendImageMsg_t)(g_WeChatWinDllAddr + offset::kSendImageMsg); funcSendImageMsg_t funcSendImage = (funcSendImageMsg_t)(g_WeChatWinDllAddr + offset::kSendImageMsg);
=======
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW);
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
SendMsgMgr_t funcSendMsgMgr = (SendMsgMgr_t)(g_WeChatWinDllAddr + OS_SEND_MSG_MGR);
SendImageMsg_t funcSendImage = (SendImageMsg_t)(g_WeChatWinDllAddr + OS_SEND_IMAGE);
>>>>>>> master
char msg[0x460] = { 0 }; char msg[0x460] = { 0 };
char msgTmp[0x460] = { 0 }; char msgTmp[0x460] = { 0 };
@ -98,10 +139,17 @@ void SendFileMessage(string wxid, string path)
WxString wxWxid(wsWxid); WxString wxWxid(wsWxid);
WxString wxPath(wsPath); WxString wxPath(wsPath);
<<<<<<< HEAD
funcNew_t funcNew = (funcNew_t)(g_WeChatWinDllAddr + offset::kChatMsgInstanceCounter); funcNew_t funcNew = (funcNew_t)(g_WeChatWinDllAddr + offset::kChatMsgInstanceCounter);
funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg); funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeChatMsg);
funcGetAppMsgMgr_t funcGetAppMsgMgr = (funcGetAppMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetAppMsgMgr); funcGetAppMsgMgr_t funcGetAppMsgMgr = (funcGetAppMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetAppMsgMgr);
funcSendFileMsg_t funcSendFile = (funcSendFileMsg_t)(g_WeChatWinDllAddr + offset::kSendFileMsg); funcSendFileMsg_t funcSendFile = (funcSendFileMsg_t)(g_WeChatWinDllAddr + offset::kSendFileMsg);
=======
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_NEW);
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_FREE);
GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR);
SendFileMsg_t funcSendFile = (SendFileMsg_t)(g_WeChatWinDllAddr + OS_SEND_FILE);
>>>>>>> master
char msg[0x460] = { 0 }; char msg[0x460] = { 0 };
QWORD tmp1[4] = { 0 }; QWORD tmp1[4] = { 0 };
@ -114,29 +162,11 @@ void SendFileMessage(string wxid, string path)
funcFree(pMsg); funcFree(pMsg);
} }
WxString *NewWxString(const std::wstring &ws)
{
WxString *p = (WxString *)HeapAlloc(GetProcessHeap(), 0, sizeof(WxString));
wchar_t *pWstring = (wchar_t *)HeapAlloc(GetProcessHeap(), 0, (ws.size() + 1) * 2);
if (p == NULL || pWstring == NULL) {
LOG_ERROR("Out of Memory...");
return NULL;
}
wmemcpy(pWstring, ws.c_str(), ws.size() + 1);
p->wptr = pWstring;
p->size = (DWORD)ws.size();
p->capacity = (DWORD)ws.size();
p->ptr = 0;
p->clen = 0;
return p;
}
int SendRichTextMessage(RichText_t &rt) int SendRichTextMessage(RichText_t &rt)
{ // TODO: Fix memory leak { // TODO: Fix memory leak
#define SRTM_SIZE 0x3F0
QWORD status = -1; QWORD status = -1;
<<<<<<< HEAD
wstring receiver = String2Wstring(rt.receiver); wstring receiver = String2Wstring(rt.receiver);
wstring title = String2Wstring(rt.title); wstring title = String2Wstring(rt.title);
wstring url = String2Wstring(rt.url); wstring url = String2Wstring(rt.url);
@ -149,6 +179,12 @@ int SendRichTextMessage(RichText_t &rt)
funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeRChatMsg); funcFree_t funcFree = (funcFree_t)(g_WeChatWinDllAddr + offset::kFreeRChatMsg);
funcGetAppMsgMgr_t funcGetAppMsgMgr = (funcGetAppMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetAppMsgMgr); funcGetAppMsgMgr_t funcGetAppMsgMgr = (funcGetAppMsgMgr_t)(g_WeChatWinDllAddr + offset::kGetAppMsgMgr);
funcSendRichTextMsg_t funcForwordPublicMsg = (funcSendRichTextMsg_t)(g_WeChatWinDllAddr + offset::kSendRichTextMsg); funcSendRichTextMsg_t funcForwordPublicMsg = (funcSendRichTextMsg_t)(g_WeChatWinDllAddr + offset::kSendRichTextMsg);
=======
New_t funcNew = (New_t)(g_WeChatWinDllAddr + OS_RTM_NEW);
Free_t funcFree = (Free_t)(g_WeChatWinDllAddr + OS_RTM_FREE);
GetAppMsgMgr_t funcGetAppMsgMgr = (GetAppMsgMgr_t)(g_WeChatWinDllAddr + OS_GET_APP_MSG_MGR);
SendRichTextMsg_t funcForwordPublicMsg = (SendRichTextMsg_t)(g_WeChatWinDllAddr + OS_SEND_RICH_TEXT);
>>>>>>> master
char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE); char *buff = (char *)HeapAlloc(GetProcessHeap(), 0, SRTM_SIZE);
if (buff == NULL) { if (buff == NULL) {
@ -158,13 +194,13 @@ int SendRichTextMessage(RichText_t &rt)
memset(buff, 0, SRTM_SIZE); memset(buff, 0, SRTM_SIZE);
funcNew((QWORD)buff); funcNew((QWORD)buff);
WxString *pReceiver = NewWxString(receiver); WxString *pReceiver = NewWxStringFromStr(rt.receiver);
WxString *pTitle = NewWxString(title); WxString *pTitle = NewWxStringFromStr(rt.title);
WxString *pUrl = NewWxString(url); WxString *pUrl = NewWxStringFromStr(rt.url);
WxString *pThumburl = NewWxString(thumburl); WxString *pThumburl = NewWxStringFromStr(rt.thumburl);
WxString *pDigest = NewWxString(digest); WxString *pDigest = NewWxStringFromStr(rt.digest);
WxString *pAccount = NewWxString(account); WxString *pAccount = NewWxStringFromStr(rt.account);
WxString *pName = NewWxString(name); WxString *pName = NewWxStringFromStr(rt.name);
memcpy(buff + 0x8, pTitle, sizeof(WxString)); memcpy(buff + 0x8, pTitle, sizeof(WxString));
memcpy(buff + 0x48, pUrl, sizeof(WxString)); memcpy(buff + 0x48, pUrl, sizeof(WxString));
@ -180,6 +216,66 @@ int SendRichTextMessage(RichText_t &rt)
return (int)status; return (int)status;
} }
<<<<<<< HEAD
=======
int SendPatMessage(string roomid, string wxid)
{
QWORD status = -1;
wstring wsRoomid = String2Wstring(roomid);
wstring wsWxid = String2Wstring(wxid);
WxString wxRoomid(wsRoomid);
WxString wxWxid(wsWxid);
SendPatMsg_t funcSendPatMsg = (SendPatMsg_t)(g_WeChatWinDllAddr + OS_SEND_PAT_MSG);
status = funcSendPatMsg((QWORD)(&wxRoomid), (QWORD)(&wxWxid));
return (int)status;
}
int ForwardMessage(QWORD msgid, string receiver)
{
int status = -1;
uint32_t dbIdx = 0;
QWORD localId = 0;
ForwardMsg_t funcForwardMsg = (ForwardMsg_t)(g_WeChatWinDllAddr + OS_FORWARD_MSG);
if (GetLocalIdandDbidx(msgid, &localId, &dbIdx) != 0) {
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(msgid));
return status;
}
WxString *pReceiver = NewWxStringFromStr(receiver);
LARGE_INTEGER l;
l.HighPart = dbIdx;
l.LowPart = (DWORD)localId;
status = (int)funcForwardMsg((QWORD)pReceiver, l.QuadPart, 0x4, 0x0);
return status;
}
void SendEmotionMessage(string wxid, string path)
{
GetEmotionMgr_t GetEmotionMgr = (GetEmotionMgr_t)(g_WeChatWinDllAddr + OS_GET_EMOTION_MGR);
SendEmotion_t SendEmotion = (SendEmotion_t)(g_WeChatWinDllAddr + OS_SEND_EMOTION);
WxString *pWxPath = NewWxStringFromStr(path);
WxString *pWxWxid = NewWxStringFromStr(wxid);
QWORD *buff = (QWORD *)HeapAlloc(GetProcessHeap(), 0, 0x20);
if (buff == NULL) {
LOG_ERROR("Out of Memory...");
return;
}
memset(buff, 0, 0x20);
QWORD mgr = GetEmotionMgr();
SendEmotion(mgr, (QWORD)pWxPath, (QWORD)buff, (QWORD)pWxWxid, 2, (QWORD)buff, 0, (QWORD)buff);
}
>>>>>>> master
#if 0 #if 0
void SendXmlMessage(string receiver, string xml, string path, int type) void SendXmlMessage(string receiver, string xml, string path, int type)
{ {
@ -246,6 +342,7 @@ void SendXmlMessage(string receiver, string xml, string path, int type)
popad; popad;
} }
} }
<<<<<<< HEAD
void SendEmotionMessage(string wxid, string path) void SendEmotionMessage(string wxid, string path)
{ {
@ -445,4 +542,6 @@ int ForwardMessage(QWORD msgid, string receiver)
return status; return status;
} }
=======
>>>>>>> master
#endif #endif

Binary file not shown.

View File

@ -1,14 +1,24 @@
#include <filesystem> #include <filesystem>
#include "load_calls.h"
#include "log.h" #include "log.h"
#include "rpc_server.h" #include "rpc_server.h"
#include "spy.h" #include "spy.h"
#include "util.h" #include "util.h"
<<<<<<< HEAD
//WxCalls_t g_WxCalls = { 0 }; //WxCalls_t g_WxCalls = { 0 };
=======
>>>>>>> master
UINT64 g_WeChatWinDllAddr = 0; UINT64 g_WeChatWinDllAddr = 0;
static bool IsWxVersionMatched(const wchar_t *version)
{
if (wcscmp(version, SUPPORT_VERSION) != 0) {
return false;
}
return true;
}
void InitSpy(LPVOID args) void InitSpy(LPVOID args)
{ {
@ -19,7 +29,7 @@ void InitSpy(LPVOID args)
g_WeChatWinDllAddr = (UINT64)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址 g_WeChatWinDllAddr = (UINT64)GetModuleHandle(L"WeChatWin.dll"); // 获取wechatWin模块地址
if (g_WeChatWinDllAddr == 0) { if (g_WeChatWinDllAddr == 0) {
LOG_ERROR("获取 wechatWin.dll 模块地址失败"); LOG_ERROR("获取 wechatWin.dll 模块地址失败");
return; return; // TODO: 退出进程,避免后面操作失败
} }
if (!GetWeChatVersion(version)) { // 获取微信版本 if (!GetWeChatVersion(version)) { // 获取微信版本
@ -27,11 +37,19 @@ void InitSpy(LPVOID args)
return; return;
} }
LOG_INFO("WeChat version: {}", Wstring2String(version).c_str()); LOG_INFO("WeChat version: {}", Wstring2String(version).c_str());
<<<<<<< HEAD
//if (LoadCalls(version, &g_WxCalls) != 0) { // 加载微信版本对应的Call地址 //if (LoadCalls(version, &g_WxCalls) != 0) { // 加载微信版本对应的Call地址
// LOG_ERROR("不支持当前版本"); // LOG_ERROR("不支持当前版本");
// MessageBox(NULL, L"不支持当前版本", L"错误", 0); // MessageBox(NULL, L"不支持当前版本", L"错误", 0);
// return; // return;
//} //}
=======
if (!IsWxVersionMatched(version)) {
LOG_ERROR("不支持当前版本");
MessageBox(NULL, L"不支持当前版本", L"错误", 0);
return;
}
>>>>>>> master
RpcStartServer(pp->port); RpcStartServer(pp->port);
} }

View File

@ -2,5 +2,11 @@
#include "framework.h" #include "framework.h"
<<<<<<< HEAD
void InitSpy(LPVOID port); void InitSpy(LPVOID port);
=======
#define SUPPORT_VERSION L"3.9.10.27"
void InitSpy(int port);
>>>>>>> master
void CleanupSpy(); void CleanupSpy();

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 39,1,0,0 FILEVERSION 39,2,4,0
PRODUCTVERSION 3,9,10,19 PRODUCTVERSION 3,9,10,27
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "WeChatFerry" VALUE "CompanyName", "WeChatFerry"
VALUE "FileDescription", "WeChatFerry" VALUE "FileDescription", "WeChatFerry"
VALUE "FileVersion", "39.1.0.0" VALUE "FileVersion", "39.2.4.0"
VALUE "InternalName", "spy.dll" VALUE "InternalName", "spy.dll"
VALUE "LegalCopyright", "Copyright (C) 2023" VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "spy.dll" VALUE "OriginalFilename", "spy.dll"
VALUE "ProductName", "WeChatFerry" VALUE "ProductName", "WeChatFerry"
VALUE "ProductVersion", "3.9.10.19" VALUE "ProductVersion", "3.9.10.27"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -4,6 +4,7 @@
#include <string> #include <string>
typedef uint64_t QWORD; typedef uint64_t QWORD;
<<<<<<< HEAD
typedef struct UserInfoCall { typedef struct UserInfoCall {
DWORD wxid = 0x5AB7FB8; DWORD wxid = 0x5AB7FB8;
DWORD nickName = 0x5AB8098; DWORD nickName = 0x5AB8098;
@ -207,6 +208,8 @@ typedef struct WxCalls {
//CallFm_t fm; // 转发消息 //CallFm_t fm; // 转发消息
//CallRfLoginQr_t rlq; // 刷新登录二维码 //CallRfLoginQr_t rlq; // 刷新登录二维码
} WxCalls_t; } WxCalls_t;
=======
>>>>>>> master
struct WxString { struct WxString {
const wchar_t *wptr; const wchar_t *wptr;

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include "Windows.h" #include "Windows.h"
#include "spy_types.h"
#define SQLITE_OK 0 /* Successful result */ #define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */ /* beginning-of-error-codes */

View File

@ -1,18 +1,25 @@
#include "user_info.h" #include "user_info.h"
#include "load_calls.h"
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#include "wechat_function.h" #include "wechat_function.h"
extern WxCalls_t g_WxCalls;
extern UINT64 g_WeChatWinDllAddr; extern UINT64 g_WeChatWinDllAddr;
#define OS_USER_HOME 0x5A7E190
#define OS_USER_WXID 0x5AB7F30
#define OS_USER_NAME 0x5AB8098
#define OS_USER_MOBILE 0x5AB7FD8
static char home[MAX_PATH] = { 0 }; static char home[MAX_PATH] = { 0 };
string GetHomePath() string GetHomePath()
{ {
if (home[0] == 0) { if (home[0] == 0) {
<<<<<<< HEAD
string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + offset::wcf_home)) + "\\WeChat Files\\"; string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + offset::wcf_home)) + "\\WeChat Files\\";
=======
string path = Wstring2String(GET_WSTRING(g_WeChatWinDllAddr + OS_USER_HOME)) + "\\WeChat Files\\";
>>>>>>> master
strncpy_s(home, path.c_str(), path.size()); strncpy_s(home, path.c_str(), path.size());
} }
@ -23,6 +30,7 @@ string GetSelfWxid()
{ {
UINT64 wxidType = 0; UINT64 wxidType = 0;
try { try {
<<<<<<< HEAD
wxidType = GET_UINT64(g_WeChatWinDllAddr + offset::wcf_iwxid + 0x18); wxidType = GET_UINT64(g_WeChatWinDllAddr + offset::wcf_iwxid + 0x18);
if (wxidType == 0xF) { if (wxidType == 0xF) {
return GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_iwxid); return GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_iwxid);
@ -32,6 +40,17 @@ string GetSelfWxid()
} catch (...) { } catch (...) {
LOG_ERROR("wxid type: {:#x}", wxidType); LOG_ERROR("wxid type: {:#x}", wxidType);
LOG_BUFFER((uint8_t *)(g_WeChatWinDllAddr + offset::wcf_iwxid), 20); LOG_BUFFER((uint8_t *)(g_WeChatWinDllAddr + offset::wcf_iwxid), 20);
=======
wxidType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_WXID + 0x18);
if (wxidType == 0xF) {
return GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_WXID);
} else {
return GET_STRING(g_WeChatWinDllAddr + OS_USER_WXID);
}
} catch (...) {
LOG_ERROR("wxid type: {:#x}", wxidType);
LOG_BUFFER((uint8_t *)(g_WeChatWinDllAddr + OS_USER_WXID), 20);
>>>>>>> master
return "empty_wxid"; return "empty_wxid";
} }
} }
@ -42,6 +61,7 @@ UserInfo_t GetUserInfo()
ui.wxid = GetSelfWxid(); ui.wxid = GetSelfWxid();
<<<<<<< HEAD
UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + offset::wcf_nickName + 0x18); UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + offset::wcf_nickName + 0x18);
if (nameType == 0xF) { if (nameType == 0xF) {
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_nickName); ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_nickName);
@ -50,6 +70,16 @@ UserInfo_t GetUserInfo()
} }
ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_mobile); ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + offset::wcf_mobile);
=======
UINT64 nameType = GET_UINT64(g_WeChatWinDllAddr + OS_USER_NAME + 0x18);
if (nameType == 0xF) {
ui.name = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_NAME);
} else { // 0x1F
ui.name = GET_STRING(g_WeChatWinDllAddr + OS_USER_NAME);
}
ui.mobile = GET_STRING_FROM_P(g_WeChatWinDllAddr + OS_USER_MOBILE);
>>>>>>> master
ui.home = GetHomePath(); ui.home = GetHomePath();
return ui; return ui;

16
clients/go_wcf_http/README.MD vendored Normal file
View File

@ -0,0 +1,16 @@
# wechatFerry 的 go版本http端
接口文档https://apifox.com/apidoc/shared-6e6950ec-1a6d-4545-90d6-d27d31af2b7c
http服务器的端口是 8000 需要修改的自行编译懒得写配置文件
localhost:8000是本地接口文档
由于用到了cgo 编译需要安装Mingw
Mingw下载地址https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-win32/sjlj/x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0.7z/download
打包命令
#x86 win 编译
set GOOS=windows
set GOARCH=amd64
go build -ldflags="-s -w" -o go_wcf_http3.9.10.27.exe .\main.go

469
clients/go_wcf_http/app/api.go vendored Normal file
View File

@ -0,0 +1,469 @@
package app
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type Result struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
// SetMessageCallbackUrl 设置消息回调地址
func SetMessageCallbackUrl(c *gin.Context) {
var result Result
var RequestData struct {
CallbackUrl string `json:"callback_url"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "回调url设置成功"
var data = map[string]string{"callback_url": RequestData.CallbackUrl}
result.Data = data
WxClient.MessageCallbackUrl = RequestData.CallbackUrl
c.JSON(http.StatusOK, result)
}
// GetSelfWXID 获取登录者的wxid
func GetSelfWXID(c *gin.Context) {
var result Result
wxId := WxClient.GetSelfWXID()
if wxId == "" {
result.Code = 0
result.Message = "获取登录者的wx_id失败"
var data = map[string]string{"wx_id": wxId}
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "获取登录者的wx_id成功"
var data = map[string]string{"wx_id": wxId}
result.Data = data
c.JSON(http.StatusOK, result)
}
// GetUserInfo 获取自己的信息
func GetUserInfo(c *gin.Context) {
var result Result
result.Code = 1
result.Message = "获取个人信息成功"
result.Data = WxClient.GetUserInfo()
c.JSON(http.StatusOK, result)
}
// GetMsgTypes 获取消息类型列表
func GetMsgTypes(c *gin.Context) {
var result Result
result.Code = 1
result.Message = "获取消息类型列表成功"
result.Data = WxClient.GetMsgTypes()
c.JSON(http.StatusOK, result)
}
// GetContacts 获取通讯录
func GetContacts(c *gin.Context) {
var result Result
// 此处手动修改了wcf.pd.go文件 原文件为json字段为空时不返回 如有需要可以自行补上, omitempty
result.Code = 1
result.Message = "获取通讯录成功"
result.Data = WxClient.GetContacts()
c.JSON(http.StatusOK, result)
}
// GetRoomMembersAll 获取全部群的群成员
func GetRoomMembersAll(c *gin.Context) {
var result Result
var RoomMemberList = make(map[string]string)
contacts := WxClient.ExecDBQuery("MicroMsg.db", "SELECT UserName, NickName FROM Contact;")
for _, v := range contacts {
RoomMemberList[string(v.GetFields()[0].Content)] = string(v.GetFields()[1].Content)
}
result.Code = 1
result.Message = "获取全部数据成功"
result.Data = RoomMemberList
c.JSON(http.StatusOK, result)
}
// GetRoomMember 获取指定群成员
func GetRoomMember(c *gin.Context) {
var result Result
var RequestData struct {
RoomId string `json:"room_id"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
contacts := WxClient.ExecDBQuery("MicroMsg.db", "SELECT RoomData FROM ChatRoom WHERE ChatRoomName = '"+RequestData.RoomId+"';")
for _, v := range contacts {
fmt.Print(v.GetFields()[0].Content)
}
}
// GetDBNames 获取全部的数据库
func GetDBNames(c *gin.Context) {
var result Result
// 此处手动修改了wcf.pd.go文件 原文件为json字段为空时不返回 如有需要可以自行补上, omitempty
result.Code = 1
result.Message = "获取全部的数据库成功"
result.Data = WxClient.GetDBNames()
c.JSON(http.StatusOK, result)
}
// GetDBTables 获取表
func GetDBTables(c *gin.Context) {
var result Result
var RequestData struct {
DbName string `json:"db_name"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "获取成功"
result.Data = WxClient.GetDBTables(RequestData.DbName)
c.JSON(http.StatusOK, result)
}
// ExecDBQuery 执行sql
func ExecDBQuery(c *gin.Context) {
var result Result
var RequestData struct {
Db string `json:"db"`
Sql string `json:"sql"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "获取成功"
var data = WxClient.ExecDBQuery(RequestData.Db, RequestData.Sql)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendTxt 发送文本内容
func SendTxt(c *gin.Context) {
var result Result
var RequestData struct {
Msg string `json:"msg"`
Receiver string `json:"receiver"`
Ates []string `json:"ates"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendTxt(RequestData.Msg, RequestData.Receiver, RequestData.Ates)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendIMG 发送图片
func SendIMG(c *gin.Context) {
var result Result
var RequestData struct {
Path string `json:"path"`
Receiver string `json:"receiver"`
Suffix string `json:"suffix"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
if RequestData.Path[0:4] == "http" {
RequestData.Path, _ = DownloadFile(RequestData.Path, "file", RequestData.Suffix)
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendIMG(RequestData.Path, RequestData.Receiver)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendFile 发送文件
func SendFile(c *gin.Context) {
var result Result
var RequestData struct {
Path string `json:"path"`
Receiver string `json:"receiver"`
Suffix string `json:"suffix"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
if RequestData.Path[0:4] == "http" {
RequestData.Path, _ = DownloadFile(RequestData.Path, "file", RequestData.Suffix)
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendFile(RequestData.Path, RequestData.Receiver)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendRichText 发送卡片消息
func SendRichText(c *gin.Context) {
var result Result
var RequestData struct {
Name string `json:"name"`
Account string `json:"account"`
Title string `json:"title"`
Digest string `json:"digest"`
Url string `json:"url"`
ThumbUrl string `json:"thumb_url"`
Receiver string `json:"receiver"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendRichText(RequestData.Name, RequestData.Account, RequestData.Title, RequestData.Digest, RequestData.Url, RequestData.ThumbUrl, RequestData.Receiver)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendPat 发送拍一拍消息
func SendPat(c *gin.Context) {
var result Result
var RequestData struct {
RoomId string `json:"room_id"`
WxId string `json:"wx_id"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendPat(RequestData.RoomId, RequestData.WxId)
result.Data = data
c.JSON(http.StatusOK, result)
}
// ForwardMsg 发送拍一拍消息
func ForwardMsg(c *gin.Context) {
var result Result
var RequestData struct {
Id uint64 `json:"id"`
Receiver string `json:"receiver"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "转发完成"
var data = WxClient.ForwardMsg(RequestData.Id, RequestData.Receiver)
result.Data = data
c.JSON(http.StatusOK, result)
}
// SendEmotion 发送gif
func SendEmotion(c *gin.Context) {
var result Result
var RequestData struct {
Path string `json:"path"`
Receiver string `json:"receiver"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.SendEmotion(RequestData.Path, RequestData.Receiver)
result.Data = data
c.JSON(http.StatusOK, result)
}
// AcceptFriend 接受好友请求
func AcceptFriend(c *gin.Context) {
var result Result
var RequestData struct {
V3 string `json:"v3"`
V4 string `json:"v4"`
Scene int32 `json:"scene"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "接收成功"
var data = WxClient.AcceptFriend(RequestData.V3, RequestData.V4, RequestData.Scene)
result.Data = data
c.JSON(http.StatusOK, result)
}
// AddChatroomMembers 添加群成员
func AddChatroomMembers(c *gin.Context) {
var result Result
var RequestData struct {
RoomId string `json:"room_id"`
WxId []string `json:"wx_ids"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.AddChatRoomMembers(RequestData.RoomId, RequestData.WxId)
result.Data = data
c.JSON(http.StatusOK, result)
}
// DelChatRoomMembers 添加群成员
func DelChatRoomMembers(c *gin.Context) {
var result Result
var RequestData struct {
RoomId string `json:"room_id"`
WxId []string `json:"wx_ids"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.DelChatRoomMembers(RequestData.RoomId, RequestData.WxId)
result.Data = data
c.JSON(http.StatusOK, result)
}
// InvChatRoomMembers 邀请群成员
func InvChatRoomMembers(c *gin.Context) {
var result Result
var RequestData struct {
RoomId string `json:"room_id"`
WxId []string `json:"wx_ids"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "发送完成"
var data = WxClient.InvChatRoomMembers(RequestData.RoomId, RequestData.WxId)
result.Data = data
c.JSON(http.StatusOK, result)
}
// RefreshPyq 刷新朋友圈
func RefreshPyq(c *gin.Context) {
var result Result
result.Code = 1
result.Message = "发送完成"
var data = WxClient.RefreshPYQ()
result.Data = data
c.JSON(http.StatusOK, result)
}
// DownloadAttach 下载附件
func DownloadAttach(c *gin.Context) {
var result Result
var RequestData struct {
Id uint64 `json:"id"`
Thumb string `json:"thumb"`
Extra string `json:"extra"`
}
if err := c.BindJSON(&RequestData); err != nil {
result.Code = 0
result.Message = "json解析失败"
var data = make(map[string]interface{})
result.Data = data
c.JSON(http.StatusOK, result)
return
}
result.Code = 1
result.Message = "下载附件调用成功"
WxClient.DownloadAttach(RequestData.Id, "", RequestData.Extra)
times := 1
path := ""
for times < 30 {
path = WxClient.DecryptImage(RequestData.Extra, RequestData.Thumb)
if path != "func:FUNC_DECRYPT_IMAGE str:\"\"" && path != "func:FUNC_DECRYPT_IMAGE str:\"\"" {
break
}
time.Sleep(time.Millisecond * 1000)
times += 1
}
result.Data = map[string]string{"path": path}
c.JSON(http.StatusOK, result)
}

145
clients/go_wcf_http/app/robot.go vendored Normal file
View File

@ -0,0 +1,145 @@
package app
/*
#cgo LDFLAGS: -L../ -lsdk
#include <stdlib.h>
#include <stdbool.h>
extern int WxInitSDK(bool, int);
extern int WxDestroySDK();
*/
import "C"
import (
"bytes"
"fmt"
"github.com/go-resty/resty/v2"
"github.com/google/uuid"
"go_wechatFerry/wcf"
"io"
"os"
"path/filepath"
"strings"
"time"
)
var WxClient *wcf.Client
// Message 组装成一个结构体展示消息
type Message struct {
IsSelf bool `json:"is_self,omitempty"`
IsGroup bool `json:"is_group,omitempty"`
MessageId uint64 `json:"message_id,omitempty"`
Type uint32 `json:"type,omitempty"`
Ts uint32 `json:"ts,omitempty"`
RoomId string `json:"room_id,omitempty"`
Content string `json:"content,omitempty"`
WxId string `json:"wx_id,omitempty"`
Sign string `json:"sign,omitempty"`
Thumb string `json:"thumb,omitempty"`
Extra string `json:"extra,omitempty"`
Xml string `json:"xml,omitempty"`
}
// WechatFerryInit 调用sdk.dll中的WxInitSdk 进行启动微信并注入
func WechatFerryInit() {
// 调试模式 端口
initSuccess := C.WxInitSDK(C.bool(false), C.int(10086))
if initSuccess == 0 {
fmt.Println("SDK 初始化成功")
} else {
fmt.Println("SDK 初始化失败")
}
time.Sleep(time.Millisecond * 5000)
// 连接服务器
client, errs := wcf.NewWCF("")
if errs != nil {
return
}
// 一定要在这里判断是否登录成功 否则会导致用户列表获取失败
for true {
if client.IsLogin() == true {
fmt.Println("登录成功...等待初始化中...")
time.Sleep(2000 * time.Millisecond)
break
}
time.Sleep(1000 * time.Millisecond)
}
WxClient = client
ContactsInit()
fmt.Println("初始化完成")
}
// MessageProcess 在这里可以继续写代码了
func MessageProcess(msg Message) {
// 方法都在WxClient中
//WxClient.SendTxt("测试","","")
fmt.Println(msg)
}
// ContactsInit 通讯录初始化
func ContactsInit() {
var contactsMap []map[string]string
contacts := WxClient.GetContacts()
for _, v := range contacts {
gender := ""
if v.Gender == 1 {
gender = "男"
}
if v.Gender == 2 {
gender = "女"
}
contactsMaps := map[string]string{
"wxId": v.Wxid,
"code": v.Code,
"remark": v.Remark,
"name": v.Name,
"country": v.Country,
"province": v.Province,
"city": v.City,
"gender": gender,
}
contactsMap = append(contactsMap, contactsMaps)
}
WxClient.ContactsMap = contactsMap
}
// DownloadFile 下载文件
func DownloadFile(url string, fileType string, suffix string) (string, error) {
fmt.Println(url)
// 发送HTTP请求获取文件
resp, err := resty.New().R().Get(url)
if err != nil {
return "", err
}
// 获取当前日期
currentTime := time.Now()
datePath := filepath.Join("./resource/static/"+fileType, currentTime.Format("2006-01-02"))
// 创建目录
if err := os.MkdirAll(datePath, os.ModePerm); err != nil {
return "", err
}
// 生成唯一的文件名
fileName := uuid.New().String() + "." + suffix
filePath := filepath.Join(datePath, fileName)
// 创建文件
file, err := os.Create(filePath)
if err != nil {
return "", err
}
defer file.Close()
// 将HTTP响应的Body复制到文件
_, err = io.Copy(file, bytes.NewBuffer(resp.Body()))
if err != nil {
return "", err
}
currentDir, err := os.Getwd()
if err != nil {
return "", err
}
filePath = currentDir + "/" + filePath
filePath = strings.Replace(filePath, "\\", "/", -1)
return filePath, nil
}

44
clients/go_wcf_http/go.mod vendored Normal file
View File

@ -0,0 +1,44 @@
module go_wechatFerry
go 1.21.5
require (
github.com/danbai225/go-logs v0.3.2
github.com/gin-gonic/gin v1.10.0
github.com/go-resty/resty/v2 v2.13.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.0
go.nanomsg.org/mangos/v3 v3.4.2
google.golang.org/protobuf v1.34.2
)
require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kpango/fastime v1.1.9 // indirect
github.com/kpango/glg v1.6.15 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

183
clients/go_wcf_http/go.sum vendored Normal file
View File

@ -0,0 +1,183 @@
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/danbai225/go-logs v0.3.2 h1:CXMudhrC9rj5hb3tyZvn2APZStioB68QZauZeBPFkmU=
github.com/danbai225/go-logs v0.3.2/go.mod h1:hHxvTTAIkZ3a6XRksnN50gxkqGIlQ1XkNl2U//2erH0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gdamore/optopia v0.2.0/go.mod h1:YKYEwo5C1Pa617H7NlPcmQXl+vG6YnSSNB44n8dNL0Q=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kpango/fastime v1.1.9 h1:xVQHcqyPt5M69DyFH7g1EPRns1YQNap9d5eLhl/Jy84=
github.com/kpango/fastime v1.1.9/go.mod h1:vyD7FnUn08zxY4b/QFBZVG+9EWMYsNl+QF0uE46urD4=
github.com/kpango/glg v1.6.15 h1:nw0xSxpSyrDIWHeb3dvnE08PW+SCbK+aYFETT75IeLA=
github.com/kpango/glg v1.6.15/go.mod h1:cmsc7Yeu8AS3wHLmN7bhwENXOpxfq+QoqxCIk2FneRk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.nanomsg.org/mangos/v3 v3.4.2 h1:gHlopxjWvJcVCcUilQIsRQk9jdj6/HB7wrTiUN8Ki7Q=
go.nanomsg.org/mangos/v3 v3.4.2/go.mod h1:8+hjBMQub6HvXmuGvIq6hf19uxGQIjCofmc62lbedLA=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

229
clients/go_wcf_http/mian.go vendored Normal file
View File

@ -0,0 +1,229 @@
package main
import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
resty "github.com/go-resty/resty/v2"
"github.com/gorilla/websocket"
"go_wechatFerry/app"
"go_wechatFerry/wcf"
"log"
"net"
"net/http"
"os"
"os/signal"
"strings"
"time"
)
func init() {
// 运行sdk.dll中的函数
app.WechatFerryInit()
}
func httpInit() {
// 1.创建路由
r := gin.New()
gin.SetMode(gin.ReleaseMode)
// 2.绑定路由规则,执行的函数
// gin.Context封装了request和response
// 设置模板目录
r.LoadHTMLGlob("templates/*")
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "wechatFerryGoHttp.html", gin.H{})
})
r.POST("/testHttp", func(c *gin.Context) {
type RequestData struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
IsGroup bool `json:"is_group"`
MessageId uint64 `json:"message_id"`
Type uint32 `json:"type"`
Ts uint32 `json:"ts"`
RoomId string `json:"room_id"`
Content string `json:"content"`
WxId string `json:"wx_id"`
Sign string `json:"sign"`
Xml string `json:"xml"`
} `json:"data"`
}
var requestData RequestData
c.BindJSON(&requestData)
fmt.Println(requestData)
})
// 设置消息回调地址
r.POST("/api/SetMessageCallbackUrl", app.SetMessageCallbackUrl)
// 获取登录的wx_id
r.GET("/api/GetSelfWXID", app.GetSelfWXID)
// 获取自己的信息
r.GET("/api/GetUserInfo", app.GetUserInfo)
// 获取消息类型列表
r.GET("/api/GetMsgTypes", app.GetMsgTypes)
// 获取通讯录成功
r.GET("/api/GetContacts", app.GetContacts)
// 获取全部群的群成员
r.GET("/api/GetRoomMembersAll", app.GetRoomMembersAll)
// 获取单个群成员列表
r.POST("/api/GetRoomMember", app.GetRoomMember)
// 获取数据库名
r.GET("/api/GetDBNames", app.GetDBNames)
// 获取表
r.POST("/api/GetDBTables", app.GetDBTables)
// 执行sql
r.POST("/api/ExecDBQuery", app.ExecDBQuery)
// 发送文本消息
r.POST("/api/SendTxt", app.SendTxt)
// 发送图片
r.POST("/api/SendIMG", app.SendIMG)
// 发送文件
r.POST("/api/SendFile", app.SendFile)
// 发送卡片消息
r.POST("/api/SendRichText", app.SendRichText)
// 发送拍一拍消息
r.POST("/api/SendPat", app.SendPat)
// 转发消息
r.POST("/api/ForwardMsg", app.ForwardMsg)
// 发送emoji消息
r.POST("/api/SendEmotion", app.SendEmotion)
// 接受好友请求
r.POST("/api/AcceptFriend", app.AcceptFriend)
// 添加群成员
r.POST("/api/AddChatroomMembers", app.AddChatroomMembers)
// 邀请群成员
r.POST("/api/InvChatRoomMembers", app.InvChatRoomMembers)
// 删除群成员
r.POST("/api/DelChatRoomMembers", app.DelChatRoomMembers)
// 刷新朋友圈
r.POST("/api/RefreshPyq", app.RefreshPyq)
// 下载附件
r.POST("/api/DownloadAttach", app.DownloadAttach)
r.Run("127.0.0.1:8000")
}
func OnMsg() {
err := app.WxClient.OnMSG(func(msg *wcf.WxMsg) {
var message app.Message
message.IsSelf = msg.IsSelf
message.IsGroup = msg.IsGroup
message.MessageId = msg.Id
message.Type = msg.Type
message.Ts = msg.Ts
message.RoomId = msg.Roomid
message.Content = msg.Content
message.Sign = msg.Sign
message.WxId = msg.Sender
message.Thumb = msg.Thumb
message.Extra = msg.Extra
message.Xml = msg.Xml
// 如果你设置了回调链接 那么他就是会传给你 如果你没设置 你可以在else中 添加你的代码 直接删掉 回调的判断即可
if app.WxClient.MessageCallbackUrl != "" {
var data = map[string]interface{}{
"code": 0,
"message": "微信消息",
"data": message,
}
jsonData, _ := json.Marshal(data)
if strings.Contains(app.WxClient.MessageCallbackUrl, "tcp://") {
conn, err := net.Dial("tcp", app.WxClient.MessageCallbackUrl)
defer conn.Close()
if err != nil {
fmt.Println("err :", err)
} else {
_, err := conn.Write(jsonData)
fmt.Println("err :", err)
}
}
if strings.Contains(app.WxClient.MessageCallbackUrl, "udp://") {
addr, err := net.ResolveUDPAddr("udp", app.WxClient.MessageCallbackUrl)
if err != nil {
fmt.Println("Error resolving address:", err)
return
}
// 创建 UDP 连接
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
fmt.Println("Error dialing:", err)
return
}
defer conn.Close()
// 发送消息
_, err = conn.Write(jsonData)
if err != nil {
fmt.Println("Error sending message:", err)
return
}
}
if strings.Contains(app.WxClient.MessageCallbackUrl, "ws://") {
// 创建 WebSocket 连接
conn, _, err := websocket.DefaultDialer.Dial(app.WxClient.MessageCallbackUrl, nil)
if err != nil {
log.Fatal("Dial error:", err)
}
defer conn.Close()
// 设置写入超时
conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
// 发送消息
err = conn.WriteMessage(websocket.TextMessage, jsonData)
if err != nil {
log.Fatal("Write error:", err)
}
}
if strings.Contains(app.WxClient.MessageCallbackUrl, "http") {
_, err := resty.New().SetTimeout(5 * time.Second).R().SetBody(jsonData).Post(app.WxClient.MessageCallbackUrl)
if err != nil {
fmt.Println("http消息发送失败")
}
}
} else {
//fmt.Println("消息类型:", message.Type)
//fmt.Println("消息Thumb", message.Thumb) // 这个可以直接下载
//fmt.Println("消息Extra", message.Extra) // 这个要点一下才能下载(自行处理)
//fmt.Println("消息xml", message.Xml)
//if message.Type == 3 {
// resp, _ := resty.New().R().SetBody(map[string]interface{}{
// "id": message.MessageId,
// "thumb": "F:/c++/WeChatFerry/clients/go_wcf_http/", //下载到本地的哪里
// "extra": message.Thumb, // 看上面的
// }).Post("http://127.0.0.1:8001/api/DownloadAttach")
// fmt.Println(resp.String())
// fmt.Println(resp.Error())
// fmt.Println(resp.StatusCode())
//}
go app.MessageProcess(message)
}
})
if err != nil {
fmt.Println(err)
OnMsg()
} else {
fmt.Println("为正常接受消息状态")
}
}
// 入口
func main() {
// 注册Ctrl+C信号处理函数
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
go func() {
<-signalChan
// 在收到Ctrl+C信号时执行清理操作
fmt.Println("\n感谢温柔的ctrl+c关闭下次可直接运行程序无需重启微信。")
app.WxClient.Close()
os.Exit(0)
}()
// 开启接收消息
_ = app.WxClient.EnableRecvTxt()
// 先启动http服务器 下面的会阻塞
go httpInit()
// 启动推送消息的地方
go OnMsg()
// 防止主goroutine退出
select {}
}

236
clients/go_wcf_http/proto/wcf.proto vendored Normal file
View File

@ -0,0 +1,236 @@
syntax = "proto3";
package wcf;
option java_package = "com.iamteer";
option go_package = "../wcf";
enum Functions {
FUNC_RESERVED = 0x00;
FUNC_IS_LOGIN = 0x01;
FUNC_GET_SELF_WXID = 0x10;
FUNC_GET_MSG_TYPES = 0x11;
FUNC_GET_CONTACTS = 0x12;
FUNC_GET_DB_NAMES = 0x13;
FUNC_GET_DB_TABLES = 0x14;
FUNC_GET_USER_INFO = 0x15;
FUNC_GET_AUDIO_MSG = 0x16;
FUNC_SEND_TXT = 0x20;
FUNC_SEND_IMG = 0x21;
FUNC_SEND_FILE = 0x22;
FUNC_SEND_XML = 0x23;
FUNC_SEND_EMOTION = 0x24;
FUNC_SEND_RICH_TXT = 0x25;
FUNC_SEND_PAT_MSG = 0x26;
FUNC_FORWARD_MSG = 0x27;
FUNC_ENABLE_RECV_TXT = 0x30;
FUNC_DISABLE_RECV_TXT = 0x40;
FUNC_EXEC_DB_QUERY = 0x50;
FUNC_ACCEPT_FRIEND = 0x51;
FUNC_RECV_TRANSFER = 0x52;
FUNC_REFRESH_PYQ = 0x53;
FUNC_DOWNLOAD_ATTACH = 0x54;
FUNC_GET_CONTACT_INFO = 0x55;
FUNC_REVOKE_MSG = 0x56;
FUNC_DECRYPT_IMAGE = 0x60;
FUNC_EXEC_OCR = 0x61;
FUNC_ADD_ROOM_MEMBERS = 0x70;
FUNC_DEL_ROOM_MEMBERS = 0x71;
FUNC_INV_ROOM_MEMBERS = 0x72;
}
message Request
{
Functions func = 1;
oneof msg
{
Empty empty = 2;
string str = 3;
TextMsg txt = 4;
PathMsg file = 5;
DbQuery query = 6;
Verification v = 7;
MemberMgmt m = 8; //
XmlMsg xml = 9;
DecPath dec = 10;
Transfer tf = 11;
uint64 ui64 = 12; // 64
bool flag = 13;
AttachMsg att = 14;
AudioMsg am = 15;
RichText rt = 16;
PatMsg pm = 17;
ForwardMsg fm = 18;
}
}
message Response
{
Functions func = 1;
oneof msg
{
int32 status = 2; // Int
string str = 3; //
WxMsg wxmsg = 4; //
MsgTypes types = 5; //
RpcContacts contacts = 6; //
DbNames dbs = 7; //
DbTables tables = 8; //
DbRows rows = 9; //
UserInfo ui = 10; //
OcrMsg ocr = 11; // OCR
};
}
message Empty { }
message WxMsg
{
bool is_self = 1; //
bool is_group = 2; //
uint64 id = 3; // id
uint32 type = 4; //
uint32 ts = 5; //
string roomid = 6; // id
string content = 7; //
string sender = 8; //
string sign = 9; // Sign
string thumb = 10; //
string extra = 11; //
string xml = 12; // xml
}
message TextMsg
{
string msg = 1; //
string receiver = 2; // @
string aters = 3; // @
}
message PathMsg
{
string path = 1; //
string receiver = 2; //
}
message XmlMsg
{
string receiver = 1; //
string content = 2; // xml
string path = 3; //
int32 type = 4; //
}
message MsgTypes { map<int32, string> types = 1; }
message RpcContact
{
string wxid = 1; // id
string code = 2; //
string remark = 3; //
string name = 4; //
string country = 5; //
string province = 6; // /
string city = 7; //
int32 gender = 8; //
}
message RpcContacts { repeated RpcContact contacts = 1; }
message DbNames { repeated string names = 1; }
message DbTable
{
string name = 1; //
string sql = 2; // SQL
}
message DbTables { repeated DbTable tables = 1; }
message DbQuery
{
string db = 1; //
string sql = 2; // SQL
}
message DbField
{
int32 type = 1; //
string column = 2; //
bytes content = 3; //
}
message DbRow { repeated DbField fields = 1; }
message DbRows { repeated DbRow rows = 1; }
message Verification
{
string v3 = 1; //
string v4 = 2; // Ticket
int32 scene = 3; // 17 30
}
message MemberMgmt
{
string roomid = 1; // ID
string wxids = 2; //
}
message UserInfo
{
string wxid = 1; // ID
string name = 2; //
string mobile = 3; //
string home = 4; // /
}
message DecPath
{
string src = 1; //
string dst = 2; //
}
message Transfer
{
string wxid = 1; //
string tfid = 2; // id transferid
string taid = 3; // Transaction id
}
message AttachMsg
{
uint64 id = 1; // id
string thumb = 2; // thumb
string extra = 3; // extra
}
message AudioMsg
{
uint64 id = 1; // id
string dir = 2; //
}
message RichText
{
string name = 1; //
string account = 2; // id
string title = 3; //
string digest = 4; //
string url = 5; //
string thumburl = 6; //
string receiver = 7; //
}
message PatMsg
{
string roomid = 1; // id
string wxid = 2; // wxid
}
message OcrMsg
{
int32 status = 1; //
string result = 2; //
}
message ForwardMsg
{
uint64 id = 1; // ID
string receiver = 2; // roomId wxid
}

File diff suppressed because one or more lines are too long

606
clients/go_wcf_http/wcf/wcf.go vendored Normal file
View File

@ -0,0 +1,606 @@
package wcf
import (
logs "github.com/danbai225/go-logs"
"go.nanomsg.org/mangos/v3"
"go.nanomsg.org/mangos/v3/protocol"
"go.nanomsg.org/mangos/v3/protocol/pair1"
_ "go.nanomsg.org/mangos/v3/transport/all"
"google.golang.org/protobuf/proto"
"strconv"
"strings"
)
type Client struct {
add string
socket protocol.Socket
RecvTxt bool
ContactsMap []map[string]string
MessageCallbackUrl string
}
func (c *Client) conn() error {
socket, err := pair1.NewSocket()
if err != nil {
return err
}
err = socket.Dial(c.add)
if err != nil {
return err
}
c.socket = socket
return err
}
func (c *Client) send(data []byte) error {
return c.socket.Send(data)
}
func (c *Client) Recv() (*Response, error) {
msg := &Response{}
recv, err := c.socket.Recv()
if err != nil {
return msg, err
}
err = proto.Unmarshal(recv, msg)
return msg, err
}
// Close 退出
func (c *Client) Close() error {
c.DisableRecvTxt()
return c.socket.Close()
}
// IsLogin 查看是否登录
func (c *Client) IsLogin() bool {
err := c.send(genFunReq(Functions_FUNC_IS_LOGIN).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
if recv.GetStatus() == 1 {
return true
}
return false
}
// GetSelfWXID 获取登录的id
func (c *Client) GetSelfWXID() string {
err := c.send(genFunReq(Functions_FUNC_GET_SELF_WXID).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStr()
}
// GetMsgTypes 获取消息类型
func (c *Client) GetMsgTypes() map[int32]string {
err := c.send(genFunReq(Functions_FUNC_GET_MSG_TYPES).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetTypes().GetTypes()
}
// GetContacts 获取通讯录
func (c *Client) GetContacts() []*RpcContact {
err := c.send(genFunReq(Functions_FUNC_GET_CONTACTS).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetContacts().GetContacts()
}
// GetDBNames 获取数据库名
func (c *Client) GetDBNames() []string {
err := c.send(genFunReq(Functions_FUNC_GET_DB_NAMES).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetDbs().Names
}
// GetDBTables 获取表
func (c *Client) GetDBTables(tab string) []*DbTable {
req := genFunReq(Functions_FUNC_GET_DB_TABLES)
str := &Request_Str{Str: tab}
req.Msg = str
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetTables().GetTables()
}
// ExecDBQuery 执行sql
func (c *Client) ExecDBQuery(db, sql string) []*DbRow {
req := genFunReq(Functions_FUNC_EXEC_DB_QUERY)
q := Request_Query{
Query: &DbQuery{
Db: db,
Sql: sql,
},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetRows().GetRows()
}
// AcceptFriend 接收好友请求
func (c *Client) AcceptFriend(v3, v4 string, scene int32) int32 {
req := genFunReq(Functions_FUNC_ACCEPT_FRIEND)
q := Request_V{
V: &Verification{
V3: v3,
V4: v4,
Scene: scene,
}}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
func (c *Client) AddChatroomMembers(roomID, wxIDs string) int32 {
req := genFunReq(Functions_FUNC_ADD_ROOM_MEMBERS)
q := Request_M{
M: &MemberMgmt{Roomid: roomID, Wxids: wxIDs},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// ReceiveTransfer 接收转账
func (c *Client) ReceiveTransfer(wxid, tfid, taid string) int32 {
req := genFunReq(Functions_FUNC_RECV_TRANSFER)
q := Request_Tf{
Tf: &Transfer{
Wxid: wxid,
Tfid: tfid,
Taid: taid,
},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// RefreshPYQ 刷新朋友圈
func (c *Client) RefreshPYQ() int32 {
req := genFunReq(Functions_FUNC_REFRESH_PYQ)
q := Request_Ui64{
Ui64: 0,
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// DecryptImage 解密图片 加密路径,解密路径
func (c *Client) DecryptImage(src, dst string) string {
req := genFunReq(Functions_FUNC_DECRYPT_IMAGE)
q := Request_Dec{
Dec: &DecPath{Src: src, Dst: dst},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.String()
}
// AddChatRoomMembers 添加群成员
func (c *Client) AddChatRoomMembers(roomId string, wxIds []string) int32 {
req := genFunReq(Functions_FUNC_ADD_ROOM_MEMBERS)
q := Request_M{
M: &MemberMgmt{Roomid: roomId,
Wxids: strings.Join(wxIds, ",")},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// InvChatRoomMembers 邀请群成员
func (c *Client) InvChatRoomMembers(roomId string, wxIds []string) int32 {
req := genFunReq(Functions_FUNC_INV_ROOM_MEMBERS)
q := Request_M{
M: &MemberMgmt{Roomid: roomId,
Wxids: strings.Join(wxIds, ",")},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// DelChatRoomMembers 删除群成员
func (c *Client) DelChatRoomMembers(roomId string, wxIds []string) int32 {
req := genFunReq(Functions_FUNC_DEL_ROOM_MEMBERS)
q := Request_M{
M: &MemberMgmt{Roomid: roomId,
Wxids: strings.Join(wxIds, ",")},
}
req.Msg = &q
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// GetUserInfo 获取自己的信息
func (c *Client) GetUserInfo() *UserInfo {
err := c.send(genFunReq(Functions_FUNC_GET_USER_INFO).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetUi()
}
// SendTxt 发送文本内容
func (c *Client) SendTxt(msg string, receiver string, ates []string) int32 {
req := genFunReq(Functions_FUNC_SEND_TXT)
req.Msg = &Request_Txt{
Txt: &TextMsg{
Msg: msg,
Receiver: receiver,
Aters: strings.Join(ates, ","),
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// ForwardMsg 转发消息
func (c *Client) ForwardMsg(Id uint64, receiver string) int32 {
req := genFunReq(Functions_FUNC_FORWARD_MSG)
req.Msg = &Request_Fm{
Fm: &ForwardMsg{
Id: Id,
Receiver: receiver,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendIMG 发送图片
func (c *Client) SendIMG(path string, receiver string) int32 {
req := genFunReq(Functions_FUNC_SEND_IMG)
req.Msg = &Request_File{
File: &PathMsg{
Path: path,
Receiver: receiver,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendFile 发送文件
func (c *Client) SendFile(path string, receiver string) int32 {
req := genFunReq(Functions_FUNC_SEND_FILE)
req.Msg = &Request_File{
File: &PathMsg{
Path: path,
Receiver: receiver,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendRichText 发送卡片消息
func (c *Client) SendRichText(name string, account string, title string, digest string, url string, thumburl string, receiver string) int32 {
req := genFunReq(Functions_FUNC_SEND_RICH_TXT)
req.Msg = &Request_Rt{
Rt: &RichText{
Name: name,
Account: account,
Title: title,
Digest: digest,
Url: url,
Thumburl: thumburl,
Receiver: receiver,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendXml 发送xml数据
func (c *Client) SendXml(path, content, receiver string, Type int32) int32 {
req := genFunReq(Functions_FUNC_SEND_XML)
req.Msg = &Request_Xml{
Xml: &XmlMsg{
Receiver: receiver,
Content: content,
Path: path,
Type: Type,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendEmotion 发送emoji
func (c *Client) SendEmotion(path, receiver string) int32 {
req := genFunReq(Functions_FUNC_SEND_EMOTION)
req.Msg = &Request_File{
File: &PathMsg{
Path: path,
Receiver: receiver,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// SendPat 发送拍一拍消息
func (c *Client) SendPat(roomId, wxId string) int32 {
req := genFunReq(Functions_FUNC_SEND_PAT_MSG)
req.Msg = &Request_Pm{
Pm: &PatMsg{
Roomid: roomId,
Wxid: wxId,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// DownloadAttach 下载附件
func (c *Client) DownloadAttach(id uint64, thumb, extra string) int32 {
req := genFunReq(Functions_FUNC_SEND_PAT_MSG)
req.Msg = &Request_Att{
Att: &AttachMsg{
Id: id,
Thumb: thumb,
Extra: extra,
},
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
return recv.GetStatus()
}
// EnableRecvTxt 开启接收数据
func (c *Client) EnableRecvTxt() int32 {
req := genFunReq(Functions_FUNC_ENABLE_RECV_TXT)
req.Msg = &Request_Flag{
Flag: true,
}
err := c.send(req.build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
c.RecvTxt = true
return recv.GetStatus()
}
// DisableRecvTxt 关闭接收消息
func (c *Client) DisableRecvTxt() int32 {
err := c.send(genFunReq(Functions_FUNC_DISABLE_RECV_TXT).build())
if err != nil {
logs.Err(err)
}
recv, err := c.Recv()
if err != nil {
logs.Err(err)
}
c.RecvTxt = false
return recv.GetStatus()
}
// OnMSG 接收消息
func (c *Client) OnMSG(f func(msg *WxMsg)) error {
socket, err := pair1.NewSocket()
if err != nil {
return err
}
_ = socket.SetOption(mangos.OptionRecvDeadline, 5000)
_ = socket.SetOption(mangos.OptionSendDeadline, 5000)
err = socket.Dial(addPort(c.add))
if err != nil {
return err
}
defer socket.Close()
for c.RecvTxt {
msg := &Response{}
recv, err := socket.Recv()
if err != nil {
return err
}
_ = proto.Unmarshal(recv, msg)
go f(msg.GetWxmsg())
}
return err
}
// NewWCF 连接
func NewWCF(add string) (*Client, error) {
if add == "" {
add = "tcp://127.0.0.1:10086"
}
client := &Client{add: add}
err := client.conn()
return client, err
}
type cmdMSG struct {
*Request
}
func (c *cmdMSG) build() []byte {
marshal, _ := proto.Marshal(c)
return marshal
}
func genFunReq(fun Functions) *cmdMSG {
return &cmdMSG{
&Request{Func: fun,
Msg: nil},
}
}
func addPort(add string) string {
parts := strings.Split(add, ":")
port, _ := strconv.Atoi(parts[2])
newPort := port + 1
return parts[0] + ":" + parts[1] + ":" + strconv.Itoa(newPort)
}

2982
clients/go_wcf_http/wcf/wcf.pb.go vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
## 快速开始 ## 快速开始
* 下载 [最新发布的文件](https://github.com/lich0821/WeChatFerry/releases/latest),解压到 `WeChatFerry\clients\java\wcferry\src\main\resources\win32-x86-64` * 下载 [最新发布的文件](https://github.com/lich0821/WeChatFerry/releases/latest),解压到 `WeChatFerry\clients\java\wcferry\dll`目录下
* 使用惯用 IDE打开工程编译运行。 * 使用惯用 IDE打开工程编译运行。
@ -68,9 +68,9 @@ cd C:/Projs/WeChatFerry/java/wcferry/src/main/java
protoc.exe --java_out=. --proto_path=C:\Projs\WeChatFerry\WeChatFerry\rpc\proto wcf.proto protoc.exe --java_out=. --proto_path=C:\Projs\WeChatFerry\WeChatFerry\rpc\proto wcf.proto
``` ```
### 添加 `wcferry` 依赖 ### 添加 `dll` 依赖
`wcf.exe` 、 `spy.dll` 、 `spy_debug.dll` 添加到 `WeChatFerry\clients\java\wcferry\src\main\resources\win32-x86-64`。 将 `spy.dll` 、 `spy_debug.dll`、 `spy.dll` 添加到 `WeChatFerry\clients\java\wcferry\dll`。
### 其他问题 ### 其他问题

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ public class Main {
// Client client = new Client("127.0.0.1", 10086); // Client client = new Client("127.0.0.1", 10086);
// 本地启动 RPC // 本地启动 RPC
Client client = new Client(true); // 默认 10086 端口 Client client = new Client(); // 默认 10086 端口
// Client client = new Client(10088,true); // 也可以指定端口 // Client client = new Client(10088,true); // 也可以指定端口
// 是否已登录 // 是否已登录
@ -60,3 +60,4 @@ public class Main {
client.keepRunning(); client.keepRunning();
} }
} }

View File

@ -0,0 +1,30 @@
package com.iamteer;
import com.sun.jna.Library;
import com.sun.jna.Native;
/**
* SDK.dll的接口类
* @Description
* @Author xinggq
* @Date 2024/7/10
*/
public interface SDK extends Library {
// 读取项目根目录下dll文件夹而且只能写绝对路径放在resource下会有问题暂时先不解决
// 打包后dll文件应该放在jar外这样dll更新不需要生成jar包重启下就ok了
SDK INSTANCE = Native.load(System.getProperty("user.dir")+"\\dll\\sdk.dll", SDK.class);
/**
* 初始化SDK
* @param debug
* @param port
* @return
*/
int WxInitSDK(boolean debug, int port);
/**
* 退出SDK
* @return
*/
int WxDestroySDK();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,15 @@
# WeChatFerry Python 客户端 # WeChatFerry Python 客户端
[![PyPi](https://img.shields.io/pypi/v/wcferry.svg)](https://pypi.python.org/pypi/wcferry) [![Downloads](https://static.pepy.tech/badge/wcferry)](https://pypi.python.org/pypi/wcferry) [![Documentation Status](https://readthedocs.org/projects/wechatferry/badge/?version=latest)](https://wechatferry.readthedocs.io/zh/latest/?badge=latest) [![PyPi](https://img.shields.io/pypi/v/wcferry.svg)](https://pypi.python.org/pypi/wcferry) [![Downloads](https://static.pepy.tech/badge/wcferry)](https://pypi.python.org/pypi/wcferry) [![Documentation Status](https://readthedocs.org/projects/wechatferry/badge/?version=latest)](https://wechatferry.readthedocs.io/zh/latest/?badge=latest)
|[📖 文档](https://wechatferry.readthedocs.io/)|[📺 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/vAGpn1C9stI8Xzt1hUJhLA)| |[📖 Python 文档](https://wechatferry.readthedocs.io/)|[📺 Python 视频教程](https://mp.weixin.qq.com/s/APdjGyZ2hllXxyG_sNCfXQ)|[🙋 FAQ](https://mp.weixin.qq.com/s/I6n_6fuQa60CrROWSgq0TA)|
|:-:|:-:|:-:| |:-:|:-:|:-:|
🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。 🤖示例机器人框架:[WeChatRobot](https://github.com/lich0821/WeChatRobot)。
|![碲矿](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/TEQuant.jpg)|![赞赏](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/QR.jpeg)|
|:-:|:-:|
|后台回复 `WCF` 加群交流|如果你觉得有用|
## 快速开始 ## 快速开始
```sh ```sh
pip install --upgrade wcferry pip install --upgrade wcferry
@ -14,10 +18,6 @@ pip install --upgrade wcferry
### Demo ### Demo
参考 [WeChatRobot](https://github.com/lich0821/WeChatRobot) 和上面的文档。 参考 [WeChatRobot](https://github.com/lich0821/WeChatRobot) 和上面的文档。
|![碲矿](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/TEQuant.jpg)|![赞赏](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/QR.jpeg)|
|:-:|:-:|
|后台回复 `WCF` 加群交流|如果你觉得有用|
## 一起开发 ## 一起开发
### 配置环境 ### 配置环境
```sh ```sh
@ -44,9 +44,8 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc
## 版本更新 ## 版本更新
### v39.0.14.0 (2024.02.18) ### v39.2.4.0 (2024.07.08)
* 若干优化 * 修复 wxid 问题
* 若干功能
<details><summary>点击查看更多</summary> <details><summary>点击查看更多</summary>
@ -60,33 +59,28 @@ python -m grpc_tools.protoc --python_out=. --proto_path=../../../WeChatFerry/rpc
功能: 功能:
* 查登录状态 * 查登录状态
* 获取登录账号的 wxid * 获取登录账号信息
* 获取消息类型 * 获取消息类型
* 获取所有联系人 * 获取联系人
* 获取所有好友 * 获取可查询数据库
* 获取数据库 * 获取数据库所有表
* 获取某数据库下的表 * 获取语音消息
* 获取用户信息
* 发送文本消息(可 @ * 发送文本消息(可 @
* 发送图片(支持网络路径) * 发送图片消息
* 发送文件(支持网络路径) * 发送文件消息
* 允许接收消息 * 发送卡片消息
* 停止接收消息 * 发送 GIF
* 执行 SQL 查询 * 拍一拍群友
* 接受好友申请 * 转发消息
* 开启接收消息
* 关闭接收消息
* 查询数据库
* 获取朋友圈消息
* 下载图片、视频、文件
* 解密图片
* 添加群成员 * 添加群成员
* 删除群成员 * 删除群成员
* 解密图片
* 获取朋友圈消息
* 保存图片
* 保存语音
* 发送卡片消息
* 拍一拍群友
* 邀请群成员 * 邀请群成员
* 图片 OCR
* 转发消息
* 撤回消息
* 获取登录二维码
</details> </details>

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
__version__ = "39.1.0.0" __version__ = "39.2.4.0"
import atexit import atexit
import base64 import base64
@ -418,7 +418,6 @@ class Wcf():
Returns: Returns:
int: 0 为成功其他失败 int: 0 为成功其他失败
""" """
raise Exception("Not implemented, yet")
req = wcf_pb2.Request() req = wcf_pb2.Request()
req.func = wcf_pb2.FUNC_SEND_EMOTION # FUNC_SEND_EMOTION req.func = wcf_pb2.FUNC_SEND_EMOTION # FUNC_SEND_EMOTION
req.file.path = path req.file.path = path

View File

@ -56,7 +56,7 @@ class WxMsg():
if not self.from_group(): if not self.from_group():
return False # 只有群消息才能 @ return False # 只有群消息才能 @
if not re.findall(f"<atuserlist>.*({wxid}).*</atuserlist>", self.xml): if not re.findall(f"<atuserlist>[\s|\S]*({wxid})[\s|\S]*</atuserlist>", self.xml):
return False # 不在 @ 清单里 return False # 不在 @ 清单里
if re.findall(r"@(?:所有人|all|All)", self.content): if re.findall(r"@(?:所有人|all|All)", self.content):

1
clients/wcferry-node vendored Submodule

@ -0,0 +1 @@
Subproject commit 2f0ff1584ff74efef6eeb6a20fb159837ed1bf7b