提交 60789bf1 编写于 作者: L ljc545w

修复部分已知bug,新增获取二维码功能

上级 e5eb8671
......@@ -3,10 +3,10 @@
struct ForwardMessageStruct
{
DWORD wxid;
DWORD localId;
ULONG64 msgid;
};
BOOL ForwardMessage(DWORD pid, wchar_t *wxid, int localId)
BOOL ForwardMessage(DWORD pid, wchar_t *wxid, ULONG64 msgid)
{
WeChatProcess hp(pid);
if (!hp.m_init)
......@@ -19,7 +19,7 @@ BOOL ForwardMessage(DWORD pid, wchar_t *wxid, int localId)
ForwardMessageStruct params = {0};
WeChatData<wchar_t *> r_wxid(hp.GetHandle(), wxid, TEXTLENGTH(wxid));
params.wxid = (DWORD)r_wxid.GetAddr();
params.localId = localId;
params.msgid = msgid;
WeChatData<ForwardMessageStruct *> r_params(hp.GetHandle(), &params, sizeof(params));
if (!params.wxid || !r_params.GetAddr())
{
......
#pragma once
#include <windows.h>
BOOL ForwardMessage(DWORD pid, wchar_t *wxid, int localId);
BOOL ForwardMessage(DWORD pid, wchar_t *wxid, ULONG64 msgid);
#include "pch.h"
VARIANT GetQrcodeImage(DWORD pid)
{
VARIANT vsa;
vsa.vt = VT_ARRAY | VT_UI1;
V_ARRAY(&vsa) = NULL;
WeChatProcess hp(pid);
if (!hp.m_init)
return vsa;
DWORD GetQrcodeImageAddr = hp.GetProcAddr(GetQrcodeImageRemote);
DWORD ret = CallRemoteFunction(hp.GetHandle(), GetQrcodeImageAddr, NULL);
if (ret == 0)
return vsa;
DWORD ret_info[2] = {0};
ReadProcessMemory(hp.GetHandle(), (LPCVOID)ret, &ret_info, sizeof(ret_info), 0);
DWORD buf_addr = ret_info[0];
int size = ret_info[1];
if (size == 0 || buf_addr == 0)
return vsa;
unique_ptr<BYTE[]> image(new BYTE[size + 1]());
ReadProcessMemory(hp.GetHandle(), (LPCVOID)buf_addr, image.get(), size, 0);
SAFEARRAYBOUND rgsaBound = {(ULONG)size, 0};
SAFEARRAY *psaValue = SafeArrayCreate(VT_UI1, 1, &rgsaBound);
BYTE *buf = NULL;
::SafeArrayAccessData(psaValue, (void **)&buf);
memcpy(buf, image.get(), size);
::SafeArrayUnaccessData(psaValue);
V_ARRAY(&vsa) = psaValue;
return vsa;
}
#pragma once
#include <windows.h>
VARIANT GetQrcodeImage(DWORD pid);
......@@ -558,8 +558,24 @@ STDMETHODIMP CWeChatRobot::CGetHistoryPublicMsg(DWORD pid, BSTR PublicId, BSTR O
return S_OK;
}
STDMETHODIMP CWeChatRobot::CForwardMessage(DWORD pid, BSTR wxid, int localId, int *__result)
/*
* 参数0:目标进程pid
* 参数1:消息接收人wxid
* 参数2:要转发的消息id
* 参数3:预返回的值,调用时无需提供
*/
STDMETHODIMP CWeChatRobot::CForwardMessage(DWORD pid, BSTR wxid, ULONG64 msgid, int *__result)
{
*__result = ForwardMessage(pid, wxid, msgid);
return S_OK;
}
/*
* 参数0:目标进程pid
* 参数1:预返回的值,调用时无需提供
*/
STDMETHODIMP CWeChatRobot::CGetQrcodeImage(DWORD pid, VARIANT *__result)
{
*__result = ForwardMessage(pid, wxid, localId);
*__result = GetQrcodeImage(pid);
return S_OK;
}
......@@ -85,7 +85,8 @@ public:
STDMETHODIMP CAddChatRoomMember(DWORD pid, BSTR chatroomid, VARIANT *wxids, int *__result);
STDMETHODIMP COpenBrowser(DWORD pid, BSTR url, int *__result);
STDMETHODIMP CGetHistoryPublicMsg(DWORD pid, BSTR PublicId, BSTR Offset, VARIANT *__result);
STDMETHODIMP CForwardMessage(DWORD pid, BSTR wxid, int localId, int *__result);
STDMETHODIMP CForwardMessage(DWORD pid, BSTR wxid, ULONG64 msgid, int *__result);
STDMETHODIMP CGetQrcodeImage(DWORD pid, VARIANT *__result);
};
OBJECT_ENTRY_AUTO(__uuidof(WeChatRobot), CWeChatRobot)
......@@ -60,7 +60,8 @@ interface IWeChatRobot : IDispatch
[id(45), helpstring("添加群成员")] HRESULT CAddChatRoomMember([in] DWORD pid, [in] BSTR chatroomid, [in] VARIANT* wxids, [out, retval] int* __result);
[id(46), helpstring("打开微信内置浏览器")] HRESULT COpenBrowser([in] DWORD pid, [in] BSTR url, [ out, retval ] int *__result);
[id(47), helpstring("获取公众号历史消息")] HRESULT CGetHistoryPublicMsg([in] DWORD pid, [in] BSTR PublicId, [in] BSTR Offset, [out, retval] VARIANT * __result);
[id(48), helpstring("转发消息") ] HRESULT CForwardMessage([in] DWORD pid, [in] BSTR wxid, [in] int localId, [out, retval] int * __result);
[id(48), helpstring("转发消息") ] HRESULT CForwardMessage([in] DWORD pid, [in] BSTR wxid, [in] unsigned long long localId, [out, retval] int * __result);
[id(49), helpstring("获取二维码")] HRESULT CGetQrcodeImage([in] DWORD pid, [out, retval] VARIANT * __result);
};
[
object,
......
......@@ -240,6 +240,7 @@
<ClInclude Include="ntapi.h" />
<ClInclude Include="OpenBrowser.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="GetQrcodeImage.h" />
<ClInclude Include="ReceiveMessage.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="robotdata.h" />
......@@ -294,6 +295,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="GetQrcodeImage.cpp" />
<ClCompile Include="ReceiveMessage.cpp" />
<ClCompile Include="RobotEvent.cpp" />
<ClCompile Include="SearchContactByNet.cpp" />
......
......@@ -128,6 +128,9 @@
<Filter Include="发送消息\转发消息">
<UniqueIdentifier>{f44839a7-3cf0-415f-886e-22a8635c3dbd}</UniqueIdentifier>
</Filter>
<Filter Include="二维码">
<UniqueIdentifier>{fb5a07d9-648d-4e1c-aed3-158f872c3d3e}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
......@@ -262,6 +265,9 @@
<ClInclude Include="ForwardMessage.h">
<Filter>发送消息\转发消息</Filter>
</ClInclude>
<ClInclude Include="GetQrcodeImage.h">
<Filter>二维码</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="WeChatRobotCOM.cpp">
......@@ -396,6 +402,9 @@
<ClCompile Include="ForwardMessage.cpp">
<Filter>发送消息\转发消息</Filter>
</ClCompile>
<ClCompile Include="GetQrcodeImage.cpp">
<Filter>二维码</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="WeChatRobotCOM.rc">
......
......@@ -348,9 +348,13 @@ EXTERN_C const IID IID_IWeChatRobot;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CForwardMessage(
/* [in] */ DWORD pid,
/* [in] */ BSTR wxid,
/* [in] */ int localId,
/* [in] */ unsigned long long localId,
/* [retval][out] */ int *__result) = 0;
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE CGetQrcodeImage(
/* [in] */ DWORD pid,
/* [retval][out] */ VARIANT *__result) = 0;
};
......@@ -688,9 +692,14 @@ EXTERN_C const IID IID_IWeChatRobot;
IWeChatRobot * This,
/* [in] */ DWORD pid,
/* [in] */ BSTR wxid,
/* [in] */ int localId,
/* [in] */ unsigned long long localId,
/* [retval][out] */ int *__result);
/* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *CGetQrcodeImage )(
IWeChatRobot * This,
/* [in] */ DWORD pid,
/* [retval][out] */ VARIANT *__result);
END_INTERFACE
} IWeChatRobotVtbl;
......@@ -862,6 +871,9 @@ EXTERN_C const IID IID_IWeChatRobot;
#define IWeChatRobot_CForwardMessage(This,pid,wxid,localId,__result) \
( (This)->lpVtbl -> CForwardMessage(This,pid,wxid,localId,__result) )
#define IWeChatRobot_CGetQrcodeImage(This,pid,__result) \
( (This)->lpVtbl -> CGetQrcodeImage(This,pid,__result) )
#endif /* COBJMACROS */
......
......@@ -49,7 +49,7 @@
#include "WeChatRobotCOM_i.h"
#define TYPE_FORMAT_STRING_SIZE 1239
#define PROC_FORMAT_STRING_SIZE 2341
#define PROC_FORMAT_STRING_SIZE 2383
#define EXPR_FORMAT_STRING_SIZE 1
#define TRANSMIT_AS_TABLE_SIZE 0
#define WIRE_MARSHAL_TABLE_SIZE 2
......@@ -2112,8 +2112,8 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor
0x6c, /* Old Flags: object, Oi2 */
/* 2180 */ NdrFcLong( 0x0 ), /* 0 */
/* 2184 */ NdrFcShort( 0x33 ), /* 51 */
/* 2186 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */
/* 2188 */ NdrFcShort( 0x10 ), /* 16 */
/* 2186 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */
/* 2188 */ NdrFcShort( 0x18 ), /* 24 */
/* 2190 */ NdrFcShort( 0x24 ), /* 36 */
/* 2192 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */
0x5, /* 5 */
......@@ -2140,38 +2140,38 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor
/* 2214 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2216 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2218 */ 0x8, /* FC_LONG */
/* 2218 */ 0xb, /* FC_HYPER */
0x0, /* 0 */
/* Parameter __result */
/* 2220 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 2222 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 2222 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2224 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Return value */
/* 2226 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2228 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2228 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */
/* 2230 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CPostMessage */
/* Procedure CGetQrcodeImage */
/* 2232 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 2234 */ NdrFcLong( 0x0 ), /* 0 */
/* 2238 */ NdrFcShort( 0x7 ), /* 7 */
/* 2240 */ NdrFcShort( 0x20 ), /* x86 Stack size/offset = 32 */
/* 2242 */ NdrFcShort( 0x20 ), /* 32 */
/* 2244 */ NdrFcShort( 0x24 ), /* 36 */
/* 2246 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */
0x6, /* 6 */
/* 2238 */ NdrFcShort( 0x34 ), /* 52 */
/* 2240 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 2242 */ NdrFcShort( 0x8 ), /* 8 */
/* 2244 */ NdrFcShort( 0x8 ), /* 8 */
/* 2246 */ 0x45, /* Oi2 Flags: srv must size, has return, has ext, */
0x3, /* 3 */
/* 2248 */ 0x8, /* 8 */
0x45, /* Ext Flags: new corr desc, srv corr check, has range on conformance */
/* 2250 */ NdrFcShort( 0x0 ), /* 0 */
/* 2252 */ NdrFcShort( 0x1 ), /* 1 */
0x43, /* Ext Flags: new corr desc, clt corr check, has range on conformance */
/* 2250 */ NdrFcShort( 0x1 ), /* 1 */
/* 2252 */ NdrFcShort( 0x0 ), /* 0 */
/* 2254 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter pid */
......@@ -2181,83 +2181,120 @@ static const WeChatRobotCOM_MIDL_PROC_FORMAT_STRING WeChatRobotCOM__MIDL_ProcFor
/* 2260 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter msgtype */
/* Parameter __result */
/* 2262 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2262 */ NdrFcShort( 0x4113 ), /* Flags: must size, must free, out, simple ref, srv alloc size=16 */
/* 2264 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 2266 */ 0x8, /* FC_LONG */
/* 2266 */ NdrFcShort( 0x4ac ), /* Type Offset=1196 */
/* Return value */
/* 2268 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2270 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2272 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CPostMessage */
/* 2274 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 2276 */ NdrFcLong( 0x0 ), /* 0 */
/* 2280 */ NdrFcShort( 0x7 ), /* 7 */
/* 2282 */ NdrFcShort( 0x20 ), /* x86 Stack size/offset = 32 */
/* 2284 */ NdrFcShort( 0x20 ), /* 32 */
/* 2286 */ NdrFcShort( 0x24 ), /* 36 */
/* 2288 */ 0x46, /* Oi2 Flags: clt must size, has return, has ext, */
0x6, /* 6 */
/* 2290 */ 0x8, /* 8 */
0x45, /* Ext Flags: new corr desc, srv corr check, has range on conformance */
/* 2292 */ NdrFcShort( 0x0 ), /* 0 */
/* 2294 */ NdrFcShort( 0x1 ), /* 1 */
/* 2296 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter pid */
/* 2298 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2300 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 2302 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter msgtype */
/* 2304 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2306 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 2308 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter msgid */
/* 2268 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2270 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2272 */ 0xb, /* FC_HYPER */
/* 2310 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2312 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2314 */ 0xb, /* FC_HYPER */
0x0, /* 0 */
/* Parameter msg */
/* 2274 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */
/* 2276 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2278 */ NdrFcShort( 0x4cc ), /* Type Offset=1228 */
/* 2316 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */
/* 2318 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2320 */ NdrFcShort( 0x4cc ), /* Type Offset=1228 */
/* Parameter __result */
/* 2280 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 2282 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */
/* 2284 */ 0x8, /* FC_LONG */
/* 2322 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 2324 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */
/* 2326 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Return value */
/* 2286 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2288 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */
/* 2290 */ 0x8, /* FC_LONG */
/* 2328 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2330 */ NdrFcShort( 0x1c ), /* x86 Stack size/offset = 28 */
/* 2332 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Procedure CRegisterWxPidWithCookie */
/* 2292 */ 0x33, /* FC_AUTO_HANDLE */
/* 2334 */ 0x33, /* FC_AUTO_HANDLE */
0x6c, /* Old Flags: object, Oi2 */
/* 2294 */ NdrFcLong( 0x0 ), /* 0 */
/* 2298 */ NdrFcShort( 0x8 ), /* 8 */
/* 2300 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2302 */ NdrFcShort( 0x10 ), /* 16 */
/* 2304 */ NdrFcShort( 0x24 ), /* 36 */
/* 2306 */ 0x44, /* Oi2 Flags: has return, has ext, */
/* 2336 */ NdrFcLong( 0x0 ), /* 0 */
/* 2340 */ NdrFcShort( 0x8 ), /* 8 */
/* 2342 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */
/* 2344 */ NdrFcShort( 0x10 ), /* 16 */
/* 2346 */ NdrFcShort( 0x24 ), /* 36 */
/* 2348 */ 0x44, /* Oi2 Flags: has return, has ext, */
0x4, /* 4 */
/* 2308 */ 0x8, /* 8 */
/* 2350 */ 0x8, /* 8 */
0x41, /* Ext Flags: new corr desc, has range on conformance */
/* 2310 */ NdrFcShort( 0x0 ), /* 0 */
/* 2312 */ NdrFcShort( 0x0 ), /* 0 */
/* 2314 */ NdrFcShort( 0x0 ), /* 0 */
/* 2352 */ NdrFcShort( 0x0 ), /* 0 */
/* 2354 */ NdrFcShort( 0x0 ), /* 0 */
/* 2356 */ NdrFcShort( 0x0 ), /* 0 */
/* Parameter pid */
/* 2316 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2318 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 2320 */ 0x8, /* FC_LONG */
/* 2358 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2360 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */
/* 2362 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter cookie */
/* 2322 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2324 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 2326 */ 0x8, /* FC_LONG */
/* 2364 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */
/* 2366 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */
/* 2368 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Parameter __result */
/* 2328 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 2330 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2332 */ 0x8, /* FC_LONG */
/* 2370 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */
/* 2372 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */
/* 2374 */ 0x8, /* FC_LONG */
0x0, /* 0 */
/* Return value */
/* 2334 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2336 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 2338 */ 0x8, /* FC_LONG */
/* 2376 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */
/* 2378 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */
/* 2380 */ 0x8, /* FC_LONG */
0x0, /* 0 */
0x0
......@@ -3149,7 +3186,8 @@ static const unsigned short IWeChatRobot_FormatStringOffsetTable[] =
2022,
2076,
2124,
2178
2178,
2232
};
static const MIDL_STUBLESS_PROXY_INFO IWeChatRobot_ProxyInfo =
......@@ -3173,7 +3211,7 @@ static const MIDL_SERVER_INFO IWeChatRobot_ServerInfo =
0,
0,
0};
CINTERFACE_PROXY_VTABLE(52) _IWeChatRobotProxyVtbl =
CINTERFACE_PROXY_VTABLE(53) _IWeChatRobotProxyVtbl =
{
&IWeChatRobot_ProxyInfo,
&IID_IWeChatRobot,
......@@ -3228,7 +3266,8 @@ CINTERFACE_PROXY_VTABLE(52) _IWeChatRobotProxyVtbl =
(void *) (INT_PTR) -1 /* IWeChatRobot::CAddChatRoomMember */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::COpenBrowser */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CGetHistoryPublicMsg */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CForwardMessage */
(void *) (INT_PTR) -1 /* IWeChatRobot::CForwardMessage */ ,
(void *) (INT_PTR) -1 /* IWeChatRobot::CGetQrcodeImage */
};
......@@ -3282,6 +3321,7 @@ static const PRPC_STUB_FUNCTION IWeChatRobot_table[] =
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2,
NdrStubCall2
};
......@@ -3289,7 +3329,7 @@ CInterfaceStubVtbl _IWeChatRobotStubVtbl =
{
&IID_IWeChatRobot,
&IWeChatRobot_ServerInfo,
52,
53,
&IWeChatRobot_table[-3],
CStdStubBuffer_DELEGATING_METHODS
};
......@@ -3305,8 +3345,8 @@ static const unsigned short IRobotEvent_FormatStringOffsetTable[] =
(unsigned short) -1,
(unsigned short) -1,
(unsigned short) -1,
2232,
2292
2274,
2334
};
static const MIDL_STUBLESS_PROXY_INFO IRobotEvent_ProxyInfo =
......
......@@ -30,6 +30,7 @@
#include "OpenBrowser.h"
#include "GetHistoryPublicMsg.h"
#include "ForwardMessage.h"
#include "GetQrcodeImage.h"
#define DLLNAME L"DWeChatRobot.dll"
......@@ -89,3 +90,4 @@
#define OpenBrowserRemote "OpenBrowserRemote"
#define GetHistoryPublicMsgRemote "GetHistoryPublicMsgRemote"
#define GetQrcodeImageRemote "GetQrcodeImageRemote"
......@@ -328,6 +328,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http
<ClInclude Include="http_overload.hpp" />
<ClInclude Include="OpenBrowser.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="GetQrcodeImage.h" />
<ClInclude Include="ReceiveMessage.h" />
<ClInclude Include="SelfInfo.h" />
<ClInclude Include="SendAppMsg.h" />
......@@ -346,6 +347,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http
<ClInclude Include="wechatver.h" />
<ClInclude Include="wxapi.h" />
<ClInclude Include="wxdata.h" />
<ClInclude Include="wxsignal.h" />
<ClInclude Include="wxsocketapi.h" />
</ItemGroup>
<ItemGroup>
......@@ -381,6 +383,7 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SOCKET_Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="GetQrcodeImage.cpp" />
<ClCompile Include="ReceiveMessage.cpp" />
<ClCompile Include="SearchContactByNet.cpp" />
<ClCompile Include="SelfInfo.cpp" />
......
......@@ -127,6 +127,9 @@
<Filter Include="发送消息\转发消息">
<UniqueIdentifier>{da7b0dbb-2d48-473f-9bb9-6d36ec5b02d3}</UniqueIdentifier>
</Filter>
<Filter Include="二维码">
<UniqueIdentifier>{a0a64bc2-f48e-41a0-838a-45b9985f8d68}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
......@@ -246,6 +249,12 @@
<ClInclude Include="ForwardMessage.h">
<Filter>发送消息\转发消息</Filter>
</ClInclude>
<ClInclude Include="GetQrcodeImage.h">
<Filter>二维码</Filter>
</ClInclude>
<ClInclude Include="wxsignal.h">
<Filter>通用标头</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
......@@ -371,5 +380,8 @@
<ClCompile Include="ForwardMessage.cpp">
<Filter>发送消息\转发消息</Filter>
</ClCompile>
<ClCompile Include="GetQrcodeImage.cpp">
<Filter>二维码</Filter>
</ClCompile>
</ItemGroup>
</Project>
......@@ -317,7 +317,8 @@ int SelectDataRemote(LPVOID lpParameter)
}
return 0;
}
#else
#endif
vector<vector<string>> SelectData(DWORD db_hanle, const char *sql)
{
vector<vector<string>> ret;
......@@ -350,4 +351,3 @@ vector<vector<string>> SelectData(DWORD db_hanle, const char *sql)
ClearResultArray();
return ret;
}
#endif
......@@ -7,8 +7,7 @@ int query(void *data, int argc, char **argv, char **azColName);
#ifndef USE_SOCKET
extern "C" __declspec(dllexport) DWORD ExecuteSQLRemote(LPVOID lpParameter);
extern "C" __declspec(dllexport) int SelectDataRemote(LPVOID lpParameter);
#else
vector<vector<string>> SelectData(DWORD db_hanle, const char *sql);
#endif
vector<vector<string>> SelectData(DWORD db_hanle, const char *sql);
void *ExecuteSQL(DWORD ptrDb, const char *sql, DWORD callback, void *data);
void *SelectData(DWORD db, const char *sql, void *data);
......@@ -7,7 +7,7 @@
struct ForwardMessageStruct
{
wchar_t *wxid;
int localId;
unsigned long long localId;
};
BOOL ForwardMessageRemote(LPVOID lpParameter)
......@@ -17,17 +17,22 @@ BOOL ForwardMessageRemote(LPVOID lpParameter)
}
#endif
BOOL __stdcall ForwardMessage(wchar_t *wxid, int localId)
BOOL __stdcall ForwardMessage(wchar_t *wxid, unsigned long long msgid)
{
DWORD WeChatWinBase = GetWeChatWinBase();
DWORD ForwardMessageCall1 = WeChatWinBase + ForwardMessageCall1Offset;
DWORD ForwardMessageCall2 = WeChatWinBase + ForwardMessageCall2Offset;
int dbIndex = 0;
int localId = GetLocalIdByMsgId(msgid, dbIndex);
if (localId == 0)
return FALSE;
dbIndex = 0x5000000 + (dbIndex << 8);
WxString p_wxid(wxid);
int isSuccess = 0;
__asm {
pushad;
pushfd;
mov eax, 0x5000100;
mov eax, dword ptr ds:[dbIndex];
push eax;
mov ecx, dword ptr ds:[localId];
push ecx;
......
#pragma once
#include <windows.h>
BOOL __stdcall ForwardMessage(wchar_t *wxid, int localId);
BOOL __stdcall ForwardMessage(wchar_t *wxid, unsigned long long localId);
#ifndef USE_SOCKET
extern "C" __declspec(dllexport) BOOL ForwardMessageRemote(LPVOID lpParameter);
......
......@@ -9,20 +9,38 @@
// 保存数据库信息的容器
vector<DbInfoStruct> dbs;
map<wstring, DbInfoStruct> dbmap;
/*
* 根据数据库名从`dbs`中检索数据库句柄
* 根据数据库名从`dbmap`中检索数据库句柄
* dbname:数据库名
* return:DWORD,如果检索成功,返回数据库句柄,否则返回`0`
*/
DWORD GetDbHandleByDbName(wchar_t *dbname)
{
if (dbs.size() == 0)
if (dbmap.size() == 0)
GetDbHandles();
for (unsigned int i = 0; i < dbs.size() - 1; i++)
if (dbmap.find(dbname) != dbmap.end())
return dbmap[dbname].handle;
return 0;
}
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex)
{
char sql[260] = {0};
sprintf_s(sql, "select localId from MSG where MsgSvrID=%llu;", msgid);
wchar_t dbname[20] = {0};
for (int i = 0;; i++)
{
if (!lstrcmpW(dbs[i].dbname, dbname))
return dbs[i].handle;
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
if (handle == 0)
return 0;
vector<vector<string>> result = SelectData(handle, (const char *)sql);
if (result.size() == 0)
continue;
dbIndex = i + 1;
return stoi(result[1][0]);
}
return 0;
}
......@@ -63,7 +81,6 @@ vector<void *> GetDbHandles()
mov SqlHandleEndAddr, eax;
}
DWORD dwHandle = 0x0;
wstring dbnames = L"";
// 获取联系人数据库句柄
while (SqlHandleBeginAddr < SqlHandleEndAddr)
{
......@@ -71,29 +88,31 @@ vector<void *> GetDbHandles()
SqlHandleBeginAddr += 0x4;
if (SqlHandleBeginAddr == SqlHandleEndAddr)
break;
if (dbnames.find(L"|" + (wstring)(wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|", 0) != wstring::npos)
wstring dbname = wstring((wchar_t *)(*(DWORD *)(dwHandle + 0x50)));
if (dbmap.find(dbname) != dbmap.end())
continue;
DbInfoStruct db = {0};
dbnames = dbnames + L"|" + (wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|";
db.dbname = (wchar_t *)(*(DWORD *)(dwHandle + 0x50));
db.l_dbname = wcslen(db.dbname);
db.handle = *(DWORD *)(dwHandle + 0x3C);
ExecuteSQL(*(DWORD *)(dwHandle + 0x3C), "select * from sqlite_master where type=\"table\";", (DWORD)GetDbInfo, &db);
dbs.push_back(db);
dbmap[dbname] = db;
}
// 获取公众号数据库句柄
for (int i = 1; i < 4; i++)
{
dwHandle = *((DWORD *)(SqlHandlePublicMsgAddr + i * 0x4));
if (dbnames.find(L"|" + (wstring)(wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|", 0) != wstring::npos)
wstring dbname = wstring((wchar_t *)(*(DWORD *)(dwHandle + 0x50)));
if (dbmap.find(dbname) != dbmap.end())
continue;
DbInfoStruct db = {0};
dbnames = dbnames + L"|" + (wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|";
db.dbname = (wchar_t *)(*(DWORD *)(dwHandle + 0x50));
db.l_dbname = wcslen(db.dbname);
db.handle = *(DWORD *)(dwHandle + 0x3C);
ExecuteSQL(*(DWORD *)(dwHandle + 0x3C), "select * from sqlite_master where type=\"table\";", (DWORD)GetDbInfo, &db);
dbs.push_back(db);
dbmap[dbname] = db;
}
// 获取聊天记录数据库句柄
int msgdb_count = *(int *)(SqlHandleMSGAddr + 0x4);
......@@ -103,15 +122,16 @@ vector<void *> GetDbHandles()
for (int j = 0; j < 4; j++)
{
dwHandle = *(DWORD *)(MsgdwHandle + 0x14 + j * 4);
if (dbnames.find(L"|" + (wstring)(wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|", 0) != wstring::npos)
wstring dbname = wstring((wchar_t *)(*(DWORD *)(dwHandle + 0x50)));
if (dbmap.find(dbname) != dbmap.end())
continue;
DbInfoStruct db = {0};
dbnames = dbnames + L"|" + (wchar_t *)(*(DWORD *)(dwHandle + 0x50)) + L"|";
db.dbname = (wchar_t *)(*(DWORD *)(dwHandle + 0x50));
db.l_dbname = wcslen(db.dbname);
db.handle = *(DWORD *)(dwHandle + 0x3C);
ExecuteSQL(*(DWORD *)(dwHandle + 0x3C), "select * from sqlite_master where type=\"table\";", (DWORD)GetDbInfo, &db);
dbs.push_back(db);
dbmap[dbname] = db;
}
MsgdwHandle += 0x68;
}
......
......@@ -8,3 +8,4 @@ vector<void *> GetDbHandles();
extern "C" __declspec(dllexport) DWORD GetDbHandlesRemote();
#endif
DWORD GetDbHandleByDbName(wchar_t *dbname);
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
#include "pch.h"
#define SwitchQrcodeLoginCall1Offset 0x372AA0
#define SwitchQrcodeLoginCall2Offset 0x5177D0
#define SaveQrcodeImageHookOffset 0x2815DA
#define SaveQrcodeImageNextCallOffset 0x76F660
static DWORD SaveQrcodeImageHookAddr;
static DWORD SaveQrcodeImageNextCall;
static DWORD SaveQrcodeImageJmpBackAddress;
static bool SaveQrcodeImageHooked = false;
static char SaveQrcodeImageOldAsmCode[5] = {0};
static DWORD SignalThreadId = 0;
struct QrcodeStruct
{
unsigned char *image = NULL;
int size = 0;
void update(unsigned char *buf, int len)
{
this->free();
this->image = new unsigned char[len + 1];
memcpy(this->image, buf, len);
this->size = len;
}
void free()
{
if (this->image != NULL)
{
delete[] this->image;
this->image = NULL;
}
this->size = 0;
}
~QrcodeStruct()
{
this->free();
}
};
static unique_ptr<QrcodeStruct> qc(new QrcodeStruct);
void SaveQrcodeImage(unsigned char *src, int size)
{
qc->update(src, size);
SIGNAL(SignalThreadId, WM_WAIT_QRCODE);
}
_declspec(naked) void dealQrcodeImage()
{
__asm {
pushad;
pushfd;
push dword ptr[eax + 4];
push dword ptr[eax];
call SaveQrcodeImage;
add esp, 0x8;
popfd;
popad;
call SaveQrcodeImageNextCall;
jmp SaveQrcodeImageJmpBackAddress;
}
}
void HookQrcodeImage()
{
if (SaveQrcodeImageHooked)
return;
DWORD WeChatWinBase = GetWeChatWinBase();
SaveQrcodeImageHookAddr = WeChatWinBase + SaveQrcodeImageHookOffset;
SaveQrcodeImageNextCall = WeChatWinBase + SaveQrcodeImageNextCallOffset;
SaveQrcodeImageJmpBackAddress = SaveQrcodeImageHookAddr + 0x5;
HookAnyAddress(SaveQrcodeImageHookAddr, (LPVOID)dealQrcodeImage, SaveQrcodeImageOldAsmCode);
SaveQrcodeImageHooked = true;
}
void UnHookQrcodeImage()
{
if (!SaveQrcodeImageHooked)
return;
UnHookAnyAddress(SaveQrcodeImageHookAddr, SaveQrcodeImageOldAsmCode);
SaveQrcodeImageHooked = false;
}
BOOL __stdcall SwitchToQrcodeLogin()
{
qc->free();
DWORD WeChatWinBase = GetWeChatWinBase();
DWORD SwitchQrcodeLoginCall1 = WeChatWinBase + SwitchQrcodeLoginCall1Offset;
DWORD SwitchQrcodeLoginCall2 = WeChatWinBase + SwitchQrcodeLoginCall2Offset;
int isSuccess = 0;
__asm {
pushad;
pushfd;
call SwitchQrcodeLoginCall1;
mov ecx,eax;
call SwitchQrcodeLoginCall2;
movzx eax,al;
mov isSuccess,eax;
popfd;
popad;
}
return isSuccess == 1;
}
#ifndef USE_SOCKET
DWORD GetQrcodeImageRemote()
{
if (isWxLogin())
return 0;
if (!SaveQrcodeImageHooked)
HookQrcodeImage();
WxSignal sg(WM_WAIT_QRCODE);
SignalThreadId = sg.GetThreadId();
SwitchToQrcodeLogin();
sg.wait(5000);
return (DWORD)qc.get();
}
#else
BYTE *__stdcall GetQrcodeImage(int &size)
{
if (isWxLogin())
return NULL;
if (!SaveQrcodeImageHooked)
HookQrcodeImage();
WxSignal sg(WM_WAIT_QRCODE);
SignalThreadId = sg.GetThreadId();
SwitchToQrcodeLogin();
sg.wait(5000);
size = qc->size;
if (qc->size == 0)
return NULL;
return qc->image;
}
#endif
#pragma once
#include <windows.h>
BOOL __stdcall SwitchToQrcodeLogin();
void HookQrcodeImage();
void UnHookQrcodeImage();
#ifndef USE_SOCKET
extern "C" __declspec(dllexport) DWORD GetQrcodeImageRemote();
#else
BYTE *__stdcall GetQrcodeImage(int &size);
#endif
......@@ -13,9 +13,9 @@ using namespace std;
#define CLTIP "127.0.0.1"
// 接收消息的HOOK地址偏移
#define ReceiveMessageHookOffset 0x5D39C359 - 0x5D1F0000
#define ReceiveMessageHookOffset 0x655F0F4C - 0x650A0000 // 0x5D39C359 - 0x5D1F0000
// 接收消息HOOK的CALL偏移
#define ReceiveMessageNextCallOffset 0x5D5F7F00 - 0x5D1F0000
#define ReceiveMessageNextCallOffset 0x65B36350 - 0x650A0000 // 0x5D5F7F00 - 0x5D1F0000
// 发送消息的HOOK地址偏移
#define SendMessageHookOffset 0x78B88E42 - 0x786A0000
......@@ -27,7 +27,7 @@ using namespace std;
// 撤回消息HOOK的CALL偏移
#define RevokeMessageNextCallOffset 0x5D6D3430 - 0x5D1F0000
#define READ_WSTRING(addr, offset) wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4))
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? wstring(L"") : wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
static int SRVPORT = 0;
......@@ -131,17 +131,24 @@ void SendSocketMessageInThread(SocketMessageStruct *param)
if (param == NULL)
return;
unique_ptr<SocketMessageStruct> sms(param);
string jstr(param->buffer, param->length);
#ifdef USE_COM
// 通过连接点,将消息广播给客户端;将广播过程放在线程中完成,客户端才可以等待图片、语音落地
VARIANT vsaValue = (_variant_t)utf8_to_unicode(jstr.c_str()).c_str();
json jMsg = json::parse(param->buffer, param->buffer + param->length, nullptr, false);
if (jMsg.is_discarded() != true)
if (jMsg.is_discarded() == true)
{
DWORD type = jMsg["type"].get<DWORD>();
ULONG64 msgid = (type != 10000) ? jMsg["msgid"].get<ULONG64>() : 0;
PostComMessage(jMsg["pid"].get<int>(), WX_MESSAGE, msgid, &vsaValue);
return;
}
/*int dbIndex;
while (jMsg["localId"].get<unsigned int>() == 0)
{
jMsg["localId"] = GetLocalIdByMsgId(jMsg["msgid"].get<ULONG64>(),dbIndex);
Sleep(200);
}*/
string jstr = jMsg.dump() + "\n";
#ifdef USE_COM
// 通过连接点,将消息广播给客户端;将广播过程放在线程中完成,客户端才可以等待图片、语音落地
VARIANT vsaValue = (_variant_t)utf8_to_unicode(jstr.c_str()).c_str();
DWORD type = jMsg["type"].get<DWORD>();
ULONG64 msgid = (type != 10000) ? jMsg["msgid"].get<ULONG64>() : 0;
PostComMessage(jMsg["pid"].get<int>(), WX_MESSAGE, msgid, &vsaValue);
#endif
SendSocketMessage(jstr.c_str(), jstr.size());
}
......@@ -153,17 +160,23 @@ static void dealMessage(DWORD messageAddr)
jMsg["pid"] = GetCurrentProcessId();
jMsg["type"] = *(DWORD *)(messageAddr + 0x38);
jMsg["isSendMsg"] = *(BOOL *)(messageAddr + 0x3C);
if (jMsg["isSendMsg"].get<BOOL>())
{
jMsg["isSendByPhone"] = (int)(*(BYTE *)(messageAddr + 0xD8));
}
jMsg["msgid"] = msgid;
jMsg["localId"] = *(unsigned int *)(messageAddr + 0x20);
// jMsg["localId"] = *(unsigned int *)(messageAddr + 0x20);
jMsg["sender"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x48).c_str());
int length = *(DWORD *)(messageAddr + 0x170 + 0x4);
jMsg["wxid"] = length == 0 ? jMsg["sender"].get<std::string>() : unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x170).c_str());
jMsg["message"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x70).c_str());
jMsg["sign"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x184).c_str());
if (jMsg["type"].get<int>() != 10000)
{
jMsg["filepath"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x1AC).c_str());
string extrabuf = base64_encode((BYTE *)(*(DWORD *)(messageAddr + 0x8C)), *(DWORD *)(messageAddr + 0x8C + 0x4));
jMsg["extrainfo"] = extrabuf;
/*string extrabuf = base64_encode((BYTE *)(*(DWORD *)(messageAddr + 0x8C)), *(DWORD *)(messageAddr + 0x8C + 0x4));
jMsg["extrainfo"] = extrabuf;*/
jMsg["extrainfo"] = unicode_to_utf8((wchar_t *)READ_WSTRING(messageAddr, 0x1EC).c_str());
}
else
{
......@@ -190,14 +203,14 @@ static void dealMessage(DWORD messageAddr)
* messageAddr:保存消息的缓冲区地址
* return:void
*/
// VOID ReceiveMessage(DWORD messagesAddr)
//{
// DWORD *messages = (DWORD *)messagesAddr;
// for (DWORD messageAddr = messages[0]; messageAddr < messages[1]; messageAddr += 0x298)
// {
// dealMessage(messageAddr);
// }
// }
VOID ReceiveMessage(DWORD messagesAddr)
{
DWORD *messages = (DWORD *)messagesAddr;
for (DWORD messageAddr = messages[0]; messageAddr < messages[1]; messageAddr += 0x298)
{
dealMessage(messageAddr);
}
}
/*
* HOOK的具体实现,接收到消息后调用处理函数
......@@ -208,7 +221,7 @@ _declspec(naked) void dealReceiveMessage()
pushad;
pushfd;
push edi;
call dealMessage;
call ReceiveMessage;
add esp, 0x4;
popfd;
popad;
......
#include "pch.h"
#include "json/json.hpp"
#include <map>
using namespace nlohmann;
#define CheckLoginOffset 0x2366538
......@@ -8,10 +7,10 @@ using namespace nlohmann;
#define SelfWxidAddrOffset 0x236607C
/*
* 外部调用时的返回类型
* message:selfinfo.c_str()
* length:selfinfo字符串长度
*/
* 外部调用时的返回类型
* message:selfinfo.c_str()
* length:selfinfo字符串长度
*/
#ifndef USE_SOCKET
struct SelfInfoStruct
{
......@@ -21,9 +20,9 @@ struct SelfInfoStruct
#endif // !USE_SOCKET
/*
* 供外部调用的获取个人信息接口
* return:DWORD,ret的首地址
*/
* 供外部调用的获取个人信息接口
* return:DWORD,ret的首地址
*/
#ifndef USE_SOCKET
DWORD GetSelfInfoRemote()
{
......@@ -39,35 +38,26 @@ DWORD GetSelfInfoRemote()
wstring GetSelfWxid()
{
DWORD baseAddr = GetWeChatWinBase() + SelfWxidAddrOffset;
char wxidbuffer[0x100] = {0};
DWORD SelfWxIdAddr = 0x0;
sprintf_s(wxidbuffer, "%s", (char *)baseAddr);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
DWORD addr = GetWeChatWinBase() + SelfWxidAddrOffset;
string wxid;
if (*(DWORD *)(addr + 0x14) == 0xF)
{
SelfWxIdAddr = *(DWORD *)baseAddr;
wxid = string((char *)addr, *(int *)(addr + 0x10));
}
else
{
SelfWxIdAddr = baseAddr;
wxid = string((char *)(*(DWORD *)addr), *(int *)(addr + 0x10));
}
if (SelfWxIdAddr == 0)
{
return L"";
}
char *sselfwxid = (char *)SelfWxIdAddr;
wchar_t *wselfwxid = new wchar_t[strlen(sselfwxid) + 1];
MultiByteToWideChar(CP_ACP, 0, sselfwxid, -1, wselfwxid, strlen(sselfwxid) + 1);
wstring wxid(wselfwxid);
delete[] wselfwxid;
return wxid;
return utf8_to_unicode(wxid.c_str());
}
/*
* 获取个人信息
*/
* 获取个人信息
*/
wstring GetSelfInfo()
{
if (!isWxLogin())
return L"请先登录微信.";
json jData;
map<string, DWORD> self_info_addr;
DWORD WeChatWinBase = GetWeChatWinBase();
......@@ -75,70 +65,44 @@ wstring GetSelfInfo()
self_info_addr["wxNumber"] = WeChatWinBase + 0x2366548;
self_info_addr["wxNickName"] = WeChatWinBase + 0x23660F4;
self_info_addr["Sex"] = WeChatWinBase + 0x23661F8;
self_info_addr["wxSignature"] = *(DWORD *)(WeChatWinBase + 0x236622C);
self_info_addr["wxBigAvatar"] = *(DWORD *)(WeChatWinBase + 0x23A111C);
self_info_addr["wxSmallAvatar"] = *(DWORD *)(WeChatWinBase + 0x23663D4);
self_info_addr["wxSignature"] = WeChatWinBase + 0x236622C;
self_info_addr["wxBigAvatar"] = WeChatWinBase + 0x23A111C;
self_info_addr["wxSmallAvatar"] = WeChatWinBase + 0x23663D4;
self_info_addr["wxNation"] = WeChatWinBase + 0x23662E8;
self_info_addr["wxProvince"] = WeChatWinBase + 0x23661FC;
self_info_addr["wxCity"] = WeChatWinBase + 0x2366214;
self_info_addr["PhoneNumber"] = WeChatWinBase + 0x2366128;
self_info_addr["wxFilePath"] = *(DWORD *)(WeChatWinBase + 0x2385020);
for (auto it = self_info_addr.begin(); it != self_info_addr.end(); it++)
{
string key = it->first;
DWORD addr = it->second;
string temp;
if (!key.compare("wxNickName"))
string utf8_str;
if (key == "Sex")
{
if (*(DWORD *)(addr + 0x14) == 0xF)
{
temp = (*((DWORD *)addr) != 0) ? string((char *)addr) : gb2312_to_utf8("null");
}
else
{
temp = (*((DWORD *)addr) != 0) ? string((char *)(*(DWORD *)addr)) : gb2312_to_utf8("null");
}
int sex = *(int *)addr;
utf8_str = gb2312_to_utf8(((sex == 1) ? "男" : ((sex == 2) ? "女" : "未知")));
}
else if (!key.compare("wxId"))
else if (key == "wxFilePath")
{
char wxidbuffer[0x100] = {0};
sprintf_s(wxidbuffer, "%s", (char *)addr);
if (strlen(wxidbuffer) < 0x6 || strlen(wxidbuffer) > 0x14)
{
//新的微信号 微信ID用地址保存
temp = string((char *)(*(DWORD *)addr));
}
else
{
temp = string((char *)addr);
}
utf8_str = unicode_to_utf8((wchar_t *)addr);
}
else if (!key.compare("Sex"))
else
{
int sex = *(int *)addr;
switch (sex)
{
case 1:
if (*(DWORD *)addr == 0)
{
temp = gb2312_to_utf8("男");
break;
utf8_str = "";
}
case 2:
else if (*(DWORD *)(addr + 0x14) == 0xF)
{
temp = gb2312_to_utf8("女");
break;
utf8_str = string((char *)addr, *(int *)(addr + 0x10));
}
default:
else
{
temp = gb2312_to_utf8("未知");
break;
}
utf8_str = string((char *)(*(DWORD *)addr), *(int *)(addr + 0x10));
}
}
else
{
temp = addr != 0 ? string((char *)addr) : gb2312_to_utf8("null");
}
jData[key] = temp.c_str();
jData[key] = utf8_str.c_str();
}
wstring selfinfo = utf8_to_unicode(jData.dump().c_str());
return selfinfo;
......@@ -151,9 +115,9 @@ BOOL isWxLogin()
}
/*
* 删除个人信息缓存
* return:void
*/
* 删除个人信息缓存
* return:void
*/
#ifndef USE_SOCKET
VOID DeleteSelfInfoCacheRemote()
{
......
......@@ -81,7 +81,7 @@ BOOL __stdcall SendAtText(wchar_t *wsChatRoomId, DWORD wsWxId[], wchar_t *wsText
nickname = L"所有人";
}
else
nickname = GetUserNickNameByWxId((wchar_t *)wsWxId[i]);
nickname = GetChatRoomMemberNickname(wsChatRoomId, (wchar_t *)wsWxId[i]);
if (nickname.length() == 0)
continue;
WxString temp = {0};
......
......@@ -134,8 +134,8 @@ BOOL __stdcall OpenBrowser(wstring url)
return OpenBrowser(WS2LW(url));
}
BOOL __stdcall ForwardMessage(wstring wxid, int localId)
BOOL __stdcall ForwardMessage(wstring wxid, ULONG64 msgid)
{
return ForwardMessage(WS2LW(wxid), localId);
return ForwardMessage(WS2LW(wxid), msgid);
}
#endif
......@@ -188,6 +188,7 @@ void UnHookAll()
UnHookVoiceMsg();
UnHookImageMsg();
UnHookH5ExtBuf();
UnHookQrcodeImage();
return;
}
......
......@@ -11,12 +11,15 @@
#include "framework.h"
#include <iostream>
#include <vector>
#include <map>
#include <strstream>
#include <string>
#include <string>
#include <sstream>
#include "wxdata.h"
#include "wxapi.h"
#include "base64/base64.h"
#endif //PCH_H
#endif // PCH_H
#ifdef USE_SOCKET
#include "wxsocketapi.h"
......
#pragma once
#include "wxsignal.h"
#include "SendImage.h"
#include "SendText.h"
#include "SendFile.h"
......@@ -31,6 +32,7 @@
#include "OpenBrowser.h"
#include "GetHistoryPublicMsg.h"
#include "ForwardMessage.h"
#include "GetQrcodeImage.h"
using namespace std;
#pragma comment(lib, "version.lib")
......
......@@ -2,15 +2,18 @@
#include <windows.h>
using namespace std;
// 用于Hook到数据后,给主线程发送信号
#define WM_WAIT_QRCODE WM_USER + 0x1
/*
* 微信中的基础数据结构
* buffer:UNICODE字符串
* length:`buffer`字符数
* maxLength:`buffer`最大字符数
* fill1:占位成员1,默认为0
* fill2:占位成员2,默认为0
* WxString:默认构造函数
*/
* 微信中的基础数据结构
* buffer:UNICODE字符串
* length:`buffer`字符数
* maxLength:`buffer`最大字符数
* fill1:占位成员1,默认为0
* fill2:占位成员2,默认为0
* WxString:默认构造函数
*/
struct WxString
{
wchar_t *buffer;
......@@ -47,13 +50,13 @@ struct WxString
};
/*
* 保存单条信息的结构
* messagetype:消息类型
* sender:发送者wxid
* wxid:如果sender是群聊id,则此成员保存具体发送人wxid,否则与`sender`一致
* message:消息内容,非文本消息是xml格式
* filepath:图片、文件及其他资源的保存路径
*/
* 保存单条信息的结构
* messagetype:消息类型
* sender:发送者wxid
* wxid:如果sender是群聊id,则此成员保存具体发送人wxid,否则与`sender`一致
* message:消息内容,非文本消息是xml格式
* filepath:图片、文件及其他资源的保存路径
*/
struct ReceiveMsgStruct
{
DWORD pid = 0;
......@@ -110,12 +113,12 @@ struct UserInfo
};
/*
* 保存数据库单个表信息的结构体
* name:表名;l_name:`name`字符数
* tbl_name:表名;l_tbl_name:`tbl_name`字符数
* sql:建表语句;l_sql:`sql`字符数
* rootpage:表编号;l_rootpage:`rootpage`字符数
*/
* 保存数据库单个表信息的结构体
* name:表名;l_name:`name`字符数
* tbl_name:表名;l_tbl_name:`tbl_name`字符数
* sql:建表语句;l_sql:`sql`字符数
* rootpage:表编号;l_rootpage:`rootpage`字符数
*/
struct TableInfoStruct
{
char *name;
......@@ -129,13 +132,13 @@ struct TableInfoStruct
};
/*
* 保存数据库信息的结构体
* handle:数据库句柄
* dbname:数据库名
* l_dbname:`dbname`字符数
* tables:保存库中所有表信息的容器
* count:库中表的数量
*/
* 保存数据库信息的结构体
* handle:数据库句柄
* dbname:数据库名
* l_dbname:`dbname`字符数
* tables:保存库中所有表信息的容器
* count:库中表的数量
*/
struct DbInfoStruct
{
DWORD handle;
......@@ -146,13 +149,13 @@ struct DbInfoStruct
};
/*
* 保存单个好友信息的结构体
* wxIdAddr:wxid保存地址
* wxNumberAddr:微信号保存地址
* wxNickNameAddr:昵称保存地址
* wxRemarkAddr:备注保存地址
* WxFriendStructW:默认构造函数
*/
* 保存单个好友信息的结构体
* wxIdAddr:wxid保存地址
* wxNumberAddr:微信号保存地址
* wxNickNameAddr:昵称保存地址
* wxRemarkAddr:备注保存地址
* WxFriendStructW:默认构造函数
*/
struct WxFriendStruct
{
DWORD wxIdAddr;
......
#pragma once
#include <windows.h>
#define SIGNAL(id, uMsg) PostThreadMessage(id, uMsg, 0, 0)
class WxSignal
{
public:
WxSignal(UINT uMsg)
{
this->hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)this->Pump, (LPVOID)uMsg, 0, &this->threadId);
}
~WxSignal()
{
if (this->hThread)
CloseHandle(this->hThread);
SIGNAL(this->threadId, WM_QUIT);
}
static void Pump(UINT uMsg)
{
MSG msg = {0};
int ret;
while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (msg.message == uMsg)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void wait(int timeout)
{
if (this->hThread)
{
WaitForSingleObject(this->hThread, timeout);
PostThreadMessage(this->threadId, WM_QUIT, 0, 0);
CloseHandle(this->hThread);
this->hThread = NULL;
}
}
DWORD GetThreadId()
{
return this->threadId;
}
private:
HANDLE hThread;
DWORD threadId;
};
......@@ -108,6 +108,38 @@ static int get_http_param_int(mg_http_message *hm, json jData, string key, int m
return result;
}
static unsigned long long get_http_param_ulong64(mg_http_message *hm, json jData, string key, int method)
{
unsigned long long result = 0;
switch (method)
{
case HTTP_METHOD_GET:
{
string value = getMgVarA(hm, key);
istringstream is(value);
is >> result;
break;
}
case HTTP_METHOD_POST:
{
try
{
result = jData[key].get<ULONG64>();
}
catch (json::exception)
{
string value = jData[key].get<string>();
istringstream is(value);
is >> result;
}
break;
}
default:
break;
}
return result;
}
static vector<wstring> get_http_param_array(mg_http_message *hm, json jData, string key, int method)
{
vector<wstring> result;
......@@ -129,12 +161,12 @@ static vector<wstring> get_http_param_array(mg_http_message *hm, json jData, str
return result;
}
void request_event(mg_http_message *hm, string &ret)
void request_event(mg_http_message *hm, string &ret, struct mg_connection *c)
{
int method = I_METHOD(getMgStrA(hm->method));
// 第四个参数设置为false,不抛出异常
json jData = json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
if (jData.is_discarded() == true && method == HTTP_METHOD_POST)
if (hm->body.len != 0 && jData.is_discarded() == true && method == HTTP_METHOD_POST)
{
json ret_data = {{"result", "ERROR"},
{"err_msg", "json string is invalid."}};
......@@ -534,12 +566,36 @@ void request_event(mg_http_message *hm, string &ret)
case WECHAT_MSG_FORWARD_MESSAGE:
{
wstring wxid = get_http_param_str(hm, jData, "wxid", method);
int localId = get_http_param_int(hm, jData, "localId", method);
BOOL status = ForwardMessage(wxid, localId);
ULONG64 msgid = get_http_param_ulong64(hm, jData, "msgid", method);
BOOL status = ForwardMessage(wxid, msgid);
json ret_data = {{"msg", status}, {"result", "OK"}};
ret = ret_data.dump();
break;
}
case WECHAT_GET_QRCODE_IMAGE:
{
int size = 0;
BYTE *image = GetQrcodeImage(size);
// string b64data = base64_encode(image, size,false);
if (image != NULL)
{
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: image/png\r\n\r\n");
mg_http_write_chunk(c, (const char *)image, size);
mg_http_printf_chunk(c, "");
ret = "";
}
else
{
string message;
if (isWxLogin())
message = "获取失败,微信已登录.";
else
message = "获取失败.";
json ret_data = {{"msg", gb2312_to_utf8(message.c_str())}, {"result", "OK"}};
ret = ret_data.dump();
}
break;
}
default:
// char* wxid = mg_json_get_str(hm->body, "$.wxid");
break;
......@@ -573,20 +629,15 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data)
{
try
{
request_event(hm, ret);
request_event(hm, ret, c);
}
catch (json::exception &e)
{
json res = {{"result", "ERROR"}, {"err_msg", e.what()}};
ret = res.dump();
}
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
}
else if (mg_http_match_uri(hm, "/api/f2/*"))
{
mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
mg_http_printf_chunk(c, "ID PROTO TYPE LOCAL REMOTE\n");
mg_http_printf_chunk(c, "");
if (ret != "")
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
}
else
{
......
......@@ -72,6 +72,7 @@ typedef enum WECHAT_HTTP_APISTag
WECHAT_GET_PUBLIC_MSG,
// IJ
WECHAT_MSG_FORWARD_MESSAGE,
WECHAT_GET_QRCODE_IMAGE,
} WECHAT_HTTP_APIS,
*PWECHAT_HTTP_APIS;
#endif
......@@ -88,6 +88,5 @@ if __name__ == '__main__':
wx = WeChatRobot(pid_list[0])
wx.StartService()
wx.StartReceiveMessage()
wx.HookImageMsg(r"D:\wxdata")
wxRobot.register_msg_event(pid_list[0])
wx.StopService()
......@@ -9,7 +9,6 @@ Created on Thu Feb 24 16:19:48 2022
import os
import ctypes
import json
import base64
import ctypes.wintypes
import socketserver
import threading
......@@ -53,7 +52,6 @@ class WeChatEventSink:
def OnGetMessageEvent(self, msg):
msg = json.loads(msg)
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
print(msg)
......@@ -84,7 +82,6 @@ class ReceiveMsgBaseServer(socketserver.BaseRequestHandler):
@staticmethod
def msg_callback(msg):
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
# 主线程中已经注入,此处禁止调用StartService和StopService
robot = comtypes.client.CreateObject("WeChatRobot.CWeChatRobot")
event = comtypes.client.CreateObject("WeChatRobot.RobotEvent")
......@@ -1044,7 +1041,7 @@ class WeChatRobot:
pass
return ret
def ForwardMessage(self,wxid:str,localId:int) -> int:
def ForwardMessage(self,wxid:str,msgid:int) -> int:
"""
转发消息,只支持单条转发
......@@ -1052,8 +1049,8 @@ class WeChatRobot:
----------
wxid : str
消息接收人wxid.
localId : int
消息短id,可以在实时消息接口中获取或查询MSG{x}.db.
msgid : int
消息id,可以在实时消息接口中获取.
Returns
-------
......@@ -1061,7 +1058,26 @@ class WeChatRobot:
成功返回0,失败返回非0值.
"""
return self.robot.CForwardMessage(self.pid,wxid,localId)
return self.robot.CForwardMessage(self.pid,wxid,msgid)
def GetQrcodeImage(self) -> bytes:
"""
获取二维码,同时切换到扫码登录
Returns
-------
bytes
二维码bytes数据.
You can convert it to image object,like this:
>>> from io import BytesIO
>>> from PIL import Image
>>> buf = wx.GetQrcodeImage()
>>> image = Image.open(BytesIO(buf)).convert("L")
>>> image.save('./qrcode.png')
"""
data = self.robot.CGetQrcodeImage(self.pid)
return bytes(data)
def get_wechat_pid_list() -> list:
......
......@@ -3,7 +3,6 @@ import json
import copy
import threading
import requests
import base64
import socketserver
if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulonglong):
......@@ -85,6 +84,7 @@ class WECHAT_HTTP_APIS:
WECHAT_GET_PUBLIC_MSG = 39 # 获取公众号历史消息
WECHAT_MSG_FORWARD_MESSAGE = 40 # 转发消息
WECHAT_GET_QRCODE_IMAGE = 41 # 获取二维码
APIS = WECHAT_HTTP_APIS
......@@ -188,7 +188,8 @@ class WECHAT_HTTP_API_PARAM_TEMPLATES:
APIS.WECHAT_BROWSER_OPEN_WITH_URL: {"url": "https://www.baidu.com/"},
APIS.WECHAT_GET_PUBLIC_MSG: {"public_id": "","offset": ""},
APIS.WECHAT_MSG_FORWARD_MESSAGE: {"wxid": "filehelper","localId": 1},
APIS.WECHAT_MSG_FORWARD_MESSAGE: {"wxid": "filehelper","msgid": 2 ** 64 - 1},
APIS.WECHAT_GET_QRCODE_IMAGE: {}
}
def get_http_template(self, api_number):
......@@ -224,11 +225,8 @@ class ReceiveMsgSocketServer(socketserver.BaseRequestHandler):
@staticmethod
def msg_callback(msg):
# 附加信息是protobuf格式,需要自行处理
msg['extrainfo'] = base64.b64decode(msg['extrainfo'])
# TODO: 在这里写额外的消息处理逻辑
print(msg)
# TODO: 在这里写额外的消息处理逻辑
def post_wechat_http_api(api,port,data = {}):
url = "http://127.0.0.1:{}/api/?type={}".format(port,api)
......@@ -334,6 +332,7 @@ if __name__ == '__main__':
pids.append(new_wechat())
start_listen(pids[0],port)
post_wechat_http_api(APIS.WECHAT_LOG_START_HOOK,8000)
print(post_wechat_http_api(APIS.WECHAT_GET_SELF_INFO, 8000))
post_wechat_http_api(APIS.WECHAT_MSG_START_HOOK,8000,{"port":10808})
start_socket_server()
stop_listen(pids[0])
......@@ -137,6 +137,14 @@ CWeChatRobot.exe /unregserver
2. 新增转发消息功能,请勿转发语音、红包等消息
3. 实时消息接口新增`localId`字段,该字段用于转发消息接口;现在也可以接收到撤回消息提醒
4. 优化COM连接点,在线程中进行消息广播,客户端可以阻塞以等待图片、语音等资源落地
## 2022.09.18
1. 修复了一个bug,在多个MSG.db存在时,无法转发准确的消息;现在转发消息功能使用msgid作为参数
2. 修复了一个bug,该bug曾导致微信没有选中的会话时,无法获取实时消息
3. 修复了一个bug,该bug曾导致部分微信号获取个人信息时出现内存访问冲突
4. 优化实时消息接口,不再返回localId字段;extrabuf现在返回原始信息而不是base64编码数据;新增一个字段,用于区分是否手机发送的消息(接收到的消息不含该字段)
5. 优化个人信息接口,现在可以返回个人文件夹路径
6. 优化群艾特接口,优先填充群内昵称
7. 新增获取二维码接口,调用该接口时会切换到二维码登录
# 打赏作者
请给作者一个star,感谢感谢
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册