Bump gRPC
This commit is contained in:
+45
-29
@@ -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">
|
||||
|
||||
+47
-35
@@ -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>
|
||||
+6
-11
@@ -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;
|
||||
}
|
||||
|
||||
+37
-46
@@ -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,77 +106,69 @@ 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_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);
|
||||
Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + 0x13EB630);
|
||||
Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + 0x13EB470);
|
||||
Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + 0x13EAD10);
|
||||
Sqlite3_column_name func_column_name = (Sqlite3_column_name)(g_WeChatWinDllAddr + 0x13EB630);
|
||||
Sqlite3_column_type func_column_type = (Sqlite3_column_type)(g_WeChatWinDllAddr + 0x13EB470);
|
||||
Sqlite3_column_blob func_column_blob = (Sqlite3_column_blob)(g_WeChatWinDllAddr + 0x13EAD10);
|
||||
Sqlite3_column_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + 0x13EADD0);
|
||||
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730);
|
||||
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730);
|
||||
|
||||
if (dbMap.empty()) {
|
||||
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));
|
||||
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);
|
||||
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 && (field->type() != 5)) {
|
||||
field->set_content(string((char *)blob, length));
|
||||
}
|
||||
|
||||
vResult.push_back(result);
|
||||
}
|
||||
vvSqlResult.push_back(vResult);
|
||||
}
|
||||
|
||||
return vvSqlResult;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
|
||||
// Windows 头文件
|
||||
#include <windows.h>
|
||||
|
||||
+13
-14
@@ -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;
|
||||
}
|
||||
|
||||
+2
-4
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
+69
-48
@@ -1,48 +1,63 @@
|
||||
#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 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])
|
||||
{
|
||||
//组装跳转数据
|
||||
BYTE jmpCode[5] = { 0 };
|
||||
jmpCode[0] = 0xE9;
|
||||
jmpCode[0] = 0xE9;
|
||||
|
||||
//计算偏移
|
||||
*(DWORD *)&jmpCode[1] = (DWORD)funcAddr - hookAddr - 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,23 +121,23 @@ __declspec(naked) void RecieveMsgFunc()
|
||||
void ListenMessage()
|
||||
{
|
||||
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
|
||||
if (isListened || (g_WeChatWinDllAddr == 0)) {
|
||||
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
|
||||
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
|
||||
recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
|
||||
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
|
||||
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;
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,4 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../proto/wcf.grpc.pb.h"
|
||||
|
||||
void ListenMessage();
|
||||
void UnListenMessage();
|
||||
void GetMsgTypes(wcf::MsgTypes* types);
|
||||
|
||||
+253
-254
@@ -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;
|
||||
|
||||
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();
|
||||
}
|
||||
ResetEvent(g_hEvent);
|
||||
}
|
||||
if (lIsRunning) {
|
||||
UnListenMessage();
|
||||
unique_ptr<Server> &server = GetServer();
|
||||
LOG_DEBUG("server: {}", fmt::ptr(server));
|
||||
server->Shutdown();
|
||||
LOG_INFO("Server stoped.");
|
||||
}
|
||||
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); }
|
||||
|
||||
@@ -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();
|
||||
|
||||
+2
-2
@@ -3,11 +3,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "spy_types.h"
|
||||
#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;
|
||||
|
||||
+12
-17
@@ -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 };
|
||||
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); }
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
EXPORTS
|
||||
InitSpy
|
||||
CleanupSpy
|
||||
IsLogin
|
||||
@@ -3,4 +3,5 @@
|
||||
#include "framework.h"
|
||||
|
||||
void InitSpy();
|
||||
void DestroySpy(HMODULE hModule);
|
||||
void CleanupSpy();
|
||||
int IsLogin(void);
|
||||
|
||||
+1
-5
@@ -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;
|
||||
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
#include "Shlwapi.h"
|
||||
#include "framework.h"
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <string.h>
|
||||
#include <strsafe.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#pragma comment(lib, "shlwapi")
|
||||
#pragma comment(lib, "Version.lib")
|
||||
|
||||
using namespace std;
|
||||
|
||||
//static wstring_convert<codecvt_utf8<wchar_t>, wchar_t> S_WS_Converter;
|
||||
|
||||
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)
|
||||
{
|
||||
int ret = -1;
|
||||
HKEY hKey = NULL;
|
||||
// HKEY_CURRENT_USER\Software\Tencent\WeChat InstallPath = xx
|
||||
if (ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, L"Software\\Tencent\\WeChat", &hKey)) {
|
||||
ret = GetLastError();
|
||||
return ret;
|
||||
}
|
||||
|
||||
DWORD Type = REG_SZ;
|
||||
DWORD cbData = MAX_PATH * sizeof(WCHAR);
|
||||
if (ERROR_SUCCESS != RegQueryValueEx(hKey, L"InstallPath", 0, &Type, (LPBYTE)path, &cbData)) {
|
||||
ret = GetLastError();
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
if (path != NULL) {
|
||||
PathAppend(path, WECHAREXE);
|
||||
}
|
||||
|
||||
__exit:
|
||||
if (hKey) {
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static int GetWeChatWinDLLPath(wchar_t *path)
|
||||
{
|
||||
int ret = GetWeChatPath(path);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
PathRemoveFileSpecW(path);
|
||||
PathAppendW(path, WECHATWINDLL);
|
||||
if (!PathFileExists(path)) {
|
||||
// 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29]
|
||||
PathRemoveFileSpec(path);
|
||||
_wfinddata_t findData;
|
||||
wstring dir = wstring(path) + L"\\[*.*";
|
||||
intptr_t handle = _wfindfirst(dir.c_str(), &findData);
|
||||
if (handle == -1) { // 检查是否成功
|
||||
return -1;
|
||||
}
|
||||
wstring dllPath = wstring(path) + L"\\" + findData.name;
|
||||
wcscpy_s(path, MAX_PATH, dllPath.c_str());
|
||||
PathAppend(path, WECHATWINDLL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool GetFileVersion(const wchar_t *filePath, wchar_t *version)
|
||||
{
|
||||
if (wcslen(filePath) > 0 && PathFileExists(filePath)) {
|
||||
VS_FIXEDFILEINFO *pVerInfo = NULL;
|
||||
DWORD dwTemp, dwSize;
|
||||
BYTE *pData = NULL;
|
||||
UINT uLen;
|
||||
|
||||
dwSize = GetFileVersionInfoSize(filePath, &dwTemp);
|
||||
if (dwSize == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pData = new BYTE[dwSize + 1];
|
||||
if (pData == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetFileVersionInfo(filePath, 0, dwSize, pData)) {
|
||||
delete[] pData;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!VerQueryValue(pData, TEXT("\\"), (void **)&pVerInfo, &uLen)) {
|
||||
delete[] pData;
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD verMS = pVerInfo->dwFileVersionMS;
|
||||
DWORD verLS = pVerInfo->dwFileVersionLS;
|
||||
DWORD major = HIWORD(verMS);
|
||||
DWORD minor = LOWORD(verMS);
|
||||
DWORD build = HIWORD(verLS);
|
||||
DWORD revision = LOWORD(verLS);
|
||||
delete[] pData;
|
||||
|
||||
StringCbPrintf(version, 0x20, TEXT("%d.%d.%d.%d"), major, minor, build, revision);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetWeChatVersion(wchar_t *version)
|
||||
{
|
||||
WCHAR Path[MAX_PATH] = { 0 };
|
||||
|
||||
int ret = GetWeChatWinDLLPath(Path);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = GetFileVersion(Path, version);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD GetWeChatPid()
|
||||
{
|
||||
DWORD pid = 0;
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
|
||||
while (Process32Next(hSnapshot, &pe32)) {
|
||||
wstring strProcess = pe32.szExeFile;
|
||||
if (strProcess == WECHAREXE) {
|
||||
pid = pe32.th32ProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int OpenWeChat(DWORD *pid)
|
||||
{
|
||||
*pid = GetWeChatPid();
|
||||
if (*pid) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
STARTUPINFO si = { sizeof(si) };
|
||||
WCHAR Path[MAX_PATH] = { 0 };
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
|
||||
ret = GetWeChatPath(Path);
|
||||
if (ERROR_SUCCESS != ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
|
||||
*pid = pi.dwProcessId;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
|
||||
{
|
||||
DWORD strLength = GET_DWORD(address + 4);
|
||||
if (strLength == 0) {
|
||||
return 0;
|
||||
} else if (strLength > buffer_size) {
|
||||
strLength = buffer_size - 1;
|
||||
}
|
||||
|
||||
wmemcpy_s(buffer, strLength + 1, GET_WSTRING(address), strLength + 1);
|
||||
|
||||
return strLength;
|
||||
}
|
||||
|
||||
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);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SysAllocStringLen(GET_WSTRING(address), GET_DWORD(address + 4));
|
||||
}
|
||||
|
||||
wstring GetWstringFromBstr(BSTR p)
|
||||
{
|
||||
wstring ws = L"";
|
||||
if (p != NULL) {
|
||||
ws = wstring(p);
|
||||
SysFreeString(p);
|
||||
}
|
||||
return ws;
|
||||
}
|
||||
|
||||
BSTR GetBstrFromString(const char *str)
|
||||
{
|
||||
int wslen = MultiByteToWideChar(CP_ACP, 0, str, strlen(str), 0, 0);
|
||||
BSTR bstr = SysAllocStringLen(0, wslen);
|
||||
MultiByteToWideChar(CP_ACP, 0, str, strlen(str), bstr, wslen);
|
||||
|
||||
return bstr;
|
||||
}
|
||||
|
||||
BSTR GetBstrFromWstring(wstring ws)
|
||||
{
|
||||
if (!ws.empty()) {
|
||||
return SysAllocStringLen(ws.data(), ws.size());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BSTR GetBstrFromStringBuffer(const char *str, int length)
|
||||
{
|
||||
int wslen = MultiByteToWideChar(CP_ACP, 0, str, length, 0, 0);
|
||||
BSTR bstr = SysAllocStringLen(0, wslen);
|
||||
MultiByteToWideChar(CP_ACP, 0, str, length, bstr, wslen);
|
||||
|
||||
return bstr;
|
||||
}
|
||||
|
||||
BSTR GetBstrFromByteArray(const byte *b, int len)
|
||||
{
|
||||
BSTR bstr = SysAllocStringLen(0, len);
|
||||
if (bstr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy((byte *)bstr, b, len);
|
||||
|
||||
return bstr;
|
||||
}
|
||||
|
||||
string GetBytesFromBstr(BSTR bstr)
|
||||
{
|
||||
string s = "";
|
||||
if (bstr) {
|
||||
int len = SysStringByteLen(bstr) / 2;
|
||||
char *tmp = new char[len];
|
||||
char *p = (char *)bstr;
|
||||
for (int i = 0; i < len; i++) {
|
||||
tmp[i] = p[i];
|
||||
}
|
||||
SysFreeString(bstr);
|
||||
s = string(tmp, len);
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg)
|
||||
{
|
||||
wxMsg->self = rpcMsg.self;
|
||||
wxMsg->type = rpcMsg.type;
|
||||
wxMsg->source = rpcMsg.source;
|
||||
wxMsg->id = GetWstringFromBstr(rpcMsg.id);
|
||||
wxMsg->xml = GetWstringFromBstr(rpcMsg.xml);
|
||||
wxMsg->wxId = GetWstringFromBstr(rpcMsg.wxId);
|
||||
wxMsg->roomId = GetWstringFromBstr(rpcMsg.roomId);
|
||||
wxMsg->content = GetWstringFromBstr(rpcMsg.content);
|
||||
}
|
||||
#endif
|
||||
|
||||
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
|
||||
{
|
||||
DWORD value = 0;
|
||||
|
||||
unsigned char data[4] = { 0 };
|
||||
if (ReadProcessMemory(hProcess, (LPVOID)address, data, 4, 0)) {
|
||||
value = data[0] & 0xFF;
|
||||
value |= ((data[1] << 8) & 0xFF00);
|
||||
value |= ((data[2] << 16) & 0xFF0000);
|
||||
value |= ((data[3] << 24) & 0xFF000000);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address)
|
||||
{
|
||||
wstring value = L"";
|
||||
|
||||
DWORD strAddress = GetMemoryIntByAddress(hProcess, address);
|
||||
DWORD strLen = GetMemoryIntByAddress(hProcess, address + 0x4);
|
||||
if (strLen > 500)
|
||||
return value;
|
||||
|
||||
wchar_t cValue[500] = { 0 };
|
||||
memset(cValue, 0, sizeof(cValue) / sizeof(wchar_t));
|
||||
if (ReadProcessMemory(hProcess, (LPVOID)strAddress, cValue, (strLen + 1) * 2, 0)) {
|
||||
value = wstring(cValue);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#define WECHAREXE L"WeChat.exe"
|
||||
#define WECHATWINDLL L"WeChatWin.dll"
|
||||
#define WECHATSDKDLL L"sdk.dll"
|
||||
#define WECHATINJECTDLL L"spy.dll"
|
||||
|
||||
#define GET_DWORD(addr) ((DWORD) * (DWORD *)(addr))
|
||||
#define GET_STRING(addr) ((CHAR *)(*(DWORD *)(addr)))
|
||||
#define GET_WSTRING(addr) ((WCHAR *)(*(DWORD *)(addr)))
|
||||
|
||||
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);
|
||||
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);
|
||||
std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);
|
||||
std::wstring String2Wstring(std::string s);
|
||||
std::string Wstring2String(std::wstring ws);
|
||||
std::string GetStringByAddress(DWORD address);
|
||||
Reference in New Issue
Block a user