Initial commit

This commit is contained in:
Changhua 2021-02-12 23:21:57 +08:00
commit 16754c3279
45 changed files with 2896 additions and 0 deletions

7
.editorconfig Normal file
View File

@ -0,0 +1,7 @@
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
.*
!.gitignore
!.editorconfig
# VS2019 build files
Debug/
Release/
x64/
# RPC generated files
*_c.c
*_s.c
*_h.h

58
App/App.cpp Normal file
View File

@ -0,0 +1,58 @@
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <process.h>
#include <windows.h>
#include "sdk.h"
/*
#pragma comment(lib, "SDK.lib")
*/
int onTextMsg(WxMessage_t msg)
{
try {
wcout << msg.id << L" msgType: " << msg.type << L", msgSource: " << msg.source << L", isSelf: " << msg.self
<< endl;
wcout << msg.wxId << L"[" << msg.roomId << L"]" << L" >> " << msg.content << endl;
wcout << L"msgSourceXml: " << msg.xml << endl;
} catch (...) {
wcout << "something wrong..." << endl;
}
wcout.flush();
return 0;
}
int main()
{
DWORD status = 0;
wstring wxid = L"filehelper"; // 微信ID
wstring at_wxid = L"";
wstring content = L"这里填写消息内容";
//_setmode(_fileno(stdout), _O_WTEXT); // 没有这个wcout遇到一些字符会导致console卡死用了会导致脱离控制台
_wsetlocale(LC_ALL, L"chs"); // 这是个大坑,不设置中文直接不见了。。。
// 获取消息类型
const MsgTypesMap_t WxMsgTypes = WxGetMsgTypes();
for (auto it = WxMsgTypes.begin(); it != WxMsgTypes.end(); ++it) {
wcout << it->first << L": " << it->second << endl;
}
status = WxInitSDK();
wcout << L"WxInitSDK: " << status << endl;
if (status != 0) {
return 0;
}
wcout << L"Message: 接收通知中......" << endl;
WxSetTextMsgCb(onTextMsg);
// 测试消息发送
WxSendTextMsg(wxid, at_wxid, content);
while (1) {
Sleep(10000); // 休眠释放CPU
}
}

54
App/App.py Normal file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import time
import wcferry as sdk
def main():
print(dir(sdk)) # 查看SDK支持的方法和属性
help(sdk.WxSetTextMsgCb) # 查看某方法的情况
help(sdk.WxMessage) # 查看消息结构
WxMsgTypes = sdk.WxGetMsgTypes() # 获取消息类型
print(WxMsgTypes) # 查看消息类型
# 初始化SDK如果成功返回0否则失败
status = sdk.WxInitSDK()
if status != 0:
print("初始化失败")
exit(-1)
print("初始化成功")
time.sleep(2)
print("发送文本消息......")
sdk.WxSendTextMsg("filehelper", "", "message from WeChatFerry...")
# 接收消息。先定义消息处理回调
def OnTextMsg(msg: sdk.WxMessage):
if msg.self == 1: # 忽略自己发的消息
return 0
s = ""
msgType = WxMsgTypes.get(msg.type, '未知消息类型')
if msg.source == 0:
s += f"收到来自好友[{msg.wxId}]的{msgType}消息:"
else:
s += f"收到来自群[{msg.roomId}]的[{msg.wxId}]的{msgType}消息:"
s += f"\r\n{msg.content}"
if msg.type != 0x01:
s += f"\r\n{msg.xml}"
print(f"\n{s}")
return 0
print("Message: 接收通知中......")
sdk.WxSetTextMsgCb(OnTextMsg) # 设置回调,接收消息
while True:
time.sleep(1)
if __name__ == '__main__':
main()

163
App/App.vcxproj Normal file
View File

@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="app.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{44c1a579-22a7-4ba3-a618-45bd01600294}</ProjectGuid>
<RootNamespace>App</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions> /utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)SDK.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)SDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(OutDir)SDK.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>md wx
xcopy /y $(OutDir)Spy.dll $(OutDir)wx\
xcopy /y $(OutDir)SDK.dll $(OutDir)wx\
xcopy /y $(OutDir)wcferry.pyd $(OutDir)wx\
xcopy /y $(OutDir)App.exe $(OutDir)wx\
xcopy /y $(SolutionDir)App\App.py $(OutDir)wx\</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy output</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

22
App/App.vcxproj.filters Normal file
View File

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

4
App/App.vcxproj.user Normal file
View File

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

28
README.MD Normal file
View File

@ -0,0 +1,28 @@
# WeChatFerry
传送信息往返微信的摆渡车。
## 快速开始
1. 使用 VS2019 编译。
2. 打开 `CMD`,运行 `App.exe`
## 项目结构
### Spy
间谍模块,注入到微信中,通过 RPC 做消息转发工作。
### SDK
RPC 的客户端,封装接口,供其他方调用。
### SDKpy
用于生成 Python 接口。为编译该项目,需要做一些配置:
1. 添加附加包含目录
* Python 头:`C:\Program Files (x86)\Python37-32\Include`
* Pybind11 头:`C:\Projs\.pyenv\pybind11\lib\site-packages\pybind11\include`
*注*
1. pybind11 可以通过 Python 安装(本工程安装到虚拟环境里了):`pip install pybind11`
2. 然后通过命令查找:`python -m pybind11 --includes`
2. 添加 Python 的库
* `C:\Program Files (x86)\Python37-32\libs`
### App
示例应用,介绍如何调用 SDK。

16
Rpc/rpc.idl Normal file
View File

@ -0,0 +1,16 @@
[
uuid(ed838ecd-8a1e-4da7-bfda-9f2d12d07893),
version(1.0),
implicit_handle(handle_t hSpyBinding),
]
interface ISpy
{
import "rpc_types.h";
int IsLogin();
int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *at_wxid, [ in, string ] const wchar_t *msg);
void EnableReceiveMsg();
[callback] int ReceiveMsg([ in ] RpcMessage_t *msg);
};

9
Rpc/rpc_memory.cpp Normal file
View File

@ -0,0 +1,9 @@
#include <windows.h>
/******************************************************/
/* MIDL allocate and free */
/******************************************************/
void __RPC_FAR *__RPC_USER midl_user_allocate(size_t len) { return (malloc(len)); }
void __RPC_USER midl_user_free(void __RPC_FAR *ptr) { free(ptr); }

18
Rpc/rpc_types.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#define MSG_SIZE_MSG_ID 64
#define MSG_SIZE_MSG_XML 4096
#define MSG_SIZE_WXID 64
#define MSG_SIZE_ROOMID 64
#define MSG_SIZE_CONTENT 16385
typedef struct RpcMessage {
int self; // 是否自己发的消息0=否1=是
int type; // 消息类型
int source; // 消息来源0=好友消息1=群消息
wchar_t id[MSG_SIZE_MSG_ID]; // 消息ID
wchar_t xml[MSG_SIZE_MSG_XML]; // 群其他消息
wchar_t wxId[MSG_SIZE_WXID]; // 发送人微信ID
wchar_t roomId[MSG_SIZE_ROOMID]; // 群ID
wchar_t content[MSG_SIZE_CONTENT]; // 消息内容MAC版最大16384即16KB
} RpcMessage_t;

181
SDK/SDK.vcxproj Normal file
View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{707f2dcd-1001-42a7-b20e-b85b1bbab228}</ProjectGuid>
<RootNamespace>SDK</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalOptions> /utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<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>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="injector.h" />
<ClInclude Include="sdk.h" />
<ClInclude Include="util.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Rpc\rpc_c.c" />
<ClCompile Include="..\Rpc\rpc_memory.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="injector.cpp" />
<ClCompile Include="sdk.cpp" />
<ClCompile Include="util.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="sdk.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

59
SDK/SDK.vcxproj.filters Normal file
View File

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

4
SDK/SDK.vcxproj.user Normal file
View File

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

21
SDK/dllmain.cpp Normal file
View File

@ -0,0 +1,21 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "framework.h"
#include <rpc.h>
extern RPC_STATUS RpcConnectServer();
extern RPC_STATUS RpcDisconnectServer();
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH: {
RpcDisconnectServer();
break;
}
}
return TRUE;
}

5
SDK/framework.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

653
SDK/injector.cpp Normal file
View File

@ -0,0 +1,653 @@
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "injector.h"
#include <malloc.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
typedef BOOL(WINAPI *IsWow64Process2_t)(HANDLE hProcess, USHORT *pProcessMachine, USHORT *pNativeMachine);
static DWORD page_size = 0;
static size_t func_LoadLibraryW;
static size_t func_FreeLibrary;
static size_t func_GetLastError;
static char errmsg[512];
static injector_t *g_injector;
#ifdef _M_AMD64
static const char x64_code_template[] =
// ---------- call LoadLibraryW ----------
/* 0000: */ "\x48\x83\xEC\x28" // sub rsp,28h
/* 0004: */ "\xFF\x15\x3E\x00\x00\x00" // call LoadLibraryW
// 0x0000003e = X64_ADDR_LoadLibraryW - (0x0004 + 6)
/* 000A: */ "\x48\x85\xC0" // test rax,rax
/* 000D: */ "\x74\x0B" // je L1
/* 000F: */ "\x48\x89\x05\xEA\x0F\x00\x00" // mov [load_address], rax
// 0x00000fea = 0x1000 - (0x000F + 7)
/* 0016: */ "\x33\xC0" // xor eax,eax
/* 0018: */ "\xEB\x06" // jmp L2
/* 001A: L1: */ "\xFF\x15\x38\x00\x00\x00" // call GetLastError
// 0x00000038 = X64_ADDR_GetLastError - (0x001A + 6)
/* 0020: L2: */ "\x48\x83\xC4\x28" // add rsp,28h
/* 0024: */ "\xC3" // ret
// ---------- call FreeLibrary ----------
#define X64_UNINJECTION_CODE_OFFSET 0x25
/* 0025: */ "\x48\x83\xEC\x28" // sub rsp,28h
/* 0029: */ "\xFF\x15\x21\x00\x00\x00" // call FreeLibrary
// 0x00000021 = X64_ADDR_FreeLibrary - (0x0029 + 6)
/* 002F: */ "\x85\xC0" // test eax,eax
/* 0031: */ "\x74\x04" // je L1
/* 0033: */ "\x33\xC0" // xor eax,eax
/* 0035: */ "\xEB\x06" // jmp L2
/* 0037: L1: */ "\xFF\x15\x1B\x00\x00\x00" // call GetLastError
// 0x0000001B = X64_ADDR_GetLastError - (0x0037 + 6)
/* 003D: L2: */ "\x48\x83\xC4\x28" // add rsp,28h
/* 0041: */ "\xC3" // ret
// padding
/* 0042: */ "\x90\x90\x90\x90\x90\x90"
// ---------- literal pool ----------
#define X64_ADDR_LoadLibraryW 0x0048
/* 0048: */ "\x90\x90\x90\x90\x90\x90\x90\x90"
#define X64_ADDR_FreeLibrary 0x0050
/* 0050: */ "\x90\x90\x90\x90\x90\x90\x90\x90"
#define X64_ADDR_GetLastError 0x0058
/* 0058: */ "\x90\x90\x90\x90\x90\x90\x90\x90";
#define X64_CODE_SIZE 0x0060
#endif
#if defined(_M_AMD64) || defined(_M_IX86)
static const char x86_code_template[] =
// ---------- call LoadLibraryW ----------
/* 0000: */ "\xFF\x74\x24\x04" // push dword ptr [esp+4]
#define X86_CALL_LoadLibraryW 0x0004
/* 0004: */ "\xE8\x00\x00\x00\x00" // call LoadLibraryW@4
/* 0009: */ "\x85\xC0" // test eax,eax
/* 000B: */ "\x74\x09" // je L1
#define X86_MOV_EAX 0x000D
/* 000D: */ "\xA3\x00\x00\x00\x00" // mov dword ptr [load_address], eax
/* 0012: */ "\x33\xC0" // xor eax,eax
/* 0014: */ "\xEB\x05" // jmp L2
#define X86_CALL_GetLastError1 0x0016
/* 0016: L1: */ "\xE8\x00\x00\x00\x00" // call GetLastError@0
/* 001B: L2: */ "\xC2\x04\x00" // ret 4
// ---------- call FreeLibrary ----------
#define X86_UNINJECTION_CODE_OFFSET 0x001E
/* 001E: */ "\xFF\x74\x24\x04" // push dword ptr [esp+4]
#define X86_CALL_FreeLibrary 0x0022
/* 0022: */ "\xE8\x00\x00\x00\x00" // call FreeLibrary@4
/* 0027: */ "\x85\xC0" // test eax,eax
/* 0029: */ "\x74\x04" // je L1
/* 002B: */ "\x33\xC0" // xor eax,eax
/* 002D: */ "\xEB\x05" // jmp L2
#define X86_CALL_GetLastError2 0x002F
/* 002F: L1: */ "\xE8\x00\x00\x00\x00" // call GetLastError@0
/* 0034: L2: */ "\xC2\x04\x00" // ret 4
;
#define X86_CODE_SIZE 0x0037
#endif
#ifdef _M_AMD64
#define CURRENT_ARCH "x64"
#define CODE_SIZE X64_CODE_SIZE
#endif
#ifdef _M_IX86
#define CURRENT_ARCH "x86"
#define CODE_SIZE X86_CODE_SIZE
#endif
static void set_errmsg(const char *format, ...);
static const char *w32strerr(DWORD err);
static USHORT process_arch(HANDLE hProcess);
static const char *arch_name(USHORT arch);
struct injector {
HANDLE hProcess;
char *remote_mem;
char *injection_code;
char *uninjection_code;
};
static BOOL init(void)
{
SYSTEM_INFO si;
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
HMODULE kernel32 = GetModuleHandleA("kernel32");
if (kernel32 == 0) {
return FALSE;
}
GetSystemInfo(&si);
page_size = si.dwPageSize;
func_LoadLibraryW = (size_t)GetProcAddress(kernel32, "LoadLibraryW");
func_FreeLibrary = (size_t)GetProcAddress(kernel32, "FreeLibrary");
func_GetLastError = (size_t)GetProcAddress(kernel32, "GetLastError");
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
return FALSE;
}
if (!LookupPrivilegeValue(0, SE_DEBUG_NAME, &luid)) {
CloseHandle(hToken);
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}
#if defined(_M_AMD64)
static int cmp_func(const void *context, const void *key, const void *datum)
{
ptrdiff_t rva_to_va = (ptrdiff_t)context;
const char *k = (const char *)key;
const char *d = (const char *)(rva_to_va + *(const DWORD *)datum);
return strcmp(k, d);
}
static int funcaddr(DWORD pid, size_t *load_library, size_t *free_library, size_t *get_last_error)
{
HANDLE hSnapshot;
MODULEENTRY32W me;
BOOL ok;
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hFileMapping = NULL;
void *base = NULL;
IMAGE_NT_HEADERS *nt_hdrs;
ULONG exp_size;
const IMAGE_EXPORT_DIRECTORY *exp;
const DWORD *names, *name, *funcs;
const WORD *ordinals;
ptrdiff_t rva_to_va;
int rv = INJERR_OTHER;
/* Get the full path of kernel32.dll. */
retry:
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (hSnapshot == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
switch (err) {
case ERROR_BAD_LENGTH:
goto retry;
case ERROR_ACCESS_DENIED:
rv = INJERR_PERMISSION;
break;
case ERROR_INVALID_PARAMETER:
rv = INJERR_NO_PROCESS;
break;
default:
rv = INJERR_OTHER;
}
set_errmsg("CreateToolhelp32Snapshot error: %s", w32strerr(err));
return rv;
}
me.dwSize = sizeof(me);
for (ok = Module32FirstW(hSnapshot, &me); ok; ok = Module32NextW(hSnapshot, &me)) {
if (wcsicmp(me.szModule, L"kernel32.dll") == 0) {
break;
}
}
CloseHandle(hSnapshot);
if (!ok) {
set_errmsg("kernel32.dll could not be found.");
return INJERR_OTHER;
}
/* Get the export directory in the kernel32.dll. */
hFile = CreateFileW(me.szExePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
set_errmsg("failed to open file %s: %s", me.szExePath, w32strerr(GetLastError()));
goto exit;
}
hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMapping == NULL) {
set_errmsg("failed to create file mapping of %s: %s", me.szExePath, w32strerr(GetLastError()));
goto exit;
}
base = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
if (base == NULL) {
set_errmsg("failed to map file %s to memory: %s", me.szExePath, w32strerr(GetLastError()));
goto exit;
}
nt_hdrs = ImageNtHeader(base);
if (nt_hdrs == NULL) {
set_errmsg("ImageNtHeader error: %s", w32strerr(GetLastError()));
goto exit;
}
exp = (const IMAGE_EXPORT_DIRECTORY *)ImageDirectoryEntryToDataEx(base, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT,
&exp_size, NULL);
if (exp == NULL) {
set_errmsg("ImageDirectoryEntryToDataEx error: %s", w32strerr(GetLastError()));
goto exit;
}
if (exp->NumberOfNames == 0) {
set_errmsg("No export entires are not found.");
goto exit;
}
names = (const DWORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNames, NULL);
if (names == NULL) {
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
goto exit;
}
ordinals = (const WORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfNameOrdinals, NULL);
if (ordinals == NULL) {
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
goto exit;
}
funcs = (const DWORD *)ImageRvaToVa(nt_hdrs, base, exp->AddressOfFunctions, NULL);
if (funcs == NULL) {
set_errmsg("ImageRvaToVa error: %s", w32strerr(GetLastError()));
goto exit;
}
rva_to_va = (size_t)ImageRvaToVa(nt_hdrs, base, names[0], NULL) - (size_t)names[0];
/* Find the address of LoadLibraryW */
name = bsearch_s((void *)"LoadLibraryW", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
if (name == NULL) {
set_errmsg("Could not find the address of LoadLibraryW");
goto exit;
}
*load_library = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
/* Find the address of FreeLibrary */
name = bsearch_s((void *)"FreeLibrary", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
if (name == NULL) {
set_errmsg("Could not find the address of FreeLibrary");
goto exit;
}
*free_library = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
/* Find the address of GetLastError */
name = bsearch_s((void *)"GetLastError", names, exp->NumberOfNames, sizeof(DWORD), cmp_func, (void *)rva_to_va);
if (name == NULL) {
set_errmsg("Could not find the address of GetLastError");
goto exit;
}
*get_last_error = (size_t)me.modBaseAddr + funcs[ordinals[name - names]];
rv = 0;
exit:
if (base != NULL) {
UnmapViewOfFile(base);
}
if (hFileMapping != NULL) {
CloseHandle(hFileMapping);
}
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
return rv;
}
#endif
int cki_attach(injector_t **injector_out, DWORD pid)
{
injector_t *injector;
DWORD dwDesiredAccess = PROCESS_QUERY_LIMITED_INFORMATION | /* for IsWow64Process() */
PROCESS_CREATE_THREAD | /* for CreateRemoteThread() */
PROCESS_VM_OPERATION | /* for VirtualAllocEx() */
PROCESS_VM_READ | /* for ReadProcessMemory() */
PROCESS_VM_WRITE; /* for WriteProcessMemory() */
USHORT arch;
DWORD old_protect;
SIZE_T written;
int rv;
char code[CODE_SIZE];
size_t code_size;
size_t load_library, free_library, get_last_error;
if (page_size == 0) {
init();
}
load_library = func_LoadLibraryW;
free_library = func_FreeLibrary;
get_last_error = func_GetLastError;
injector = (injector_t *)calloc(1, sizeof(injector_t));
if (injector == NULL) {
set_errmsg("malloc error: %s", strerror(errno));
return INJERR_NO_MEMORY;
}
injector->hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
if (injector->hProcess == NULL) {
DWORD err = GetLastError();
set_errmsg("OpenProcess error: %s", w32strerr(err));
switch (err) {
case ERROR_ACCESS_DENIED:
rv = INJERR_PERMISSION;
break;
case ERROR_INVALID_PARAMETER:
rv = INJERR_NO_PROCESS;
break;
default:
rv = INJERR_OTHER;
}
goto error_exit;
}
arch = process_arch(injector->hProcess);
switch (arch) {
#ifdef _M_AMD64
case IMAGE_FILE_MACHINE_AMD64:
break;
case IMAGE_FILE_MACHINE_I386:
rv = funcaddr(pid, &load_library, &free_library, &get_last_error);
if (rv != 0) {
goto error_exit;
}
break;
#endif
#ifdef _M_IX86
case IMAGE_FILE_MACHINE_I386:
break;
#endif
default:
set_errmsg("%s target process isn't supported by %s process.", arch_name(arch), CURRENT_ARCH);
rv = INJERR_UNSUPPORTED_TARGET;
goto error_exit;
}
injector->remote_mem
= (char *)VirtualAllocEx(injector->hProcess, NULL, 2 * page_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (injector->remote_mem == NULL) {
set_errmsg("VirtualAllocEx error: %s", w32strerr(GetLastError()));
rv = INJERR_OTHER;
goto error_exit;
}
injector->injection_code = injector->remote_mem;
switch (arch) {
#ifdef _M_AMD64
case IMAGE_FILE_MACHINE_AMD64: /* x64 */
memcpy(code, x64_code_template, X64_CODE_SIZE);
code_size = X64_CODE_SIZE;
*(size_t *)(code + X64_ADDR_LoadLibraryW) = load_library;
*(size_t *)(code + X64_ADDR_FreeLibrary) = free_library;
*(size_t *)(code + X64_ADDR_GetLastError) = get_last_error;
injector->uninjection_code = injector->remote_mem + X64_UNINJECTION_CODE_OFFSET;
break;
#endif
#if defined(_M_AMD64) || defined(_M_IX86)
case IMAGE_FILE_MACHINE_I386: /* x86 */
memcpy(code, x86_code_template, X86_CODE_SIZE);
code_size = X86_CODE_SIZE;
#define FIX_CALL_RELATIVE(addr, offset) \
*(uint32_t *)(code + offset + 1) = addr - ((uint32_t)(size_t)injector->remote_mem + offset + 5)
FIX_CALL_RELATIVE(load_library, X86_CALL_LoadLibraryW);
FIX_CALL_RELATIVE(free_library, X86_CALL_FreeLibrary);
FIX_CALL_RELATIVE(get_last_error, X86_CALL_GetLastError1);
FIX_CALL_RELATIVE(get_last_error, X86_CALL_GetLastError2);
*(uint32_t *)(code + X86_MOV_EAX + 1) = (uint32_t)(size_t)injector->remote_mem + page_size;
injector->uninjection_code = injector->remote_mem + X86_UNINJECTION_CODE_OFFSET;
break;
#endif
default:
set_errmsg("Never reach here: arch=0x%x", arch);
rv = INJERR_OTHER;
goto error_exit;
}
if (!WriteProcessMemory(injector->hProcess, injector->remote_mem, code, code_size, &written)) {
set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError()));
rv = INJERR_OTHER;
goto error_exit;
}
if (!VirtualProtectEx(injector->hProcess, injector->remote_mem, page_size, PAGE_EXECUTE_READ, &old_protect)) {
set_errmsg("VirtualProtectEx error: %s", w32strerr(GetLastError()));
rv = INJERR_OTHER;
goto error_exit;
}
*injector_out = injector;
return 0;
error_exit:
cki_detach(injector);
return rv;
}
int cki_inject(injector_t *injector, const char *path, void **handle)
{
DWORD pathlen = (DWORD)strlen(path);
wchar_t *wpath;
DWORD wpathlen;
if (pathlen == 0) {
set_errmsg("The specified path is empty.");
return INJERR_FILE_NOT_FOUND;
}
if (pathlen > MAX_PATH) {
set_errmsg("too long file path: %s", path);
return INJERR_FILE_NOT_FOUND;
}
wpath = (wchar_t *)_alloca((pathlen + 1) * sizeof(wchar_t));
wpathlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, path, pathlen, wpath, pathlen + 1);
wpath[wpathlen] = L'\0';
return cki_inject_w(injector, wpath, handle);
}
int cki_inject_w(injector_t *injector, const wchar_t *path, void **handle)
{
struct {
void *load_address;
wchar_t fullpath[MAX_PATH];
} data = {
NULL,
};
DWORD pathlen;
SIZE_T written;
HANDLE hThread;
DWORD err;
pathlen = GetFullPathNameW(path, MAX_PATH, data.fullpath, NULL);
if (pathlen > MAX_PATH) {
set_errmsg("too long file path: %S", path);
return INJERR_FILE_NOT_FOUND;
}
if (pathlen == 0) {
set_errmsg("failed to get the full path: %S", path);
return INJERR_FILE_NOT_FOUND;
}
if (!WriteProcessMemory(injector->hProcess, injector->remote_mem + page_size, &data, sizeof(data), &written)) {
set_errmsg("WriteProcessMemory error: %s", w32strerr(GetLastError()));
return INJERR_OTHER;
}
hThread = CreateRemoteThread(injector->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)injector->injection_code,
injector->remote_mem + page_size + sizeof(void *), 0, NULL);
if (hThread == NULL) {
set_errmsg("CreateRemoteThread error: %s", w32strerr(GetLastError()));
return INJERR_OTHER;
}
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &err);
CloseHandle(hThread);
if (err != 0) {
set_errmsg("LoadLibrary in the target process failed: %s", w32strerr(err));
return INJERR_ERROR_IN_TARGET;
}
if (!ReadProcessMemory(injector->hProcess, injector->remote_mem + page_size, &data, sizeof(void *), &written)) {
set_errmsg("ReadProcessMemory error: %s", w32strerr(GetLastError()));
return INJERR_OTHER;
}
if (handle != NULL) {
*handle = data.load_address;
}
return 0;
}
int cki_uninject(injector_t *injector, void *handle)
{
HANDLE hThread;
DWORD err;
hThread = CreateRemoteThread(injector->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)injector->uninjection_code,
handle, 0, NULL);
if (hThread == NULL) {
set_errmsg("CreateRemoteThread error: %s", w32strerr(GetLastError()));
return INJERR_OTHER;
}
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &err);
CloseHandle(hThread);
if (err != 0) {
set_errmsg("FreeLibrary in the target process failed: %s", w32strerr(err));
return INJERR_ERROR_IN_TARGET;
}
return 0;
}
int cki_detach(injector_t *injector)
{
if (injector->remote_mem != NULL) {
VirtualFreeEx(injector->hProcess, injector->remote_mem, 0, MEM_RELEASE);
}
if (injector->hProcess != NULL) {
CloseHandle(injector->hProcess);
}
free(injector);
return 0;
}
const char *cki_error(void) { return errmsg; }
static void set_errmsg(const char *format, ...)
{
va_list ap;
int rv;
va_start(ap, format);
rv = vsnprintf(errmsg, sizeof(errmsg), format, ap);
va_end(ap);
if (rv == -1 || rv >= sizeof(errmsg)) {
errmsg[sizeof(errmsg) - 1] = '\0';
}
}
static const char *w32strerr(DWORD err)
{
static char errmsg[512];
DWORD len;
len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), errmsg, sizeof(errmsg), NULL);
if (len > 0) {
while (len > 0) {
char c = errmsg[len - 1];
if (c == ' ' || c == '\n' || c == '\r') {
len--;
} else {
break;
}
}
errmsg[len] = '\0';
} else if ((int)err >= 0) {
sprintf(errmsg, "win32 error code %d", err);
} else {
sprintf(errmsg, "win32 error code 0x%x", err);
}
return errmsg;
}
static USHORT process_arch(HANDLE hProcess)
{
static IsWow64Process2_t IsWow64Process2_func = (IsWow64Process2_t)-1;
if (IsWow64Process2_func == (IsWow64Process2_t)-1) {
IsWow64Process2_func = (IsWow64Process2_t)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process2");
}
if (IsWow64Process2_func != NULL) {
/* Windows 10 */
USHORT process_machine;
USHORT native_machine;
if (IsWow64Process2_func(hProcess, &process_machine, &native_machine)) {
if (process_machine != IMAGE_FILE_MACHINE_UNKNOWN) {
return process_machine;
} else {
return native_machine;
}
}
} else {
/* Windows 8.1 or earlier */
/* arch will be either x86 or x64. */
#ifdef _M_AMD64
BOOL is_wow64_proc;
if (IsWow64Process(hProcess, &is_wow64_proc)) {
if (is_wow64_proc) {
return IMAGE_FILE_MACHINE_I386;
} else {
return IMAGE_FILE_MACHINE_AMD64;
}
}
#endif
#ifdef _M_IX86
BOOL is_wow64_proc;
if (IsWow64Process(GetCurrentProcess(), &is_wow64_proc)) {
if (!is_wow64_proc) {
/* Run on 32-bit Windows */
return IMAGE_FILE_MACHINE_I386;
}
/* Run on Windows x64 */
if (IsWow64Process(hProcess, &is_wow64_proc)) {
if (is_wow64_proc) {
return IMAGE_FILE_MACHINE_I386;
} else {
return IMAGE_FILE_MACHINE_AMD64;
}
}
}
#endif
}
return IMAGE_FILE_MACHINE_UNKNOWN;
}
static const char *arch_name(USHORT arch)
{
switch (arch) {
case IMAGE_FILE_MACHINE_AMD64:
return "x64";
case IMAGE_FILE_MACHINE_I386:
return "x86";
default:
return "unknown";
}
}
BOOL InjectDll(DWORD pid, const WCHAR *dllpath)
{
if (cki_attach(&g_injector, pid) != 0) {
printf("%s\n", cki_error());
return FALSE;
}
if (cki_inject_w(g_injector, dllpath, NULL) == 0) {
return TRUE;
} else {
fprintf(stderr, " %s\n", cki_error());
return FALSE;
}
}
BOOL EnjectDll(DWORD pid, const WCHAR *dllname)
{
if (cki_detach(g_injector) == 0) {
return TRUE;
}
return FALSE;
}

40
SDK/injector.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef __INJECTOR_H__
#define __INJECTOR_H__
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
#define INJERR_SUCCESS 0
#define INJERR_OTHER -1
#define INJERR_NO_MEMORY -2
#define INJERR_NO_PROCESS -3
#define INJERR_NO_LIBRARY -4
#define INJERR_NO_FUNCTION -4
#define INJERR_ERROR_IN_TARGET -5
#define INJERR_FILE_NOT_FOUND -6
#define INJERR_INVALID_MEMORY_AREA -7
#define INJERR_PERMISSION -8
#define INJERR_UNSUPPORTED_TARGET -9
#define INJERR_INVALID_ELF_FORMAT -10
#define INJERR_WAIT_TRACEE -11
typedef struct injector injector_t;
int cki_attach(injector_t **injector, DWORD pid);
int cki_inject(injector_t *injector, const char *path, void **handle);
int cki_inject_w(injector_t *injector, const wchar_t *path, void **handle);
int cki_uninject(injector_t *injector, void *handle);
int cki_detach(injector_t *injector);
const char *cki_error(void);
BOOL InjectDll(DWORD pid, const WCHAR *dllpath);
BOOL EnjectDll(DWORD pid, const WCHAR *dllname);
#ifdef __cplusplus
}; /* extern "C" */
#endif
#endif

282
SDK/sdk.cpp Normal file
View File

@ -0,0 +1,282 @@
#include "Shlwapi.h"
#include "framework.h"
#include <process.h>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <tlhelp32.h>
#include <vector>
#include "../Rpc/rpc_h.h"
#pragma comment(lib, "Rpcrt4.lib")
#include "injector.h"
#include "rpc_types.h"
#include "sdk.h"
#include "util.h"
static HANDLE hEvent;
static std::queue<RpcMessage_t> MsgQueue;
static RPC_WSTR pszStringBinding = NULL;
static std::function<int(WxMessage_t)> cbReceiveTextMsg;
static const MsgTypesMap_t WxMsgTypes = MsgTypesMap_t { { 0x01, L"文字" },
{ 0x03, L"图片" },
{ 0x22, L"语音" },
{ 0x25, L"好友确认" },
{ 0x28, L"POSSIBLEFRIEND_MSG" },
{ 0x2A, L"名片" },
{ 0x2B, L"视频" },
{ 0x2F, L"石头剪刀布 | 表情图片" },
{ 0x30, L"位置" },
{ 0x31, L"共享实时位置、文件、转账、链接" },
{ 0x32, L"VOIPMSG" },
{ 0x33, L"微信初始化" },
{ 0x34, L"VOIPNOTIFY" },
{ 0x35, L"VOIPINVITE" },
{ 0x3E, L"小视频" },
{ 0x270F, L"SYSNOTICE" },
{ 0x2710, L"红包、系统消息" },
{ 0x2712, L"撤回消息" } };
RPC_STATUS RpcConnectServer()
{
RPC_STATUS status = 0;
// Creates a string binding handle.
status = RpcStringBindingCompose(NULL, // UUID to bind to
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
NULL, // TCP/IP network address to use
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"tmp_endpoint"), // TCP/IP port to use
NULL, // Protocol dependent network options to use
&pszStringBinding); // String binding output
if (status)
return status;
/* Validates the format of the string binding handle and converts it to a binding handle.
pszStringBinding: The string binding to validate
hSpyBinding: Put the result in the implicit binding(defined in the IDL file)
*/
status = RpcBindingFromStringBinding(pszStringBinding, &hSpyBinding);
return status;
}
RPC_STATUS RpcDisconnectServer()
{
RPC_STATUS status;
// Free the memory allocated by a string
status = RpcStringFree(&pszStringBinding);
if (status)
return status;
// Releases binding handle resources and disconnects from the server
status = RpcBindingFree(&hSpyBinding);
return status;
}
int WxInitSDK()
{
int loginFlag = 0;
unsigned long ulCode = 0;
DWORD status = 0;
DWORD pid = 0;
WCHAR DllPath[MAX_PATH] = { 0 };
GetModuleFileNameW(GetModuleHandleW(WECHATSDKDLL), DllPath, MAX_PATH);
PathRemoveFileSpecW(DllPath);
PathAppendW(DllPath, WECHATINJECTDLL);
if (!PathFileExistsW(DllPath)) {
return ERROR_FILE_NOT_FOUND;
}
status = OpenWeChat(&pid);
if (status != 0) {
return status;
}
if (!InjectDll(pid, DllPath)) {
return -1;
}
RpcConnectServer();
while (!loginFlag) {
RpcTryExcept
{
// 查询登录状态
loginFlag = client_IsLogin();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
Sleep(1000);
}
return ERROR_SUCCESS;
}
static unsigned int __stdcall waitForMsg(void *p)
{
RpcMessage_t *rpcMsg;
while (true) {
// 中断式兼顾及时性和CPU使用率
WaitForSingleObject(hEvent, INFINITE); // 等待消息
while (!MsgQueue.empty()) {
rpcMsg = (RpcMessage_t *)&MsgQueue.front();
WxMessage_t msg;
msg.id = wstring(rpcMsg->id);
msg.self = rpcMsg->self;
msg.type = rpcMsg->type;
msg.source = rpcMsg->source;
msg.xml = wstring(rpcMsg->xml);
msg.wxId = wstring(rpcMsg->wxId);
msg.roomId = wstring(rpcMsg->roomId);
msg.content = wstring(rpcMsg->content);
try {
cbReceiveTextMsg(msg); // 调用接收消息回调
} catch (...) {
printf("callback error...\n");
}
MsgQueue.pop();
}
ResetEvent(hEvent);
}
return 0;
}
static unsigned int __stdcall innerWxSetTextMsgCb(void *p)
{
unsigned long ulCode = 0;
RpcTryExcept
{
// 建立RPC通道让服务端能够调用客户端的回调函数。该接口会被服务端阻塞直到异常退出
client_EnableReceiveMsg();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
return 0;
}
int WxSetTextMsgCb(const std::function<int(WxMessage_t)> &onMsg)
{
if (onMsg) {
HANDLE msgThread;
cbReceiveTextMsg = onMsg;
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
msgThread = (HANDLE)_beginthreadex(NULL, 0, waitForMsg, NULL, 0, NULL);
if (msgThread == NULL) {
printf("Failed to create message listening thread.\n");
return -2;
}
CloseHandle(msgThread);
msgThread = (HANDLE)_beginthreadex(NULL, 0, innerWxSetTextMsgCb, NULL, 0, NULL);
if (msgThread == NULL) {
printf("Failed to create innerWxRecvTextMsg.\n");
return -2;
}
CloseHandle(msgThread);
return 0;
}
printf("Empty Callback.\n");
return -1;
}
int server_ReceiveMsg(RpcMessage_t *rpcMsg)
{
MsgQueue.push(*rpcMsg); // 发送消息
SetEvent(hEvent); // 发送消息通知
return 0;
}
static int innerWxSendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendTextMsg(wxid, at_wxid, msg); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
return ret;
}
int WxSendTextMsg(wstring wxid, wstring at_wxid, wstring msg)
{
return innerWxSendTextMsg(wxid.c_str(), at_wxid.c_str(), msg.c_str());
}
static int getAddrHandle(DWORD *addr, HANDLE *handle)
{
DWORD processID = 0;
wstring processName = L"WeChat.exe";
wstring moduleName = L"WeChatWin.dll";
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
while (Process32Next(hSnapshot, &pe32)) {
wstring strProcess = pe32.szExeFile;
if (strProcess == processName) {
processID = pe32.th32ProcessID;
break;
}
}
CloseHandle(hSnapshot);
if (processID == 0) {
printf("Failed to get Process ID\r\n");
return -1;
}
HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processID);
if (hProcessSnapshot == INVALID_HANDLE_VALUE) {
printf("Failed to get Process Snapshot\r\n");
return -2;
}
MODULEENTRY32 me32;
SecureZeroMemory(&me32, sizeof(MODULEENTRY32));
me32.dwSize = sizeof(MODULEENTRY32);
while (Module32Next(hProcessSnapshot, &me32)) {
me32.dwSize = sizeof(MODULEENTRY32);
if (!wcscmp(me32.szModule, moduleName.c_str())) {
*addr = (DWORD)me32.modBaseAddr;
break;
}
}
CloseHandle(hProcessSnapshot);
if (*addr == 0) {
printf("Failed to get Module Address\r\n");
return -3;
}
*handle = OpenProcess(PROCESS_VM_READ, FALSE, processID);
if (*handle == 0) {
printf("Failed to open Process\r\n");
return -4;
}
return 0;
}
MsgTypesMap_t WxGetMsgTypes() { return WxMsgTypes; }

5
SDK/sdk.def Normal file
View File

@ -0,0 +1,5 @@
EXPORTS
WxInitSDK
WxSetTextMsgCb
WxSendTextMsg
WxGetMsgTypes

25
SDK/sdk.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <functional>
#include <map>
#include <string>
using namespace std;
typedef struct WxMessage {
int self; // 是否自己发的消息0=否1=是
int type; // 消息类型
int source; // 消息来源0=好友消息1=群消息
wstring id; // 消息ID
wstring xml; // 群其他消息
wstring wxId; // 发送人微信ID
wstring roomId; // 群ID
wstring content; // 消息内容MAC版最大16384即16KB
} WxMessage_t;
typedef map<int, wstring> MsgTypesMap_t;
int WxInitSDK();
int WxSetTextMsgCb(const std::function<int(WxMessage_t)> &onMsg);
int WxSendTextMsg(wstring wxid, wstring at_wxid, wstring msg);
MsgTypesMap_t WxGetMsgTypes();

191
SDK/util.cpp Normal file
View File

@ -0,0 +1,191 @@
#include "Shlwapi.h"
#include "framework.h"
#include <string.h>
#include <strsafe.h>
#include <wchar.h>
#include "util.h"
#pragma comment(lib, "shlwapi")
#pragma comment(lib, "Version.lib")
using namespace std;
int GetWeChatPath(wchar_t *path);
int GetWeChatWinDLLPath(wchar_t *path);
int GetWeChatVersion(wchar_t *version);
bool GetFileVersion(const wchar_t *filePath, wchar_t *version);
int GetWeChatPath(wchar_t *path)
{
int ret = -1;
HKEY hKey = NULL;
// HKEY_CURRENT_USER\Software\Tencent\WeChat InstallPath = xx
if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, L"Software\\Tencent\\WeChat", &hKey)) {
ret = GetLastError();
return ret;
}
DWORD Type = REG_SZ;
DWORD cbData = MAX_PATH * sizeof(WCHAR);
if (ERROR_SUCCESS != RegQueryValueEx(hKey, L"InstallPath", 0, &Type, (LPBYTE)path, &cbData)) {
ret = GetLastError();
goto __exit;
}
if (path != NULL) {
PathAppend(path, WECHAREXE);
}
__exit:
if (hKey) {
RegCloseKey(hKey);
}
return ERROR_SUCCESS;
}
int GetWeChatWinDLLPath(wchar_t *path)
{
int ret = GetWeChatPath(path);
if (ret != ERROR_SUCCESS) {
return ret;
}
PathRemoveFileSpecW(path);
PathAppendW(path, WECHATWINDLL);
return ret;
}
int GetWeChatVersion(wchar_t *version)
{
WCHAR Path[MAX_PATH] = { 0 };
int ret = GetWeChatWinDLLPath(Path);
if (ret != ERROR_SUCCESS) {
return ret;
}
ret = GetFileVersion(Path, version);
return ret;
}
bool GetFileVersion(const wchar_t *filePath, wchar_t *version)
{
if (wcslen(filePath) > 0 && PathFileExists(filePath)) {
VS_FIXEDFILEINFO *pVerInfo = NULL;
DWORD dwTemp, dwSize;
BYTE *pData = NULL;
UINT uLen;
dwSize = GetFileVersionInfoSize(filePath, &dwTemp);
if (dwSize == 0) {
return false;
}
pData = new BYTE[dwSize + 1];
if (pData == NULL) {
return false;
}
if (!GetFileVersionInfo(filePath, 0, dwSize, pData)) {
delete[] pData;
return false;
}
if (!VerQueryValue(pData, TEXT("\\"), (void **)&pVerInfo, &uLen)) {
delete[] pData;
return false;
}
DWORD verMS = pVerInfo->dwFileVersionMS;
DWORD verLS = pVerInfo->dwFileVersionLS;
DWORD major = HIWORD(verMS);
DWORD minor = LOWORD(verMS);
DWORD build = HIWORD(verLS);
DWORD revision = LOWORD(verLS);
delete[] pData;
StringCbPrintf(version, 0x20, TEXT("%d.%d.%d.%d"), major, minor, build, revision);
return true;
}
return false;
}
int OpenWeChat(DWORD *pid)
{
int ret = -1;
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
WCHAR Path[MAX_PATH] = { 0 };
ret = GetWeChatPath(Path);
if (ERROR_SUCCESS != ret) {
return ret;
}
if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
ret = GetLastError();
return ret;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
*pid = pi.dwProcessId;
ret = ERROR_SUCCESS;
return ret;
}
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
{
DWORD strLength = GET_DWORD(address + 4);
if (strLength == 0) {
return 0;
} else if (strLength > buffer_size) {
strLength = buffer_size - 1;
}
wmemcpy_s(buffer, strLength + 1, GET_WSTRING(address), strLength + 1);
return strLength;
}
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
{
DWORD value = 0;
unsigned char data[4] = { 0 };
if (ReadProcessMemory(hProcess, (LPVOID)address, data, 4, 0)) {
value = data[0] & 0xFF;
value |= ((data[1] << 8) & 0xFF00);
value |= ((data[2] << 16) & 0xFF0000);
value |= ((data[3] << 24) & 0xFF000000);
}
return value;
}
wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address)
{
wstring value = L"";
DWORD strAddress = GetMemoryIntByAddress(hProcess, address);
DWORD strLen = GetMemoryIntByAddress(hProcess, address + 0x4);
if (strLen > 500)
return value;
wchar_t cValue[500] = { 0 };
memset(cValue, 0, sizeof(cValue) / sizeof(wchar_t));
if (ReadProcessMemory(hProcess, (LPVOID)strAddress, cValue, (strLen + 1) * 2, 0)) {
value = wstring(cValue);
}
return value;
}

21
SDK/util.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <string>
#define WECHAREXE L"WeChat.exe"
#define WECHATWINDLL L"WeChatWin.dll"
#define WECHATSDKDLL L"SDK.dll"
#define WECHATINJECTDLL L"Spy.dll"
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
#define GET_STRING(addr) ((CHAR *)(addr))
#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr)))
int OpenWeChat(DWORD *pid);
int GetWeChatPath(wchar_t *path);
int GetWeChatWinDLLPath(wchar_t *path);
int GetWeChatVersion(wchar_t *version);
bool GetFileVersion(const wchar_t *filePath, wchar_t *version);
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);

168
SDKpy/SDKpy.vcxproj Normal file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{121ad245-72fb-47a6-99d6-5427b74fa7b9}</ProjectGuid>
<RootNamespace>SDKpy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<TargetExt>.pyd</TargetExt>
<TargetName>wcferry</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SDKPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SDKPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)SDK;$(SolutionDir)Rpc;C:\Program Files (x86)\Python37-32\Include;C:\Projs\.pyenv\pybind11\lib\site-packages\pybind11\include;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>C:\Program Files (x86)\Python37-32\libs;</AdditionalLibraryDirectories>
<AdditionalDependencies>$(OutDir)SDK.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SDKPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SDKPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\SDK\sdk.h" />
<ClInclude Include="framework.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="sdkpy.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

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

4
SDKpy/SDKpy.vcxproj.user Normal file
View File

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

5
SDKpy/framework.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

35
SDKpy/sdkpy.cpp Normal file
View File

@ -0,0 +1,35 @@
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "sdk.h"
namespace py = pybind11;
int WxSetTextMsgCbPy(const std::function<int(WxMessage_t)> &onMsg) { return WxSetTextMsgCb(onMsg); }
PYBIND11_MODULE(wcferry, m)
{
m.doc() = "SDK python API";
py::class_<WxMessage>(m, "WxMessage")
.def_readonly("id", &WxMessage::id)
.def_readonly("self", &WxMessage::self)
.def_readonly("type", &WxMessage::type)
.def_readonly("source", &WxMessage::source)
.def_readonly("xml", &WxMessage::xml)
.def_readonly("wxId", &WxMessage::wxId)
.def_readonly("roomId", &WxMessage::roomId)
.def_readonly("content", &WxMessage::content);
m.def("WxInitSDK", &WxInitSDK);
m.def("WxSetTextMsgCb", &WxSetTextMsgCbPy);
m.def("WxSendTextMsg", &WxSendTextMsg);
m.def("WxGetMsgTypes", &WxGetMsgTypes, py::return_value_policy::reference);
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}

200
Spy/Spy.vcxproj Normal file
View File

@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{4a0a22f7-0b1c-4565-a443-c43fac6c6396}</ProjectGuid>
<RootNamespace>Spy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc;$(SolutionDir)SDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions> /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
<Midl>
<AdditionalOptions>/app_config /prefix client "client_" server "server_" </AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</Midl>
</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>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc;$(SolutionDir)SDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions> /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
<Midl>
<AdditionalOptions>/prefix client "client_" server "server_" </AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</Midl>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Rpc\rpc_types.h" />
<ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="..\SDK\util.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="load_calls.h" />
<ClInclude Include="monitor.h" />
<ClInclude Include="receive_msg.h" />
<ClInclude Include="rpc_server.h" />
<ClInclude Include="send_msg.h" />
<ClInclude Include="spy_types.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Rpc\rpc_memory.cpp" />
<ClCompile Include="..\Rpc\rpc_s.c" />
<ClCompile Include="..\SDK\util.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="load_calls.cpp" />
<ClCompile Include="monitor.cpp" />
<ClCompile Include="receive_msg.cpp" />
<ClCompile Include="rpc_server.cpp" />
<ClCompile Include="send_msg.cpp" />
</ItemGroup>
<ItemGroup>
<Midl Include="..\Rpc\rpc.idl">
<OutputDirectory Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)Rpc</OutputDirectory>
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/app_config /ms_ext /prefix client "client_" server "server_" </AdditionalOptions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)Rpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<OutputDirectory Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)Rpc</OutputDirectory>
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/app_config /ms_ext /prefix client "client_" server "server_" %(AdditionalOptions)</AdditionalOptions>
</Midl>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

86
Spy/Spy.vcxproj.filters Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Rpc">
<UniqueIdentifier>{37eb8a5c-e792-4c10-a858-9abc84f79f80}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Rpc\rpc_h.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="monitor.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Rpc\rpc_types.h">
<Filter>Rpc</Filter>
</ClInclude>
<ClInclude Include="rpc_server.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="load_calls.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\SDK\util.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="receive_msg.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="send_msg.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="spy_types.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\Rpc\rpc_s.c">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\Rpc\rpc_memory.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="monitor.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="rpc_server.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="load_calls.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\SDK\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="receive_msg.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="send_msg.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Midl Include="..\Rpc\rpc.idl">
<Filter>Rpc</Filter>
</Midl>
</ItemGroup>
</Project>

4
Spy/Spy.vcxproj.user Normal file
View File

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

37
Spy/dllmain.cpp Normal file
View File

@ -0,0 +1,37 @@
#include <stdlib.h>
#include "monitor.h"
#include "rpc_server.h"
extern HANDLE g_hEvent;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
// MessageBox(NULL, L"RpcStartServer", L"Hey", 0);
if (InitDLL() != 0) {
// Exit
FreeLibraryAndExitThread(hModule, 0);
}
HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RpcStartServer, hModule, NULL, 0);
if (rpcThread != 0) {
CloseHandle(rpcThread);
}
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建消息句柄
HANDLE mThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Monitor, hModule, NULL, 0);
if (mThread != 0) {
CloseHandle(mThread);
}
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH: {
RpcStopServer();
break;
}
}
return TRUE;
}

5
Spy/framework.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>

26
Spy/load_calls.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <iostream>
#include <map>
#include "load_calls.h"
std::map<std::wstring, WxCalls_t> wxCalls {
{ L"3.0.0.57",
{ 0x1874F38, // Login Status
{ 0x1856BF0, 0x1856A8C, 0x1856AC0 }, // User Info: wxid, nickname, mobile
0x38D8A0, // Send Message
// Receive Message:
// Hook, call, type, self, id, msgXml, roomId, wxId, content
{ 0x36A350, 0x36A5A0, 0x30, 0x34, 0x164, 0x1A4, 0x40, 0x150, 0x68 } } }
};
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
{
auto iter = wxCalls.find(version);
if (iter == wxCalls.end()) {
return -1;
}
memcpy_s(calls, sizeof(WxCalls_t), &(iter->second), sizeof(WxCalls_t));
return 0;
}

5
Spy/load_calls.h Normal file
View File

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

54
Spy/monitor.cpp Normal file
View File

@ -0,0 +1,54 @@
#include <atlstr.h>
#include <stdio.h>
#include "load_calls.h"
#include "monitor.h"
#include "receive_msg.h"
#include "util.h"
HANDLE g_hEvent = NULL;
WxCalls_t g_WxCalls = { 0 };
RpcMessage_t *g_pMsg = NULL; // Find a palce to free
DWORD g_WeChatWinDllAddr = 0;
int InitDLL(void)
{
wchar_t version[16] = { 0 };
g_WeChatWinDllAddr = (DWORD)LoadLibrary(L"WeChatWin.dll"); //获取wechatWin模块地址
if (g_WeChatWinDllAddr == 0) {
MessageBox(NULL, L"获取wechatWin.dll模块地址", L"错误", 0);
return -1;
}
if (!GetWeChatVersion(version)) { //获取微信版本
MessageBox(NULL, L"获取微信版本失败", L"错误", 0);
return -2;
}
if (LoadCalls(version, &g_WxCalls) != 0) { //加载微信版本对应的Call地址
MessageBox(NULL, L"不支持当前版本", L"错误", 0);
return -3;
}
g_pMsg = new RpcMessage_t;
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
return 0;
}
DWORD WINAPI Monitor(HMODULE hModule)
{
ListenMessage();
return TRUE;
}
int IsLogin(void)
{
if (g_WeChatWinDllAddr == 0) {
return 0;
}
return (int)GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.login);
}

7
Spy/monitor.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "framework.h"
int InitDLL(void);
DWORD WINAPI Monitor(HMODULE hModule);
int IsLogin();

79
Spy/receive_msg.cpp Normal file
View File

@ -0,0 +1,79 @@
#include "framework.h"
#include "load_calls.h"
#include "receive_msg.h"
#include "spy_types.h"
#include "util.h"
extern HANDLE g_hEvent;
extern RpcMessage_t *g_pMsg;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
MsgQueue_t g_MsgQueue;
DWORD reg_buffer = 0;
DWORD recvMsgCallAddr = 0;
DWORD recvMsgJumpBackAddr = 0;
void DispatchMsg(DWORD reg)
{
DWORD **p = (DWORD **)reg; //消息结构基址
memset(g_pMsg, 0, sizeof(RpcMessage_t));
g_pMsg->type = GET_DWORD(**p + g_WxCalls.recvMsg.type);
g_pMsg->self = GET_DWORD(**p + g_WxCalls.recvMsg.isSelf);
GetWstringByAddress(**p + g_WxCalls.recvMsg.msgId, g_pMsg->id, MSG_SIZE_MSG_ID);
GetWstringByAddress(**p + g_WxCalls.recvMsg.msgXml, g_pMsg->xml, MSG_SIZE_MSG_XML);
if (wcsstr(g_pMsg->xml, L"<membercount>") == NULL) {
// g_pMsg.roomId = {0};
GetWstringByAddress(**p + g_WxCalls.recvMsg.roomId, g_pMsg->wxId, MSG_SIZE_WXID);
} else {
g_pMsg->source = 1;
GetWstringByAddress(**p + g_WxCalls.recvMsg.roomId, g_pMsg->roomId, MSG_SIZE_ROOMID);
GetWstringByAddress(**p + g_WxCalls.recvMsg.wxId, g_pMsg->wxId, MSG_SIZE_WXID);
}
GetWstringByAddress(**p + g_WxCalls.recvMsg.content, g_pMsg->content, MSG_SIZE_CONTENT);
g_MsgQueue.push(*g_pMsg); // 发送消息
SetEvent(g_hEvent); // 发送消息通知
}
__declspec(naked) void RecieveMsgHook()
{
__asm {
push ebp // 保护现场
add ebp, 0x3C // 地址为 ebp + 0x3C
mov reg_buffer, ebp //把值复制出来
pop ebp // 还原现场
}
DispatchMsg(reg_buffer);
__asm
{
call recvMsgCallAddr // 这个为被覆盖的call
jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令
}
}
void ListenMessage()
{
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
if (g_WeChatWinDllAddr == 0) {
return;
}
DWORD hookAddress = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
recvMsgJumpBackAddr = hookAddress + 5;
BYTE jmpCode[5] = { 0 };
jmpCode[0] = 0xE9;
*(DWORD *)&jmpCode[1] = (DWORD)RecieveMsgHook - hookAddress - 5;
// 6FB6A350 E8 4B020000 call WeChatWi .6FB6A5A0;
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddress, jmpCode, 5, 0);
}

3
Spy/receive_msg.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void ListenMessage();

94
Spy/rpc_server.cpp Normal file
View File

@ -0,0 +1,94 @@
#include <stdio.h>
#include <stdlib.h>
#include "monitor.h"
#include "rpc_server.h"
#include "send_msg.h"
#include "spy_types.h"
#include "../Rpc/rpc_h.h"
#pragma comment(lib, "Rpcrt4.lib")
extern HANDLE g_hEvent;
extern MsgQueue_t g_MsgQueue;
int server_IsLogin() { return IsLogin(); }
void server_EnableReceiveMsg()
{
unsigned long ulCode = 0;
RpcTryExcept
{
// 调用客户端的回调函数
while (true) {
// 中断式兼顾及时性和CPU使用率
WaitForSingleObject(g_hEvent, INFINITE); // 等待消息
while (!g_MsgQueue.empty()) {
client_ReceiveMsg((RpcMessage_t *)&g_MsgQueue.front()); // 调用接收消息回调
g_MsgQueue.pop();
}
ResetEvent(g_hEvent);
}
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
}
int server_SendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
{
SendTextMessage(wxid, at_wxid, msg);
return 0;
}
RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/)
{
return RPC_S_OK; // Always allow anyone.
}
int RpcStartServer(HMODULE hModule)
{
RPC_STATUS status;
// Uses the protocol combined with the endpoint for receiving
// remote procedure calls.
status = RpcServerUseProtseqEp(reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP.
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"tmp_endpoint"), // TCP/IP port to use
NULL // No security
);
if (status)
return status;
// Registers the interface and auto listen
// Equal to RpcServerRegisterIf + RpcServerListen
status = RpcServerRegisterIf2(server_ISpy_v1_0_s_ifspec, // Interface to register.
NULL, // Use the MIDL generated entry-point vector.
NULL, // Use the MIDL generated entry-point vector.
RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_AUTOLISTEN, // Forces use of security callback.
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Use default number of concurrent calls.
(unsigned)-1, // Infinite max size of incoming data blocks.
SecurityCallback); // Naive security callback.
while (1) {
Sleep(10000); // 休眠释放CPU
}
return 0;
}
int RpcStopServer(void)
{
RPC_STATUS status;
status = RpcMgmtStopServerListening(NULL);
if (status)
return status;
status = RpcServerUnregisterIf(NULL, NULL, FALSE);
return status;
}

5
Spy/rpc_server.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "framework.h"
int RpcStartServer(HMODULE hModule);
int RpcStopServer(void);

49
Spy/send_msg.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "framework.h"
#include <string>
#include "spy_types.h"
extern HANDLE g_hEvent;
extern WxCalls_t g_WxCalls;
extern RpcMessage_t *g_pMsg;
extern DWORD g_WeChatWinDllAddr;
using namespace std;
void SendTextMessage(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
{
if (g_WeChatWinDllAddr == 0) {
return;
}
char buffer[0x5F0] = { 0 };
TextStruct_t txtWxid = { 0 };
TextStruct_t txtAtWxid = { 0 };
TextStruct_t txtMsg = { 0 };
wstring wsWxid = wxid;
wstring wsAtWxid = at_wxid;
wstring wsMsg = msg;
// 发送消息Call地址 = 微信基址 + 偏移
DWORD sendCallAddress = g_WeChatWinDllAddr + g_WxCalls.sendTextMsg;
txtWxid.text = (wchar_t *)wsWxid.c_str();
txtWxid.size = wsWxid.size();
txtWxid.capacity = wsWxid.capacity();
txtMsg.text = (wchar_t *)wsMsg.c_str();
txtMsg.size = wsMsg.size();
txtMsg.capacity = wsMsg.capacity();
__asm {
lea edx, txtWxid
lea edi, txtAtWxid
lea ebx, txtMsg
push 0x01
push edi
push ebx
lea ecx, buffer;
call sendCallAddress
add esp, 0xC
}
}

3
Spy/send_msg.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void SendTextMessage(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg);

46
Spy/spy_types.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include "framework.h"
#include <queue>
#include "rpc_types.h"
typedef struct UserInfoCall {
DWORD wxid;
DWORD nickName;
DWORD mobile;
} UserInfoCall_t;
typedef struct RecvMsg {
DWORD hook; // Hook地址
DWORD call; // Call地址
DWORD type; // 消息类型地址
DWORD isSelf; // 是否自己发送标志地址
DWORD msgId; // 消息ID地址
DWORD msgXml; // 消息xml内容地址
DWORD roomId; // 群聊时为群ID私聊时为微信ID
DWORD wxId; // 私聊时为空群群时为发送者微信ID
DWORD content; // 消息内容地址
} RecvMsg_t;
typedef struct SendImg {
DWORD call1;
DWORD call2;
DWORD call3;
} SendImg_t;
typedef struct WxCalls {
DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息
DWORD sendTextMsg; // 发送消息
RecvMsg_t recvMsg; // 接收消息
} WxCalls_t;
typedef struct TextStruct {
wchar_t *text;
DWORD size;
DWORD capacity;
char fill[8];
} TextStruct_t;
typedef std::queue<RpcMessage_t> MsgQueue_t;

72
WeChatFerry.sln Normal file
View File

@ -0,0 +1,72 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30503.244
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Spy", "Spy\Spy.vcxproj", "{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDK", "SDK\SDK.vcxproj", "{707F2DCD-1001-42A7-B20E-B85B1BBAB228}"
ProjectSection(ProjectDependencies) = postProject
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396} = {4A0A22F7-0B1C-4565-A443-C43FAC6C6396}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "App", "App\App.vcxproj", "{44C1A579-22A7-4BA3-A618-45BD01600294}"
ProjectSection(ProjectDependencies) = postProject
{121AD245-72FB-47A6-99D6-5427B74FA7B9} = {121AD245-72FB-47A6-99D6-5427B74FA7B9}
{707F2DCD-1001-42A7-B20E-B85B1BBAB228} = {707F2DCD-1001-42A7-B20E-B85B1BBAB228}
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396} = {4A0A22F7-0B1C-4565-A443-C43FAC6C6396}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDKpy", "SDKpy\SDKpy.vcxproj", "{121AD245-72FB-47A6-99D6-5427B74FA7B9}"
ProjectSection(ProjectDependencies) = postProject
{707F2DCD-1001-42A7-B20E-B85B1BBAB228} = {707F2DCD-1001-42A7-B20E-B85B1BBAB228}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Debug|x64.ActiveCfg = Debug|x64
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Debug|x64.Build.0 = Debug|x64
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Debug|x86.ActiveCfg = Debug|Win32
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Debug|x86.Build.0 = Debug|Win32
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Release|x64.ActiveCfg = Release|x64
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Release|x64.Build.0 = Release|x64
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Release|x86.ActiveCfg = Release|Win32
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}.Release|x86.Build.0 = Release|Win32
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Debug|x64.ActiveCfg = Debug|x64
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Debug|x64.Build.0 = Debug|x64
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Debug|x86.ActiveCfg = Debug|Win32
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Debug|x86.Build.0 = Debug|Win32
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Release|x64.ActiveCfg = Release|x64
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Release|x64.Build.0 = Release|x64
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Release|x86.ActiveCfg = Release|Win32
{707F2DCD-1001-42A7-B20E-B85B1BBAB228}.Release|x86.Build.0 = Release|Win32
{44C1A579-22A7-4BA3-A618-45BD01600294}.Debug|x64.ActiveCfg = Debug|x64
{44C1A579-22A7-4BA3-A618-45BD01600294}.Debug|x64.Build.0 = Debug|x64
{44C1A579-22A7-4BA3-A618-45BD01600294}.Debug|x86.ActiveCfg = Debug|Win32
{44C1A579-22A7-4BA3-A618-45BD01600294}.Debug|x86.Build.0 = Debug|Win32
{44C1A579-22A7-4BA3-A618-45BD01600294}.Release|x64.ActiveCfg = Release|x64
{44C1A579-22A7-4BA3-A618-45BD01600294}.Release|x64.Build.0 = Release|x64
{44C1A579-22A7-4BA3-A618-45BD01600294}.Release|x86.ActiveCfg = Release|Win32
{44C1A579-22A7-4BA3-A618-45BD01600294}.Release|x86.Build.0 = Release|Win32
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Debug|x64.ActiveCfg = Debug|x64
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Debug|x64.Build.0 = Debug|x64
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Debug|x86.ActiveCfg = Debug|Win32
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Debug|x86.Build.0 = Debug|Win32
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Release|x64.ActiveCfg = Release|x64
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Release|x64.Build.0 = Release|x64
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Release|x86.ActiveCfg = Release|Win32
{121AD245-72FB-47A6-99D6-5427B74FA7B9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {569E7E61-8FD2-43B5-8F34-C61D6417F905}
EndGlobalSection
EndGlobal