diff --git a/App/App.cpp b/App/App.cpp
index 0008770..ce5c043 100644
--- a/App/App.cpp
+++ b/App/App.cpp
@@ -39,32 +39,34 @@ int main()
_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: ");
status = WxInitSDK();
wcout << status << endl;
wprintf(L"%d\n", status);
if (status != 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");
WxSetTextMsgCb(onTextMsg);
+ Sleep(1000); // 等待1秒
// 测试发送消息
wprintf(L"测试发送消息\n");
WxSendTextMsg(wxid, at_wxid, content);
+ Sleep(1000); // 等待1秒
// 测试发送照片
wprintf(L"测试发送照片\n");
WxSendImageMsg(wxid, img_path);
-
- Sleep(10000); // 等待10秒
+ Sleep(1000); // 等待1秒
// 测试获取联系人
auto mContact = WxGetContacts();
diff --git a/Rpc/rpc.idl b/Rpc/rpc.idl
index 50d0893..3b55c2a 100644
--- a/Rpc/rpc.idl
+++ b/Rpc/rpc.idl
@@ -1,17 +1,49 @@
-[
+[
uuid(ed838ecd-8a1e-4da7-bfda-9f2d12d07893),
version(1.0),
implicit_handle(handle_t hSpyBinding),
]
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 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 GetMsgTypes([ out ] int *pNum, [ out, size_is(, *pNum) ] PPRpcIntBstrPair *msgTypes);
+ int GetContacts([ out ] int *pNum, [ out, size_is(, *pNum) ] PPRpcContact *contacts);
void EnableReceiveMsg();
- [callback] int ReceiveMsg([ in ] RpcMessage_t *msg);
+ [callback] int ReceiveMsg([ in ] RpcMessage_t rpcMsg);
};
diff --git a/Rpc/rpc_types.h b/Rpc/rpc_types.h
deleted file mode 100644
index b897a96..0000000
--- a/Rpc/rpc_types.h
+++ /dev/null
@@ -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;
diff --git a/SDK/SDK.vcxproj b/SDK/SDK.vcxproj
index f16a252..cafe36f 100644
--- a/SDK/SDK.vcxproj
+++ b/SDK/SDK.vcxproj
@@ -119,6 +119,7 @@
true
false
sdk.def
+ Rpcrt4.lib;%(AdditionalDependencies)
@@ -161,6 +162,7 @@
+
@@ -169,6 +171,7 @@
+
diff --git a/SDK/SDK.vcxproj.filters b/SDK/SDK.vcxproj.filters
index 848686a..66ebf04 100644
--- a/SDK/SDK.vcxproj.filters
+++ b/SDK/SDK.vcxproj.filters
@@ -30,6 +30,9 @@
头文件
+
+ 头文件
+
@@ -50,6 +53,9 @@
源文件
+
+ 源文件
+
diff --git a/SDK/rpc_client.cpp b/SDK/rpc_client.cpp
new file mode 100644
index 0000000..269e656
--- /dev/null
+++ b/SDK/rpc_client.cpp
@@ -0,0 +1,167 @@
+#include "rpc_client.h"
+#include "sdk.h"
+#include "util.h"
+
+static RPC_WSTR pszStringBinding = NULL;
+extern std::function 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)L"ncalrpc"), // Use TCP/IP protocol
+ NULL, // TCP/IP network address to use
+ reinterpret_cast((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;
+}
diff --git a/SDK/rpc_client.h b/SDK/rpc_client.h
new file mode 100644
index 0000000..800d02c
--- /dev/null
+++ b/SDK/rpc_client.h
@@ -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);
diff --git a/SDK/sdk.cpp b/SDK/sdk.cpp
index 9d45954..de7e39f 100644
--- a/SDK/sdk.cpp
+++ b/SDK/sdk.cpp
@@ -7,87 +7,25 @@
#include
#include
-#include "../Rpc/rpc_h.h"
-#pragma comment(lib, "Rpcrt4.lib")
-
#include "injector.h"
-#include "rpc_types.h"
+#include "rpc_client.h"
#include "sdk.h"
#include "util.h"
-static HANDLE hEvent;
-static std::queue MsgQueue;
-static RPC_WSTR pszStringBinding = NULL;
-static std::function 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)L"ncalrpc"), // Use TCP/IP protocol
- NULL, // TCP/IP network address to use
- reinterpret_cast((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;
-}
+std::function g_cbReceiveTextMsg;
int WxInitSDK()
{
- int loginFlag = 0;
unsigned long ulCode = 0;
DWORD status = 0;
DWORD pid = 0;
WCHAR DllPath[MAX_PATH] = { 0 };
- GetModuleFileNameW(GetModuleHandleW(WECHATSDKDLL), DllPath, MAX_PATH);
- PathRemoveFileSpecW(DllPath);
- PathAppendW(DllPath, WECHATINJECTDLL);
+ GetModuleFileName(GetModuleHandle(WECHATSDKDLL), DllPath, MAX_PATH);
+ PathRemoveFileSpec(DllPath);
+ PathAppend(DllPath, WECHATINJECTDLL);
- if (!PathFileExistsW(DllPath)) {
+ if (!PathFileExists(DllPath)) {
return ERROR_FILE_NOT_FOUND;
}
@@ -102,88 +40,20 @@ int WxInitSDK()
RpcConnectServer();
- while (!loginFlag) {
- RpcTryExcept
- {
- // 查询登录状态
- loginFlag = client_IsLogin();
- }
- RpcExcept(1)
- {
- ulCode = RpcExceptionCode();
- printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
- }
- RpcEndExcept
-
- Sleep(1000);
+ while (!RpcIsLogin()) {
+ Sleep(1000);
}
return ERROR_SUCCESS;
}
-static unsigned int __stdcall waitForMsg(void *p)
-{
- RpcMessage_t *rpcMsg;
- while (true) {
- // 中断式,兼顾及时性和CPU使用率
- WaitForSingleObject(hEvent, INFINITE); // 等待消息
- while (!MsgQueue.empty()) {
- rpcMsg = (RpcMessage_t *)&MsgQueue.front();
- WxMessage_t msg;
- msg.id = wstring(rpcMsg->id);
- msg.self = rpcMsg->self;
- msg.type = rpcMsg->type;
- msg.source = rpcMsg->source;
- msg.xml = wstring(rpcMsg->xml);
- msg.wxId = wstring(rpcMsg->wxId);
- msg.roomId = wstring(rpcMsg->roomId);
- msg.content = wstring(rpcMsg->content);
-
- try {
- cbReceiveTextMsg(msg); // 调用接收消息回调
- } catch (...) {
- printf("callback error...\n");
- }
- MsgQueue.pop();
- }
- ResetEvent(hEvent);
- }
-
- return 0;
-}
-
-static unsigned int __stdcall innerWxSetTextMsgCb(void *p)
-{
- unsigned long ulCode = 0;
- RpcTryExcept
- {
- // 建立RPC通道,让服务端能够调用客户端的回调函数。(该接口会被服务端阻塞直到异常退出)
- client_EnableReceiveMsg();
- }
- RpcExcept(1)
- {
- ulCode = RpcExceptionCode();
- printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
- }
- RpcEndExcept
-
- return 0;
-}
-
int WxSetTextMsgCb(const std::function &onMsg)
{
if (onMsg) {
HANDLE msgThread;
- cbReceiveTextMsg = onMsg;
- hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- msgThread = (HANDLE)_beginthreadex(NULL, 0, waitForMsg, NULL, 0, NULL);
- if (msgThread == NULL) {
- printf("Failed to create message listening thread.\n");
- return -2;
- }
- CloseHandle(msgThread);
+ g_cbReceiveTextMsg = onMsg;
- msgThread = (HANDLE)_beginthreadex(NULL, 0, innerWxSetTextMsgCb, NULL, 0, NULL);
+ msgThread = (HANDLE)_beginthreadex(NULL, 0, RpcSetTextMsgCb, NULL, 0, NULL);
if (msgThread == NULL) {
printf("Failed to create innerWxRecvTextMsg.\n");
return -2;
@@ -197,51 +67,12 @@ int WxSetTextMsgCb(const std::function &onMsg)
return -1;
}
-int server_ReceiveMsg(RpcMessage_t *rpcMsg)
-{
- MsgQueue.push(*rpcMsg); // 发送消息
- SetEvent(hEvent); // 发送消息通知
- return 0;
-}
-
-static int innerWxSendTextMsg(const wchar_t *wxid, const wchar_t *at_wxid, const wchar_t *msg)
-{
- int ret = 0;
- unsigned long ulCode = 0;
-
- RpcTryExcept { ret = client_SendTextMsg(wxid, at_wxid, msg); }
- RpcExcept(1)
- {
- ulCode = RpcExceptionCode();
- printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
- }
- RpcEndExcept
-
- return ret;
-}
-
int WxSendTextMsg(wstring wxid, wstring at_wxid, wstring msg)
{
- return innerWxSendTextMsg(wxid.c_str(), at_wxid.c_str(), msg.c_str());
+ return RpcSendTextMsg(wxid.c_str(), at_wxid.c_str(), msg.c_str());
}
-static int innerWxSendImageMsg(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("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()); }
+int WxSendImageMsg(wstring wxid, wstring path) { return RpcSendImageMsg(wxid.c_str(), path.c_str()); }
static int getAddrHandle(DWORD *addr, HANDLE *handle)
{
@@ -297,45 +128,46 @@ static int getAddrHandle(DWORD *addr, HANDLE *handle)
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 mContact;
- DWORD moduleBaseAddress;
- HANDLE hProcess;
+ int size = 0;
+ PPRpcContact pp = RpcGetContacts(&size);
+ for (int i = 0; i < size; i++) {
+ WxContact_t contact;
+ contact.wxId = GetWstringFromBstr(pp[i]->wxId);
+ contact.wxCode = GetWstringFromBstr(pp[i]->wxCode);
+ contact.wxName = GetWstringFromBstr(pp[i]->wxName);
+ contact.wxCountry = GetWstringFromBstr(pp[i]->wxCountry);
+ contact.wxProvince = GetWstringFromBstr(pp[i]->wxProvince);
+ contact.wxCity = GetWstringFromBstr(pp[i]->wxCity);
+ contact.wxGender = GetWstringFromBstr(pp[i]->wxGender);
- if (getAddrHandle(&moduleBaseAddress, &hProcess) != 0) {
- return mContact;
- }
- 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);
+ mContact.insert(make_pair(contact.wxId, contact));
+ midl_user_free(pp[i]);
}
- CloseHandle(hProcess);
+ if (pp) {
+ midl_user_free(pp);
+ }
return mContact;
}
-
-MsgTypesMap_t WxGetMsgTypes() { return WxMsgTypes; }
diff --git a/SDK/util.cpp b/SDK/util.cpp
index 0d8a96e..61100be 100644
--- a/SDK/util.cpp
+++ b/SDK/util.cpp
@@ -58,7 +58,7 @@ int GetWeChatWinDLLPath(wchar_t *path)
// 微信从(大约)3.7开始,增加了一层版本目录: [3.7.0.29]
PathRemoveFileSpec(path);
_wfinddata_t findData;
- wstring dir = wstring(path) + L"\\[*.*";
+ wstring dir = wstring(path) + L"\\[*.*";
intptr_t handle = _wfindfirst(dir.c_str(), &findData);
if (handle == -1) { // 检查是否成功
return -1;
@@ -66,7 +66,7 @@ int GetWeChatWinDLLPath(wchar_t *path)
wstring dllPath = wstring(path) + L"\\" + findData.name;
wcscpy_s(path, MAX_PATH, dllPath.c_str());
PathAppend(path, WECHATWINDLL);
- }
+ }
return ret;
}
@@ -133,17 +133,16 @@ int OpenWeChat(DWORD *pid)
{
int ret = -1;
STARTUPINFO si = { sizeof(si) };
+ WCHAR Path[MAX_PATH] = { 0 };
PROCESS_INFORMATION pi = { 0 };
- WCHAR Path[MAX_PATH] = { 0 };
- ret = GetWeChatPath(Path);
+ ret = GetWeChatPath(Path);
if (ERROR_SUCCESS != ret) {
return ret;
}
if (!CreateProcess(NULL, Path, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
- ret = GetLastError();
- return ret;
+ return GetLastError();
}
CloseHandle(pi.hThread);
@@ -151,9 +150,7 @@ int OpenWeChat(DWORD *pid)
*pid = pi.dwProcessId;
- ret = ERROR_SUCCESS;
-
- return ret;
+ return ERROR_SUCCESS;
}
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;
}
+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 value = 0;
diff --git a/SDK/util.h b/SDK/util.h
index 19084e1..0579361 100644
--- a/SDK/util.h
+++ b/SDK/util.h
@@ -1,6 +1,9 @@
-#pragma once
+#pragma once
-#include
+#include
+
+#include "sdk.h"
+#include "rpc_h.h"
#define WECHAREXE L"WeChat.exe"
#define WECHATWINDLL L"WeChatWin.dll"
@@ -16,6 +19,9 @@ int GetWeChatPath(wchar_t *path);
int GetWeChatWinDLLPath(wchar_t *path);
int GetWeChatVersion(wchar_t *version);
bool GetFileVersion(const wchar_t *filePath, wchar_t *version);
-int GetWstringByAddress(DWORD address, wchar_t *buffer, DWORD buffer_size);
-DWORD GetMemoryIntByAddress(HANDLE hProcess, DWORD address);
+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);
+std::wstring GetWstringFromBstr(BSTR p);
std::wstring GetUnicodeInfoByAddress(HANDLE hProcess, DWORD address);
diff --git a/Spy/Spy.vcxproj b/Spy/Spy.vcxproj
index 2b4569a..8eae960 100644
--- a/Spy/Spy.vcxproj
+++ b/Spy/Spy.vcxproj
@@ -122,6 +122,7 @@
true
true
false
+ Rpcrt4.lib;%(AdditionalDependencies)
/prefix client "client_" server "server_"
@@ -163,10 +164,10 @@
-
+
@@ -179,6 +180,7 @@
+
diff --git a/Spy/Spy.vcxproj.filters b/Spy/Spy.vcxproj.filters
index d34335b..be1f776 100644
--- a/Spy/Spy.vcxproj.filters
+++ b/Spy/Spy.vcxproj.filters
@@ -27,9 +27,6 @@
头文件
-
- Rpc
-
头文件
@@ -48,6 +45,9 @@
头文件
+
+ 头文件
+
@@ -77,6 +77,9 @@
源文件
+
+ 源文件
+
diff --git a/Spy/get_contacts.cpp b/Spy/get_contacts.cpp
new file mode 100644
index 0000000..8282e2c
--- /dev/null
+++ b/Spy/get_contacts.cpp
@@ -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 GetContacts()
+{
+ int gender = 0;
+ vector 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;
+}
diff --git a/Spy/get_contacts.h b/Spy/get_contacts.h
new file mode 100644
index 0000000..5662225
--- /dev/null
+++ b/Spy/get_contacts.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include
+
+#include "rpc_h.h"
+
+std::vector GetContacts();
diff --git a/Spy/load_calls.cpp b/Spy/load_calls.cpp
index 18ee717..0145286 100644
--- a/Spy/load_calls.cpp
+++ b/Spy/load_calls.cpp
@@ -4,17 +4,18 @@
#include "load_calls.h"
#define SUPPORT_VERSION L"3.7.0.29"
-WxCalls_t wxCalls = {
- 0x23631D0, // Login Status
- { 0x236307C, 0x23630F4, 0x2363128 }, // User Info: wxid, nickname, mobile
- 0x521D30, // Send Message
- /* Receive Message:
- Hook, call, type, self, id, msgXml, roomId, wxId, content */
- { 0x550F4C, 0xA94A50, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 },
- { 0xBD780, 0x770120, 0x521640 } // Send Image Message
-};
+WxCalls_t wxCalls = { 0x23631D0, // Login Status
+ { 0x236307C, 0x23630F4, 0x2363128 }, // User Info: wxid, nickname, mobile
+ 0x521D30, // Send Message
+ /* Receive Message:
+ Hook, call, type, self, id, msgXml, roomId, wxId, content */
+ { 0x550F4C, 0xA94A50, 0x38, 0x3C, 0x184, 0x1EC, 0x48, 0x170, 0x70 },
+ { 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)
{
if (wcscmp(version, SUPPORT_VERSION) != 0) {
return -1;
diff --git a/Spy/receive_msg.cpp b/Spy/receive_msg.cpp
index ce21af1..ac0f7af 100644
--- a/Spy/receive_msg.cpp
+++ b/Spy/receive_msg.cpp
@@ -14,30 +14,50 @@ MsgQueue_t g_MsgQueue;
DWORD reg_buffer = 0;
DWORD recvMsgCallAddr = 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)
{
- 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);
- pMsg->self = GET_DWORD(*p + g_WxCalls.recvMsg.isSelf);
+ 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);
- 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"") == NULL) {
+ if (wcsstr(lMsg.xml, L"") == NULL) {
// pMsg.roomId = {0};
- GetWstringByAddress(*p + g_WxCalls.recvMsg.roomId, pMsg->wxId, MSG_SIZE_WXID);
- } 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);
+ lMsg.wxId = GetBstrByAddress(*p + g_WxCalls.recvMsg.roomId);
}
- GetWstringByAddress(*p + g_WxCalls.recvMsg.content, pMsg->content, MSG_SIZE_CONTENT);
- g_MsgQueue.push(*pMsg); // 发送消息
+ else {
+ 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); // 发送消息通知
}
@@ -63,7 +83,6 @@ void ListenMessage()
return;
}
- pMsg = new RpcMessage_t;
DWORD hookAddress = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook;
recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call;
recvMsgJumpBackAddr = hookAddress + 5;
diff --git a/Spy/rpc_server.cpp b/Spy/rpc_server.cpp
index 932a155..972d8d3 100644
--- a/Spy/rpc_server.cpp
+++ b/Spy/rpc_server.cpp
@@ -1,16 +1,17 @@
-#include
+#include
#include
+#include "get_contacts.h"
#include "monitor.h"
+#include "rpc_h.h"
#include "rpc_server.h"
+#include "sdk.h"
#include "send_msg.h"
#include "spy_types.h"
-#include "../Rpc/rpc_h.h"
-#pragma comment(lib, "Rpcrt4.lib")
-
extern HANDLE g_hEvent;
extern MsgQueue_t g_MsgQueue;
+extern const MsgTypesMap_t g_WxMsgTypes;
int server_IsLogin() { return IsLogin(); }
@@ -25,7 +26,7 @@ void server_EnableReceiveMsg()
// 中断式,兼顾及时性和CPU使用率
WaitForSingleObject(g_hEvent, INFINITE); // 等待消息
while (!g_MsgQueue.empty()) {
- client_ReceiveMsg((RpcMessage_t *)&g_MsgQueue.front()); // 调用接收消息回调
+ client_ReceiveMsg(g_MsgQueue.front()); // 调用接收消息回调
g_MsgQueue.pop();
}
ResetEvent(g_hEvent);
@@ -34,7 +35,7 @@ void server_EnableReceiveMsg()
RpcExcept(1)
{
ulCode = RpcExceptionCode();
- printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
+ printf("server_EnableReceiveMsg exception 0x%lx = %ld\n", ulCode, ulCode);
}
RpcEndExcept
}
@@ -53,6 +54,67 @@ int server_SendImageMsg(const wchar_t *wxid, const wchar_t *path)
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 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*/)
{
return RPC_S_OK; // Always allow anyone.
@@ -65,8 +127,8 @@ int RpcStartServer(HMODULE hModule)
// remote procedure calls.
status = RpcServerUseProtseqEp(reinterpret_cast((RPC_WSTR)L"ncalrpc"), // Use TCP/IP protocol
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Backlog queue length for TCP/IP.
- reinterpret_cast((RPC_WSTR)L"tmp_endpoint"), // TCP/IP port to use
- NULL // No security
+ reinterpret_cast((RPC_WSTR)L"wcferry"), // TCP/IP port to use
+ NULL // No security
);
if (status)
diff --git a/Spy/spy_types.h b/Spy/spy_types.h
index 3b2ee29..a565153 100644
--- a/Spy/spy_types.h
+++ b/Spy/spy_types.h
@@ -3,7 +3,7 @@
#include "framework.h"
#include
-#include "rpc_types.h"
+#include "rpc_h.h"
typedef struct UserInfoCall {
DWORD wxid;
@@ -19,7 +19,7 @@ typedef struct RecvMsg {
DWORD msgId; // 消息ID地址
DWORD msgXml; // 消息xml内容地址
DWORD roomId; // 群聊时,为群ID;私聊时,为微信ID
- DWORD wxId; // 私聊时,为空;群群时,为发送者微信ID
+ DWORD wxId; // 私聊时,为空;群聊时,为发送者微信ID
DWORD content; // 消息内容地址
} RecvMsg_t;
@@ -29,12 +29,25 @@ typedef struct SendImg {
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 WxCalls {
DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息
DWORD sendTextMsg; // 发送消息
RecvMsg_t recvMsg; // 接收消息
SendImg_t sendImg; // 发送图片
+ Contact_t contact; // 获取联系人
} WxCalls_t;
typedef struct TextStruct {