diff --git a/CWeChatRobot/GetMsgCDN.cpp b/CWeChatRobot/GetMsgCDN.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fecd86364b8c5b9d98e1cb9063272fb9b1f673f --- /dev/null +++ b/CWeChatRobot/GetMsgCDN.cpp @@ -0,0 +1,28 @@ +#include "pch.h" + +wstring GetMsgCND(DWORD pid, ULONG64 msgid) +{ + WeChatProcess hp(pid); + if (!hp.m_init) + return L""; + DWORD GetMsgCDNRemoteAddr = hp.GetProcAddr(GetMsgCDNRemote); + if (GetMsgCDNRemoteAddr == 0) + { + return L""; + } + WeChatData r_msgid(hp.GetHandle(), &msgid, sizeof(ULONG64)); + if (!r_msgid.GetAddr()) + { + return L""; + } + DWORD dwRet = CallRemoteFunction(hp.GetHandle(), GetMsgCDNRemoteAddr, r_msgid.GetAddr()); + if (dwRet == 0) + return L""; + DWORD get_cdn_resp[2] = {0}; + ReadProcessMemory(hp.GetHandle(), (LPVOID)dwRet, &get_cdn_resp, sizeof(get_cdn_resp), 0); + if (!get_cdn_resp[0] || !get_cdn_resp[1]) + return L""; + unique_ptr path_buf = make_unique(get_cdn_resp[1] + 1); + ReadProcessMemory(hp.GetHandle(), (LPVOID)get_cdn_resp[0], path_buf.get(), get_cdn_resp[1] * 2, 0); + return wstring(path_buf.get(), get_cdn_resp[1]); +} diff --git a/CWeChatRobot/ReceiveMessage.h b/CWeChatRobot/ReceiveMessage.h index aa8cd0bc8b45e2b2dc36e1748a39acfeafc124fb..9183fc9399d9624717a482545860a81ab42556fb 100644 --- a/CWeChatRobot/ReceiveMessage.h +++ b/CWeChatRobot/ReceiveMessage.h @@ -1,9 +1,12 @@ #pragma once -#include -BOOL StartReceiveMessage(DWORD pid,int port); +#include +#include +using namespace std; +BOOL StartReceiveMessage(DWORD pid, int port); BOOL StopReceiveMessage(DWORD pid); -BOOL HookImageMsg(DWORD pid,wchar_t* savepath); -BOOL HookVoiceMsg(DWORD pid,wchar_t* savepath); +BOOL HookImageMsg(DWORD pid, wchar_t *savepath); +BOOL HookVoiceMsg(DWORD pid, wchar_t *savepath); void UnHookImageMsg(DWORD pid); -void UnHookVoiceMsg(DWORD pid); \ No newline at end of file +void UnHookVoiceMsg(DWORD pid); +wstring GetMsgCND(DWORD pid, ULONG64 msgid); diff --git a/CWeChatRobot/SendEmotion.cpp b/CWeChatRobot/SendEmotion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9df5ce9b39dae72cebbfee1e85d1728f3c5761b6 --- /dev/null +++ b/CWeChatRobot/SendEmotion.cpp @@ -0,0 +1,32 @@ +#include "pch.h" + +struct SendEmotionStruct +{ + DWORD wxid; + DWORD img_path; +}; + +int SendEmotion(DWORD pid, wchar_t *wxid, wchar_t *img_path) +{ + WeChatProcess hp(pid); + if (!hp.m_init) + return 1; + DWORD SendEmitonRemoteAddr = hp.GetProcAddr(SendEmotionRemote); + if (SendEmitonRemoteAddr == 0) + { + return 1; + } + SendEmotionStruct params = {0}; + WeChatData r_wxid(hp.GetHandle(), wxid, TEXTLENGTH(wxid)); + WeChatData r_img_path(hp.GetHandle(), img_path, TEXTLENGTH(img_path)); + + params.wxid = (DWORD)r_wxid.GetAddr(); + params.img_path = (DWORD)r_img_path.GetAddr(); + WeChatData r_params(hp.GetHandle(), ¶ms, sizeof(params)); + if (!params.wxid || !params.img_path || !r_params.GetAddr()) + { + return 1; + } + DWORD dwRet = CallRemoteFunction(hp.GetHandle(), SendEmitonRemoteAddr, r_params.GetAddr()); + return (dwRet != 1); +} diff --git a/CWeChatRobot/SendEmotion.h b/CWeChatRobot/SendEmotion.h new file mode 100644 index 0000000000000000000000000000000000000000..4249a978394063aad2211bc38f23e46bdf6ff433 --- /dev/null +++ b/CWeChatRobot/SendEmotion.h @@ -0,0 +1,4 @@ +#pragma once +#include + +int SendEmotion(DWORD pid, wchar_t *wxid, wchar_t *img_path); diff --git a/CWeChatRobot/WeChatRobot.cpp b/CWeChatRobot/WeChatRobot.cpp index cdef7186fe30adc66156366789d447299af8e5c4..1a6c125395e5767940714aa70c16719d339d3a0e 100644 --- a/CWeChatRobot/WeChatRobot.cpp +++ b/CWeChatRobot/WeChatRobot.cpp @@ -626,3 +626,27 @@ STDMETHODIMP CWeChatRobot::CGetTransfer(DWORD pid, BSTR wxid, BSTR transcationid *__result = GetTransfer(pid, wxid, transcationid, transferid); return S_OK; } + +/* + * 参数0:目标进程pid + * 参数1:接收人wxid + * 参数2:表情绝对路径 + * 参数3:预返回的值,调用时无需提供 + */ +STDMETHODIMP CWeChatRobot::CSendEmotion(DWORD pid, BSTR wxid, BSTR img_path, int *__result) +{ + *__result = SendEmotion(pid, wxid, img_path); + return S_OK; +} + +/* + * 参数0:目标进程pid + * 参数1:消息id + * 参数2:预返回的值,调用时无需提供 + */ +STDMETHODIMP CWeChatRobot::CGetMsgCDN(DWORD pid, ULONG64 msgid, BSTR *__result) +{ + _bstr_t path = (_bstr_t)GetMsgCND(pid, msgid).c_str(); + *__result = path; + return S_OK; +} diff --git a/CWeChatRobot/WeChatRobot.h b/CWeChatRobot/WeChatRobot.h index f0b730e35dda06d8a68baaaab92d40261370df3b..e8e1025a7f0d7dbe32310ec4ba3967f7ddc9b72a 100644 --- a/CWeChatRobot/WeChatRobot.h +++ b/CWeChatRobot/WeChatRobot.h @@ -91,6 +91,8 @@ public: STDMETHODIMP CSendXmlMsg(DWORD pid, BSTR wxid, BSTR xml, BSTR imgpath, int *__result); STDMETHODIMP CLogout(DWORD pid, int *__result); STDMETHODIMP CGetTransfer(DWORD pid, BSTR wxid, BSTR transcationid, BSTR transferid, int *__result); + STDMETHODIMP CSendEmotion(DWORD pid, BSTR wxid, BSTR img_path, int *__result); + STDMETHODIMP CWeChatRobot::CGetMsgCDN(DWORD pid, ULONG64 msgid, BSTR *__result); }; OBJECT_ENTRY_AUTO(__uuidof(WeChatRobot), CWeChatRobot) diff --git a/CWeChatRobot/WeChatRobotCOM.idl b/CWeChatRobot/WeChatRobotCOM.idl index 8c097ed038c2a4c277492863fd93d832eaaebb60..a8e81454558c46f6c437e6983cdb1b9be73c0919 100644 --- a/CWeChatRobot/WeChatRobotCOM.idl +++ b/CWeChatRobot/WeChatRobotCOM.idl @@ -66,6 +66,8 @@ interface IWeChatRobot : IDispatch [id(51), helpstring("发送xml消息")] HRESULT CSendXmlMsg([in] DWORD pid, [in] BSTR wxid, [in] BSTR xml, [in] BSTR imgpath,[out, retval] int *__result); [id(52), helpstring("退出登录")] HRESULT CLogout([in] DWORD pid,[out, retval] int *__result); [id(53), helpstring("收款")] HRESULT CGetTransfer([in] DWORD pid, [in] BSTR wxid, [in] BSTR transcationid, [in] BSTR transferid, [out, retval] int *__result); + [id(54), helpstring("发送表情")] HRESULT CSendEmotion([in] DWORD pid, [in] BSTR wxid, [in] BSTR img_path, [ out, retval ] int *__result); + [id(55), helpstring("获取CDN")] HRESULT CGetMsgCDN([in] DWORD pid, [in] ULONG64 msgid, [ out, retval ] BSTR *__result); }; [ object, diff --git a/CWeChatRobot/WeChatRobotCOM.vcxproj b/CWeChatRobot/WeChatRobotCOM.vcxproj index ac30117f528a9cb41e5b60253d0bb644f50b8981..ab760c96a7bca4df08c01b95651baad1d81dff32 100644 --- a/CWeChatRobot/WeChatRobotCOM.vcxproj +++ b/CWeChatRobot/WeChatRobotCOM.vcxproj @@ -253,6 +253,7 @@ + @@ -289,6 +290,7 @@ + @@ -311,6 +313,7 @@ + diff --git a/CWeChatRobot/WeChatRobotCOM.vcxproj.filters b/CWeChatRobot/WeChatRobotCOM.vcxproj.filters index db211ef66ab901a6d690c636a0bf3493c194aaee..4f808cb9fc0ac1323b8d73bda5c68add35be3c27 100644 --- a/CWeChatRobot/WeChatRobotCOM.vcxproj.filters +++ b/CWeChatRobot/WeChatRobotCOM.vcxproj.filters @@ -149,6 +149,9 @@ {79bb1058-041b-4bdc-8678-0369c294e570} + + {75c46b26-c4df-4772-862b-839be6a2bf95} + @@ -298,6 +301,9 @@ 未分类\收款 + + 发送消息\发送表情 + @@ -447,6 +453,12 @@ 未分类\收款 + + 发送消息\发送表情 + + + 接收消息 + diff --git a/CWeChatRobot/WeChatRobotCOM_i.h b/CWeChatRobot/WeChatRobotCOM_i.h index 7cca1a4ac9ec138738487b64e8d16b147dd8fe3f..12432f5dc46bd3c664cd41cf204c07aee75d3c57 100644 --- a/CWeChatRobot/WeChatRobotCOM_i.h +++ b/CWeChatRobot/WeChatRobotCOM_i.h @@ -378,6 +378,17 @@ EXTERN_C const IID IID_IWeChatRobot; /* [in] */ BSTR transferid, /* [retval][out] */ int *__result) = 0; + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CSendEmotion( + /* [in] */ DWORD pid, + /* [in] */ BSTR wxid, + /* [in] */ BSTR img_path, + /* [retval][out] */ int *__result) = 0; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CGetMsgCDN( + /* [in] */ DWORD pid, + /* [in] */ ULONG64 msgid, + /* [retval][out] */ BSTR *__result) = 0; + }; @@ -750,6 +761,19 @@ EXTERN_C const IID IID_IWeChatRobot; /* [in] */ BSTR transferid, /* [retval][out] */ int *__result); + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CSendEmotion )( + IWeChatRobot * This, + /* [in] */ DWORD pid, + /* [in] */ BSTR wxid, + /* [in] */ BSTR img_path, + /* [retval][out] */ int *__result); + + /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CGetMsgCDN )( + IWeChatRobot * This, + /* [in] */ DWORD pid, + /* [in] */ ULONG64 msgid, + /* [retval][out] */ BSTR *__result); + END_INTERFACE } IWeChatRobotVtbl; @@ -936,6 +960,12 @@ EXTERN_C const IID IID_IWeChatRobot; #define IWeChatRobot_CGetTransfer(This,pid,wxid,transcationid,transferid,__result) \ ( (This)->lpVtbl -> CGetTransfer(This,pid,wxid,transcationid,transferid,__result) ) +#define IWeChatRobot_CSendEmotion(This,pid,wxid,img_path,__result) \ + ( (This)->lpVtbl -> CSendEmotion(This,pid,wxid,img_path,__result) ) + +#define IWeChatRobot_CGetMsgCDN(This,pid,msgid,__result) \ + ( (This)->lpVtbl -> CGetMsgCDN(This,pid,msgid,__result) ) + #endif /* COBJMACROS */ diff --git a/CWeChatRobot/WeChatRobotCOM_p.c b/CWeChatRobot/WeChatRobotCOM_p.c index 4231a991968567540bc6d1583cc8d169d2bf680c..0174249c2ff28660b706250fa44fb3ff652953f2 100644 --- a/CWeChatRobot/WeChatRobotCOM_p.c +++ b/CWeChatRobot/WeChatRobotCOM_p.c @@ -49,7 +49,7 @@ #include "WeChatRobotCOM_i.h" #define TYPE_FORMAT_STRING_SIZE 1239 -#define PROC_FORMAT_STRING_SIZE 2593 +#define PROC_FORMAT_STRING_SIZE 2695 #define EXPR_FORMAT_STRING_SIZE 1 #define TRANSMIT_AS_TABLE_SIZE 0 #define WIRE_MARSHAL_TABLE_SIZE 2 @@ -2387,17 +2387,17 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor /* 2482 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ - /* Procedure CPostMessage */ + /* Procedure CSendEmotion */ /* 2484 */ 0x33, /* FC_AUTO_HANDLE */ 0x6c, /* Old Flags: object, Oi2 */ /* 2486 */ NdrFcLong( 0x0 ), /* 0 */ -/* 2490 */ NdrFcShort( 0x7 ), /* 7 */ -/* 2492 */ NdrFcShort( 0x20 ), /* x86 Stack size/offset = 32 */ -/* 2494 */ NdrFcShort( 0x20 ), /* 32 */ +/* 2490 */ NdrFcShort( 0x39 ), /* 57 */ +/* 2492 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2494 */ NdrFcShort( 0x8 ), /* 8 */ /* 2496 */ NdrFcShort( 0x24 ), /* 36 */ /* 2498 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ - 0x6, /* 6 */ + 0x5, /* 5 */ /* 2500 */ 0x8, /* 8 */ 0x45, /* Ext Flags: new corr desc, srv corr check, has range on conformance */ /* 2502 */ NdrFcShort( 0x0 ), /* 0 */ @@ -2411,83 +2411,177 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor /* 2512 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ - /* Parameter msgtype */ + /* Parameter wxid */ -/* 2514 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2514 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ /* 2516 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ -/* 2518 */ 0x8, /* FC_LONG */ +/* 2518 */ NdrFcShort( 0x2a ), /* Type Offset=42 */ + + /* Parameter img_path */ + +/* 2520 */ NdrFcShort( 0x8b ), /* Flags: must size, must free, in, by val, */ +/* 2522 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2524 */ NdrFcShort( 0x2a ), /* Type Offset=42 */ + + /* Parameter __result */ + +/* 2526 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2528 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 2530 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Return value */ + +/* 2532 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2534 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2536 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure CGetMsgCDN */ + +/* 2538 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2540 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2544 */ NdrFcShort( 0x3a ), /* 58 */ +/* 2546 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2548 */ NdrFcShort( 0x18 ), /* 24 */ +/* 2550 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2552 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */ + 0x4, /* 4 */ +/* 2554 */ 0x8, /* 8 */ + 0x43, /* Ext Flags: new corr desc, clt corr check, has range on conformance */ +/* 2556 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2558 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2560 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pid */ + +/* 2562 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2564 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2566 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Parameter msgid */ -/* 2520 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ -/* 2522 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ -/* 2524 */ 0xb, /* FC_HYPER */ +/* 2568 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2570 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2572 */ 0xb, /* FC_HYPER */ + 0x0, /* 0 */ + + /* Parameter __result */ + +/* 2574 */ NdrFcShort( 0x2113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=8 */ +/* 2576 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 2578 */ NdrFcShort( 0x4ba ), /* Type Offset=1210 */ + + /* Return value */ + +/* 2580 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2582 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2584 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Procedure CPostMessage */ + +/* 2586 */ 0x33, /* FC_AUTO_HANDLE */ + 0x6c, /* Old Flags: object, Oi2 */ +/* 2588 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2592 */ NdrFcShort( 0x7 ), /* 7 */ +/* 2594 */ NdrFcShort( 0x20 ), /* x86 Stack size/offset = 32 */ +/* 2596 */ NdrFcShort( 0x20 ), /* 32 */ +/* 2598 */ NdrFcShort( 0x24 ), /* 36 */ +/* 2600 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */ + 0x6, /* 6 */ +/* 2602 */ 0x8, /* 8 */ + 0x45, /* Ext Flags: new corr desc, srv corr check, has range on conformance */ +/* 2604 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2606 */ NdrFcShort( 0x1 ), /* 1 */ +/* 2608 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter pid */ + +/* 2610 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2612 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2614 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter msgtype */ + +/* 2616 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2618 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2620 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter msgid */ + +/* 2622 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2624 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2626 */ 0xb, /* FC_HYPER */ 0x0, /* 0 */ /* Parameter msg */ -/* 2526 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ -/* 2528 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ -/* 2530 */ NdrFcShort( 0x4cc ), /* Type Offset=1228 */ +/* 2628 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ +/* 2630 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2632 */ NdrFcShort( 0x4cc ), /* Type Offset=1228 */ /* Parameter __result */ -/* 2532 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ -/* 2534 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ -/* 2536 */ 0x8, /* FC_LONG */ +/* 2634 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2636 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 2638 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Return value */ -/* 2538 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ -/* 2540 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */ -/* 2542 */ 0x8, /* FC_LONG */ +/* 2640 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2642 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */ +/* 2644 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Procedure CRegisterWxPidWithCookie */ -/* 2544 */ 0x33, /* FC_AUTO_HANDLE */ +/* 2646 */ 0x33, /* FC_AUTO_HANDLE */ 0x6c, /* Old Flags: object, Oi2 */ -/* 2546 */ NdrFcLong( 0x0 ), /* 0 */ -/* 2550 */ NdrFcShort( 0x8 ), /* 8 */ -/* 2552 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ -/* 2554 */ NdrFcShort( 0x10 ), /* 16 */ -/* 2556 */ NdrFcShort( 0x24 ), /* 36 */ -/* 2558 */ 0x44, /* Oi2 Flags: has return, has ext, */ +/* 2648 */ NdrFcLong( 0x0 ), /* 0 */ +/* 2652 */ NdrFcShort( 0x8 ), /* 8 */ +/* 2654 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 2656 */ NdrFcShort( 0x10 ), /* 16 */ +/* 2658 */ NdrFcShort( 0x24 ), /* 36 */ +/* 2660 */ 0x44, /* Oi2 Flags: has return, has ext, */ 0x4, /* 4 */ -/* 2560 */ 0x8, /* 8 */ +/* 2662 */ 0x8, /* 8 */ 0x41, /* Ext Flags: new corr desc, has range on conformance */ -/* 2562 */ NdrFcShort( 0x0 ), /* 0 */ -/* 2564 */ NdrFcShort( 0x0 ), /* 0 */ -/* 2566 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2664 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2666 */ NdrFcShort( 0x0 ), /* 0 */ +/* 2668 */ NdrFcShort( 0x0 ), /* 0 */ /* Parameter pid */ -/* 2568 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ -/* 2570 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ -/* 2572 */ 0x8, /* FC_LONG */ +/* 2670 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2672 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 2674 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Parameter cookie */ -/* 2574 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ -/* 2576 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ -/* 2578 */ 0x8, /* FC_LONG */ +/* 2676 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 2678 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 2680 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Parameter __result */ -/* 2580 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ -/* 2582 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ -/* 2584 */ 0x8, /* FC_LONG */ +/* 2682 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 2684 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 2686 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ /* Return value */ -/* 2586 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ -/* 2588 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ -/* 2590 */ 0x8, /* FC_LONG */ +/* 2688 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 2690 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 2692 */ 0x8, /* FC_LONG */ 0x0, /* 0 */ 0x0 @@ -3384,7 +3478,9 @@ static const unsigned short IWeChatRobot_FormatStringOffsetTable[] = 2274, 2322, 2382, - 2424 + 2424, + 2484, + 2538 }; static const MIDL_STUBLESS_PROXY_INFO IWeChatRobot_ProxyInfo = @@ -3408,7 +3504,7 @@ static const MIDL_SERVER_INFO IWeChatRobot_ServerInfo = 0, 0, 0}; -CINTERFACE_PROXY_VTABLE(57) _IWeChatRobotProxyVtbl = +CINTERFACE_PROXY_VTABLE(59) _IWeChatRobotProxyVtbl = { &IWeChatRobot_ProxyInfo, &IID_IWeChatRobot, @@ -3468,7 +3564,9 @@ CINTERFACE_PROXY_VTABLE(57) _IWeChatRobotProxyVtbl = (void *) (INT_PTR) -1 /* IWeChatRobot::CGetA8Key */ , (void *) (INT_PTR) -1 /* IWeChatRobot::CSendXmlMsg */ , (void *) (INT_PTR) -1 /* IWeChatRobot::CLogout */ , - (void *) (INT_PTR) -1 /* IWeChatRobot::CGetTransfer */ + (void *) (INT_PTR) -1 /* IWeChatRobot::CGetTransfer */ , + (void *) (INT_PTR) -1 /* IWeChatRobot::CSendEmotion */ , + (void *) (INT_PTR) -1 /* IWeChatRobot::CGetMsgCDN */ }; @@ -3527,6 +3625,8 @@ static const PRPC_STUB_FUNCTION IWeChatRobot_table[] = NdrStubCall2, NdrStubCall2, NdrStubCall2, + NdrStubCall2, + NdrStubCall2, NdrStubCall2 }; @@ -3534,7 +3634,7 @@ CInterfaceStubVtbl _IWeChatRobotStubVtbl = { &IID_IWeChatRobot, &IWeChatRobot_ServerInfo, - 57, + 59, &IWeChatRobot_table[-3], CStdStubBuffer_DELEGATING_METHODS }; @@ -3550,8 +3650,8 @@ static const unsigned short IRobotEvent_FormatStringOffsetTable[] = (unsigned short) -1, (unsigned short) -1, (unsigned short) -1, - 2484, - 2544 + 2586, + 2646 }; static const MIDL_STUBLESS_PROXY_INFO IRobotEvent_ProxyInfo = diff --git a/CWeChatRobot/robotdata.h b/CWeChatRobot/robotdata.h index 0b62edde714615021d675cc5d516cb117c6e8aae..0e08398be1cf2734767a475b163d8334bb79aac2 100644 --- a/CWeChatRobot/robotdata.h +++ b/CWeChatRobot/robotdata.h @@ -35,11 +35,13 @@ #include "SendXmlMsg.h" #include "Logout.h" #include "GetTransfer.h" +#include "SendEmotion.h" #define DLLNAME L"DWeChatRobot.dll" #define SendTextRemote "SendTextRemote" #define SendImageRemote "SendImageRemote" +#define SendEmotionRemote "SendEmotionRemote" #define SendFileRemote "SendFileRemote" #define SendArticleRemote "SendArticleRemote" #define SendCardRemote "SendCardRemote" @@ -100,3 +102,4 @@ #define LogoutRemote "Logout" #define GetTransferRemote "GetTransferRemote" +#define GetMsgCDNRemote "GetMsgCDNRemote" diff --git a/DWeChatRobot/ChatMsg.cpp b/DWeChatRobot/ChatMsg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..709e86fde2e429a5aef25d5048bdfabc2136add6 --- /dev/null +++ b/DWeChatRobot/ChatMsg.cpp @@ -0,0 +1,46 @@ +#include "pch.h" + +#define ChatMsgHandleOffset 0x5AF6803C - 0x590F0000 +#define GetChatMsgCallOffset 0x59522730 - 0x590F0000 +#define ReleaseChatMsgCallOffset 0x78757780 - 0x786A0000 + +BOOL __stdcall GetChatMsgBySvrId(ULONG64 msgid, PCHAT_MSG p_chat_msg) +{ + int dbIndex = 0; + int localId = GetLocalIdByMsgId(msgid, dbIndex); + if (localId == 0) + return FALSE; + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD ChatMsgHandle = WeChatWinBase + ChatMsgHandleOffset; + DWORD GetChatMsgCall = WeChatWinBase + GetChatMsgCallOffset; + p_chat_msg->handle1 = ChatMsgHandle; + int isSuccess = 0x0; + __asm { + pushad; + pushfd; + push dword ptr [dbIndex]; + mov ecx,dword ptr [p_chat_msg]; + push dword ptr [localId]; + call GetChatMsgCall; + add esp,0x8; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + return (isSuccess == 0x1); +} + +BOOL __stdcall ReleaseChatMsg(PCHAT_MSG p_chat_msg) +{ + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD ReleaseChatMsgCall = WeChatWinBase + ReleaseChatMsgCallOffset; + int isSuccess = 0; + __asm { + pushad; + mov ecx, dword ptr [p_chat_msg]; + call ReleaseChatMsgCall; + popad; + } + return TRUE; +} diff --git a/DWeChatRobot/DWeChatRobot.vcxproj b/DWeChatRobot/DWeChatRobot.vcxproj index 09629f25c2fb85d595e0dd01b442d741742024ba..c84782eeb9103300de97cfae593bfdccddd022fa 100644 --- a/DWeChatRobot/DWeChatRobot.vcxproj +++ b/DWeChatRobot/DWeChatRobot.vcxproj @@ -344,6 +344,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http + @@ -366,6 +367,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http + @@ -373,6 +375,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http + @@ -404,6 +407,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http + diff --git a/DWeChatRobot/DWeChatRobot.vcxproj.filters b/DWeChatRobot/DWeChatRobot.vcxproj.filters index cccb3ce9d5a6a02c666ec263286623ad5bf97272..31b925be8bf2ec956c29ccd19f5d5194fdd2f647 100644 --- a/DWeChatRobot/DWeChatRobot.vcxproj.filters +++ b/DWeChatRobot/DWeChatRobot.vcxproj.filters @@ -148,6 +148,9 @@ {f24eb4af-96d0-41a3-ba1a-799d49f2fb4e} + + {63a49bf5-1537-4fb1-be9a-acecc57ca98c} + @@ -285,6 +288,9 @@ 未分类\收款 + + 发送消息\发送表情 + @@ -425,5 +431,14 @@ 未分类\收款 + + 发送消息\发送表情 + + + 接收消息 + + + 接收消息 + diff --git a/DWeChatRobot/ForwardMessage.cpp b/DWeChatRobot/ForwardMessage.cpp index 9bc76bec67619be54dd541e71bb6a53b402ad756..23b0e72721551eae4ca309e77c72d9c478dda718 100644 --- a/DWeChatRobot/ForwardMessage.cpp +++ b/DWeChatRobot/ForwardMessage.cpp @@ -7,13 +7,13 @@ struct ForwardMessageStruct { wchar_t *wxid; - unsigned long long localId; + unsigned long long msgid; }; BOOL ForwardMessageRemote(LPVOID lpParameter) { ForwardMessageStruct *fms = (ForwardMessageStruct *)lpParameter; - return ForwardMessage(fms->wxid, fms->localId); + return ForwardMessage(fms->wxid, fms->msgid); } #endif diff --git a/DWeChatRobot/GetHistoryPublicMsg.cpp b/DWeChatRobot/GetHistoryPublicMsg.cpp index 80fb2c88596477cd1aed45949ad2ed069f9a7396..a4b4d147c2873e0de8001051da8cdcda1bfd2ff0 100644 --- a/DWeChatRobot/GetHistoryPublicMsg.cpp +++ b/DWeChatRobot/GetHistoryPublicMsg.cpp @@ -148,8 +148,13 @@ BOOL __stdcall GetHistoryPublicMsg(wchar_t *PublicId, wchar_t *Offset) if (!H5ExtBufHooked || isSuccess == 0) return FALSE; return TRUE; } - #ifndef USE_SOCKET +struct GetPublicMsgStruct +{ + wchar_t *PublicId; + wchar_t *Offset; +}; + struct PublicMsgResponseStruct { DWORD buffer = 0; diff --git a/DWeChatRobot/GetMsgCDN.cpp b/DWeChatRobot/GetMsgCDN.cpp new file mode 100644 index 0000000000000000000000000000000000000000..740ecd3139665a61f76abaa411ab3754c1811144 --- /dev/null +++ b/DWeChatRobot/GetMsgCDN.cpp @@ -0,0 +1,276 @@ +#include "pch.h" + +#define WeChatFilePathOffset 0x2385020 +#define DownloadImageCall1Offset 0x591D4010 - 0x590F0000 +#define DownloadImageCall2Offset 0x5951AAE0 - 0x590F0000 + +#define ParserAppXmlCall1Offset 0x588F0C70 - 0x587D0000 +#define ParserAppXmlCall2Offset 0x58E51340 - 0x587D0000 +#define DownloadFileCall1Offset 0x58893B70 - 0x587D0000 +#define DownloadFileCall2Offset 0x58BC7330 - 0x587D0000 + +#define ParserVideoXmlCallOffset 0x59784620 - 0x590F0000 +#define DownloadVideoThumbCallOffset 0x58D3C9B0 - 0x587D0000 +#define DownloadVideoCallOffset 0x58C852F0 - 0x587D0000 + +#define XorKeyOffset 0x5B4569D6 - 0x590F0000 +#define GetWeChatCDNCallOffset 0x58C852F0 - 0x587D0000 + +#define AutoDownloadImageTimeSettingOffset 0x239EC50 +#define ImageAutoPatchOffset 0x48D56B +#define AutoDownloadVideoTimeSettingOffset 0x239EBD8 +#define VideoAutoPatchOffset 0x48CE1B + +static BOOL AutoDownloadTimeSeted = FALSE; + +void __stdcall SetDownloadTime() +{ + if (AutoDownloadTimeSeted) + return; + DWORD WeChatWinBase = GetWeChatWinBase(); + char settime[] = "00:00-00:00"; + DWORD AutoDownloadTimeSettingAddr1 = GetWeChatWinBase() + AutoDownloadImageTimeSettingOffset; + DWORD AutoDownloadTimeSettingAddr2 = GetWeChatWinBase() + AutoDownloadVideoTimeSettingOffset; + WriteProcessMemory(GetCurrentProcess(), (LPVOID)AutoDownloadTimeSettingAddr1, settime, strlen(settime) + 1, 0); + WriteProcessMemory(GetCurrentProcess(), (LPVOID)AutoDownloadTimeSettingAddr2, settime, strlen(settime) + 1, 0); + + BYTE nopVideo[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + DWORD nopVideoAddr = WeChatWinBase + VideoAutoPatchOffset; + WriteProcessMemory(GetCurrentProcess(), (LPVOID)nopVideoAddr, &nopVideo, sizeof(nopVideo), 0); + + BYTE nopImg[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; + DWORD nopImgAddr = WeChatWinBase + ImageAutoPatchOffset; + WriteProcessMemory(GetCurrentProcess(), (LPVOID)nopImgAddr, &nopImg, sizeof(nopImg), 0); + AutoDownloadTimeSeted = TRUE; +} + +static BOOL GetWeChatCDN(CHAT_MSG *chat_msg) +{ + DWORD GetWeChatCDNCall = GetWeChatWinBase() + GetWeChatCDNCallOffset; + int isSuccess = 0x0; + __asm { + pushad; + pushfd; + mov esi,dword ptr[chat_msg]; + push esi; + call GetWeChatCDNCall; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + return (isSuccess == 0x1); +} + +BOOL ParserAppXml(wchar_t *xml, char *xml_buf) +{ + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD ParserAppXmlCall1 = WeChatWinBase + ParserAppXmlCall1Offset; + DWORD ParserAppXmlCall2 = WeChatWinBase + ParserAppXmlCall2Offset; + WxString p_xml(xml); + int isSuccess = 0x0; + __asm { + pushad; + pushfd; + mov ecx,dword ptr [xml_buf]; + call ParserAppXmlCall1; + mov ecx,dword ptr [xml_buf]; + lea eax,p_xml; + push 0x1; + push eax; + call ParserAppXmlCall2; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + return (isSuccess == 0x1); +} + +BOOL ParserVideoXml(wchar_t *xml, char *xml_buf) +{ + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD ParserVideoXmlCall = WeChatWinBase + ParserVideoXmlCallOffset; + string s_xml = unicode_to_utf8(xml).c_str(); + WxStringA p_xml(s_xml); + int isSuccess = 0x0; + __asm { + pushad; + pushfd; + mov ecx,dword ptr [xml_buf]; + lea eax,p_xml; + push eax; + call ParserVideoXmlCall; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + return (isSuccess == 0x1); +} + +wstring GetWeChatFilePath() +{ + DWORD WeChatWinBase = GetWeChatWinBase(); + WxString *wechat_file_path = (WxString *)(WeChatWinBase + 0x2385020); + return wstring(wechat_file_path->buffer, wechat_file_path->length); +} + +wstring __stdcall GetMsgCDN(ULONG64 msgid) +{ + SetDownloadTime(); + wstring robot_base_dir = GetWeChatFilePath() + L"WeChatRobot\\"; + CHAT_MSG chat_msg = {0}; + if (!FindOrCreateDirectory(robot_base_dir.c_str()) || !GetChatMsgBySvrId(msgid, &chat_msg)) + return L""; + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD param[4] = {0}; + param[0] = (DWORD)¶m; + param[1] = (DWORD)¶m; + param[2] = (DWORD)¶m; + param[3] = 0x101; + chat_msg.unknown_ptr2 = ¶m; + int isSuccess = 0x0; + wstring abs_path(robot_base_dir); + switch (chat_msg.type) + { + case 0x3: + { + abs_path += L"Image\\"; + FindOrCreateDirectory(abs_path.c_str()); + abs_path = abs_path + gb2312_to_unicode(to_string(msgid).c_str()) + L".png"; + if (!_waccess(abs_path.c_str(), 0)) + return abs_path; + CHAT_MSG image_msg = {0}; + image_msg.handle1 = chat_msg.handle1; + image_msg.content = chat_msg.content; + image_msg.unknown_ptr2 = chat_msg.unknown_ptr2; + image_msg.file_save_path.buffer = (wchar_t *)abs_path.c_str(); + image_msg.file_save_path.length = abs_path.length(); + image_msg.file_save_path.maxLength = abs_path.length() * 2; + DWORD DownloadImageCall1 = WeChatWinBase + DownloadImageCall1Offset; + DWORD DownloadImageCall2 = WeChatWinBase + DownloadImageCall2Offset; + __asm { + pushad; + pushfd; + call DownloadImageCall1; + push 0x0; + push 0x0; + push 0x1; + lea ecx,image_msg; + push ecx; + mov ecx,eax; + call DownloadImageCall2; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + break; + } + case 0x2B: + { + abs_path += L"Video\\"; + FindOrCreateDirectory(abs_path.c_str()); + unique_ptr xml_data = make_unique(0x680); + char *xml_buf = xml_data.get(); + if (!ParserVideoXml(chat_msg.content.buffer, xml_buf)) + return L""; + DWORD DownloadVideoThumbCall = WeChatWinBase + DownloadVideoThumbCallOffset; + DWORD DownloadVideoCall = WeChatWinBase + DownloadVideoCallOffset; + wstring thumbnail_path = abs_path + gb2312_to_unicode(to_string(msgid).c_str()) + L".jpg"; + abs_path = abs_path + gb2312_to_unicode(to_string(msgid).c_str()) + L".mp4"; + if (!_waccess(abs_path.c_str(), 0)) + return abs_path; + chat_msg.file_save_path.buffer = (wchar_t *)abs_path.c_str(); + chat_msg.file_save_path.length = abs_path.length(); + chat_msg.file_save_path.maxLength = abs_path.length() * 2; + chat_msg.thumbnail.buffer = (wchar_t *)thumbnail_path.c_str(); + chat_msg.thumbnail.length = thumbnail_path.length(); + chat_msg.thumbnail.maxLength = thumbnail_path.length() * 2; + DWORD param[20] = {0}; + param[17] = 0x1FFF; + __asm { + pushad; + pushfd; + mov eax,dword ptr [xml_buf]; + push eax; + lea eax,chat_msg; + push eax; + lea eax,param; + push eax; + call DownloadVideoThumbCall; + lea esi,chat_msg; + push esi; + call DownloadVideoCall; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + break; + } + case 0x31: + { + abs_path += L"Files\\"; + FindOrCreateDirectory(abs_path.c_str()); + unique_ptr xml_data = make_unique(0xC48); + char *xml_buf = xml_data.get(); + if (!ParserAppXml(chat_msg.content.buffer, xml_buf)) + return L""; + DWORD DownloadFileCall1 = WeChatWinBase + DownloadFileCall1Offset; + DWORD DownloadFileCall2 = WeChatWinBase + DownloadFileCall2Offset; + WxString *filename = (WxString *)((DWORD)xml_buf + 0x44); + abs_path = abs_path + gb2312_to_unicode(to_string(msgid).c_str()) + L"_" + wstring(filename->buffer, filename->length); + if (!_waccess(abs_path.c_str(), 0)) + return abs_path; + chat_msg.file_save_path.buffer = (wchar_t *)abs_path.c_str(); + chat_msg.file_save_path.length = abs_path.length(); + chat_msg.file_save_path.maxLength = abs_path.length() * 2; + __asm { + pushad; + pushfd; + call DownloadFileCall1; + mov ecx,dword ptr [xml_buf]; + push ecx; + lea ecx,chat_msg; + push ecx; + mov ecx,eax; + call DownloadFileCall2; + xor al,0x1; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + break; + } + default: + break; + } + return (isSuccess == 0x1) ? abs_path : L""; +} + +#ifndef USE_SOCKET +struct GetMsgCDNRespStruct +{ + wchar_t *path = NULL; + int length = 0; +} cdn_resp; + +DWORD GetMsgCDNRemote(ULONG64 *p_msgid) +{ + if (cdn_resp.length != 0) + { + delete[] cdn_resp.path; + cdn_resp.length = 0; + } + wstring cdn_path = GetMsgCDN(*p_msgid); + if (cdn_path.length() == 0) + return 0; + cdn_resp.path = new wchar_t[cdn_path.length() + 1](); + cdn_resp.length = cdn_path.length(); + memcpy(cdn_resp.path, cdn_path.c_str(), cdn_path.length() * 2); + return (DWORD)&cdn_resp; +} +#endif diff --git a/DWeChatRobot/HookImageMessage.cpp b/DWeChatRobot/HookImageMessage.cpp index 876487a3eab88eaf2664935f2fe5fee666f01a37..2bb94c2c8176be902f0907c248de640984132ee9 100644 --- a/DWeChatRobot/HookImageMessage.cpp +++ b/DWeChatRobot/HookImageMessage.cpp @@ -2,13 +2,11 @@ #define HookImageMsgAddrOffset 0x10732D26 - 0x10000000 #define HookImageMsgNextCallOffset 0x10732160 - 0x10000000 -#define AutoDownloadTimeSettingOffset 0x239EC50 BOOL ImageMsgHooked = false; -static DWORD WeChatWinBase = GetWeChatWinBase(); -static DWORD HookImageMsgAddr = WeChatWinBase + HookImageMsgAddrOffset; -static DWORD HookImageMsgNextCall = WeChatWinBase + HookImageMsgNextCallOffset; -static DWORD HookImageMsgJmpBackAddr = HookImageMsgAddr + 0x5; +static DWORD HookImageMsgAddr = 0; +static DWORD HookImageMsgNextCall = 0; +static DWORD HookImageMsgJmpBackAddr = 0; static char ImageMsgOldAsm[5] = {0}; static wstring global_save_path = L""; @@ -82,27 +80,14 @@ __declspec(naked) void dealImageMsg() void __stdcall HookImageMsg() { - WeChatWinBase = GetWeChatWinBase(); + DWORD WeChatWinBase = GetWeChatWinBase(); if (ImageMsgHooked || !WeChatWinBase) return; + SetDownloadTime(); HookImageMsgAddr = WeChatWinBase + HookImageMsgAddrOffset; HookImageMsgNextCall = WeChatWinBase + HookImageMsgNextCallOffset; HookImageMsgJmpBackAddr = HookImageMsgAddr + 0x5; HookAnyAddress(HookImageMsgAddr, dealImageMsg, ImageMsgOldAsm); - char settime[] = "00:00-00:00"; - DWORD AutoDownloadTimeSettingAddr = GetWeChatWinBase() + AutoDownloadTimeSettingOffset; - WriteProcessMemory(GetCurrentProcess(), (LPVOID)AutoDownloadTimeSettingAddr, settime, strlen(settime) + 1, 0); - - // video auto - BYTE nopVideo[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - DWORD nopVideoAddr = WeChatWinBase + 0x48CE1B; - WriteProcessMemory(GetCurrentProcess(), (LPVOID)nopVideoAddr, &nopVideo, sizeof(nopVideo), 0); - - // image auto - BYTE nopImg[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; - DWORD nopImgAddr = WeChatWinBase + 0x48D56B; - WriteProcessMemory(GetCurrentProcess(), (LPVOID)nopImgAddr, &nopImg, sizeof(nopImg), 0); - ImageMsgHooked = true; } @@ -122,8 +107,7 @@ BOOL HookImageMsgRemote(LPVOID lpParameter) { global_save_path += L"\\"; } - wstring createpath = global_save_path.substr(0, global_save_path.length() - 1); - if (!FindOrCreateDirectory(createpath.c_str())) + if (!FindOrCreateDirectory(global_save_path.c_str())) { return false; } diff --git a/DWeChatRobot/HookVoiceMessage.cpp b/DWeChatRobot/HookVoiceMessage.cpp index 8161fab31f4d1cf527ed3856b78384124c84d730..7efd83a094c7530e8cef8a3f37fcd8f7d82a11c2 100644 --- a/DWeChatRobot/HookVoiceMessage.cpp +++ b/DWeChatRobot/HookVoiceMessage.cpp @@ -66,6 +66,7 @@ void __stdcall HookVoiceMsg() WeChatWinBase = GetWeChatWinBase(); if (VoiceMsgHooked || !WeChatWinBase) return; + SetDownloadTime(); HookVoiceMsgAddr = WeChatWinBase + HookVoiceMsgAddrOffset; HookVoiceMsgNextCall = WeChatWinBase + HookVoiceMsgNextCallOffset; HookVoiceMsgJmpBackAddr = HookVoiceMsgAddr + 0x5; @@ -89,8 +90,7 @@ BOOL HookVoiceMsgRemote(LPVOID lpParameter) { global_save_path += L"\\"; } - wstring createpath = global_save_path.substr(0, global_save_path.length() - 1); - if (!FindOrCreateDirectory(createpath.c_str())) + if (!FindOrCreateDirectory(global_save_path.c_str())) { return false; } diff --git a/DWeChatRobot/ReceiveMessage.cpp b/DWeChatRobot/ReceiveMessage.cpp index 90c2d2c730f875e30cce74225a8c61c3fbfcecb9..d3618bda8c92d010920e25f6336d21d1363780b0 100644 --- a/DWeChatRobot/ReceiveMessage.cpp +++ b/DWeChatRobot/ReceiveMessage.cpp @@ -335,6 +335,7 @@ VOID HookReceiveMessage(int port) WeChatWinBase = GetWeChatWinBase(); if (ReceiveMessageHooked || !WeChatWinBase) return; + SetDownloadTime(); ReceiveMessageHookAddress = WeChatWinBase + ReceiveMessageHookOffset; ReceiveMessageNextCall = WeChatWinBase + ReceiveMessageNextCallOffset; ReceiveMessageJmpBackAddress = ReceiveMessageHookAddress + 0x5; diff --git a/DWeChatRobot/ReceiveMessage.h b/DWeChatRobot/ReceiveMessage.h index 35fb7a114d543860bd294ba550dbbcc98c974f26..08561a7d9f51339a01f5a1553b36f6112e069526 100644 --- a/DWeChatRobot/ReceiveMessage.h +++ b/DWeChatRobot/ReceiveMessage.h @@ -1,5 +1,6 @@ #pragma once #include +#include "wxdata.h" #ifndef USE_SOCKET extern "C" __declspec(dllexport) VOID HookReceiveMessage(int port); extern "C" __declspec(dllexport) VOID UnHookReceiveMessage(); @@ -7,6 +8,7 @@ extern "C" __declspec(dllexport) void UnHookVoiceMsg(); extern "C" __declspec(dllexport) BOOL HookVoiceMsgRemote(LPVOID lpParameter); extern "C" __declspec(dllexport) void UnHookImageMsg(); extern "C" __declspec(dllexport) BOOL HookImageMsgRemote(LPVOID lpParameter); +extern "C" __declspec(dllexport) DWORD GetMsgCDNRemote(ULONG64 *p_msgid); #else VOID HookReceiveMessage(int port); VOID UnHookReceiveMessage(); @@ -18,6 +20,10 @@ BOOL __stdcall HookImageMsg(wstring save_path); void __stdcall HookVoiceMsg(); void __stdcall HookImageMsg(); +BOOL __stdcall GetChatMsgBySvrId(ULONG64 msgid, PCHAT_MSG p_chat_msg); +BOOL __stdcall ReleaseChatMsg(PCHAT_MSG p_chat_msg); +wstring __stdcall GetMsgCDN(ULONG64 msgid); +void __stdcall SetDownloadTime(); typedef enum MSG_SOURCE_TYPETag { diff --git a/DWeChatRobot/SendEmotion.cpp b/DWeChatRobot/SendEmotion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74d688b350c0b98f12752cff390a7c901ec934a0 --- /dev/null +++ b/DWeChatRobot/SendEmotion.cpp @@ -0,0 +1,70 @@ +#include "pch.h" + +#define SendEmotionCall1Offset 0x5FEC1980 - 0x5F750000 +#define SendEmotionCall2Offset 0x5FBC77E0 - 0x5F750000 +#define SendEmotionHandleOffset 0x61AEE888 - 0x5F750000 + +#ifndef USE_SOCKET +struct SendEmotionStruct +{ + wchar_t *wxid; + wchar_t *img_path; +}; +BOOL SendEmotionRemote(LPVOID lparameter) +{ + SendEmotionStruct *ses = (SendEmotionStruct *)lparameter; + BOOL status = SendEmotion(ses->wxid, ses->img_path); + return status; +} +#endif + +BOOL __stdcall SendEmotion(wchar_t *wxid, wchar_t *img_path) +{ + DWORD WeChatWinBase = GetWeChatWinBase(); + DWORD SendEmotionCall1 = WeChatWinBase + SendEmotionCall1Offset; + DWORD SendEmotionCall2 = WeChatWinBase + SendEmotionCall2Offset; + DWORD SendEmotionHandle = WeChatWinBase + SendEmotionHandleOffset; + WxString p_wxid(wxid), p_img_path(img_path), p_null(NULL); + char buf[0x1C] = {0}; + int isSuccess = 0x0; + __asm { + pushad; + pushfd; + mov ebx,dword ptr[SendEmotionHandle]; + lea eax,buf; + push eax; + push 0x0; + sub esp,0x14; + mov esi,esp; + mov dword ptr [esi], 0x0; + mov dword ptr [esi+0x4], 0x0; + mov dword ptr [esi+0x8], 0x0; + mov dword ptr [esi+0xC], 0x0; + mov dword ptr [esi+0x10], 0x0; + push 0x2; + lea eax,p_wxid; + sub esp,0x14; + mov ecx,esp; + push eax; + call SendEmotionCall1; + sub esp,0x14; + mov esi,esp; + mov dword ptr [esi], 0x0; + mov dword ptr [esi+0x4], 0x0; + mov dword ptr [esi+0x8], 0x0; + mov dword ptr [esi+0xC], 0x0; + mov dword ptr [esi+0x10], 0x0; + sub esp,0x14; + mov ecx,esp; + lea eax,p_img_path; + push eax; + call SendEmotionCall1; + mov ecx,ebx; + call SendEmotionCall2; + movzx eax,al; + mov isSuccess,eax; + popfd; + popad; + } + return (isSuccess == 0x1); +} diff --git a/DWeChatRobot/SendEmotion.h b/DWeChatRobot/SendEmotion.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef00aad777953873dac313849d3bbd2226024fb --- /dev/null +++ b/DWeChatRobot/SendEmotion.h @@ -0,0 +1,8 @@ +#pragma once +#include + +BOOL __stdcall SendEmotion(wchar_t *wxid, wchar_t *img_path); + +#ifndef USE_SOCKET +extern "C" __declspec(dllexport) BOOL SendEmotionRemote(LPVOID lparameter); +#endif diff --git a/DWeChatRobot/http_overload.hpp b/DWeChatRobot/http_overload.hpp index 933bf53e00673fbef6e3b4fd2c06360027d642b0..c05af30b31d2c3e2ac5a9a776062341e037d7c8e 100644 --- a/DWeChatRobot/http_overload.hpp +++ b/DWeChatRobot/http_overload.hpp @@ -148,4 +148,9 @@ BOOL __stdcall GetTransfer(wstring wxid, wstring transcationid, wstring transfer { return GetTransfer(WS2LW(wxid), WS2LW(transcationid), WS2LW(transferid)); } + +BOOL __stdcall SendEmotion(wstring wxid, wstring img_path) +{ + return SendEmotion(WS2LW(wxid), WS2LW(img_path)); +} #endif diff --git a/DWeChatRobot/pch.cpp b/DWeChatRobot/pch.cpp index 465bbd0175c7e7b66b3426f8582341ca9701b083..e036f182c9ffaf55155aee8b3045359b35e78ec8 100644 --- a/DWeChatRobot/pch.cpp +++ b/DWeChatRobot/pch.cpp @@ -1,6 +1,7 @@ // pch.cpp: 与预编译标头对应的源文件 #include "pch.h" +#include "io.h" #include // 当使用预编译的头时,需要使用此源文件,编译才能成功。 @@ -37,19 +38,15 @@ DWORD GetWeChatWinBase() BOOL FindOrCreateDirectory(const wchar_t *pszPath) { - WIN32_FIND_DATA fd; - HANDLE hFind = ::FindFirstFile(pszPath, &fd); - if (hFind != INVALID_HANDLE_VALUE) + string dir = unicode_to_gb2312((wchar_t *)pszPath); + char last_char = dir.back(); + if (last_char != '\\') { - FindClose(hFind); - return true; + dir += '\\'; } - - if (!::CreateDirectory(pszPath, NULL)) - { - return false; - } - return true; + if (!_access(dir.c_str(), 0)) + return true; + return MakeSureDirectoryPathExists(dir.c_str()); } /* diff --git a/DWeChatRobot/pch.h b/DWeChatRobot/pch.h index 8682bf3fda94d6009a0555d3eec516a300582127..96cd7c26d5a52918ee4e22e6ebb08a1356e1b865 100644 --- a/DWeChatRobot/pch.h +++ b/DWeChatRobot/pch.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "wxdata.h" #include "wxapi.h" diff --git a/DWeChatRobot/wxapi.h b/DWeChatRobot/wxapi.h index cd3b7cf80841e446d0f1b7881148c3321814c457..59efa7d936df9a507be8bd1ab4210c511577799a 100644 --- a/DWeChatRobot/wxapi.h +++ b/DWeChatRobot/wxapi.h @@ -37,6 +37,7 @@ #include "GetA8Key.h" #include "Logout.h" #include "GetTransfer.h" +#include "SendEmotion.h" using namespace std; #pragma comment(lib, "version.lib") diff --git a/DWeChatRobot/wxdata.h b/DWeChatRobot/wxdata.h index 1bd03ee5427088ab154ed6127e81bd4b924e6434..3572fb1d2fbe34f9fae92272d430f6e7afdd0672 100644 --- a/DWeChatRobot/wxdata.h +++ b/DWeChatRobot/wxdata.h @@ -14,34 +14,33 @@ using namespace std; * fill2ռλԱ2ĬΪ0 * WxStringĬϹ캯 */ -struct WxString +typedef struct WxStringW { - wchar_t *buffer; - DWORD length; - DWORD maxLength; + wchar_t *buffer = NULL; + DWORD length = 0; + DWORD maxLength = 0; DWORD fill1 = 0; DWORD fill2 = 0; - WxString() - { - WxString(NULL); - } - WxString(wstring &str) + WxStringW() {} + WxStringW(wstring &str) { buffer = (wchar_t *)str.c_str(); length = str.length(); maxLength = str.length() * 2; } - WxString(const wchar_t *pStr) + WxStringW(const wchar_t *pStr) { - WxString((wchar_t *)pStr); + buffer = (wchar_t *)pStr; + length = wcslen(pStr); + maxLength = wcslen(pStr) * 2; } - WxString(int tmp) + WxStringW(int tmp) { buffer = NULL; length = 0x0; maxLength = 0x0; } - WxString(wchar_t *pStr) + WxStringW(wchar_t *pStr) { buffer = pStr; length = wcslen(pStr); @@ -53,7 +52,7 @@ struct WxString length = wcslen(pStr); maxLength = wcslen(pStr) * 2; } -}; +} WxString; /* * 浥ϢĽṹ @@ -184,8 +183,97 @@ struct WxFriendStruct } }; -struct GetPublicMsgStruct +typedef struct CHAT_MSGTag +{ + DWORD handle1 = 0; + DWORD null_value1 = 0; + ULONG64 sequence = 0x0; + DWORD null_value2[2] = {0}; + ULONG64 msgsequence = 0x0; + DWORD localId = 0; + DWORD null_value3[3] = {0}; + ULONG64 msgid = 0x0; + DWORD type = 0x1; + DWORD isSendMsg = 0x1; + DWORD unknown_value1 = 0x2; + DWORD create_time = 0x0; + WxString takler = {0}; + WxString null_string1 = {0}; + WxString content = {0}; + DWORD null_value4[2] = {0}; + DWORD extrabuf = 0; + DWORD extrabuf_len = 0; + DWORD null_value5[17] = {0}; + BOOL isSyncMsg = 0x1; + DWORD null_value6[21] = {0}; + DWORD handle2 = 0; + DWORD handle3 = 0; + void *unknown_ptr1 = NULL; + DWORD null_value7[13] = {0}; + WxString chatroom_member = {0}; + WxString md5 = {0}; + WxString thumbnail = {0}; + WxString file_save_path = {0}; + DWORD null_value8[11] = {0}; + WxString extra_info = {0}; + DWORD null_value9[16] = {0}; + DWORD unknown_value2 = 0x1; + DWORD unknown_value3 = 0x1; + DWORD null_value10[7] = {0}; + DWORD unknown_value4 = 0x1; + DWORD null_value11 = 0; + DWORD unknown_value5 = 0xFF; + DWORD unknown_value6 = 0x1; + DWORD null_value12[6] = {0}; + void *unknown_ptr2 = NULL; + DWORD null_value13[2] = {0}; +} CHAT_MSG, *PCHAT_MSG; + +struct WxStringA { - wchar_t *PublicId; - wchar_t *Offset; + char buffer[0x10] = {0}; + int length; + int maxLength; + WxStringA(string &str) + { + this->length = str.length(); + this->maxLength = this->length - (this->length % 0x10) + 0xF; + if (this->length == 0) + { + *(DWORD *)this->buffer = 0; + } + else if (this->length < 0x10) + { + memcpy(this->buffer, str.c_str(), this->length + 1); + } + else + { + *(DWORD *)this->buffer = (DWORD)str.c_str(); + } + } + WxStringA(const char *buf) + { + this->length = strlen(buf); + this->maxLength = this->length - (this->length % 0x10) + 0xF; + if (this->length == 0) + { + *(DWORD *)this->buffer = 0; + } + else if (this->length < 0x10) + { + memcpy(this->buffer, buf, this->length + 1); + } + else + { + *(DWORD *)this->buffer = (DWORD)buf; + } + } + char *get() + { + if (this->length < 0x10) + { + return this->buffer; + } + return (char *)(*(DWORD *)this->buffer); + } }; diff --git a/DWeChatRobot/wxsocket.cpp b/DWeChatRobot/wxsocket.cpp index db0dc238109f420b2d9bfd070f3a1299e8c6ed66..80854365d9825838e8434c5a18786a22dadd973b 100644 --- a/DWeChatRobot/wxsocket.cpp +++ b/DWeChatRobot/wxsocket.cpp @@ -632,6 +632,31 @@ void request_event(mg_http_message *hm, string &ret, struct mg_connection *c) ret = ret_data.dump(); break; } + case WECHAT_MSG_SEND_EMOTION: + { + wstring wxid = get_http_param_str(hm, jData, "wxid", method); + wstring img_path = get_http_param_str(hm, jData, "img_path", method); + BOOL status = SendEmotion(wxid, img_path); + json ret_data = {{"msg", status}, {"result", "OK"}}; + ret = ret_data.dump(); + break; + } + case WECHAT_GET_CDN: + { + ULONG64 msgid = get_http_param_ulong64(hm, jData, "msgid", method); + wstring cdn_path = GetMsgCDN(msgid); + if (cdn_path == L"") + { + json ret_data = {{"msg", 0}, {"result", "OK"}}; + ret = ret_data.dump(); + } + else + { + json ret_data = {{"msg", 1}, {"result", "OK"}, {"path", unicode_to_utf8(WS2LW(cdn_path))}}; + ret = ret_data.dump(); + } + break; + } default: // char* wxid = mg_json_get_str(hm->body, "$.wxid"); break; diff --git a/DWeChatRobot/wxsocketapi.h b/DWeChatRobot/wxsocketapi.h index ab3e230d348436ef2d1ca8c71f18ada496e14048..50189e7d4b59dd320c7f6eee5e159e2f5df3b14e 100644 --- a/DWeChatRobot/wxsocketapi.h +++ b/DWeChatRobot/wxsocketapi.h @@ -77,6 +77,8 @@ typedef enum WECHAT_HTTP_APISTag WECHAT_MSG_SEND_XML, WECHAT_LOGOUT, WECHAT_GET_TRANSFER, + WECHAT_MSG_SEND_EMOTION, + WECHAT_GET_CDN, } WECHAT_HTTP_APIS, *PWECHAT_HTTP_APIS; #endif diff --git a/Python/com/wxRobot.py b/Python/com/wxRobot.py index 6c9aec2f90ca67d25a319716be252f64da617f24..dc23124f3450fcb9954580c5bf913fe72d9d6f11 100644 --- a/Python/com/wxRobot.py +++ b/Python/com/wxRobot.py @@ -8,6 +8,7 @@ Created on Thu Feb 24 16:19:48 2022 # Before use,execute `CWeChatRobot.exe /regserver` in cmd by admin user import os import ctypes +import time import json import ctypes.wintypes import socketserver @@ -1150,6 +1151,46 @@ class WeChatRobot: """ return self.robot.CGetTransfer(self.pid,wxid,transcationid,transferid) + def SendEmotion(self, wxid: str, img_path: str) -> int: + """ + 发送图片消息 + + Parameters + ---------- + wxid : str + 消息接收者wxid. + img_path : str + 图片绝对路径. + + Returns + ------- + int + 0成功,非0失败. + + """ + return self.robot.CSendEmotion(self.pid, wxid, img_path) + + def GetMsgCDN(self,msgid: int) -> str: + """ + 下载图片、视频、文件 + + Parameters + ---------- + msgid : int + msgid. + + Returns + ------- + str + 成功返回文件路径,失败返回空字符串. + + """ + path = self.robot.CGetMsgCDN(self.pid,msgid) + if path != "": + while not os.path.exists(path): + time.sleep(0.5) + return path + def get_wechat_pid_list() -> list: """ diff --git a/Python/http/wxDriver.py b/Python/http/wxDriver.py index c9d3bc0e2a2e9f2bc5675c0f26a160e92bafe47f..5db769f64256e20837a1f92c97d3a4500c46ee4a 100644 --- a/Python/http/wxDriver.py +++ b/Python/http/wxDriver.py @@ -89,6 +89,8 @@ class WECHAT_HTTP_APIS: WECHAT_MSG_SEND_XML = 43 # 发送xml消息 WECHAT_LOGOUT = 44 # 退出登录 WECHAT_GET_TRANSFER = 45 # 收款 + WECHAT_MSG_SEND_EMOTION = 46 # 发送表情 + WECHAT_GET_CDN = 47 # 下载文件、视频、图片 APIS = WECHAT_HTTP_APIS @@ -197,7 +199,9 @@ class WECHAT_HTTP_API_PARAM_TEMPLATES: APIS.WECHAT_GET_A8KEY: {"url":""}, APIS.WECHAT_MSG_SEND_XML: {"wxid":"filehelper","xml":"","img_path":""}, APIS.WECHAT_LOGOUT: {}, - APIS.WECHAT_GET_TRANSFER: {"wxid":"","transcationid":"","transferid":""} + APIS.WECHAT_GET_TRANSFER: {"wxid":"","transcationid":"","transferid":""}, + APIS.WECHAT_MSG_SEND_EMOTION: {"wxid":"","img_path":""}, + APIS.WECHAT_GET_CDN: {"msgid":2 ** 64 - 1}, } def get_http_template(self, api_number): diff --git a/README.md b/README.md index f079829431afec3734f6d14557827bd1911f3a32..5e274988f9e8a17d577acde00c661cdc7b4758db 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,10 @@ PC微信机器人,实现以下功能: `./DWeChatRobot`:注入的DLL实现代码,根据平台配置可编译出socket版和COM版 `./old_projects`: 包含C#的调用示例以及3.7.0.26版本的E语言调用 `./Python`:python示例和接口测试文件 -`./wxDriver`:driver的实现代码,有些函数具有一定的学习意义 -`./Release/CWeChatRobot.exe`:编译的COM组件 -`./Release/DWeChatRobot.dll`:编译的DLL文件 -`./Release/socket`:包含wxDriver.dll和socket接口的DLL -`./Release/WeChatTools.exe`:用于调试时注入或卸载DLL程序,具体参阅相关代码 +`./wxDriver`:driver的实现代码 + +下载二进制文件请到:[Release](https://github.com/ljc545w/ComWeChatRobot/releases) + # 快速启动 以管理员权限执行以下命令: ```shell @@ -159,6 +158,10 @@ CWeChatRobot.exe /unregserver 1. 新增收款接口 2. 实时消息接口优化,支持获取音视频聊天信息,支持获取手机端切换联系人时的提示信息 3. 修复部分已知问题 +## 2022.11.2 +1. 支持发送动态表情 +2. 支持夜间自动下载视频(需开启一次实时消息监听) +3. 新增通过消息id下载消息附件功能 # 打赏作者 请给作者一个star,感谢感谢