Bump gRPC

This commit is contained in:
Changhua 2022-10-15 20:25:42 +08:00
parent 35498520c2
commit ef20038fcd
50 changed files with 1905 additions and 2387 deletions

View File

@ -1,157 +0,0 @@
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <process.h>
#include <windows.h>
#include "sdk.h"
/*
#pragma comment(lib, "SDK.lib")
*/
typedef map<int, wstring> sqlTypes_t;
static sqlTypes_t sqlTypes
= sqlTypes_t { { 1, L"INTEGER" }, { 2, L"FLOAT" }, { 3, L"TEXT" }, { 4, L"BLOB" }, { 5, L"NULL" } };
void printContacts(ContactMap_t contacts)
{
wprintf(L"contacts number: %ld\n", contacts.size());
for (auto it = contacts.begin(); it != contacts.end(); it++) {
wprintf(L"%s\t%s\t%s\t%s\t%s\t%s\t%s\r\n", it->second.wxId.c_str(), it->second.wxCode.c_str(),
it->second.wxName.c_str(), it->second.wxGender.c_str(), it->second.wxCountry.c_str(),
it->second.wxProvince.c_str(), it->second.wxCity.c_str());
}
}
void printDbNames(vector<wstring> vDbs)
{
wprintf(L"db numbers: %ld\n", vDbs.size());
for (auto it = vDbs.begin(); it != vDbs.end(); it++) {
wprintf(L"%s\n", (*it).c_str());
}
}
void printDbTables(DbTableVector_t tables)
{
wprintf(L"table numbers: %ld\n", tables.size());
for (auto it = tables.begin(); it != tables.end(); it++) {
wprintf(L"%s\n%s\n\n", (it->table).c_str(), (it->sql).c_str());
}
}
void printDbResults(SqlRetVector_t vvResults)
{
int rows = vvResults.size();
printf("vvResults.size: %d\n", rows);
rows = 0;
for (auto vv = vvResults.begin(); vv != vvResults.end(); vv++) {
printf("Row %d\n", rows++);
for (auto v = vv->begin(); v != vv->end(); v++) {
wprintf(L"%s[%s]: ", v->column.c_str(), sqlTypes[v->type].c_str());
switch (v->type) {
case 1: {
printf("%d\n", stoi(v->content.c_str()));
break;
}
case 2: {
printf("%f\n", stof(v->content.c_str()));
break;
}
case 3: {
printf("%s\n", v->content.c_str());
break;
}
case 4: {
byte *p = (byte *)(v->content.c_str());
for (unsigned int i = 0; i < v->content.size(); i++) {
printf("%02X ", p[i]);
}
printf("\n");
break;
}
default: {
printf("\n");
break;
}
}
}
}
printf("\n");
}
int onTextMsg(WxMessage_t msg)
{
wprintf(L"%s msgType: %d, msgSource: %d, isSelf: %d\n", msg.id.c_str(), msg.type, msg.source, msg.self);
wprintf(L"%s[%s] >> %s\n", msg.wxId.c_str(), msg.roomId.c_str(), msg.content.c_str());
wprintf(L"msgSourceXml: %s\n", msg.xml.c_str());
return 0;
}
int main()
{
DWORD status = 0;
wstring wxid = L"filehelper"; // 微信ID
wstring at_wxid = L"";
wstring content = L"这里填写消息内容";
wstring img_path = L"test.jpg";
setlocale(LC_ALL, "chs"); // 这是个大坑,不设置中文直接不见了。。。
wprintf(L"WxInitSDK: ");
status = WxInitSDK();
wprintf(L"%d\n", status);
if (status != 0) {
return 0;
}
// 自己的 wxid
wstring selfWxid = WxGetSelfWxid();
wprintf(L"本号WXID%s\n", selfWxid.c_str());
// 获取消息类型
wprintf(L"获取消息类型\n");
const MsgTypesMap_t WxMsgTypes = WxGetMsgTypes();
for (auto it = WxMsgTypes.begin(); it != WxMsgTypes.end(); ++it) {
wprintf(L"%d: %s\n", it->first, it->second.c_str());
}
Sleep(1000); // 等待1秒
wprintf(L"Message: 接收通知中......\n");
WxEnableRecvMsg(onTextMsg);
Sleep(1000); // 等待1秒
// 测试发送消息
wprintf(L"测试发送消息\n");
WxSendTextMsg(wxid, content, at_wxid);
Sleep(1000); // 等待1秒
// 测试发送照片
wprintf(L"测试发送照片\n");
WxSendImageMsg(wxid, img_path);
Sleep(1000); // 等待1秒
// 测试获取联系人
auto mContact = WxGetContacts();
printContacts(mContact);
Sleep(1000); // 等待1秒
// 测试获取数据库名
auto vDbNames = WxGetDbNames();
printDbNames(vDbNames);
Sleep(1000); // 等待1秒
// 测试获取数据库中的表
auto vDbTables = WxGetDbTables(L"MicroMsg.db");
printDbTables(vDbTables);
Sleep(1000); // 等待1秒
// 测试执行 SQL
auto vvResults = WxExecDbQuery(L"MicroMsg.db", L"SELECT * FROM Contact LIMIT 1;");
printDbResults(vvResults);
while (1) {
Sleep(10000); // 休眠释放CPU
}
}

View File

@ -1,84 +0,0 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import time
import wcferry as sdk
def main():
help(sdk) # 查看SDK支持的方法和属性
# 初始化SDK如果成功返回0否则失败
status = sdk.WxInitSDK()
if status != 0:
print("初始化失败")
exit(-1)
print("初始化成功")
WxMsgTypes = sdk.WxGetMsgTypes() # 获取消息类型
print(WxMsgTypes) # 查看消息类型
time.sleep(2)
print("打印通讯录......")
contacts = sdk.WxGetContacts()
for k, v in contacts.items():
print(k, v.wxCode, v.wxName, v.wxCountry, v.wxProvince, v.wxCity, v.wxGender)
time.sleep(2)
print("发送文本消息......")
sdk.WxSendTextMsg("filehelper", "message from WeChatFerry...") # 往文件传输助手发消息
# sdk.WxSendTextMsg("xxxx@chatroom", "message from WeChatFerry...") # 往群里发消息(需要改成正确的 ID下同
# sdk.WxSendTextMsg("xxxx@chatroom", "message from WeChatFerry... @ ", "wxid_xxxxxxxxxxxx") # 往群里发消息,@某人
# sdk.WxSendTextMsg("xxxx@chatroom", "message from WeChatFerry... @ ", "notify@all") # 往群里发消息,@所有人
time.sleep(2)
print("发送图片消息......")
sdk.WxSendImageMsg("filehelper", "test.jpg")
dbs = sdk.WxGetDbNames()
for db in dbs:
print(db)
tables = sdk.WxGetDbTables(dbs[0])
for t in tables:
print(f"{t.table}\n{t.sql}\n\n")
# 接收消息。先定义消息处理回调
def OnTextMsg(msg: sdk.WxMessage):
def getName(id):
contact = contacts.get(id)
if contact is None:
return id
return contact.wxName
s = "收到"
if msg.self == 1: # 忽略自己发的消息
s += f"来自自己的消息"
print(f"\n{s}")
return 0
msgType = WxMsgTypes.get(msg.type, '未知类型')
nickName = getName(msg.wxId)
if msg.source == 1:
groupName = getName(msg.roomId)
s += f"来自群[{groupName}]的[{nickName}]的{msgType}消息:"
else:
s += f"来自[{nickName}]的{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.WxEnableRecvMsg(OnTextMsg) # 设置回调,接收消息
while True:
time.sleep(1)
if __name__ == '__main__':
main()

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 KiB

View File

@ -3,7 +3,7 @@
欢迎加群交流,后台回复 `WeChatFerry `
![碲矿](碲矿.jpeg)
![碲矿](TEQuant.jpeg)
## 快速开始
1. 使用 VS2019 编译。

View File

@ -1,75 +0,0 @@
[
uuid(ed838ecd-8a1e-4da7-bfda-9f2d12d07893),
version(1.0),
implicit_handle(handle_t hSpyBinding),
]
interface ISpy
{
import "oaidl.idl";
typedef struct RpcMessage {
int self; // 是否自己发的消息0=否1=是
int type; // 消息类型
int source; // 消息来源0=好友消息1=群消息
BSTR id; // 消息ID
BSTR xml; // 群其他消息
BSTR wxId; // 发送人微信ID
BSTR roomId; // 群ID
BSTR content; // 消息内容MAC版最大16384即16KB
} RpcMessage_t;
// 模拟 map<int, wstring>
typedef struct RpcIntBstrPair {
int key;
BSTR value;
} RpcIntBstrPair_t;
typedef RpcIntBstrPair_t *PRpcIntBstrPair;
typedef RpcIntBstrPair_t **PPRpcIntBstrPair;
typedef struct RpcContact {
BSTR wxId; // 微信ID
BSTR wxCode; // 微信号
BSTR wxName; // 微信昵称
BSTR wxCountry; // 国家
BSTR wxProvince; // 省/州
BSTR wxCity; // 城市
BSTR wxGender; // 性别
} RpcContact_t;
typedef RpcContact_t *PRpcContact;
typedef RpcContact_t **PPRpcContact;
typedef struct RpcTables {
BSTR table; // 表名
BSTR sql; // 建表 SQL
} RpcTables_t;
typedef RpcTables_t *PRpcTables;
typedef RpcTables_t **PPRpcTables;
typedef struct RpcSqlResult {
int type;
BSTR column;
BSTR content;
} RpcSqlResult_t;
typedef RpcSqlResult_t *PRpcSqlResult;
typedef RpcSqlResult_t **PPRpcSqlResult;
typedef RpcSqlResult_t ***PPPRpcSqlResult;
int IsLogin();
int GetSelfWxId([ out, string ] wchar_t wxid[20]);
int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *msg,
[ in, unique, string ] const wchar_t *atWxids);
int SendImageMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *path);
int GetMsgTypes([out] int *pNum, [ out, size_is(, *pNum) ] PPRpcIntBstrPair *msgTypes);
int GetContacts([out] int *pNum, [ out, size_is(, *pNum) ] PPRpcContact *contacts);
int GetDbNames([out] int *pNum, [ out, size_is(, *pNum) ] BSTR **dbs);
int GetDbTables([ in, string ] const wchar_t *db, [out] int *pNum, [ out, size_is(, *pNum) ] PPRpcTables *tbls);
int ExecDbQuery([ in, string ] const wchar_t *db,
[ in, string ] const wchar_t *sql, [out] int *pRow, [out] int *pCol,
[ out, size_is(, *pRow, *pCol) ] PPPRpcSqlResult *ret);
BOOL AcceptNewFriend([in, string] const wchar_t *v3, [in, string] const wchar_t *v4);
void EnableReceiveMsg();
void DisableReceiveMsg();
[callback] int ReceiveMsg([in] RpcMessage_t rpcMsg);
};

View File

@ -1,9 +0,0 @@
#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); }

View File

@ -21,8 +21,8 @@
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{707f2dcd-1001-42a7-b20e-b85b1bbab228}</ProjectGuid>
<RootNamespace>SDK</RootNamespace>
<ProjectGuid>{abfcb647-137f-478b-a73e-f0b1e3adc215}</ProjectGuid>
<RootNamespace>sdk</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -82,16 +82,18 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalOptions> /utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -109,8 +111,11 @@
<PreprocessorDefinitions>WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc</AdditionalIncludeDirectories>
<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>
@ -119,8 +124,15 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
<AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y $(OutDir)sdk.dll $(SolutionDir)python
xcopy /y $(SolutionDir)TEQuant.jpeg $(SolutionDir)python
xcopy /y $(SolutionDir)TEQuant.jpeg $(SolutionDir)Release</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy files</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -159,21 +171,18 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="..\spy\log.h" />
<ClInclude Include="..\spy\util.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="injector.h" />
<ClInclude Include="rpc_client.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="..\spy\log.cpp" />
<ClCompile Include="..\spy\util.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="injector.cpp" />
<ClCompile Include="rpc_client.cpp" />
<ClCompile Include="sdk.cpp" />
<ClCompile Include="util.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="sdk.def" />

View File

@ -21,41 +21,32 @@
<ClInclude Include="sdk.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Rpc\rpc_h.h">
<ClInclude Include="..\spy\util.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="util.h">
<ClInclude Include="..\spy\log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="injector.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="rpc_client.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\spy\util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="sdk.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\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>
<ClCompile Include="rpc_client.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="sdk.def">

View File

@ -1,19 +1,19 @@
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "framework.h"
#include "sdk.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_DETACH: {
WxDestroySDK(); // 默认退出时清理 SDK
break;
}
}
return TRUE;
}

View File

@ -1,70 +1,90 @@
#include "injector.h"
int InjectDll(DWORD pid, const WCHAR *dllPath)
HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase)
{
HANDLE hThread;
DWORD dwWriteSize = 0;
// 1. 获取目标进程,并在目标进程的内存里开辟空间
SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR);
// 1. 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
// 2. 把 dll 的路径写入到目标进程的内存空间中
if (pRemoteAddress) {
WriteProcessMemory(hProcess, pRemoteAddress, dllPath, wcslen(dllPath) * 2 + 2, &dwWriteSize);
} else {
MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0);
return -1;
if (hProcess == NULL) {
MessageBox(NULL, L"打开进程失败", L"InjectDll", 0);
return NULL;
}
// 2. 在目标进程的内存里开辟空间
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteAddress == NULL) {
MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0);
return NULL;
}
// 3. 把 dll 的路径写入到目标进程的内存空间中
WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL);
// 3. 创建一个远程线程,让目标进程调用 LoadLibrary
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, NULL, NULL);
if (hThread) {
WaitForSingleObject(hThread, -1);
} else {
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, 0, NULL);
if (hThread == NULL) {
MessageBox(NULL, L"LoadLibrary 调用失败", L"InjectDll", 0);
return -2;
return NULL;
}
WaitForSingleObject(hThread, -1);
GetExitCodeThread(hThread, (LPDWORD)injectedBase);
CloseHandle(hThread);
VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
// CloseHandle(hProcess); // Close when exit
return hProcess;
}
int EjectDll(DWORD pid, const WCHAR *dllPath)
bool EjectDll(HANDLE process, HMODULE dllBase)
{
DWORD dwHandle, dwID;
HANDLE hThread = NULL;
DWORD dwWriteSize = 0;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteAddress)
WriteProcessMemory(hProcess, pRemoteAddress, dllPath, wcslen(dllPath) * 2 + 2, &dwWriteSize);
else {
MessageBox(NULL, L"DLL 路径写入失败", L"EjectDll", 0);
return -1;
}
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetModuleHandleW, pRemoteAddress, 0, &dwID);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwHandle);
} else {
MessageBox(NULL, L"GetModuleHandleW 调用失败!", L"EjectDll", 0);
return -2;
}
CloseHandle(hThread);
// 使目标进程调用 FreeLibrary卸载 DLL
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dwHandle, 0, &dwID);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
} else {
hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dllBase, 0, NULL);
if (hThread == NULL) {
MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0);
return -3;
return false;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
CloseHandle(process);
return true;
}
static void *GetFuncAddr(LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName)
{
HMODULE hLoaded = LoadLibrary(dllPath);
if (hLoaded == NULL) {
return NULL;
}
void *absAddr = GetProcAddress(hLoaded, funcName);
DWORD offset = (DWORD)absAddr - (DWORD)hLoaded;
FreeLibrary(hLoaded);
return (void *)((DWORD)dllBase + offset);
}
bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, DWORD *ret)
{
void *pFunc = GetFuncAddr(dllPath, dllBase, funcName);
if (pFunc == NULL) {
return false;
}
HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, NULL, 0, NULL);
if (hThread == NULL) {
return false;
}
WaitForSingleObject(hThread, INFINITE);
if (ret != NULL) {
GetExitCodeThread(hThread, ret);
}
CloseHandle(hThread);
return true;
}

View File

@ -2,5 +2,6 @@
#include "framework.h"
int InjectDll(DWORD pid, const WCHAR* dllPath);
int EjectDll(DWORD pid, const WCHAR* dllPath);
HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase);
bool EjectDll(HANDLE process, HMODULE dllBase);
bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, DWORD *ret);

View File

@ -1,278 +0,0 @@
#include "rpc_client.h"
#include "sdk.h"
#include "util.h"
static RPC_WSTR pszStringBinding = NULL;
extern std::function<int(WxMessage_t)> g_cbReceiveTextMsg;
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"wcferry"), // 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);
// Releases binding handle resources and disconnects from the server
status = RpcBindingFree(&hSpyBinding);
return status;
}
int RpcEnableReceiveMsg()
{
unsigned long ulCode = 0;
RpcTryExcept
{
// 建立RPC通道让服务端能够调用客户端的回调函数。该接口会被服务端阻塞直到异常退出
client_EnableReceiveMsg();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcEnableReceiveMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return 0;
}
int RpcDisableReceiveMsg()
{
unsigned long ulCode = 0;
RpcTryExcept
{
// UnHook Message receiving
client_DisableReceiveMsg();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcDisableReceiveMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return 0;
}
int RpcIsLogin()
{
int loginFlag = 0;
unsigned long ulCode = 0;
RpcTryExcept
{
// 查询登录状态
loginFlag = client_IsLogin();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcIsLogin exception 0x%lx = %ld\n", ulCode, ulCode);
return -1;
}
RpcEndExcept;
return loginFlag;
}
int RpcGetSelfWxId(wchar_t wxid[20])
{
int ret = -1;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_GetSelfWxId(wxid); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcIsLogin exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
int RpcSendTextMsg(const wchar_t *wxid, const wchar_t *msg, const wchar_t *atWxids)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendTextMsg(wxid, msg, atWxids); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcSendTextMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
int RpcSendImageMsg(const wchar_t *wxid, const wchar_t *path)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendImageMsg(wxid, path); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcSendImageMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
PPRpcIntBstrPair RpcGetMsgTypes(int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
PPRpcIntBstrPair ppRpcMsgTypes = NULL;
RpcTryExcept { ret = client_GetMsgTypes(pNum, &ppRpcMsgTypes); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetMsgTypes exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("GetMsgTypes Failed: %d\n", ret);
return NULL;
}
return ppRpcMsgTypes;
}
PPRpcContact RpcGetContacts(int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
PPRpcContact ppRpcContacts = NULL;
RpcTryExcept { ret = client_GetContacts(pNum, &ppRpcContacts); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetContacts exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("GetContacts Failed: %d\n", ret);
return NULL;
}
return ppRpcContacts;
}
BSTR *RpcGetDbNames(int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
BSTR *pBstr = NULL;
RpcTryExcept { ret = client_GetDbNames(pNum, &pBstr); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetDbNames exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("RpcGetDbNames Failed: %d\n", ret);
return NULL;
}
return pBstr;
}
PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
PPRpcTables ppRpcTables = NULL;
RpcTryExcept { ret = client_GetDbTables(db, pNum, &ppRpcTables); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetDbTables exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("RpcGetDbTables Failed: %d\n", ret);
return NULL;
}
return ppRpcTables;
}
PPPRpcSqlResult RpcExecDbQuery(const wchar_t *db, const wchar_t *sql, int *pRow, int *pCol)
{
int ret = 0;
unsigned long ulCode = 0;
PPPRpcSqlResult pppRpcSqlResult = NULL;
RpcTryExcept { ret = client_ExecDbQuery(db, sql, pRow, pCol, &pppRpcSqlResult); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcExecDbQuery exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("RpcExecDbQuery Failed: %d\n", ret);
return NULL;
}
return pppRpcSqlResult;
}
BOOL AcceptNewFriend(const wchar_t *v3, const wchar_t *v4)
{
BOOL ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_AcceptNewFriend(v3, v4); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("AcceptNewFriend exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
int server_ReceiveMsg(RpcMessage_t rpcMsg)
{
WxMessage_t msg;
GetRpcMessage(&msg, rpcMsg);
try {
g_cbReceiveTextMsg(msg); // 调用接收消息回调
} catch (...) {
printf("callback error...\n");
}
return 0;
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "rpc_h.h"
RPC_STATUS RpcConnectServer();
RPC_STATUS RpcDisconnectServer();
int RpcEnableReceiveMsg();
int RpcDisableReceiveMsg();
int RpcIsLogin();
int RpcGetSelfWxId(wchar_t wxid[20]);
int RpcSendTextMsg(const wchar_t *wxid, const wchar_t *msg, const wchar_t *atWxids);
int RpcSendImageMsg(const wchar_t *wxid, const wchar_t *path);
PPRpcIntBstrPair RpcGetMsgTypes(int *pNum);
PPRpcContact RpcGetContacts(int *pNum);
BSTR *RpcGetDbNames(int *pNum);
PPRpcTables RpcGetDbTables(const wchar_t *db, int *pNum);
PPPRpcSqlResult RpcExecDbQuery(const wchar_t *db, const wchar_t *sql, int *row, int *col);
BOOL AcceptNewFriend(const wchar_t *v3, const wchar_t *v4);

View File

@ -1,273 +1,73 @@
#include "Shlwapi.h"
#include "Shlwapi.h"
#include "framework.h"
#include <process.h>
#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <tlhelp32.h>
#include <vector>
#include "injector.h"
#include "rpc_client.h"
#include "log.h"
#include "sdk.h"
#include "util.h"
std::function<int(WxMessage_t)> g_cbReceiveTextMsg;
static DWORD WeChatPID = 0;
static WCHAR SpyDllPath[MAX_PATH] = { 0 };
static DWORD wcPid = 0;
static HANDLE wcProcess = NULL;
static HMODULE spyBase = NULL;
static WCHAR spyDllPath[MAX_PATH] = { 0 };
int WxInitSDK()
{
int status = 0;
unsigned long ulCode = 0;
InitLogger();
LOG_INFO("WxInitSDK.");
GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH);
PathRemoveFileSpec(spyDllPath);
PathAppend(spyDllPath, WECHATINJECTDLL);
GetModuleFileName(GetModuleHandle(WECHATSDKDLL), SpyDllPath, MAX_PATH);
PathRemoveFileSpec(SpyDllPath);
PathAppend(SpyDllPath, WECHATINJECTDLL);
if (!PathFileExists(SpyDllPath)) {
if (!PathFileExists(spyDllPath)) {
LOG_ERROR("DLL does not exists.");
return ERROR_FILE_NOT_FOUND;
}
status = OpenWeChat(&WeChatPID);
status = OpenWeChat(&wcPid);
if (status != 0) {
LOG_ERROR("OpenWeChat failed: {}.", status);
return status;
}
Sleep(2000); // 等待微信打开
if (InjectDll(WeChatPID, SpyDllPath)) {
wcProcess = InjectDll(wcPid, spyDllPath, &spyBase);
if (wcProcess == NULL) {
LOG_ERROR("Failed to Inject DLL into WeChat.");
return -1;
}
Sleep(1000); // 等待SPY就绪
status = RpcConnectServer();
if (status != 0) {
printf("RpcConnectServer: %d\n", status);
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "InitSpy", NULL)) {
LOG_ERROR("Failed to InitSpy.");
return -1;
}
do {
status = RpcIsLogin();
if (status == -1) {
return status;
} else if (status == 1) {
break;
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "IsLogin", (DWORD *)&status)) {
LOG_ERROR("Failed to check login status.");
return -1;
}
Sleep(1000);
} while (1);
} while (status == 0);
return ERROR_SUCCESS;
return 0;
}
int WxDestroySDK()
{
WxDisableRecvMsg();
RpcDisconnectServer();
// 关闭 RPC但不卸载 DLL方便下次使用。
// EjectDll(WeChatPID, SpyDllPath);
return ERROR_SUCCESS;
}
int WxEnableRecvMsg(const std::function<int(WxMessage_t)> &onMsg)
{
if (onMsg) {
HANDLE msgThread;
g_cbReceiveTextMsg = onMsg;
msgThread = (HANDLE)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RpcEnableReceiveMsg, 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 WxDisableRecvMsg()
{
RpcDisableReceiveMsg();
return -1;
}
int WxSendTextMsg(wstring wxid, wstring msg, wstring atWxids)
{
return RpcSendTextMsg(wxid.c_str(), msg.c_str(), atWxids.c_str());
}
int WxSendImageMsg(wstring wxid, wstring path) { return RpcSendImageMsg(wxid.c_str(), path.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");
LOG_INFO("WxDestroySDK");
if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL)) {
LOG_ERROR("Failed to CleanupSpy.");
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;
if (!EjectDll(wcProcess, spyBase)) {
LOG_ERROR("Failed to Eject DLL.");
return -1; // TODO: Unify error codes
}
return 0;
}
wstring WxGetSelfWxid()
{
wchar_t wxid[20] = { 0 };
RpcGetSelfWxId(wxid);
return wstring(wxid);
}
MsgTypesMap_t WxGetMsgTypes()
{
static MsgTypesMap_t WxMsgTypes;
if (WxMsgTypes.empty()) {
int size = 0;
PPRpcIntBstrPair pp = RpcGetMsgTypes(&size);
for (int i = 0; i < size; i++) {
WxMsgTypes.insert(make_pair(pp[i]->key, GetWstringFromBstr(pp[i]->value)));
midl_user_free(pp[i]);
}
if (pp) {
midl_user_free(pp);
}
}
return WxMsgTypes;
}
ContactMap_t WxGetContacts()
{
ContactMap_t mContact;
int size = 0;
PPRpcContact pp = RpcGetContacts(&size);
for (int i = 0; i < size; i++) {
WxContact_t contact;
contact.wxId = GetWstringFromBstr(pp[i]->wxId);
contact.wxCode = GetWstringFromBstr(pp[i]->wxCode);
contact.wxName = GetWstringFromBstr(pp[i]->wxName);
contact.wxCountry = GetWstringFromBstr(pp[i]->wxCountry);
contact.wxProvince = GetWstringFromBstr(pp[i]->wxProvince);
contact.wxCity = GetWstringFromBstr(pp[i]->wxCity);
contact.wxGender = GetWstringFromBstr(pp[i]->wxGender);
mContact.insert(make_pair(contact.wxId, contact));
midl_user_free(pp[i]);
}
if (pp) {
midl_user_free(pp);
}
return mContact;
}
std::vector<std::wstring> WxGetDbNames()
{
std::vector<std::wstring> vDbs;
int size = 0;
BSTR *pBstr = RpcGetDbNames(&size);
for (int i = 0; i < size; i++) {
vDbs.push_back(GetWstringFromBstr(pBstr[i]));
}
if (pBstr) {
midl_user_free(pBstr);
}
return vDbs;
}
DbTableVector_t WxGetDbTables(wstring db)
{
DbTableVector_t vTables;
int size = 0;
PPRpcTables pp = RpcGetDbTables(db.c_str(), &size);
for (int i = 0; i < size; i++) {
WxDbTable_t tbl;
tbl.table = GetWstringFromBstr(pp[i]->table);
tbl.sql = GetWstringFromBstr(pp[i]->sql);
vTables.push_back(tbl);
midl_user_free(pp[i]);
}
if (pp) {
midl_user_free(pp);
}
return vTables;
}
SqlRetVector_t WxExecDbQuery(wstring db, wstring sql)
{
int row, col = 0;
PPPRpcSqlResult ppp = RpcExecDbQuery(db.c_str(), sql.c_str(), &row, &col);
vector<vector<WxSqlResult_t>> vvResults;
for (int r = 0; r < row; r++) {
vector<WxSqlResult_t> vResult;
for (int c = 0; c < col; c++) {
WxSqlResult_t result = { 0 };
result.type = ppp[r][c]->type;
result.column = GetWstringFromBstr(ppp[r][c]->column);
result.content = GetBytesFromBstr(ppp[r][c]->content);
vResult.push_back(result);
midl_user_free(ppp[r][c]);
}
vvResults.push_back(vResult);
midl_user_free(ppp[r]);
}
if (ppp) {
midl_user_free(ppp);
}
return vvResults;
}
BOOL WxAcceptNewFriend(wstring v3, wstring v4) { return AcceptNewFriend(v3.c_str(), v4.c_str()); }

View File

@ -1,14 +1,3 @@
EXPORTS
WxInitSDK
WxDestroySDK
WxEnableRecvMsg
WxDisableRecvMsg
WxSendTextMsg
WxGetSelfWxid
WxGetMsgTypes
WxSendImageMsg
WxGetContacts
WxGetDbNames
WxGetDbTables
WxExecDbQuery
WxAcceptNewFriend

View File

@ -1,60 +1,4 @@
#pragma once
#include "framework.h"
#include <functional>
#include <map>
#include <string>
#include <vector>
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 struct WxContact {
wstring wxId; // 微信ID
wstring wxCode; // 微信号
wstring wxName; // 微信昵称
wstring wxCountry; // 国家
wstring wxProvince; // 省/州
wstring wxCity; // 城市
wstring wxGender; // 性别
} WxContact_t;
typedef struct WxDbTable {
wstring table; // 表名
wstring sql; // 建表 SQL
} WxDbTable_t;
typedef struct WxSqlResult {
int type;
wstring column;
string content;
} WxSqlResult_t;
typedef map<int, wstring> MsgTypesMap_t;
typedef map<wstring, WxContact_t> ContactMap_t;
typedef vector<WxDbTable_t> DbTableVector_t;
typedef vector<vector<WxSqlResult_t>> SqlRetVector_t;
#pragma once
int WxInitSDK();
int WxDestroySDK();
int WxEnableRecvMsg(const std::function<int(WxMessage_t)> &onMsg);
int WxDisableRecvMsg();
int WxSendTextMsg(wstring wxid, wstring msg, wstring vAtWxids);
int WxSendImageMsg(wstring wxid, wstring path);
wstring WxGetSelfWxid();
ContactMap_t WxGetContacts();
MsgTypesMap_t WxGetMsgTypes();
vector<wstring> WxGetDbNames();
DbTableVector_t WxGetDbTables(wstring db);
SqlRetVector_t WxExecDbQuery(wstring db, wstring sql);
BOOL WxAcceptNewFriend(wstring v3, wstring v4);

View File

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{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="..\SDK\util.h" />
<ClInclude Include="framework.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\SDK\util.cpp" />
<ClCompile Include="sdkpy.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

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

View File

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

View File

@ -1,92 +0,0 @@
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "sdk.h"
#include "util.h"
namespace py = pybind11;
int WxEnableRecvMsgPy(const std::function<int(WxMessage_t)> &onMsg) { return WxEnableRecvMsg(onMsg); }
py::object WxExecDbQueryPy(std::wstring db, std::wstring sql)
{
py::list results;
SqlRetVector_t cResults = WxExecDbQuery(db, sql);
for (auto vv = cResults.begin(); vv != cResults.end(); vv++) {
py::dict row;
for (auto v = vv->begin(); v != vv->end(); v++) {
switch (v->type) {
case 1: { // SQLITE_INTEGER
row[py::cast(v->column)] = stoi(v->content);
break;
}
case 2: { // SQLITE_FLOAT
row[py::cast(v->column)] = stof(v->content);
break;
}
case 3: { // SQLITE_TEXT
row[py::cast(v->column)] = String2Wstring(v->content);
break;
}
case 4: { // SQLITE_BLOB
row[py::cast(v->column)] = py::bytes(v->content.c_str(), v->content.size());
break;
}
default: {
row[py::cast(v->column)] = "";
break;
}
}
}
results.append(row);
}
return results;
}
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);
py::class_<WxContact>(m, "WxContact")
.def_readonly("wxId", &WxContact::wxId)
.def_readonly("wxCode", &WxContact::wxCode)
.def_readonly("wxName", &WxContact::wxName)
.def_readonly("wxCountry", &WxContact::wxCountry)
.def_readonly("wxProvince", &WxContact::wxProvince)
.def_readonly("wxCity", &WxContact::wxCity)
.def_readonly("wxGender", &WxContact::wxGender);
py::class_<WxDbTable>(m, "WxDbTable").def_readonly("table", &WxDbTable::table).def_readonly("sql", &WxDbTable::sql);
m.def("WxInitSDK", &WxInitSDK, "Initiate SDK. Return 0 on successelse on failure.");
m.def("WxEnableRecvMsg", &WxEnableRecvMsgPy, "Enable message receiving and provide a callback", py::arg("onMsg"));
m.def("WxDisableRecvMsg", &WxDisableRecvMsg, "Disable message receiving.");
m.def("WxSendTextMsg", &WxSendTextMsg, "Send text message.", py::arg("wxid"), py::arg("msg"),
py::arg("atWxids") = L"");
m.def("WxSendImageMsg", &WxSendImageMsg, "Send image message.", py::arg("wxid"), py::arg("path"));
m.def("WxGetSelfWxid", &WxGetSelfWxid, "Get Self Wxid.");
m.def("WxGetContacts", &WxGetContacts, py::return_value_policy::reference, "Get contact list.");
m.def("WxGetMsgTypes", &WxGetMsgTypes, py::return_value_policy::reference, "Get message types.");
m.def("WxGetDbNames", &WxGetDbNames, py::return_value_policy::reference, "Get DB names.");
m.def("WxGetDbTables", &WxGetDbTables, py::return_value_policy::reference, "Get DB tables.", py::arg("db"));
m.def("WxExecDbQuery", &WxExecDbQueryPy, py::return_value_policy::reference, "Get DB tables.", py::arg("db"),
py::arg("sql"));
m.def("WxAcceptNewFriend", &WxAcceptNewFriend, "Accept new friend application.", py::arg("v3"), py::arg("v4"));
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}

View File

@ -21,9 +21,11 @@
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{4a0a22f7-0b1c-4565-a443-c43fac6c6396}</ProjectGuid>
<RootNamespace>Spy</RootNamespace>
<ProjectGuid>{4de80b82-5f6a-4c4c-9d16-1574308110fa}</ProjectGuid>
<RootNamespace>spy</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
<VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -75,6 +77,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
@ -82,26 +85,24 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic>
</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>
<PrecompiledHeader>Use</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>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</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>
@ -112,9 +113,13 @@
<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>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(SolutionDir)rpc;C:\Tools\vcpkg\installed\x86-windows-static\include</AdditionalIncludeDirectories>
<PrecompiledHeaderOutputFile />
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -122,12 +127,23 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
<Midl>
<AdditionalOptions>/prefix client "client_" server "server_" </AdditionalOptions>
<AdditionalIncludeDirectories>$(SolutionDir)Rpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</Midl>
<PostBuildEvent>
<Command>xcopy /y $(OutDir)spy.dll $(SolutionDir)python</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy spy.dll</Message>
</PostBuildEvent>
<PreBuildEvent>
<Command>cd $(SolutionDir)proto
protoc -I=. --cpp_out=. wcf.proto
protoc -I=. --grpc_out=. --plugin=protoc-gen-grpc="C:\Tools\vcpkg\packages\grpc_x64-windows\tools\grpc\grpc_cpp_plugin.exe" wcf.proto</Command>
</PreBuildEvent>
<PreBuildEvent>
<Message>gRPC</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -142,6 +158,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -161,44 +178,43 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="..\SDK\util.h" />
<ClInclude Include="..\proto\wcf.grpc.pb.h" />
<ClInclude Include="..\proto\wcf.pb.h" />
<ClInclude Include="accept_new_friend.h" />
<ClInclude Include="exec_sql.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="get_contacts.h" />
<ClInclude Include="load_calls.h" />
<ClInclude Include="log.h" />
<ClInclude Include="receive_msg.h" />
<ClInclude Include="rpc_server.h" />
<ClInclude Include="send_msg.h" />
<ClInclude Include="spy.h" />
<ClInclude Include="spy_types.h" />
<ClInclude Include="util.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Rpc\rpc_memory.cpp" />
<ClCompile Include="..\Rpc\rpc_s.c" />
<ClCompile Include="..\SDK\util.cpp" />
<ClCompile Include="..\proto\wcf.grpc.pb.cc" />
<ClCompile Include="..\proto\wcf.pb.cc" />
<ClCompile Include="accept_new_friend.cpp" />
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="exec_sql.cpp" />
<ClCompile Include="get_contacts.cpp" />
<ClCompile Include="load_calls.cpp" />
<ClCompile Include="log.cpp" />
<ClCompile Include="receive_msg.cpp" />
<ClCompile Include="rpc_server.cpp" />
<ClCompile Include="send_msg.cpp" />
<ClCompile Include="spy.cpp" />
<ClCompile Include="util.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>
<None Include="..\proto\wcf.proto" />
<None Include="spy.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -13,24 +13,30 @@
<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 Include="proto">
<UniqueIdentifier>{5da8b2ee-3201-441c-b42f-a420e9aad78b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Rpc\rpc_h.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="rpc_server.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="load_calls.h">
<ClInclude Include="log.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\SDK\util.h">
<ClInclude Include="accept_new_friend.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="exec_sql.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="get_contacts.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="load_calls.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="receive_msg.h">
@ -39,39 +45,42 @@
<ClInclude Include="send_msg.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="spy_types.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="get_contacts.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="exec_sql.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="spy.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="accept_new_friend.h">
<ClInclude Include="spy_types.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="util.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\proto\wcf.grpc.pb.h">
<Filter>proto</Filter>
</ClInclude>
<ClInclude Include="..\proto\wcf.pb.h">
<Filter>proto</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="rpc_server.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="load_calls.cpp">
<ClCompile Include="log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\SDK\util.cpp">
<ClCompile Include="accept_new_friend.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="exec_sql.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="get_contacts.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="load_calls.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="receive_msg.cpp">
@ -80,22 +89,25 @@
<ClCompile Include="send_msg.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="get_contacts.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="exec_sql.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="spy.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="accept_new_friend.cpp">
<ClCompile Include="util.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\proto\wcf.grpc.pb.cc">
<Filter>proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\wcf.pb.cc">
<Filter>proto</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Midl Include="..\Rpc\rpc.idl">
<Filter>Rpc</Filter>
</Midl>
<None Include="spy.def">
<Filter>源文件</Filter>
</None>
<None Include="..\proto\wcf.proto">
<Filter>proto</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -1,23 +1,18 @@
#include "framework.h"
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "framework.h"
#include <iostream>
#include <sstream>
#include "spy.h"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
//MessageBox(NULL, L"InitSpy", L"DllMain", 0);
InitSpy();
break;
}
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
case DLL_PROCESS_DETACH: {
//MessageBox(NULL, L"DestroySpy", L"DllMain", 0);
DestroySpy(hModule);
break;
}
}
return TRUE;
}

View File

@ -48,7 +48,7 @@ using namespace std;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
typedef map<wstring, DWORD> dbMap_t;
typedef map<string, DWORD> dbMap_t;
static dbMap_t dbMap;
// 回调函数指针
@ -72,16 +72,15 @@ typedef int(__cdecl *Sqlite3_finalize)(DWORD *);
static int cbGetTables(void *ret, int argc, char **argv, char **azColName)
{
vector<RpcTables_t> *p = (vector<RpcTables_t> *)ret;
RpcTables_t tbl = { 0 };
wcf::DbTables* tbls = (wcf::DbTables*)ret;
for (int i = 0; i < argc; i++) {
wcf::DbTable* tbl = tbls->add_tables();
if (strcmp(azColName[i], "name") == 0) {
tbl.table = argv[i] ? GetBstrFromString(argv[i]) : NULL;
tbl->set_name(argv[i] ? argv[i] : "");
} else if (strcmp(azColName[i], "sql") == 0) {
tbl.sql = argv[i] ? GetBstrFromString(argv[i]) : NULL;
tbl->set_sql(argv[i] ? argv[i] : "");
}
}
p->push_back(tbl);
return 0;
}
@ -96,7 +95,7 @@ dbMap_t GetDbHandles()
DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end);
while (sqlHandleBeginAddr < sqlHandleEndAddr) {
DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr;
wstring dbName = wstring((wchar_t *)(*(DWORD *)(dwHandle + g_WxCalls.sql.name)));
string dbName = Wstring2String(wstring((wchar_t*)(*(DWORD*)(dwHandle + g_WxCalls.sql.name))));
DWORD handle = *(DWORD *)(dwHandle + g_WxCalls.sql.slot);
if (handle) {
dbMap[dbName] = handle;
@ -107,40 +106,38 @@ dbMap_t GetDbHandles()
return dbMap;
}
vector<wstring> GetDbNames()
void GetDbNames(wcf::DbNames* names)
{
vector<wstring> vDbs;
if (dbMap.empty()) {
dbMap = GetDbHandles();
}
for (auto it = dbMap.begin(); it != dbMap.end(); it++) {
vDbs.push_back(it->first);
for (auto& [k, v] : dbMap) {
auto* name = names->add_names();
name->assign(k);
}
return vDbs;
}
vector<RpcTables_t> GetDbTables(wstring db)
void GetDbTables(const string db, wcf::DbTables* tables)
{
vector<RpcTables_t> vTables;
const char *sql = "select * from sqlite_master where type=\"table\";";
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec);
if (dbMap.empty()) {
dbMap = GetDbHandles();
}
auto it = dbMap.find(db);
if (it != dbMap.end()) {
p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, &vTables, 0);
if (it == dbMap.end()) {
return; // DB not found
}
return vTables;
const char *sql = "select * from sqlite_master where type=\"table\";";
Sqlite3_exec p_Sqlite3_exec = (Sqlite3_exec)(g_WeChatWinDllAddr + g_WxCalls.sql.exec);
p_Sqlite3_exec(it->second, sql, (sqlite3_callback)cbGetTables, tables, 0);
}
vector<vector<RpcSqlResult_t>> ExecDbQuery(wstring db, wstring sql)
void ExecDbQuery(const string db, const string sql, wcf::DbRows* rows)
{
vector<vector<RpcSqlResult_t>> vvSqlResult;
Sqlite3_prepare func_prepare = (Sqlite3_prepare)(g_WeChatWinDllAddr + 0x14227F0);
Sqlite3_step func_step = (Sqlite3_step)(g_WeChatWinDllAddr + 0x13EA780);
Sqlite3_column_count func_column_count = (Sqlite3_column_count)(g_WeChatWinDllAddr + 0x13EACD0);
@ -154,30 +151,24 @@ vector<vector<RpcSqlResult_t>> ExecDbQuery(wstring db, wstring sql)
dbMap = GetDbHandles();
}
DWORD *stmt;
int rc = func_prepare(dbMap[db], Wstring2String(sql).c_str(), -1, &stmt, 0);
DWORD* stmt;
int rc = func_prepare(dbMap[db], sql.c_str(), -1, &stmt, 0);
if (rc != SQLITE_OK) {
return vvSqlResult;
return;
}
wchar_t buffer[128] = { 0 };
while (func_step(stmt) == SQLITE_ROW) {
vector<RpcSqlResult_t> vResult;
wcf::DbRow* row = rows->add_rows();
int col_count = func_column_count(stmt);
for (int i = 0; i < col_count; i++) {
RpcSqlResult_t result = { 0 };
result.type = func_column_type(stmt, i);
result.column = GetBstrFromString(func_column_name(stmt, i));
wcf::DbField* field = row->add_fields();
field->set_type(func_column_type(stmt, i));
field->set_column(func_column_name(stmt, i));
int length = func_column_bytes(stmt, i);
const void *blob = func_column_blob(stmt, i);
if (length && (result.type != 5)) {
result.content = GetBstrFromByteArray((byte *)blob, length);
const void* blob = func_column_blob(stmt, i);
if (length && (field->type() != 5)) {
field->set_content(string((char *)blob, length));
}
vResult.push_back(result);
}
vvSqlResult.push_back(vResult);
}
return vvSqlResult;
}

View File

@ -3,8 +3,8 @@
#include <string>
#include <vector>
#include "rpc_h.h"
#include "../proto/wcf.grpc.pb.h"
std::vector<std::wstring> GetDbNames();
std::vector<RpcTables_t> GetDbTables(std::wstring db);
std::vector<std::vector<RpcSqlResult_t>> ExecDbQuery(std::wstring db, std::wstring sql);
void GetDbNames(wcf::DbNames *names);
void GetDbTables(const std::string db, wcf::DbTables *tables);
void ExecDbQuery(const std::string db, const std::string sql, wcf::DbRows *rows);

View File

@ -5,35 +5,34 @@
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
std::vector<RpcContact_t> GetContacts()
bool GetContacts(wcf::Contacts* contacts)
{
int gender = 0;
vector<RpcContact_t> vContacts;
DWORD baseAddr = g_WeChatWinDllAddr + g_WxCalls.contact.base;
DWORD tempAddr = GET_DWORD(baseAddr);
DWORD head = GET_DWORD(tempAddr + g_WxCalls.contact.head);
DWORD node = GET_DWORD(head);
while (node != head) {
RpcContact_t rpcContact = { 0 };
rpcContact.wxId = GetBstrByAddress(node + g_WxCalls.contact.wxId);
rpcContact.wxCode = GetBstrByAddress(node + g_WxCalls.contact.wxCode);
rpcContact.wxName = GetBstrByAddress(node + g_WxCalls.contact.wxName);
rpcContact.wxCountry = GetBstrByAddress(node + g_WxCalls.contact.wxCountry);
rpcContact.wxProvince = GetBstrByAddress(node + g_WxCalls.contact.wxProvince);
rpcContact.wxCity = GetBstrByAddress(node + g_WxCalls.contact.wxCity);
wcf::Contact* cnt = contacts->add_contacts();
cnt->set_wxid(GetStringByAddress(node + g_WxCalls.contact.wxId));
cnt->set_code(GetStringByAddress(node + g_WxCalls.contact.wxCode));
cnt->set_name(GetStringByAddress(node + g_WxCalls.contact.wxName));
cnt->set_country(GetStringByAddress(node + g_WxCalls.contact.wxCountry));
cnt->set_province(GetStringByAddress(node + g_WxCalls.contact.wxProvince));
cnt->set_city(GetStringByAddress(node + g_WxCalls.contact.wxCity));
cnt->set_city(GetStringByAddress(node + g_WxCalls.contact.wxCity));
gender = GET_DWORD(node + g_WxCalls.contact.wxGender);
if (gender == 1)
rpcContact.wxGender = SysAllocString(L"");
cnt->set_city("");
else if (gender == 2)
rpcContact.wxGender = SysAllocString(L"");
cnt->set_city("");
else
rpcContact.wxGender = SysAllocString(L"未知");
cnt->set_city("未知");
vContacts.push_back(rpcContact);
node = GET_DWORD(node);
}
return vContacts;
return true;
}

View File

@ -1,7 +1,5 @@
#pragma once
#include <vector>
#include "../proto/wcf.grpc.pb.h"
#include "rpc_h.h"
std::vector<RpcContact_t> GetContacts();
bool GetContacts(wcf::Contacts *contacts);

23
Spy/log.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "log.h"
#define LOGGER_NAME "WCF"
#define LOGGER_FILE_NAME "logs/wcf.txt"
#define LOGGER_MAX_SIZE 1024 * 1024 * 10 // 10M
#define LOGGER_MAX_FILES 10 // 10 files
void InitLogger()
{
static std::shared_ptr<spdlog::logger> gLogger = nullptr;
if (gLogger != nullptr) {
return;
}
gLogger = spdlog::rotating_logger_mt(LOGGER_NAME, LOGGER_FILE_NAME, LOGGER_MAX_SIZE, LOGGER_MAX_FILES);
// gLogger = spdlog::stdout_color_mt("console");
spdlog::set_default_logger(gLogger);
gLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%s::%#::%!] %v");
gLogger->flush_on(spdlog::level::info);
}

14
Spy/log.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
extern std::shared_ptr<spdlog::logger> gLogger;
#define LOG_DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__);
#define LOG_INFO(...) SPDLOG_INFO(__VA_ARGS__);
#define LOG_WARN(...) SPDLOG_WARN(__VA_ARGS__);
#define LOG_ERROR(...) SPDLOG_ERROR(__VA_ARGS__);
void InitLogger();

View File

@ -1,42 +1,57 @@
#include "framework.h"
#pragma execution_character_set("utf-8")
#include <queue>
#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;
using namespace std;
using wcf::MsgTypes;
using wcf::WxMsg;
extern bool gIsListening;
extern mutex gMutex;
extern queue<WxMsg> gMsgQueue;
extern condition_variable gCv;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
MsgQueue_t g_MsgQueue;
static BOOL isListened = false;
static DWORD reg_buffer = 0;
static DWORD recvMsgHookAddr = 0;
static DWORD recvMsgCallAddr = 0;
static DWORD recvMsgJumpBackAddr = 0;
static CHAR recvMsgBackupCode[5] = { 0 };
static RpcMessage_t lMsg = { 0 };
extern const MsgTypesMap_t g_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"撤回消息" } };
void GetMsgTypes(MsgTypes *types)
{
const map<int32_t, string> m = { { 0x01, "文字" },
{ 0x03, "图片" },
{ 0x22, "语音" },
{ 0x25, "好友确认" },
{ 0x28, "POSSIBLEFRIEND_MSG" },
{ 0x2A, "名片" },
{ 0x2B, "视频" },
{ 0x2F, "石头剪刀布 | 表情图片" },
{ 0x30, "位置" },
{ 0x31, "共享实时位置、文件、转账、链接" },
{ 0x32, "VOIPMSG" },
{ 0x33, "微信初始化" },
{ 0x34, "VOIPNOTIFY" },
{ 0x35, "VOIPINVITE" },
{ 0x3E, "小视频" },
{ 0x270F, "SYSNOTICE" },
{ 0x2710, "红包、系统消息" },
{ 0x2712, "撤回消息" } };
for (auto &[k, v] : m) {
(*(types->mutable_types()))[k] = v;
}
}
void HookAddress(DWORD hookAddr, LPVOID funcAddr, CHAR recvMsgBackupCode[5])
{
@ -60,26 +75,32 @@ void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5])
void DispatchMsg(DWORD reg)
{
WxMsg wxMsg;
DWORD *p = (DWORD *)reg; //消息结构基址
memset(&lMsg, 0, sizeof(RpcMessage_t));
lMsg.type = GET_DWORD(*p + g_WxCalls.recvMsg.type);
lMsg.self = GET_DWORD(*p + g_WxCalls.recvMsg.isSelf);
lMsg.id = GetBstrByAddress(*p + g_WxCalls.recvMsg.msgId);
lMsg.xml = GetBstrByAddress(*p + g_WxCalls.recvMsg.msgXml);
wxMsg.set_type(GET_DWORD(*p + g_WxCalls.recvMsg.type));
wxMsg.set_is_self(GET_DWORD(*p + g_WxCalls.recvMsg.isSelf));
wxMsg.set_id(GetStringByAddress(*p + g_WxCalls.recvMsg.msgId));
wxMsg.set_xml(GetStringByAddress(*p + g_WxCalls.recvMsg.msgXml));
// 群里的系统消息xml 为空
if ((lMsg.xml == NULL) || (wcsstr(lMsg.xml, L"<membercount>") != NULL)) {
lMsg.source = 1;
lMsg.wxId = GetBstrByAddress(*p + g_WxCalls.recvMsg.wxId);
lMsg.roomId = GetBstrByAddress(*p + g_WxCalls.recvMsg.roomId);
if ((wxMsg.xml().empty()) || (strstr(wxMsg.xml().c_str(), "<membercount>") != NULL)) {
wxMsg.set_is_group(true);
wxMsg.set_sender(GetStringByAddress(*p + g_WxCalls.recvMsg.wxId));
wxMsg.set_roomid(GetStringByAddress(*p + g_WxCalls.recvMsg.roomId));
} else {
lMsg.wxId = GetBstrByAddress(*p + g_WxCalls.recvMsg.roomId);
wxMsg.set_is_group(false);
wxMsg.set_sender(GetStringByAddress(*p + g_WxCalls.recvMsg.roomId));
}
lMsg.content = GetBstrByAddress(*p + g_WxCalls.recvMsg.content);
g_MsgQueue.push(lMsg); // 发送消息
SetEvent(g_hEvent); // 发送消息通知
wxMsg.set_content(GetStringByAddress(*p + g_WxCalls.recvMsg.content));
// 推送到队列
unique_lock<std::mutex> lock(gMutex);
gMsgQueue.push(wxMsg);
lock.unlock();
// 通知各方消息就绪
gCv.notify_all();
}
__declspec(naked) void RecieveMsgFunc()
@ -100,7 +121,7 @@ __declspec(naked) void RecieveMsgFunc()
void ListenMessage()
{
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
if (isListened || (g_WeChatWinDllAddr == 0)) {
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
return;
}
@ -109,14 +130,14 @@ void ListenMessage()
recvMsgJumpBackAddr = recvMsgHookAddr + 5;
HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode);
isListened = true;
gIsListening = true;
}
void UnListenMessage()
{
if (!isListened) {
if (!gIsListening) {
return;
}
UnHookAddress(recvMsgHookAddr, recvMsgBackupCode);
isListened = false;
gIsListening = false;
}

View File

@ -1,4 +1,7 @@
#pragma once
#include "../proto/wcf.grpc.pb.h"
void ListenMessage();
void UnListenMessage();
void GetMsgTypes(wcf::MsgTypes* types);

View File

@ -1,60 +1,270 @@
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable : 4251)
#include <memory>
#include <queue>
#include <random>
#include <sstream>
#include <string>
#include <thread>
#include <grpc/grpc.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include "../proto/wcf.grpc.pb.h"
#include "accept_new_friend.h"
#include "exec_sql.h"
#include "get_contacts.h"
#include "log.h"
#include "receive_msg.h"
#include "rpc_h.h"
#include "rpc_server.h"
#include "sdk.h"
#include "send_msg.h"
#include "spy.h"
#include "spy_types.h"
#include "util.h"
extern int IsLogin(void); // Defined in spy.cpp
extern std::string GetSelfWxid(); // Defined in spy.cpp
using namespace std;
extern int IsLogin(void); // Defined in spy.cpp
extern wstring GetSelfWxid(); // Defined in spy.cpp
extern HANDLE g_hEvent; // New message signal
extern BOOL g_rpcKeepAlive; // Keep RPC server thread running
extern MsgQueue_t g_MsgQueue; // Queue for message
extern const MsgTypesMap_t g_WxMsgTypes; // Map of WeChat Message types
using grpc::CallbackServerContext;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerUnaryReactor;
using grpc::ServerWriteReactor;
using grpc::Status;
static BOOL listenMsgFlag = false;
using wcf::Contacts;
using wcf::DbField;
using wcf::DbNames;
using wcf::DbQuery;
using wcf::DbRow;
using wcf::DbRows;
using wcf::DbTable;
using wcf::DbTables;
using wcf::Empty;
using wcf::ImageMsg;
using wcf::MsgTypes;
using wcf::Response;
using wcf::String;
using wcf::TextMsg;
using wcf::Verification;
using wcf::Wcf;
using wcf::WxMsg;
RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/)
mutex gMutex;
queue<WxMsg> gMsgQueue;
condition_variable gCv;
bool gIsListening;
class WcfImpl final : public Wcf::CallbackService
{
return RPC_S_OK; // Always allow anyone.
public:
explicit WcfImpl() { }
ServerUnaryReactor *RpcIsLogin(CallbackServerContext *context, const Empty *empty, Response *rsp) override
{
int ret = IsLogin();
rsp->set_status(ret);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcGetSelfWxid(CallbackServerContext *context, const Empty *empty, String *rsp) override
{
string wxid = GetSelfWxid();
rsp->set_str(wxid);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerWriteReactor<WxMsg> *RpcEnableRecvMsg(CallbackServerContext *context, const Empty *empty) override
{
class Getter : public ServerWriteReactor<WxMsg>
{
public:
Getter()
{
LOG_INFO("Enable message listening.")
ListenMessage(); // gIsListening = true;
NextWrite();
}
void OnDone() override { delete this; }
void OnWriteDone(bool /*ok*/) override { NextWrite(); }
private:
void NextWrite()
{
unique_lock<std::mutex> lock(gMutex);
gCv.wait(lock, [&] { return !gMsgQueue.empty(); });
tmp_ = gMsgQueue.front();
gMsgQueue.pop();
lock.unlock();
if (gIsListening) {
StartWrite(&tmp_);
} else {
LOG_INFO("Disable message listening.")
Finish(Status::OK); // 结束本次通信
}
}
WxMsg tmp_; // 如果将它放到 NextWrite 内部StartWrite 调用时可能已经出了作用域
};
return new Getter();
}
ServerUnaryReactor *RpcDisableRecvMsg(CallbackServerContext *context, const Empty *empty, Response *rsp) override
{
if (gIsListening) {
UnListenMessage(); // gIsListening = false;
// 发送消息,触发 NextWrite 的 Finish
WxMsg wxMsg;
unique_lock<std::mutex> lock(gMutex);
gMsgQueue.push(wxMsg);
lock.unlock();
gCv.notify_all();
}
rsp->set_status(0);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcSendTextMsg(CallbackServerContext *context, const TextMsg *msg, Response *rsp) override
{
wstring wswxid = String2Wstring(msg->receiver());
wstring wsmsg = String2Wstring(msg->msg());
wstring wsatusers = String2Wstring(msg->aters());
SendTextMessage(wswxid.c_str(), wsmsg.c_str(), wsatusers.c_str());
rsp->set_status(0);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcSendImageMsg(CallbackServerContext *context, const ImageMsg *msg, Response *rsp) override
{
wstring wswxid = String2Wstring(msg->receiver());
wstring wspath = String2Wstring(msg->path());
SendImageMessage(wswxid.c_str(), wspath.c_str());
rsp->set_status(0);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcGetMsgTypes(CallbackServerContext *context, const Empty *empty, MsgTypes *rsp) override
{
GetMsgTypes(rsp);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcGetContacts(CallbackServerContext *context, const Empty *empty, Contacts *rsp) override
{
bool ret = GetContacts(rsp);
auto *reactor = context->DefaultReactor();
if (ret) {
reactor->Finish(Status::OK);
} else {
reactor->Finish(Status::CANCELLED);
}
return reactor;
}
ServerUnaryReactor *RpcGetDbNames(CallbackServerContext *context, const Empty *empty, DbNames *rsp) override
{
GetDbNames(rsp);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcGetDbTables(CallbackServerContext *context, const String *db, DbTables *rsp) override
{
GetDbTables(db->str(), rsp);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcExecDbQuery(CallbackServerContext *context, const DbQuery *query, DbRows *rsp) override
{
ExecDbQuery(query->db(), query->sql(), rsp);
auto *reactor = context->DefaultReactor();
reactor->Finish(Status::OK);
return reactor;
}
ServerUnaryReactor *RpcAcceptNewFriend(CallbackServerContext *context, const Verification *v,
Response *rsp) override
{
bool ret = AcceptNewFriend(String2Wstring(v->v3()), String2Wstring(v->v4()));
auto *reactor = context->DefaultReactor();
if (ret) {
rsp->set_status(0);
reactor->Finish(Status::OK);
} else {
LOG_ERROR("AcceptNewFriend failed.")
rsp->set_status(-1); // TODO: Unify error code
reactor->Finish(Status::CANCELLED);
}
return reactor;
}
};
static DWORD lThreadId = 0;
static bool lIsRunning = false;
static ServerBuilder lBuilder;
static unique_ptr<Server> &GetServer()
{
static unique_ptr<Server> server(lBuilder.BuildAndStart());
return server;
}
static int runServer()
{
string server_address("localhost:10086");
WcfImpl service;
lBuilder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
lBuilder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIME_MS, 2000);
lBuilder.AddChannelArgument(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 3000);
lBuilder.AddChannelArgument(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);
lBuilder.RegisterService(&service);
unique_ptr<Server> &server = GetServer();
LOG_INFO("Server listening on {}", server_address);
LOG_DEBUG("server: {}", fmt::ptr(server));
lIsRunning = true;
server->Wait();
return 0;
}
int RpcStartServer()
{
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"wcferry"), // 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 (g_rpcKeepAlive) {
Sleep(1000); // 休眠释放CPU
HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)runServer, NULL, NULL, &lThreadId);
if (rpcThread != 0) {
CloseHandle(rpcThread);
}
return 0;
@ -62,224 +272,13 @@ int RpcStartServer()
int RpcStopServer()
{
RPC_STATUS status;
if (lIsRunning) {
UnListenMessage();
listenMsgFlag = false;
g_rpcKeepAlive = false;
status = RpcMgmtStopServerListening(NULL);
if (status)
return status;
status = RpcServerUnregisterIf(server_ISpy_v1_0_s_ifspec, NULL, 0);
return status;
}
int server_IsLogin() { return IsLogin(); }
int server_GetSelfWxId(wchar_t wxid[20]) { return wcscpy_s(wxid, 20, GetSelfWxid().c_str()); }
void server_EnableReceiveMsg()
{
unsigned long ulCode = 0;
ListenMessage();
listenMsgFlag = true;
RpcTryExcept
{
// 调用客户端的回调函数
while (listenMsgFlag) {
// 中断式兼顾及时性和CPU使用率
WaitForSingleObject(g_hEvent, INFINITE); // 等待消息
while (!g_MsgQueue.empty()) {
client_ReceiveMsg(g_MsgQueue.front()); // 调用接收消息回调
g_MsgQueue.pop();
unique_ptr<Server> &server = GetServer();
LOG_DEBUG("server: {}", fmt::ptr(server));
server->Shutdown();
LOG_INFO("Server stoped.");
}
ResetEvent(g_hEvent);
}
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("server_EnableReceiveMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
}
void server_DisableReceiveMsg()
{
UnListenMessage();
listenMsgFlag = false;
}
int server_SendTextMsg(const wchar_t *wxid, const wchar_t *msg, const wchar_t *atWxids)
{
SendTextMessage(wxid, msg, atWxids);
return 0;
}
int server_SendImageMsg(const wchar_t *wxid, const wchar_t *path)
{
SendImageMessage(wxid, path);
return 0;
}
int server_GetMsgTypes(int *pNum, PPRpcIntBstrPair *msgTypes)
{
*pNum = g_WxMsgTypes.size();
PPRpcIntBstrPair pp = (PPRpcIntBstrPair)midl_user_allocate(*pNum * sizeof(PRpcIntBstrPair));
if (pp == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for pp\n");
return -2;
}
int index = 0;
for (auto it = g_WxMsgTypes.begin(); it != g_WxMsgTypes.end(); it++) {
PRpcIntBstrPair p = (PRpcIntBstrPair)midl_user_allocate(sizeof(RpcIntBstrPair_t));
if (p == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for p\n");
return -3;
}
p->key = it->first;
p->value = SysAllocString(it->second.c_str());
pp[index++] = p;
}
*msgTypes = pp;
return 0;
}
int server_GetContacts(int *pNum, PPRpcContact *contacts)
{
vector<RpcContact_t> vContacts = GetContacts();
*pNum = vContacts.size();
PPRpcContact pp = (PPRpcContact)midl_user_allocate(*pNum * sizeof(PRpcContact));
if (pp == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for pp\n");
return -2;
}
int index = 0;
for (auto it = vContacts.begin(); it != vContacts.end(); it++) {
PRpcContact p = (PRpcContact)midl_user_allocate(sizeof(RpcContact_t));
if (p == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for p\n");
return -3;
}
p->wxId = it->wxId;
p->wxCode = it->wxCode;
p->wxName = it->wxName;
p->wxCountry = it->wxCountry;
p->wxProvince = it->wxProvince;
p->wxCity = it->wxCity;
p->wxGender = it->wxGender;
pp[index++] = p;
}
*contacts = pp;
return 0;
}
int server_GetDbNames(int *pNum, BSTR **dbs)
{
vector<wstring> vDbs = GetDbNames();
*pNum = vDbs.size();
BSTR *pp = (BSTR *)midl_user_allocate(*pNum * sizeof(BSTR));
if (pp == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for pp\n");
return -2;
}
int index = 0;
for (auto it = vDbs.begin(); it != vDbs.end(); it++) {
pp[index++] = GetBstrFromWstring(*it);
}
*dbs = pp;
return 0;
}
int server_GetDbTables(const wchar_t *db, int *pNum, PPRpcTables *tbls)
{
vector<RpcTables_t> tables = GetDbTables(db);
*pNum = tables.size();
PPRpcTables pp = (PPRpcTables)midl_user_allocate(*pNum * sizeof(PRpcTables));
if (pp == NULL) {
printf("server_GetMsgTypes midl_user_allocate Failed for pp\n");
return -2;
}
int index = 0;
for (auto it = tables.begin(); it != tables.end(); it++) {
PRpcTables p = (PRpcTables)midl_user_allocate(sizeof(RpcTables_t));
if (p == NULL) {
printf("server_GetDbTables midl_user_allocate Failed for p\n");
return -3;
}
p->table = it->table;
p->sql = it->sql;
pp[index++] = p;
}
*tbls = pp;
return 0;
}
int server_ExecDbQuery(const wchar_t *db, const wchar_t *sql, int *pRow, int *pCol, PPPRpcSqlResult *ret)
{
vector<vector<RpcSqlResult_t>> vvSqlResult = ExecDbQuery(db, sql);
if (vvSqlResult.empty()) {
*pRow = *pCol = 0;
ret = NULL;
return -1;
}
*pRow = vvSqlResult.size();
*pCol = vvSqlResult[0].size();
PPPRpcSqlResult ppp = (PPPRpcSqlResult)midl_user_allocate(*pRow * sizeof(PPRpcSqlResult));
if (ppp == NULL) {
printf("server_ExecDbQuery midl_user_allocate Failed for ppp\n");
return -2;
}
for (int r = 0; r < *pRow; r++) {
PPRpcSqlResult pp = (PPRpcSqlResult)midl_user_allocate(*pCol * sizeof(PRpcSqlResult));
if (pp == NULL) {
midl_user_free(ppp);
printf("server_ExecDbQuery midl_user_allocate Failed for pp\n");
return -2;
}
for (int c = 0; c < *pCol; c++) {
PRpcSqlResult p = (PRpcSqlResult)midl_user_allocate(sizeof(RpcSqlResult_t));
if (p == NULL) {
midl_user_free(pp);
printf("server_ExecDbQuery midl_user_allocate Failed for p\n");
return -2;
}
p->type = vvSqlResult[r][c].type;
p->column = vvSqlResult[r][c].column;
p->content = vvSqlResult[r][c].content;
pp[c] = p;
}
ppp[r] = pp;
}
*ret = ppp;
return 0;
}
BOOL server_AcceptNewFriend(const wchar_t *v3, const wchar_t *v4) { return AcceptNewFriend(v3, v4); }

View File

@ -1,4 +1,10 @@
#pragma once
#ifdef SPY_EXPORTS
#define SPY_API __declspec(dllexport)
#else
#define SPY_API __declspec(dllimport)
#endif
int RpcStartServer();
int RpcStopServer();

View File

@ -4,10 +4,10 @@
#include <vector>
#include "spy_types.h"
#include "send_msg.h"
extern HANDLE g_hEvent;
extern WxCalls_t g_WxCalls;
extern RpcMessage_t *g_pMsg;
extern DWORD g_WeChatWinDllAddr;
using namespace std;

View File

@ -1,46 +1,41 @@
#include "load_calls.h"
#include "spy.h"
#include "load_calls.h"
#include "log.h"
#include "rpc_server.h"
#include "spy.h"
#include "util.h"
HANDLE g_hEvent = NULL;
BOOL g_rpcKeepAlive = false;
WxCalls_t g_WxCalls = { 0 };
DWORD g_WeChatWinDllAddr = 0;
void InitSpy()
{
wchar_t version[16] = { 0 };
InitLogger();
g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll"); //获取wechatWin模块地址
if (g_WeChatWinDllAddr == 0) {
MessageBox(NULL, L"获取wechatWin.dll模块地址失败", L"错误", 0);
LOG_ERROR("获取wechatWin.dll模块地址失败");
return;
}
if (!GetWeChatVersion(version)) { //获取微信版本
MessageBox(NULL, L"获取微信版本失败", L"错误", 0);
LOG_ERROR("获取微信版本失败");
return;
}
if (LoadCalls(version, &g_WxCalls) != 0) { //加载微信版本对应的Call地址
MessageBox(NULL, L"不支持当前版本", L"错误", 0);
LOG_ERROR("不支持当前版本");
return;
}
g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RpcStartServer, NULL, NULL, 0);
if (rpcThread != 0) {
CloseHandle(rpcThread);
}
RpcStartServer();
}
void DestroySpy(HMODULE hModule)
void CleanupSpy()
{
RpcStopServer();
FreeLibraryAndExitThread(hModule, 0);
// FreeLibraryAndExitThread(hModule, 0);
}
int IsLogin(void) { return (int)GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.login); }
wstring GetSelfWxid() { return String2Wstring(GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.wxid)); }
std::string GetSelfWxid() { return GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.wxid); }

4
Spy/spy.def Normal file
View File

@ -0,0 +1,4 @@
EXPORTS
InitSpy
CleanupSpy
IsLogin

View File

@ -3,4 +3,5 @@
#include "framework.h"
void InitSpy();
void DestroySpy(HMODULE hModule);
void CleanupSpy();
int IsLogin(void);

View File

@ -1,9 +1,7 @@
#pragma once
#include "framework.h"
#include <queue>
#include "rpc_h.h"
#include "../proto/wcf.grpc.pb.h"
typedef struct UserInfoCall {
DWORD wxid;
@ -74,5 +72,3 @@ typedef struct TextStruct {
DWORD capacity;
char fill[8];
} TextStruct_t;
typedef std::queue<RpcMessage_t> MsgQueue_t;

View File

@ -14,10 +14,26 @@
using namespace std;
static wstring_convert<codecvt_utf8<wchar_t>, wchar_t> S_WS_Converter;
//static wstring_convert<codecvt_utf8<wchar_t>, wchar_t> S_WS_Converter;
wstring String2Wstring(string s) { return S_WS_Converter.from_bytes(s); }
string Wstring2String(wstring ws) { return S_WS_Converter.to_bytes(ws); }
wstring String2Wstring(string s)
{
if (s.empty())
return wstring();
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), NULL, 0);
wstring ws(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), &ws[0], size_needed);
return ws;
}
string Wstring2String(wstring ws)
{
if (ws.empty())
return string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &ws[0], (int)ws.size(), NULL, 0, NULL, NULL);
string s(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &ws[0], (int)ws.size(), &s[0], size_needed, NULL, NULL);
return s;
}
static int GetWeChatPath(wchar_t *path)
{
@ -191,6 +207,12 @@ int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
return strLength;
}
string GetStringByAddress(DWORD address)
{
DWORD strLength = GET_DWORD(address + 4);
return Wstring2String(wstring(GET_WSTRING(address), strLength));
}
#if 0
BSTR GetBstrByAddress(DWORD address)
{
wchar_t *p = GET_WSTRING(address);
@ -277,6 +299,7 @@ void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg)
wxMsg->roomId = GetWstringFromBstr(rpcMsg.roomId);
wxMsg->content = GetWstringFromBstr(rpcMsg.content);
}
#endif
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
{

View File

@ -2,13 +2,10 @@
#include <string>
#include "rpc_h.h"
#include "sdk.h"
#define WECHAREXE L"WeChat.exe"
#define WECHATWINDLL L"WeChatWin.dll"
#define WECHATSDKDLL L"SDK.dll"
#define WECHATINJECTDLL L"Spy.dll"
#define WECHATSDKDLL L"sdk.dll"
#define WECHATINJECTDLL L"spy.dll"
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr)))
@ -17,15 +14,16 @@
int OpenWeChat(DWORD *pid);
int GetWeChatVersion(wchar_t *version);
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg);
//void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg);
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
BSTR GetBstrByAddress(DWORD address);
BSTR GetBstrFromString(const char *str);
BSTR GetBstrFromWstring(std::wstring ws);
BSTR GetBstrFromByteArray(const byte *b, int len);
BSTR GetBstrFromStringBuffer(const char *str, int length);
std::string GetBytesFromBstr(BSTR bstr);
std::wstring GetWstringFromBstr(BSTR bstr);
//BSTR GetBstrByAddress(DWORD address);
//BSTR GetBstrFromString(const char *str);
//BSTR GetBstrFromWstring(std::wstring ws);
//BSTR GetBstrFromByteArray(const byte *b, int len);
//BSTR GetBstrFromStringBuffer(const char *str, int length);
//std::string GetBytesFromBstr(BSTR bstr);
//std::wstring GetWstringFromBstr(BSTR bstr);
std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);
std::wstring String2Wstring(std::string s);
std::string Wstring2String(std::wstring ws);
std::string GetStringByAddress(DWORD address);

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -1,72 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30503.244
VisualStudioVersion = 16.0.32802.440
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Spy", "Spy\Spy.vcxproj", "{4A0A22F7-0B1C-4565-A443-C43FAC6C6396}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spy", "spy\spy.vcxproj", "{4DE80B82-5F6A-4C4C-9D16-1574308110FA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDK", "SDK\SDK.vcxproj", "{707F2DCD-1001-42A7-B20E-B85B1BBAB228}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpp", "cpp\cpp.vcxproj", "{2FC45612-A106-42D1-871F-1DE704095B2C}"
ProjectSection(ProjectDependencies) = postProject
{4A0A22F7-0B1C-4565-A443-C43FAC6C6396} = {4A0A22F7-0B1C-4565-A443-C43FAC6C6396}
{ABFCB647-137F-478B-A73E-F0B1E3ADC215} = {ABFCB647-137F-478B-A73E-F0B1E3ADC215}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "App", "App\App.vcxproj", "{44C1A579-22A7-4BA3-A618-45BD01600294}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk\sdk.vcxproj", "{ABFCB647-137F-478B-A73E-F0B1E3ADC215}"
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}
{4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA}
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
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.ActiveCfg = Release|Win32
{4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.Build.0 = Release|Win32
{2FC45612-A106-42D1-871F-1DE704095B2C}.Release|x86.ActiveCfg = Release|Win32
{2FC45612-A106-42D1-871F-1DE704095B2C}.Release|x86.Build.0 = Release|Win32
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.ActiveCfg = Release|Win32
{ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {569E7E61-8FD2-43B5-8F34-C61D6417F905}
SolutionGuid = {76A678AA-570C-4CB7-B58F-3B2C170ACAC0}
EndGlobalSection
EndGlobal

View File

@ -18,14 +18,11 @@
<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>
<ProjectGuid>{2fc45612-a106-42d1-871f-1de704095b2c}</ProjectGuid>
<RootNamespace>cpp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -85,19 +82,20 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgUseStatic>true</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<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'">
@ -108,27 +106,18 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)SDK;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)/spy;$(SolutionDir)/rpc;C:\Tools\vcpkg\installed\x86-windows-static\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</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>
<AdditionalDependencies>$(OutDir)sdk.lib;iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.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\
xcopy /y $(SolutionDir)App\test.jpg $(OutDir)wx\</Command>
</PostBuildEvent>
<PostBuildEvent>
<Message>Copy output</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -158,6 +147,19 @@ xcopy /y $(SolutionDir)App\test.jpg $(OutDir)wx\</Command>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\proto\wcf.grpc.pb.h" />
<ClInclude Include="..\proto\wcf.pb.h" />
<ClInclude Include="..\sdk\sdk.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\proto\wcf.grpc.pb.cc" />
<ClCompile Include="..\proto\wcf.pb.cc" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\proto\wcf.proto" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -13,24 +13,35 @@
<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="proto">
<UniqueIdentifier>{0b2f5211-3264-4e9b-8f6d-9f2b51780156}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>头文件</Filter>
<ClInclude Include="..\proto\wcf.grpc.pb.h">
<Filter>proto</Filter>
</ClInclude>
<ClInclude Include="..\SDK\sdk.h">
<Filter>头文件</Filter>
<ClInclude Include="..\proto\wcf.pb.h">
<Filter>proto</Filter>
</ClInclude>
<ClInclude Include="..\SDK\util.h">
<ClInclude Include="..\sdk\sdk.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="sdkpy.cpp">
<ClCompile Include="main.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\SDK\util.cpp">
<Filter>源文件</Filter>
<ClCompile Include="..\proto\wcf.grpc.pb.cc">
<Filter>proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\wcf.pb.cc">
<Filter>proto</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\proto\wcf.proto">
<Filter>proto</Filter>
</None>
</ItemGroup>
</Project>

521
cpp/main.cpp Normal file
View File

@ -0,0 +1,521 @@
/*
RPC Client
*/
#pragma warning(disable : 4251)
#pragma execution_character_set("utf-8")
#include <memory>
#include <signal.h>
#include <thread>
#include <grpcpp/grpcpp.h>
#include "../proto/wcf.grpc.pb.h"
#include "../sdk/sdk.h"
using namespace std;
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using wcf::Contact;
using wcf::Contacts;
using wcf::DbField;
using wcf::DbNames;
using wcf::DbQuery;
using wcf::DbRow;
using wcf::DbRows;
using wcf::DbTable;
using wcf::DbTables;
using wcf::Empty;
using wcf::ImageMsg;
using wcf::MsgTypes;
using wcf::Response;
using wcf::String;
using wcf::TextMsg;
using wcf::Verification;
using wcf::Wcf;
using wcf::WxMsg;
class WcfClient
{
public:
static WcfClient &Instance(string host_port)
{
static WcfClient instance(grpc::CreateChannel(host_port, grpc::InsecureChannelCredentials()));
return instance;
}
~WcfClient()
{
cout << "~WcfClient()" << endl;
this->DisableRecvMsg();
// WxDestroySDK();
}
int IsLogin()
{
Empty empty;
Response rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcIsLogin(&context, &empty, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "IsLogin rpc failed." << endl;
}
return rsp.status();
}
string GetSelfWxid()
{
Empty empty;
String rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcGetSelfWxid(&context, &empty, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "GetSelfWxid rpc failed." << endl;
}
return rsp.str();
}
void EnableRecvMsg(function<void(WxMsg &)> msg_handle_cb)
{
class Reader : public grpc::ClientReadReactor<WxMsg>
{
public:
Reader(Wcf::Stub *stub, function<void(WxMsg &)> msg_handle_cb)
: msg_handle_cb_(msg_handle_cb)
{
stub->async()->RpcEnableRecvMsg(&context_, &empty_, this);
StartRead(&msg_);
StartCall();
}
void OnReadDone(bool ok) override
{
if (ok) {
try {
msg_handle_cb_(msg_);
} catch (...) {
cout << "OnMsg wrong..." << endl;
}
StartRead(&msg_);
}
}
void OnDone(const Status &s) override
{
unique_lock<mutex> l(mu_);
status_ = s;
done_ = true;
cv_.notify_one();
}
Status Await()
{
unique_lock<mutex> l(mu_);
cv_.wait(l, [this] { return done_; });
return move(status_);
}
private:
Empty empty_;
WxMsg msg_;
ClientContext context_;
mutex mu_;
Status status_;
bool done_ = false;
condition_variable cv_;
function<void(WxMsg &)> msg_handle_cb_;
};
Reader reader(stub_.get(), msg_handle_cb);
Status status = reader.Await();
if (!status.ok()) {
cout << "GetMessage rpc failed." << endl;
}
}
// void EnableRecvMsg(function<void(WxMsg &)> msg_handle_cb) { GetMessage(msg_handle_cb); }
int DisableRecvMsg()
{
Empty empty;
Response rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcDisableRecvMsg(&context, &empty, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "DisableRecvMsg rpc failed." << endl;
}
return rsp.status();
}
int SendTextMsg(string msg, string receiver, string atusers)
{
Response rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
TextMsg t_msg;
t_msg.set_msg(msg);
t_msg.set_receiver(receiver);
t_msg.set_aters(atusers);
stub_->async()->RpcSendTextMsg(&context, &t_msg, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "SendTextMsg rpc failed." << endl;
rsp.set_status(-999); // TODO: Unify error code
}
return rsp.status();
}
int SendImageMsg(string path, string receiver)
{
Response rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
ImageMsg i_msg;
i_msg.set_path(path);
i_msg.set_receiver(receiver);
stub_->async()->RpcSendImageMsg(&context, &i_msg, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "SendImageMsg rpc failed." << endl;
rsp.set_status(-999); // TODO: Unify error code
}
return rsp.status();
}
MsgTypes GetMsgTypes(void)
{
Empty empty;
MsgTypes mt;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcGetMsgTypes(&context, &empty, &mt, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "GetMsgTypes rpc failed." << endl;
}
return mt;
}
Contacts GetContacts(void)
{
Empty empty;
Contacts contacts;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcGetContacts(&context, &empty, &contacts, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "GetContacts rpc failed." << endl;
}
return contacts;
}
DbNames GetDbNames(void)
{
Empty empty;
DbNames names;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
stub_->async()->RpcGetDbNames(&context, &empty, &names, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "GetDbNames rpc failed." << endl;
}
return names;
}
DbTables GetDbTables(string db)
{
DbTables tables;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
String s_db;
s_db.set_str(db);
stub_->async()->RpcGetDbTables(&context, &s_db, &tables, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "GetDbTables rpc failed." << endl;
}
return tables;
}
DbRows ExecDbQuery(string db, string sql)
{
DbRows rows;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
DbQuery query;
query.set_db(db);
query.set_sql(sql);
stub_->async()->RpcExecDbQuery(&context, &query, &rows, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "ExecDbQuery rpc failed." << endl;
}
return rows;
}
int AcceptNewFriend(string v3, string v4)
{
Response rsp;
ClientContext context;
std::mutex mu;
std::condition_variable cv;
bool done = false;
Status status;
Verification v;
v.set_v3(v3);
v.set_v4(v4);
stub_->async()->RpcAcceptNewFriend(&context, &v, &rsp, [&mu, &cv, &done, &status](Status s) {
status = std::move(s);
std::lock_guard<std::mutex> lock(mu);
done = true;
cv.notify_one();
});
std::unique_lock<std::mutex> lock(mu);
cv.wait(lock, [&done] { return done; });
if (!status.ok()) {
cout << "ExecDbQuery rpc failed." << endl;
rsp.set_status(-999); // TODO: Unify error code
}
return rsp.status();
}
private:
unique_ptr<Wcf::Stub> stub_;
WcfClient(shared_ptr<Channel> channel)
: stub_(Wcf::NewStub(channel))
{
WxInitSDK();
}
};
int OnMsg(WxMsg msg)
{
cout << "Got Message: \n"
<< msg.is_self() << ", " << msg.is_group() << ", " << msg.type() << ", " << msg.id() << ", " << msg.xml()
<< ", " << msg.sender() << ", " << msg.roomid() << ", " << msg.content() << endl;
return 0;
}
// volatile bool gKeepRunning = false;
// void handler(int s)
// {
// printf("Caught signal %d\n", s);
// // exit(1);
// gKeepRunning = false;
// }
int main(int argc, char **argv)
{
int ret;
// signal(SIGINT, handler);
WcfClient &client = WcfClient::Instance("localhost:10086");
ret = client.IsLogin();
cout << "IsLogin: " << ret << endl;
cout << "Self Wxid: " << client.GetSelfWxid() << endl;
ret = client.SendTextMsg("来自CPP的消息", "filehelper", "");
cout << "SendTextMsg: " << ret << endl;
ret = client.SendImageMsg("TEQuant.jpeg", "filehelper");
cout << "SendImageMsg: " << ret << endl;
MsgTypes mts = client.GetMsgTypes();
cout << "GetMsgTypes: " << mts.types_size() << endl;
map<int32_t, string> m(mts.types().begin(), mts.types().end());
for (auto &[k, v] : m) {
cout << k << ": " << v << endl;
}
Contacts cnts = client.GetContacts();
cout << "GetContacts: " << cnts.contacts().size() << endl;
vector<Contact> vcnts(cnts.contacts().begin(), cnts.contacts().end());
for (auto &c : vcnts) {
cout << c.wxid() << "\t" << c.code() << "\t" << c.name() << "\t" << c.country() << "\t" << c.province() << "\t"
<< c.city() << "\t" << c.gender() << endl;
}
DbNames db = client.GetDbNames();
cout << "GetDbNames: " << db.names().size() << endl;
vector<string> dbs(db.names().begin(), db.names().end());
for (auto &name : dbs) {
cout << name << endl;
}
DbTables tbls = client.GetDbTables("db");
cout << "GetDbTables: " << tbls.tables().size() << endl;
vector<DbTable> vtbls(tbls.tables().begin(), tbls.tables().end());
for (auto &tbl : vtbls) {
cout << tbl.name() << "\n" << tbl.sql() << endl;
}
DbRows r = client.ExecDbQuery("MicroMsg.db", "SELECT * FROM Contact LIMIT 1;");
cout << "ExecDbQuery: " << r.rows().size() << endl;
vector<DbRow> vrows(r.rows().begin(), r.rows().end());
for (auto &row : vrows) {
vector<DbField> vfields(row.fields().begin(), row.fields().end());
for (auto &field : vfields)
cout << field.column() << "[" << field.type() << "]: " << field.content() << endl;
}
// 需要正确的 v3、v4 才能调用
// ret = client.AcceptNewFriend("v3", "v4");
// cout << "AcceptNewFriend: " << ret << endl;
function<void(WxMsg &)> cb = OnMsg;
thread t1 = thread([&]() { client.EnableRecvMsg(cb); });
// client.EnableRecvMsg(cb);
cout << "Block?..." << endl;
// gKeepRunning = true;
while (true) {
// cout << gKeepRunning << endl;
Sleep(1000);
}
Sleep(1000);
cout << "Exit..." << endl;
}

87
proto/wcf.proto Normal file
View File

@ -0,0 +1,87 @@
syntax = "proto3";
package wcf;
service Wcf {
rpc RpcIsLogin(Empty) returns (Response) {}
rpc RpcGetSelfWxid(Empty) returns (String) {}
rpc RpcEnableRecvMsg(Empty) returns (stream WxMsg) {}
rpc RpcDisableRecvMsg(Empty) returns (Response) {}
rpc RpcSendTextMsg(TextMsg) returns (Response) {}
rpc RpcSendImageMsg(ImageMsg) returns (Response) {}
rpc RpcGetMsgTypes(Empty) returns (MsgTypes) {}
rpc RpcGetContacts(Empty) returns (Contacts) {}
rpc RpcGetDbNames(Empty) returns (DbNames) {}
rpc RpcGetDbTables(String) returns (DbTables) {}
rpc RpcExecDbQuery(DbQuery) returns (DbRows) {}
rpc RpcAcceptNewFriend(Verification) returns (Response) {}
}
message Empty {}
message WxMsg {
bool is_self = 1; //
bool is_group = 2; //
int32 type = 3; //
string id = 4; // id
string xml = 5; // xml
string sender = 6; //
string roomid = 7; // id
string content = 8; //
}
message Response {
int32 status = 1; //
}
message TextMsg {
string msg = 1; //
string receiver = 2; // @
string aters = 3; // @
}
message ImageMsg {
string path = 1; //
string receiver = 2; //
}
message MsgTypes { map<int32, string> types = 1; }
message Contact {
string wxid = 1; // id
string code = 2; //
string name = 3; //
string country = 4; //
string province = 5; // /
string city = 6; //
string gender = 7; //
}
message Contacts { repeated Contact contacts = 1; }
message DbNames { repeated string names = 1; }
message String { string str = 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;
}