Rename dirs

This commit is contained in:
Changhua
2022-10-15 20:46:22 +08:00
parent ef20038fcd
commit 760eeb00e2
37 changed files with 0 additions and 0 deletions
+222
View File
@@ -0,0 +1,222 @@
<?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>{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">
<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>
<PreBuildEventUseInBuild>false</PreBuildEventUseInBuild>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<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>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<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>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
<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>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>spy.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<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="..\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>
<None Include="..\proto\wcf.proto" />
<None Include="spy.def" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
+113
View File
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="proto">
<UniqueIdentifier>{5da8b2ee-3201-441c-b42f-a420e9aad78b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="rpc_server.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="log.h">
<Filter>头文件</Filter>
</ClInclude>
<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">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="send_msg.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="spy.h">
<Filter>头文件</Filter>
</ClInclude>
<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_server.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="log.cpp">
<Filter>源文件</Filter>
</ClCompile>
<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">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="send_msg.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="spy.cpp">
<Filter>源文件</Filter>
</ClCompile>
<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>
<None Include="spy.def">
<Filter>源文件</Filter>
</None>
<None Include="..\proto\wcf.proto">
<Filter>proto</Filter>
</None>
</ItemGroup>
</Project>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
+57
View File
@@ -0,0 +1,57 @@
#include "accept_new_friend.h"
#include "load_calls.h"
typedef struct NewFriendParam {
DWORD handle;
DWORD *status;
DWORD statusEnd1;
DWORD statusEnd2;
char buffer[0x3C];
} NewFriendParam_t;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
BOOL AcceptNewFriend(std::wstring v3, std::wstring v4)
{
BOOL isSucceeded = false;
DWORD acceptNewFriendCall1 = g_WeChatWinDllAddr + g_WxCalls.anf.call1;
DWORD acceptNewFriendCall2 = g_WeChatWinDllAddr + g_WxCalls.anf.call2;
DWORD acceptNewFriendHandle = g_WeChatWinDllAddr + g_WxCalls.anf.handle;
char buffer[0x94] = { 0 };
NewFriendParam_t param = { 0 };
DWORD status[9] = { 0xB2, (DWORD)&param, 0xB5, (DWORD)&param, 0xB0, (DWORD)&param, 0xB1, (DWORD)&param, 0x00 };
param.handle = acceptNewFriendHandle;
param.status = status;
param.statusEnd1 = (DWORD)&status[8];
param.statusEnd2 = (DWORD)&status[8];
NewFriendParam_t *pParam = &param;
__asm {
pushad;
pushfd;
push 0x0;
push 0x6;
sub esp, 0x14;
mov ecx, esp;
lea eax, v4;
push eax;
call acceptNewFriendCall1;
sub esp, 0x8;
push 0x0;
lea eax, buffer;
push eax;
lea eax, v3;
push eax;
mov ecx, pParam;
call acceptNewFriendCall2;
mov isSucceeded, eax;
popfd;
popad;
}
return isSucceeded;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "framework.h"
#include "string"
BOOL AcceptNewFriend(std::wstring v3, std::wstring v4);
+18
View File
@@ -0,0 +1,18 @@
// 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:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
+174
View File
@@ -0,0 +1,174 @@
#include <map>
#include <string>
#include "exec_sql.h"
#include "load_calls.h"
#include "util.h"
using namespace std;
#define SQLITE_OK 0 /* Successful result */
#define SQLITE_ERROR 1 /* Generic error */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
#define SQLITE_BUSY 5 /* The database file is locked */
#define SQLITE_LOCKED 6 /* A table in the database is locked */
#define SQLITE_NOMEM 7 /* A malloc() failed */
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
#define SQLITE_MISMATCH 20 /* Data type mismatch */
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_FORMAT 24 /* Not used */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
#define SQLITE_INTEGER 1
#define SQLITE_FLOAT 2
#define SQLITE_TEXT 3
#define SQLITE_BLOB 4
#define SQLITE_NULL 5
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
typedef map<string, DWORD> dbMap_t;
static dbMap_t dbMap;
// 回调函数指针
typedef int (*sqlite3_callback)(void *, int, char **, char **);
// sqlite3_exec函数指针
typedef int(__cdecl *Sqlite3_exec)(DWORD, /* The database on which the SQL executes */
const char *, /* The SQL to be executed */
sqlite3_callback, /* Invoke this callback routine */
void *, /* First argument to xCallback() */
char ** /* Write error messages here */
);
typedef int(__cdecl *Sqlite3_prepare)(DWORD, const char *, int, DWORD **, int);
typedef int(__cdecl *Sqlite3_step)(DWORD *);
typedef int(__cdecl *Sqlite3_column_count)(DWORD *);
typedef const char *(__cdecl *Sqlite3_column_name)(DWORD *, int);
typedef int(__cdecl *Sqlite3_column_type)(DWORD *, int);
typedef const void *(__cdecl *Sqlite3_column_blob)(DWORD *, int);
typedef int(__cdecl *Sqlite3_column_bytes)(DWORD *, int);
typedef int(__cdecl *Sqlite3_finalize)(DWORD *);
static int cbGetTables(void *ret, int argc, char **argv, char **azColName)
{
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->set_name(argv[i] ? argv[i] : "");
} else if (strcmp(azColName[i], "sql") == 0) {
tbl->set_sql(argv[i] ? argv[i] : "");
}
}
return 0;
}
dbMap_t GetDbHandles()
{
if (!dbMap.empty())
return dbMap;
g_WeChatWinDllAddr = (DWORD)GetModuleHandle(L"WeChatWin.dll");
DWORD sqlHandleBaseAddr = *(DWORD *)(g_WeChatWinDllAddr + g_WxCalls.sql.base);
DWORD sqlHandleBeginAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.start);
DWORD sqlHandleEndAddr = *(DWORD *)(sqlHandleBaseAddr + g_WxCalls.sql.end);
while (sqlHandleBeginAddr < sqlHandleEndAddr) {
DWORD dwHandle = *(DWORD *)sqlHandleBeginAddr;
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;
}
sqlHandleBeginAddr += 0x04;
}
return dbMap;
}
void GetDbNames(wcf::DbNames* names)
{
if (dbMap.empty()) {
dbMap = GetDbHandles();
}
for (auto& [k, v] : dbMap) {
auto* name = names->add_names();
name->assign(k);
}
}
void GetDbTables(const string db, wcf::DbTables* tables)
{
if (dbMap.empty()) {
dbMap = GetDbHandles();
}
auto it = dbMap.find(db);
if (it == dbMap.end()) {
return; // DB not found
}
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);
}
void ExecDbQuery(const string db, const string sql, wcf::DbRows* rows)
{
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_bytes func_column_bytes = (Sqlite3_column_bytes)(g_WeChatWinDllAddr + 0x13EADD0);
Sqlite3_finalize func_finalize = (Sqlite3_finalize)(g_WeChatWinDllAddr + 0x13E9730);
if (dbMap.empty()) {
dbMap = GetDbHandles();
}
DWORD* stmt;
int rc = func_prepare(dbMap[db], sql.c_str(), -1, &stmt, 0);
if (rc != SQLITE_OK) {
return;
}
while (func_step(stmt) == SQLITE_ROW) {
wcf::DbRow* row = rows->add_rows();
int col_count = func_column_count(stmt);
for (int i = 0; i < col_count; 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 && (field->type() != 5)) {
field->set_content(string((char *)blob, length));
}
}
}
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <string>
#include <vector>
#include "../proto/wcf.grpc.pb.h"
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);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
+38
View File
@@ -0,0 +1,38 @@
#include "get_contacts.h"
#include "load_calls.h"
#include "util.h"
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
bool GetContacts(wcf::Contacts* contacts)
{
int gender = 0;
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) {
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)
cnt->set_city("");
else if (gender == 2)
cnt->set_city("");
else
cnt->set_city("未知");
node = GET_DWORD(node);
}
return true;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "../proto/wcf.grpc.pb.h"
bool GetContacts(wcf::Contacts *contacts);
+33
View File
@@ -0,0 +1,33 @@
#include <iostream>
#include <map>
#include "load_calls.h"
#define SUPPORT_VERSION L"3.7.0.30"
WxCalls_t wxCalls = {
0x2366538, // Login Status
{ 0x236607C, 0x23660F4, 0x2366128 }, // User Info: wxid, nickname, mobile
0x521D30, // Send Message
/* Receive Message:
Hook, call, type, self, id, msgXml, roomId, wxId, content */
{ 0x550F4C, 0xA96350, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 },
{ 0xBD780, 0x771980, 0x521640 }, // Send Image Message
/* Get Contacts:
Base, head, wxId, Code, Name, Gender, Country, Province, City*/
{ 0x23668F4, 0x4C, 0x30, 0x44, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 },
/* Exec Sql:
Exec, base, start, end, slot, name*/
{ 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 },
{ 0x771980, 0x2AE8D0, 0x1EE40E0 } // Accept New Friend application
};
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
{
if (wcscmp(version, SUPPORT_VERSION) != 0) {
return -1;
}
memcpy_s(calls, sizeof(WxCalls_t), &wxCalls, sizeof(WxCalls_t));
return 0;
}
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "spy_types.h"
int LoadCalls(const wchar_t *version, WxCalls_t *calls);
+23
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
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();
+143
View File
@@ -0,0 +1,143 @@
#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"
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;
static DWORD reg_buffer = 0;
static DWORD recvMsgHookAddr = 0;
static DWORD recvMsgCallAddr = 0;
static DWORD recvMsgJumpBackAddr = 0;
static CHAR recvMsgBackupCode[5] = { 0 };
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;
//计算偏移
*(DWORD *)&jmpCode[1] = (DWORD)funcAddr - hookAddr - 5;
// 备份原来的代码
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, recvMsgBackupCode, 5, 0);
// 写入新的代码
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, jmpCode, 5, 0);
}
void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5])
{
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, restoreCode, 5, 0);
}
void DispatchMsg(DWORD reg)
{
WxMsg wxMsg;
DWORD *p = (DWORD *)reg; //消息结构基址
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 ((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 {
wxMsg.set_is_group(false);
wxMsg.set_sender(GetStringByAddress(*p + g_WxCalls.recvMsg.roomId));
}
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()
{
__asm {
mov reg_buffer, edi //把值复制出来
}
DispatchMsg(reg_buffer);
__asm
{
call recvMsgCallAddr // 这个为被覆盖的call
jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令
}
}
void ListenMessage()
{
// MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0);
if (gIsListening || (g_WeChatWinDllAddr == 0)) {
return;
}
recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
recvMsgJumpBackAddr = recvMsgHookAddr + 5;
HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode);
gIsListening = true;
}
void UnListenMessage()
{
if (!gIsListening) {
return;
}
UnHookAddress(recvMsgHookAddr, recvMsgBackupCode);
gIsListening = false;
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "../proto/wcf.grpc.pb.h"
void ListenMessage();
void UnListenMessage();
void GetMsgTypes(wcf::MsgTypes* types);
+284
View File
@@ -0,0 +1,284 @@
#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_server.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;
using grpc::CallbackServerContext;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerUnaryReactor;
using grpc::ServerWriteReactor;
using grpc::Status;
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;
mutex gMutex;
queue<WxMsg> gMsgQueue;
condition_variable gCv;
bool gIsListening;
class WcfImpl final : public Wcf::CallbackService
{
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()
{
HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)runServer, NULL, NULL, &lThreadId);
if (rpcThread != 0) {
CloseHandle(rpcThread);
}
return 0;
}
int RpcStopServer()
{
if (lIsRunning) {
UnListenMessage();
unique_ptr<Server> &server = GetServer();
LOG_DEBUG("server: {}", fmt::ptr(server));
server->Shutdown();
LOG_INFO("Server stoped.");
}
return 0;
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#ifdef SPY_EXPORTS
#define SPY_API __declspec(dllexport)
#else
#define SPY_API __declspec(dllimport)
#endif
int RpcStartServer();
int RpcStopServer();
+133
View File
@@ -0,0 +1,133 @@
#include "framework.h"
#include <sstream>
#include <string>
#include <vector>
#include "spy_types.h"
#include "send_msg.h"
extern HANDLE g_hEvent;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
using namespace std;
typedef struct AtList {
DWORD start;
DWORD end1;
DWORD end2;
} AtList_t;
void SendTextMessage(const wchar_t *wxid, const wchar_t *msg, const wchar_t *atWxids)
{
char buffer[0x3B0] = { 0 };
AtList_t atList = { 0 };
TextStruct_t txtMsg = { 0 };
TextStruct_t txtWxid = { 0 };
TextStruct_t *tsArray = NULL;
wstring wsMsg = msg;
wstring wsWxid = wxid;
// 发送消息Call地址 = 微信基址 + 偏移
DWORD sendCallAddress = g_WeChatWinDllAddr + g_WxCalls.sendTextMsg;
txtMsg.text = (wchar_t *)wsMsg.c_str();
txtMsg.size = wsMsg.size();
txtMsg.capacity = wsMsg.capacity();
txtWxid.text = (wchar_t *)wsWxid.c_str();
txtWxid.size = wsWxid.size();
txtWxid.capacity = wsWxid.capacity();
wstring tmp = atWxids;
if (!tmp.empty()) {
int i = 0;
wstring wstr;
vector<wstring> vAtWxids;
wstringstream wss(tmp);
while (wss.good()) {
getline(wss, wstr, L',');
vAtWxids.push_back(wstr);
}
tsArray = new TextStruct_t[vAtWxids.size() + 1];
// memset(tsArray, 0, (vAtWxids.size() + 1) * sizeof(TextStruct_t));
for (auto it = vAtWxids.begin(); it != vAtWxids.end(); it++) {
tsArray[i].text = (wchar_t *)it->c_str();
tsArray[i].size = it->size();
tsArray[i].capacity = it->capacity();
i++;
}
atList.start = (DWORD)tsArray;
atList.end1 = (DWORD)&tsArray[i];
atList.end2 = (DWORD)&tsArray[i];
}
__asm
{
lea eax, atList;
push 0x01;
push eax;
lea edi, txtMsg;
push edi;
lea edx, txtWxid;
lea ecx, buffer;
call sendCallAddress;
add esp, 0xC;
}
if (tsArray)
{
delete[] tsArray;
tsArray = NULL;
}
}
void SendImageMessage(const wchar_t *wxid, const wchar_t *path)
{
if (g_WeChatWinDllAddr == 0) {
return;
}
DWORD tmpEAX = 0;
char buf1[0x48] = { 0 };
char buf2[0x3B0] = { 0 };
TextStruct_t imgWxid = { 0 };
TextStruct_t imgPath = { 0 };
wstring wsWxid = wxid;
wstring wsPath = path;
imgWxid.text = (wchar_t *)wsWxid.c_str();
imgWxid.size = wsWxid.size();
imgWxid.capacity = wsWxid.capacity();
imgPath.text = (wchar_t *)wsPath.c_str();
imgPath.size = wsPath.size();
imgPath.capacity = wsPath.capacity();
// 发送图片Call地址 = 微信基址 + 偏移
DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1;
DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2;
DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3;
__asm {
pushad
call sendCall1
sub esp, 0x14
mov tmpEAX, eax
lea eax, buf1
mov ecx, esp
lea edi, imgPath
push eax
call sendCall2
mov ecx, dword ptr[tmpEAX]
lea eax, imgWxid
push edi
push eax
lea eax, buf2
push eax
call sendCall3
popad
}
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
void SendTextMessage(const wchar_t *wxid, const wchar_t *msg, const wchar_t *atWxids);
void SendImageMessage(const wchar_t *wxid, const wchar_t *path);
+41
View File
@@ -0,0 +1,41 @@
#include "spy.h"
#include "load_calls.h"
#include "log.h"
#include "rpc_server.h"
#include "util.h"
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) {
LOG_ERROR("获取wechatWin.dll模块地址失败");
return;
}
if (!GetWeChatVersion(version)) { //获取微信版本
LOG_ERROR("获取微信版本失败");
return;
}
if (LoadCalls(version, &g_WxCalls) != 0) { //加载微信版本对应的Call地址
LOG_ERROR("不支持当前版本");
return;
}
RpcStartServer();
}
void CleanupSpy()
{
RpcStopServer();
// FreeLibraryAndExitThread(hModule, 0);
}
int IsLogin(void) { return (int)GET_DWORD(g_WeChatWinDllAddr + g_WxCalls.login); }
std::string GetSelfWxid() { return GET_STRING(g_WeChatWinDllAddr + g_WxCalls.ui.wxid); }
+4
View File
@@ -0,0 +1,4 @@
EXPORTS
InitSpy
CleanupSpy
IsLogin
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include "framework.h"
void InitSpy();
void CleanupSpy();
int IsLogin(void);
+74
View File
@@ -0,0 +1,74 @@
#pragma once
#include "framework.h"
#include "../proto/wcf.grpc.pb.h"
typedef struct UserInfoCall {
DWORD wxid;
DWORD nickName;
DWORD mobile;
} UserInfoCall_t;
typedef struct RecvMsg {
DWORD hook; // Hook地址
DWORD call; // Call地址
DWORD type; // 消息类型地址
DWORD isSelf; // 是否自己发送标志地址
DWORD msgId; // 消息ID地址
DWORD msgXml; // 消息xml内容地址
DWORD roomId; // 群聊时,为群ID;私聊时,为微信ID
DWORD wxId; // 私聊时,为空;群聊时,为发送者微信ID
DWORD content; // 消息内容地址
} RecvMsg_t;
typedef struct SendImg {
DWORD call1;
DWORD call2;
DWORD call3;
} SendImg_t;
typedef struct Contact {
DWORD base;
DWORD head;
DWORD wxId;
DWORD wxCode;
DWORD wxName;
DWORD wxGender;
DWORD wxCountry;
DWORD wxProvince;
DWORD wxCity;
} Contact_t;
typedef struct Sql {
DWORD exec;
DWORD base;
DWORD start;
DWORD end;
DWORD slot;
DWORD name;
} Sql_t;
typedef struct NewFriend {
DWORD call1;
DWORD call2;
DWORD handle;
} NewFriend_t;
typedef struct WxCalls {
DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息
DWORD sendTextMsg; // 发送消息
RecvMsg_t recvMsg; // 接收消息
SendImg_t sendImg; // 发送图片
Contact_t contact; // 获取联系人
Sql_t sql; // 执行 SQL
NewFriend_t anf; // 通过好友申请
} WxCalls_t;
typedef struct TextStruct {
wchar_t *text;
DWORD size;
DWORD capacity;
char fill[8];
} TextStruct_t;
+335
View File
@@ -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
View File
@@ -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);