Merge branch 'feat_rpc'

This commit is contained in:
Changhua 2022-08-07 21:30:05 +08:00
commit da5eae278c
18 changed files with 516 additions and 298 deletions

View File

@ -39,12 +39,6 @@ int main()
_wsetlocale(LC_ALL, L"chs"); // 这是个大坑,不设置中文直接不见了。。。 _wsetlocale(LC_ALL, L"chs"); // 这是个大坑,不设置中文直接不见了。。。
// 获取消息类型
const MsgTypesMap_t WxMsgTypes = WxGetMsgTypes();
for (auto it = WxMsgTypes.begin(); it != WxMsgTypes.end(); ++it) {
wprintf(L"%d: %s\n", it->first, it->second.c_str());
}
wprintf(L"WxInitSDK: "); wprintf(L"WxInitSDK: ");
status = WxInitSDK(); status = WxInitSDK();
wcout << status << endl; wcout << status << endl;
@ -53,18 +47,26 @@ int main()
return 0; return 0;
} }
// 获取消息类型
wprintf(L"获取消息类型\n");
const MsgTypesMap_t WxMsgTypes = WxGetMsgTypes();
for (auto it = WxMsgTypes.begin(); it != WxMsgTypes.end(); ++it) {
wprintf(L"%d: %s\n", it->first, it->second.c_str());
}
wprintf(L"Message: 接收通知中......\n"); wprintf(L"Message: 接收通知中......\n");
WxSetTextMsgCb(onTextMsg); WxSetTextMsgCb(onTextMsg);
Sleep(1000); // 等待1秒
// 测试发送消息 // 测试发送消息
wprintf(L"测试发送消息\n"); wprintf(L"测试发送消息\n");
WxSendTextMsg(wxid, at_wxid, content); WxSendTextMsg(wxid, at_wxid, content);
Sleep(1000); // 等待1秒
// 测试发送照片 // 测试发送照片
wprintf(L"测试发送照片\n"); wprintf(L"测试发送照片\n");
WxSendImageMsg(wxid, img_path); WxSendImageMsg(wxid, img_path);
Sleep(1000); // 等待1秒
Sleep(10000); // 等待10秒
// 测试获取联系人 // 测试获取联系人
auto mContact = WxGetContacts(); auto mContact = WxGetContacts();

View File

@ -1,4 +1,4 @@
[ [
uuid(ed838ecd-8a1e-4da7-bfda-9f2d12d07893), uuid(ed838ecd-8a1e-4da7-bfda-9f2d12d07893),
version(1.0), version(1.0),
implicit_handle(handle_t hSpyBinding), implicit_handle(handle_t hSpyBinding),
@ -6,12 +6,44 @@
interface ISpy interface ISpy
{ {
import "rpc_types.h"; import "oaidl.idl";
typedef struct RpcMessage {
int self; // 是否自己发的消息0=否1=是
int type; // 消息类型
int source; // 消息来源0=好友消息1=群消息
BSTR id; // 消息ID
BSTR xml; // 群其他消息
BSTR wxId; // 发送人微信ID
BSTR roomId; // 群ID
BSTR content; // 消息内容MAC版最大16384即16KB
} RpcMessage_t;
typedef struct RpcIntBstrPair {
int key;
BSTR value;
} RpcIntBstrPair_t;
typedef RpcIntBstrPair_t* PRpcIntBstrPair;
typedef RpcIntBstrPair_t** PPRpcIntBstrPair;
typedef struct RpcContact {
BSTR wxId;
BSTR wxCode;
BSTR wxName;
BSTR wxCountry;
BSTR wxProvince;
BSTR wxCity;
BSTR wxGender;
} RpcContact_t;
typedef RpcContact_t *PRpcContact;
typedef RpcContact_t **PPRpcContact;
int IsLogin(); int IsLogin();
int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *at_wxid, [ in, string ] const wchar_t *msg); int SendTextMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *at_wxid, [ in, string ] const wchar_t *msg);
int SendImageMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *path); int SendImageMsg([ in, string ] const wchar_t *wxid, [ in, string ] const wchar_t *path);
int GetMsgTypes([ out ] int *pNum, [ out, size_is(, *pNum) ] PPRpcIntBstrPair *msgTypes);
int GetContacts([ out ] int *pNum, [ out, size_is(, *pNum) ] PPRpcContact *contacts);
void EnableReceiveMsg(); void EnableReceiveMsg();
[callback] int ReceiveMsg([ in ] RpcMessage_t *msg); [callback] int ReceiveMsg([ in ] RpcMessage_t rpcMsg);
}; };

View File

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

View File

@ -119,6 +119,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>sdk.def</ModuleDefinitionFile> <ModuleDefinitionFile>sdk.def</ModuleDefinitionFile>
<AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -161,6 +162,7 @@
<ClInclude Include="..\Rpc\rpc_h.h" /> <ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="framework.h" /> <ClInclude Include="framework.h" />
<ClInclude Include="injector.h" /> <ClInclude Include="injector.h" />
<ClInclude Include="rpc_client.h" />
<ClInclude Include="sdk.h" /> <ClInclude Include="sdk.h" />
<ClInclude Include="util.h" /> <ClInclude Include="util.h" />
</ItemGroup> </ItemGroup>
@ -169,6 +171,7 @@
<ClCompile Include="..\Rpc\rpc_memory.cpp" /> <ClCompile Include="..\Rpc\rpc_memory.cpp" />
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="injector.cpp" /> <ClCompile Include="injector.cpp" />
<ClCompile Include="rpc_client.cpp" />
<ClCompile Include="sdk.cpp" /> <ClCompile Include="sdk.cpp" />
<ClCompile Include="util.cpp" /> <ClCompile Include="util.cpp" />
</ItemGroup> </ItemGroup>

View File

@ -30,6 +30,9 @@
<ClInclude Include="injector.h"> <ClInclude Include="injector.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="rpc_client.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="dllmain.cpp"> <ClCompile Include="dllmain.cpp">
@ -50,6 +53,9 @@
<ClCompile Include="injector.cpp"> <ClCompile Include="injector.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="rpc_client.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="sdk.def"> <None Include="sdk.def">

167
SDK/rpc_client.cpp Normal file
View File

@ -0,0 +1,167 @@
#include "rpc_client.h"
#include "sdk.h"
#include "util.h"
static RPC_WSTR pszStringBinding = NULL;
extern std::function<int(WxMessage_t)> g_cbReceiveTextMsg;
RPC_STATUS RpcConnectServer()
{
RPC_STATUS status = 0;
// Creates a string binding handle.
status = RpcStringBindingCompose(NULL, // UUID to bind to
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
NULL, // TCP/IP network address to use
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"wcferry"), // TCP/IP port to use
NULL, // Protocol dependent network options to use
&pszStringBinding); // String binding output
if (status)
return status;
/* Validates the format of the string binding handle and converts it to a binding handle.
pszStringBinding: The string binding to validate
hSpyBinding: Put the result in the implicit binding(defined in the IDL file)
*/
status = RpcBindingFromStringBinding(pszStringBinding, &hSpyBinding);
return status;
}
RPC_STATUS RpcDisconnectServer()
{
RPC_STATUS status;
// Free the memory allocated by a string
status = RpcStringFree(&pszStringBinding);
if (status)
return status;
// Releases binding handle resources and disconnects from the server
status = RpcBindingFree(&hSpyBinding);
return status;
}
unsigned int __stdcall RpcSetTextMsgCb(void *p)
{
unsigned long ulCode = 0;
RpcTryExcept
{
// 建立RPC通道让服务端能够调用客户端的回调函数。该接口会被服务端阻塞直到异常退出
client_EnableReceiveMsg();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("rpcWxSetTextMsgCb exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return 0;
}
int RpcIsLogin()
{
int loginFlag = 0;
unsigned long ulCode = 0;
RpcTryExcept
{
// 查询登录状态
loginFlag = client_IsLogin();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("rpcIsLogin exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return loginFlag;
}
int RpcSendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendTextMsg(wxid, at_wxid, msg); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("rpcWxSendTextMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
int RpcSendImageMsg(const wchar_t *wxid, const wchar_t *path)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendImageMsg(wxid, path); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("rpcWxSendImageMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
return ret;
}
PPRpcIntBstrPair RpcGetMsgTypes(int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
PPRpcIntBstrPair ppRpcMsgTypes = NULL;
RpcTryExcept { ret = client_GetMsgTypes(pNum, &ppRpcMsgTypes); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetMsgTypes exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("GetMsgTypes Failed: %d\n", ret);
return NULL;
}
return ppRpcMsgTypes;
}
PPRpcContact RpcGetContacts(int *pNum)
{
int ret = 0;
unsigned long ulCode = 0;
PPRpcContact ppRpcContacts = NULL;
RpcTryExcept { ret = client_GetContacts(pNum, &ppRpcContacts); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("RpcGetContacts exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept;
if (ret != 0) {
printf("GetContacts Failed: %d\n", ret);
return NULL;
}
return ppRpcContacts;
}
int server_ReceiveMsg(RpcMessage_t rpcMsg)
{
WxMessage_t msg;
GetRpcMessage(&msg, rpcMsg);
try {
g_cbReceiveTextMsg(msg); // 调用接收消息回调
} catch (...) {
printf("callback error...\n");
}
return 0;
}

13
SDK/rpc_client.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include "rpc_h.h"
RPC_STATUS RpcConnectServer();
RPC_STATUS RpcDisconnectServer();
unsigned int __stdcall RpcSetTextMsgCb(void *p);
int RpcIsLogin();
int RpcSendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg);
int RpcSendImageMsg(const wchar_t *wxid, const wchar_t *path);
PPRpcIntBstrPair RpcGetMsgTypes(int *pNum);
PPRpcContact RpcGetContacts(int *pNum);

View File

@ -7,87 +7,25 @@
#include <tlhelp32.h> #include <tlhelp32.h>
#include <vector> #include <vector>
#include "../Rpc/rpc_h.h"
#pragma comment(lib, "Rpcrt4.lib")
#include "injector.h" #include "injector.h"
#include "rpc_types.h" #include "rpc_client.h"
#include "sdk.h" #include "sdk.h"
#include "util.h" #include "util.h"
static HANDLE hEvent; std::function<int(WxMessage_t)> g_cbReceiveTextMsg;
static std::queue<RpcMessage_t> MsgQueue;
static RPC_WSTR pszStringBinding = NULL;
static std::function<int(WxMessage_t)> cbReceiveTextMsg;
static const MsgTypesMap_t WxMsgTypes = MsgTypesMap_t { { 0x01, L"文字" },
{ 0x03, L"图片" },
{ 0x22, L"语音" },
{ 0x25, L"好友确认" },
{ 0x28, L"POSSIBLEFRIEND_MSG" },
{ 0x2A, L"名片" },
{ 0x2B, L"视频" },
{ 0x2F, L"石头剪刀布 | 表情图片" },
{ 0x30, L"位置" },
{ 0x31, L"共享实时位置、文件、转账、链接" },
{ 0x32, L"VOIPMSG" },
{ 0x33, L"微信初始化" },
{ 0x34, L"VOIPNOTIFY" },
{ 0x35, L"VOIPINVITE" },
{ 0x3E, L"小视频" },
{ 0x270F, L"SYSNOTICE" },
{ 0x2710, L"红包、系统消息" },
{ 0x2712, L"撤回消息" } };
RPC_STATUS RpcConnectServer()
{
RPC_STATUS status = 0;
// Creates a string binding handle.
status = RpcStringBindingCompose(NULL, // UUID to bind to
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
NULL, // TCP/IP network address to use
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"tmp_endpoint"), // TCP/IP port to use
NULL, // Protocol dependent network options to use
&pszStringBinding); // String binding output
if (status)
return status;
/* Validates the format of the string binding handle and converts it to a binding handle.
pszStringBinding: The string binding to validate
hSpyBinding: Put the result in the implicit binding(defined in the IDL file)
*/
status = RpcBindingFromStringBinding(pszStringBinding, &hSpyBinding);
return status;
}
RPC_STATUS RpcDisconnectServer()
{
RPC_STATUS status;
// Free the memory allocated by a string
status = RpcStringFree(&pszStringBinding);
if (status)
return status;
// Releases binding handle resources and disconnects from the server
status = RpcBindingFree(&hSpyBinding);
return status;
}
int WxInitSDK() int WxInitSDK()
{ {
int loginFlag = 0;
unsigned long ulCode = 0; unsigned long ulCode = 0;
DWORD status = 0; DWORD status = 0;
DWORD pid = 0; DWORD pid = 0;
WCHAR DllPath[MAX_PATH] = { 0 }; WCHAR DllPath[MAX_PATH] = { 0 };
GetModuleFileNameW(GetModuleHandleW(WECHATSDKDLL), DllPath, MAX_PATH); GetModuleFileName(GetModuleHandle(WECHATSDKDLL), DllPath, MAX_PATH);
PathRemoveFileSpecW(DllPath); PathRemoveFileSpec(DllPath);
PathAppendW(DllPath, WECHATINJECTDLL); PathAppend(DllPath, WECHATINJECTDLL);
if (!PathFileExistsW(DllPath)) { if (!PathFileExists(DllPath)) {
return ERROR_FILE_NOT_FOUND; return ERROR_FILE_NOT_FOUND;
} }
@ -102,88 +40,20 @@ int WxInitSDK()
RpcConnectServer(); RpcConnectServer();
while (!loginFlag) { while (!RpcIsLogin()) {
RpcTryExcept
{
// 查询登录状态
loginFlag = client_IsLogin();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
Sleep(1000); Sleep(1000);
} }
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
static unsigned int __stdcall waitForMsg(void *p)
{
RpcMessage_t *rpcMsg;
while (true) {
// 中断式兼顾及时性和CPU使用率
WaitForSingleObject(hEvent, INFINITE); // 等待消息
while (!MsgQueue.empty()) {
rpcMsg = (RpcMessage_t *)&MsgQueue.front();
WxMessage_t msg;
msg.id = wstring(rpcMsg->id);
msg.self = rpcMsg->self;
msg.type = rpcMsg->type;
msg.source = rpcMsg->source;
msg.xml = wstring(rpcMsg->xml);
msg.wxId = wstring(rpcMsg->wxId);
msg.roomId = wstring(rpcMsg->roomId);
msg.content = wstring(rpcMsg->content);
try {
cbReceiveTextMsg(msg); // 调用接收消息回调
} catch (...) {
printf("callback error...\n");
}
MsgQueue.pop();
}
ResetEvent(hEvent);
}
return 0;
}
static unsigned int __stdcall innerWxSetTextMsgCb(void *p)
{
unsigned long ulCode = 0;
RpcTryExcept
{
// 建立RPC通道让服务端能够调用客户端的回调函数。该接口会被服务端阻塞直到异常退出
client_EnableReceiveMsg();
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
return 0;
}
int WxSetTextMsgCb(const std::function<int(WxMessage_t)> &onMsg) int WxSetTextMsgCb(const std::function<int(WxMessage_t)> &onMsg)
{ {
if (onMsg) { if (onMsg) {
HANDLE msgThread; HANDLE msgThread;
cbReceiveTextMsg = onMsg; g_cbReceiveTextMsg = onMsg;
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
msgThread = (HANDLE)_beginthreadex(NULL, 0, waitForMsg, NULL, 0, NULL);
if (msgThread == NULL) {
printf("Failed to create message listening thread.\n");
return -2;
}
CloseHandle(msgThread);
msgThread = (HANDLE)_beginthreadex(NULL, 0, innerWxSetTextMsgCb, NULL, 0, NULL); msgThread = (HANDLE)_beginthreadex(NULL, 0, RpcSetTextMsgCb, NULL, 0, NULL);
if (msgThread == NULL) { if (msgThread == NULL) {
printf("Failed to create innerWxRecvTextMsg.\n"); printf("Failed to create innerWxRecvTextMsg.\n");
return -2; return -2;
@ -197,51 +67,12 @@ int WxSetTextMsgCb(const std::function<int(WxMessage_t)> &onMsg)
return -1; return -1;
} }
int server_ReceiveMsg(RpcMessage_t *rpcMsg)
{
MsgQueue.push(*rpcMsg); // 发送消息
SetEvent(hEvent); // 发送消息通知
return 0;
}
static int innerWxSendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendTextMsg(wxid, at_wxid, msg); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
return ret;
}
int WxSendTextMsg(wstring wxid, wstring at_wxid, wstring msg) int WxSendTextMsg(wstring wxid, wstring at_wxid, wstring msg)
{ {
return innerWxSendTextMsg(wxid.c_str(), at_wxid.c_str(), msg.c_str()); return RpcSendTextMsg(wxid.c_str(), at_wxid.c_str(), msg.c_str());
} }
static int innerWxSendImageMsg(const wchar_t *wxid, const wchar_t *path) int WxSendImageMsg(wstring wxid, wstring path) { return RpcSendImageMsg(wxid.c_str(), path.c_str()); }
{
int ret = 0;
unsigned long ulCode = 0;
RpcTryExcept { ret = client_SendImageMsg(wxid, path); }
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
return ret;
}
int WxSendImageMsg(wstring wxid, wstring path) { return innerWxSendImageMsg(wxid.c_str(), path.c_str()); }
static int getAddrHandle(DWORD *addr, HANDLE *handle) static int getAddrHandle(DWORD *addr, HANDLE *handle)
{ {
@ -297,45 +128,46 @@ static int getAddrHandle(DWORD *addr, HANDLE *handle)
return 0; return 0;
} }
MsgTypesMap_t WxGetMsgTypes()
{
static MsgTypesMap_t WxMsgTypes;
if (WxMsgTypes.empty()) {
int size = 0;
PPRpcIntBstrPair pp = RpcGetMsgTypes(&size);
for (int i = 0; i < size; i++) {
WxMsgTypes.insert(make_pair(pp[i]->key, GetWstringFromBstr(pp[i]->value)));
midl_user_free(pp[i]);
}
if (pp) {
midl_user_free(pp);
}
}
return WxMsgTypes;
}
ContactMap_t WxGetContacts() ContactMap_t WxGetContacts()
{ {
ContactMap_t mContact; ContactMap_t mContact;
DWORD moduleBaseAddress; int size = 0;
HANDLE hProcess; PPRpcContact pp = RpcGetContacts(&size);
for (int i = 0; i < size; i++) {
WxContact_t contact;
contact.wxId = GetWstringFromBstr(pp[i]->wxId);
contact.wxCode = GetWstringFromBstr(pp[i]->wxCode);
contact.wxName = GetWstringFromBstr(pp[i]->wxName);
contact.wxCountry = GetWstringFromBstr(pp[i]->wxCountry);
contact.wxProvince = GetWstringFromBstr(pp[i]->wxProvince);
contact.wxCity = GetWstringFromBstr(pp[i]->wxCity);
contact.wxGender = GetWstringFromBstr(pp[i]->wxGender);
if (getAddrHandle(&moduleBaseAddress, &hProcess) != 0) { mContact.insert(make_pair(contact.wxId, contact));
return mContact; midl_user_free(pp[i]);
}
printf("WxGetContacts\n");
DWORD baseAddr = moduleBaseAddress + 0x23638F4;
DWORD tempAddr = GetMemoryIntByAddress(hProcess, baseAddr);
DWORD head = GetMemoryIntByAddress(hProcess, tempAddr + 0x4C);
DWORD node = GetMemoryIntByAddress(hProcess, head);
while (node != head) {
WxContact_t contactItem;
contactItem.wxId = GetUnicodeInfoByAddress(hProcess, node + 0x30);
contactItem.wxCode = GetUnicodeInfoByAddress(hProcess, node + 0x44);
contactItem.wxName = GetUnicodeInfoByAddress(hProcess, node + 0x8C);
contactItem.wxCountry = GetUnicodeInfoByAddress(hProcess, node + 0x1D0);
contactItem.wxProvince = GetUnicodeInfoByAddress(hProcess, node + 0x1E4);
contactItem.wxCity = GetUnicodeInfoByAddress(hProcess, node + 0x1F8);
DWORD gender = GetMemoryIntByAddress(hProcess, node + 0x184);
if (gender == 1)
contactItem.wxGender = L"";
else if (gender == 2)
contactItem.wxGender = L"";
else
contactItem.wxGender = L"未知";
mContact.insert(make_pair(contactItem.wxId, contactItem));
node = GetMemoryIntByAddress(hProcess, node);
} }
CloseHandle(hProcess); if (pp) {
midl_user_free(pp);
}
return mContact; return mContact;
} }
MsgTypesMap_t WxGetMsgTypes() { return WxMsgTypes; }

View File

@ -133,17 +133,16 @@ int OpenWeChat(DWORD *pid)
{ {
int ret = -1; int ret = -1;
STARTUPINFO si = { sizeof(si) }; STARTUPINFO si = { sizeof(si) };
WCHAR Path[MAX_PATH] = { 0 };
PROCESS_INFORMATION pi = { 0 }; PROCESS_INFORMATION pi = { 0 };
WCHAR Path[MAX_PATH] = { 0 };
ret = GetWeChatPath(Path); ret = GetWeChatPath(Path);
if (ERROR_SUCCESS != ret) { if (ERROR_SUCCESS != ret) {
return ret; return ret;
} }
if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
ret = GetLastError(); return GetLastError();
return ret;
} }
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
@ -151,9 +150,7 @@ int OpenWeChat(DWORD *pid)
*pid = pi.dwProcessId; *pid = pi.dwProcessId;
ret = ERROR_SUCCESS; return ERROR_SUCCESS;
return ret;
} }
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size) int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
@ -170,6 +167,38 @@ int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size)
return strLength; return strLength;
} }
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;
}
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);
}
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address) DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address)
{ {
DWORD value = 0; DWORD value = 0;

View File

@ -1,7 +1,10 @@
#pragma once #pragma once
#include <string> #include <string>
#include "sdk.h"
#include "rpc_h.h"
#define WECHAREXE L"WeChat.exe" #define WECHAREXE L"WeChat.exe"
#define WECHATWINDLL L"WeChatWin.dll" #define WECHATWINDLL L"WeChatWin.dll"
#define WECHATSDKDLL L"SDK.dll" #define WECHATSDKDLL L"SDK.dll"
@ -17,5 +20,8 @@ int GetWeChatWinDLLPath(wchar_t *path);
int GetWeChatVersion(wchar_t *version); int GetWeChatVersion(wchar_t *version);
bool GetFileVersion(const wchar_t *filePath, wchar_t *version); bool GetFileVersion(const wchar_t *filePath, wchar_t *version);
int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size); int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
BSTR GetBstrByAddress(DWORD address);
void GetRpcMessage(WxMessage_t *wxMsg, RpcMessage_t rpcMsg);
DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address); DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
std::wstring GetWstringFromBstr(BSTR p);
std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address); std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);

View File

@ -122,6 +122,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<AdditionalDependencies>Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Midl> <Midl>
<AdditionalOptions>/prefix client "client_" server "server_" </AdditionalOptions> <AdditionalOptions>/prefix client "client_" server "server_" </AdditionalOptions>
@ -163,10 +164,10 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\Rpc\rpc_types.h" />
<ClInclude Include="..\Rpc\rpc_h.h" /> <ClInclude Include="..\Rpc\rpc_h.h" />
<ClInclude Include="..\SDK\util.h" /> <ClInclude Include="..\SDK\util.h" />
<ClInclude Include="framework.h" /> <ClInclude Include="framework.h" />
<ClInclude Include="get_contacts.h" />
<ClInclude Include="load_calls.h" /> <ClInclude Include="load_calls.h" />
<ClInclude Include="monitor.h" /> <ClInclude Include="monitor.h" />
<ClInclude Include="receive_msg.h" /> <ClInclude Include="receive_msg.h" />
@ -179,6 +180,7 @@
<ClCompile Include="..\Rpc\rpc_s.c" /> <ClCompile Include="..\Rpc\rpc_s.c" />
<ClCompile Include="..\SDK\util.cpp" /> <ClCompile Include="..\SDK\util.cpp" />
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="get_contacts.cpp" />
<ClCompile Include="load_calls.cpp" /> <ClCompile Include="load_calls.cpp" />
<ClCompile Include="monitor.cpp" /> <ClCompile Include="monitor.cpp" />
<ClCompile Include="receive_msg.cpp" /> <ClCompile Include="receive_msg.cpp" />

View File

@ -27,9 +27,6 @@
<ClInclude Include="monitor.h"> <ClInclude Include="monitor.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Rpc\rpc_types.h">
<Filter>Rpc</Filter>
</ClInclude>
<ClInclude Include="rpc_server.h"> <ClInclude Include="rpc_server.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
@ -48,6 +45,9 @@
<ClInclude Include="spy_types.h"> <ClInclude Include="spy_types.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="get_contacts.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="dllmain.cpp"> <ClCompile Include="dllmain.cpp">
@ -77,6 +77,9 @@
<ClCompile Include="send_msg.cpp"> <ClCompile Include="send_msg.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="get_contacts.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Midl Include="..\Rpc\rpc.idl"> <Midl Include="..\Rpc\rpc.idl">

39
Spy/get_contacts.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "get_contacts.h"
#include "load_calls.h"
#include "util.h"
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
std::vector<RpcContact_t> GetContacts()
{
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);
gender = GET_DWORD(node + g_WxCalls.contact.wxGender);
if (gender == 1)
rpcContact.wxGender = SysAllocString(L"");
else if (gender == 2)
rpcContact.wxGender = SysAllocString(L"");
else
rpcContact.wxGender = SysAllocString(L"未知");
vContacts.push_back(rpcContact);
node = GET_DWORD(node);
}
return vContacts;
}

7
Spy/get_contacts.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <vector>
#include "rpc_h.h"
std::vector<RpcContact_t> GetContacts();

View File

@ -4,15 +4,16 @@
#include "load_calls.h" #include "load_calls.h"
#define SUPPORT_VERSION L"3.7.0.29" #define SUPPORT_VERSION L"3.7.0.29"
WxCalls_t wxCalls = { WxCalls_t wxCalls = { 0x23631D0, // Login Status
0x23631D0, // Login Status
{ 0x236307C, 0x23630F4, 0x2363128 }, // User Info: wxid, nickname, mobile { 0x236307C, 0x23630F4, 0x2363128 }, // User Info: wxid, nickname, mobile
0x521D30, // Send Message 0x521D30, // Send Message
/* Receive Message: /* Receive Message:
Hook, call, type, self, id, msgXml, roomId, wxId, content */ Hook, call, type, self, id, msgXml, roomId, wxId, content */
{ 0x550F4C, 0xA94A50, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 }, { 0x550F4C, 0xA94A50, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 },
{ 0xBD780, 0x770120, 0x521640 } // Send Image Message { 0xBD780, 0x770120, 0x521640 }, // Send Image Message
}; /* Get Contacts:
Base, head, wxId, Code, Name, Gender, Country, Province, City*/
{ 0x23638F4, 0x4C, 0x30, 0x44, 0x8C, 0x184, 0x1D0, 0x1E4, 0x1F8 } };
int LoadCalls(const wchar_t *version, WxCalls_t *calls) int LoadCalls(const wchar_t *version, WxCalls_t *calls)
{ {

View File

@ -14,30 +14,50 @@ MsgQueue_t g_MsgQueue;
DWORD reg_buffer = 0; DWORD reg_buffer = 0;
DWORD recvMsgCallAddr = 0; DWORD recvMsgCallAddr = 0;
DWORD recvMsgJumpBackAddr = 0; DWORD recvMsgJumpBackAddr = 0;
RpcMessage_t *pMsg = NULL; // Find a palce to free 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 DispatchMsg(DWORD reg) void DispatchMsg(DWORD reg)
{ {
DWORD* p = (DWORD*)reg; //消息结构基址 DWORD* p = (DWORD*)reg; //消息结构基址
memset(pMsg, 0, sizeof(RpcMessage_t)); memset(&lMsg, 0, sizeof(RpcMessage_t));
pMsg->type = GET_DWORD(*p + g_WxCalls.recvMsg.type); lMsg.type = GET_DWORD(*p + g_WxCalls.recvMsg.type);
pMsg->self = GET_DWORD(*p + g_WxCalls.recvMsg.isSelf); 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);
GetWstringByAddress(*p + g_WxCalls.recvMsg.msgId, pMsg->id, MSG_SIZE_MSG_ID);
GetWstringByAddress(*p + g_WxCalls.recvMsg.msgXml, pMsg->xml, MSG_SIZE_MSG_XML);
if (wcsstr(pMsg->xml, L"<membercount>") == NULL) { if (wcsstr(lMsg.xml, L"<membercount>") == NULL) {
// pMsg.roomId = {0}; // pMsg.roomId = {0};
GetWstringByAddress(*p + g_WxCalls.recvMsg.roomId, pMsg->wxId, MSG_SIZE_WXID); lMsg.wxId = GetBstrByAddress(*p + g_WxCalls.recvMsg.roomId);
} else {
pMsg->source = 1;
GetWstringByAddress(*p + g_WxCalls.recvMsg.roomId, pMsg->roomId, MSG_SIZE_ROOMID);
GetWstringByAddress(*p + g_WxCalls.recvMsg.wxId, pMsg->wxId, MSG_SIZE_WXID);
} }
GetWstringByAddress(*p + g_WxCalls.recvMsg.content, pMsg->content, MSG_SIZE_CONTENT); else {
g_MsgQueue.push(*pMsg); // 发送消息 lMsg.source = 1;
lMsg.wxId = GetBstrByAddress(*p + g_WxCalls.recvMsg.wxId);
lMsg.roomId = GetBstrByAddress(*p + g_WxCalls.recvMsg.roomId);
}
lMsg.content = GetBstrByAddress(*p + g_WxCalls.recvMsg.content);
g_MsgQueue.push(lMsg); // 发送消息
SetEvent(g_hEvent); // 发送消息通知 SetEvent(g_hEvent); // 发送消息通知
} }
@ -63,7 +83,6 @@ void ListenMessage()
return; return;
} }
pMsg = new RpcMessage_t;
DWORD hookAddress = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook; DWORD hookAddress = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call; recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
recvMsgJumpBackAddr = hookAddress + 5; recvMsgJumpBackAddr = hookAddress + 5;

View File

@ -1,16 +1,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "get_contacts.h"
#include "monitor.h" #include "monitor.h"
#include "rpc_h.h"
#include "rpc_server.h" #include "rpc_server.h"
#include "sdk.h"
#include "send_msg.h" #include "send_msg.h"
#include "spy_types.h" #include "spy_types.h"
#include "../Rpc/rpc_h.h"
#pragma comment(lib, "Rpcrt4.lib")
extern HANDLE g_hEvent; extern HANDLE g_hEvent;
extern MsgQueue_t g_MsgQueue; extern MsgQueue_t g_MsgQueue;
extern const MsgTypesMap_t g_WxMsgTypes;
int server_IsLogin() { return IsLogin(); } int server_IsLogin() { return IsLogin(); }
@ -25,7 +26,7 @@ void server_EnableReceiveMsg()
// 中断式兼顾及时性和CPU使用率 // 中断式兼顾及时性和CPU使用率
WaitForSingleObject(g_hEvent, INFINITE); // 等待消息 WaitForSingleObject(g_hEvent, INFINITE); // 等待消息
while (!g_MsgQueue.empty()) { while (!g_MsgQueue.empty()) {
client_ReceiveMsg((RpcMessage_t *)&g_MsgQueue.front()); // 调用接收消息回调 client_ReceiveMsg(g_MsgQueue.front()); // 调用接收消息回调
g_MsgQueue.pop(); g_MsgQueue.pop();
} }
ResetEvent(g_hEvent); ResetEvent(g_hEvent);
@ -34,7 +35,7 @@ void server_EnableReceiveMsg()
RpcExcept(1) RpcExcept(1)
{ {
ulCode = RpcExceptionCode(); ulCode = RpcExceptionCode();
printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode); printf("server_EnableReceiveMsg exception 0x%lx = %ld\n", ulCode, ulCode);
} }
RpcEndExcept RpcEndExcept
} }
@ -53,6 +54,67 @@ int server_SendImageMsg(const wchar_t *wxid, const wchar_t *path)
return 0; return 0;
} }
int server_GetMsgTypes(int *pNum, PPRpcIntBstrPair *msgTypes)
{
*pNum = g_WxMsgTypes.size();
PPRpcIntBstrPair pp = (PPRpcIntBstrPair)midl_user_allocate(*pNum * sizeof(RpcIntBstrPair_t));
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)
{
std::vector<RpcContact_t> vContacts = GetContacts();
*pNum = vContacts.size();
PPRpcContact pp = (PPRpcContact)midl_user_allocate(*pNum * sizeof(RpcContact_t));
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;
}
RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/) RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/, void * /*pBindingHandle*/)
{ {
return RPC_S_OK; // Always allow anyone. return RPC_S_OK; // Always allow anyone.
@ -65,7 +127,7 @@ int RpcStartServer(HMODULE hModule)
// remote procedure calls. // remote procedure calls.
status = RpcServerUseProtseqEp(reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol 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. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP.
reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"tmp_endpoint"), // TCP/IP port to use reinterpret_cast<RPC_WSTR>((RPC_WSTR)L"wcferry"), // TCP/IP port to use
NULL // No security NULL // No security
); );

View File

@ -3,7 +3,7 @@
#include "framework.h" #include "framework.h"
#include <queue> #include <queue>
#include "rpc_types.h" #include "rpc_h.h"
typedef struct UserInfoCall { typedef struct UserInfoCall {
DWORD wxid; DWORD wxid;
@ -19,7 +19,7 @@ typedef struct RecvMsg {
DWORD msgId; // 消息ID地址 DWORD msgId; // 消息ID地址
DWORD msgXml; // 消息xml内容地址 DWORD msgXml; // 消息xml内容地址
DWORD roomId; // 群聊时为群ID私聊时为微信ID DWORD roomId; // 群聊时为群ID私聊时为微信ID
DWORD wxId; // 私聊时,为空;群为发送者微信ID DWORD wxId; // 私聊时,为空;群为发送者微信ID
DWORD content; // 消息内容地址 DWORD content; // 消息内容地址
} RecvMsg_t; } RecvMsg_t;
@ -29,12 +29,25 @@ typedef struct SendImg {
DWORD call3; DWORD call3;
} SendImg_t; } 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 WxCalls { typedef struct WxCalls {
DWORD login; // 登录状态 DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息 UserInfoCall_t ui; // 用户信息
DWORD sendTextMsg; // 发送消息 DWORD sendTextMsg; // 发送消息
RecvMsg_t recvMsg; // 接收消息 RecvMsg_t recvMsg; // 接收消息
SendImg_t sendImg; // 发送图片 SendImg_t sendImg; // 发送图片
Contact_t contact; // 获取联系人
} WxCalls_t; } WxCalls_t;
typedef struct TextStruct { typedef struct TextStruct {