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 {