mirror of
https://github.com/ttttupup/wxhelper.git
synced 2024-11-23 02:39:25 +08:00
朋友圈消息hook和朋友圈消息获取
This commit is contained in:
parent
a0f83b5a99
commit
254a9eeb30
107
README.md
107
README.md
@ -93,7 +93,9 @@ vcpkg
|
|||||||
|
|
||||||
2023-02-04 : 新增群消息置顶和取消置顶。
|
2023-02-04 : 新增群消息置顶和取消置顶。
|
||||||
|
|
||||||
2023-02-04 : 新增确认收款。
|
2023-02-06 : 新增确认收款。
|
||||||
|
|
||||||
|
2023-02-08 : 新增朋友圈消息。
|
||||||
|
|
||||||
#### 功能预览:
|
#### 功能预览:
|
||||||
0.检查是否登录
|
0.检查是否登录
|
||||||
@ -122,6 +124,8 @@ vcpkg
|
|||||||
50.拍一拍
|
50.拍一拍
|
||||||
51.群消息置顶消息
|
51.群消息置顶消息
|
||||||
52.群消息取消置顶
|
52.群消息取消置顶
|
||||||
|
53.朋友圈首页
|
||||||
|
54.朋友圈下一页
|
||||||
### 接口文档:
|
### 接口文档:
|
||||||
|
|
||||||
|
|
||||||
@ -1129,6 +1133,107 @@ vcpkg
|
|||||||
{"code":0,"result":"OK"}
|
{"code":0,"result":"OK"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 53.朋友圈首页消息**
|
||||||
|
###### 接口功能
|
||||||
|
> 获取朋友圈最新消息,调用之后,会在tcpserver服务中收到朋友圈的消息。格式如下:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
'data': [
|
||||||
|
{
|
||||||
|
'content': '朋友圈[玫瑰][玫瑰]',
|
||||||
|
'createTime': 1675827480,
|
||||||
|
'senderId': 'wxid_12333',
|
||||||
|
'snsId': 14057859804711563695,
|
||||||
|
'xml': '<TimelineObject><id><![CDATA[1405712322563695]]></id><username><![CDATA[wxid_12333]]></username><createTime><![CDATA[1675827480]]></createTime><contentDescShowType>0</contentDescShowType><contentDescScene>0</contentDescScene><private><![CDATA[0]]></private><contentDesc><![CDATA[朋友圈[玫瑰][玫瑰]]]></contentDesc><contentattr><![CDATA[0]]></contentattr><sourceUserName></sourceUserName><sourceNickName></sourceNickName><statisticsData></statisticsData><weappInfo><appUserName></appUserName><pagePath></pagePath><version><![CDATA[0]]></version><debugMode><![CDATA[0]]></debugMode><shareActionId></shareActionId><isGame><![CDATA[0]]></isGame><messageExtraData></messageExtraData><subType><![CDATA[0]]></subType><preloadResources></preloadResources></weappInfo><canvasInfoXml></canvasInfoXml><ContentObject><contentStyle><![CDATA[2]]></contentStyle><contentSubStyle><![CDATA[0]]></contentSubStyle><title></title><description></description><contentUrl></contentUrl></ContentObject><actionInfo><appMsg><mediaTagName></mediaTagName><messageExt></messageExt><messageAction></messageAction></appMsg></actionInfo><appInfo><id></id></appInfo><location poiClassifyId="" poiName="" poiAddress="" poiClassifyType="0" city=""></location><publicUserName></publicUserName><streamvideo><streamvideourl></streamvideourl><streamvideothumburl></streamvideothumburl><streamvideoweburl></streamvideoweburl></streamvideo></TimelineObject>'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=53](/api/?type=53)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, -1失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### 54.朋友圈下一页**
|
||||||
|
###### 接口功能
|
||||||
|
> 朋友圈下一页,会在tcpserver服务中收到朋友圈的消息。格式如下:
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
'data': [
|
||||||
|
{
|
||||||
|
'content': '朋友圈[玫瑰][玫瑰]',
|
||||||
|
'createTime': 1675827480,
|
||||||
|
'senderId': 'wxid_12333',
|
||||||
|
'snsId': 14057859804711563695,
|
||||||
|
'xml': '<TimelineObject><id><![CDATA[1405712322563695]]></id><username><![CDATA[wxid_12333]]></username><createTime><![CDATA[1675827480]]></createTime><contentDescShowType>0</contentDescShowType><contentDescScene>0</contentDescScene><private><![CDATA[0]]></private><contentDesc><![CDATA[朋友圈[玫瑰][玫瑰]]]></contentDesc><contentattr><![CDATA[0]]></contentattr><sourceUserName></sourceUserName><sourceNickName></sourceNickName><statisticsData></statisticsData><weappInfo><appUserName></appUserName><pagePath></pagePath><version><![CDATA[0]]></version><debugMode><![CDATA[0]]></debugMode><shareActionId></shareActionId><isGame><![CDATA[0]]></isGame><messageExtraData></messageExtraData><subType><![CDATA[0]]></subType><preloadResources></preloadResources></weappInfo><canvasInfoXml></canvasInfoXml><ContentObject><contentStyle><![CDATA[2]]></contentStyle><contentSubStyle><![CDATA[0]]></contentSubStyle><title></title><description></description><contentUrl></contentUrl></ContentObject><actionInfo><appMsg><mediaTagName></mediaTagName><messageExt></messageExt><messageAction></messageAction></appMsg></actionInfo><appInfo><id></id></appInfo><location poiClassifyId="" poiName="" poiAddress="" poiClassifyType="0" city=""></location><publicUserName></publicUserName><streamvideo><streamvideourl></streamvideourl><streamvideothumburl></streamvideothumburl><streamvideoweburl></streamvideoweburl></streamvideo></TimelineObject>'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
###### 接口地址
|
||||||
|
> [/api/?type=54](/api/?type=54)
|
||||||
|
|
||||||
|
###### HTTP请求方式
|
||||||
|
> POST JSON
|
||||||
|
|
||||||
|
###### 请求参数
|
||||||
|
|参数|必选|类型|说明|
|
||||||
|
|---|---|---|---|
|
||||||
|
|snsId |ture |string| 朋友圈的snsId |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 返回字段
|
||||||
|
|返回字段|字段类型|说明 |
|
||||||
|
|---|---|---|
|
||||||
|
|code|int|返回状态,1成功, -1失败|
|
||||||
|
|result|string|成功提示|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### 接口示例
|
||||||
|
入参:
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
响应:
|
||||||
|
``` javascript
|
||||||
|
{"code":1,"result":"OK"}
|
||||||
|
```
|
||||||
|
|
||||||
#### 感谢
|
#### 感谢
|
||||||
https://github.com/ljc545w/ComWeChatRobot
|
https://github.com/ljc545w/ComWeChatRobot
|
||||||
|
|
||||||
|
14
src/api.cc
14
src/api.cc
@ -21,6 +21,7 @@
|
|||||||
#include "ocr.h"
|
#include "ocr.h"
|
||||||
#include "pat.h"
|
#include "pat.h"
|
||||||
#include "confirm_receipt.h"
|
#include "confirm_receipt.h"
|
||||||
|
#include "sns.h"
|
||||||
|
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -591,6 +592,19 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) {
|
|||||||
ret = ret_data.dump();
|
ret = ret_data.dump();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WECHAT_SNS_GET_FIRST_PAGE:{
|
||||||
|
int success = GetFirstPage();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SNS_GET_NEXT_PAGE:{
|
||||||
|
ULONG64 snsid = get_http_param_ulong64(hm, j_param, "snsId", is_post);
|
||||||
|
int success = GetNextPage(snsid);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,8 @@ typedef enum WECHAT_HTTP_APISTag
|
|||||||
WECHAT_SEND_PAT_MSG,
|
WECHAT_SEND_PAT_MSG,
|
||||||
WECHAT_SET_TOP_MSG,
|
WECHAT_SET_TOP_MSG,
|
||||||
WECHAT_REMOVE_TOP_MSG,
|
WECHAT_REMOVE_TOP_MSG,
|
||||||
|
WECHAT_SNS_GET_FIRST_PAGE,
|
||||||
|
WECHAT_SNS_GET_NEXT_PAGE,
|
||||||
} WECHAT_HTTP_APIS,
|
} WECHAT_HTTP_APIS,
|
||||||
*PWECHAT_HTTP_APIS;
|
*PWECHAT_HTTP_APIS;
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ using namespace nlohmann;
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
#define WX_RECV_MSG_HOOK_OFFSET 0xb97126
|
#define WX_RECV_MSG_HOOK_OFFSET 0xb97126
|
||||||
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x6fc850
|
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x6fc850
|
||||||
|
#define WX_SNS_HOOK_OFFSET 0x12fb9a5
|
||||||
|
#define WX_SNS_HOOK_NEXT_OFFSET 0x12fbc30
|
||||||
|
|
||||||
// SyncMgr::addMsgListToDB
|
// SyncMgr::addMsgListToDB
|
||||||
// #define WX_RECV_MSG_HOOK_OFFSET 0xB9C919
|
// #define WX_RECV_MSG_HOOK_OFFSET 0xB9C919
|
||||||
@ -29,6 +31,13 @@ static DWORD kReceMsgJmpBackAddress =
|
|||||||
static DWORD kReceMsgNextAddress =
|
static DWORD kReceMsgNextAddress =
|
||||||
kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
|
kWeChatWinBase + WX_RECV_MSG_HOOK_NEXT_OFFSET;
|
||||||
|
|
||||||
|
|
||||||
|
static char kOriginSnsMsgAsmCode[5] = {0};
|
||||||
|
static DWORD kSnsMsgJmpBackAddress =
|
||||||
|
kWeChatWinBase + WX_SNS_HOOK_OFFSET + 0x5;
|
||||||
|
static DWORD kSnsMsgNextAddress =
|
||||||
|
kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
|
||||||
|
|
||||||
struct InnerMessageStruct {
|
struct InnerMessageStruct {
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int length;
|
int length;
|
||||||
@ -112,7 +121,7 @@ void SendSocketMessage(InnerMessageStruct *msg) {
|
|||||||
}
|
}
|
||||||
/// @brief msg handle
|
/// @brief msg handle
|
||||||
/// @param msg_addr msg address in memory
|
/// @param msg_addr msg address in memory
|
||||||
void OnRecvMsg(DWORD msg_addr) {
|
void __cdecl OnRecvMsg(DWORD msg_addr) {
|
||||||
json j_msg;
|
json j_msg;
|
||||||
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
||||||
j_msg["msgId"] = msgid;
|
j_msg["msgId"] = msgid;
|
||||||
@ -175,6 +184,50 @@ void OnRecvMsg(DWORD msg_addr) {
|
|||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
|
||||||
|
json j_sns;
|
||||||
|
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
|
||||||
|
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cout << "begin" <<begin_addr<<endl;
|
||||||
|
cout << "end" <<end_addr<<endl;
|
||||||
|
#endif
|
||||||
|
if (begin_addr == 0) {
|
||||||
|
j_sns = {{"data", json::array()}};
|
||||||
|
} else {
|
||||||
|
while (begin_addr < end_addr) {
|
||||||
|
json j_item;
|
||||||
|
j_item["snsId"] = *(unsigned long long *)(begin_addr);
|
||||||
|
j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C);
|
||||||
|
|
||||||
|
j_item["senderId"] =
|
||||||
|
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x18).c_str());
|
||||||
|
|
||||||
|
j_item["content"] =
|
||||||
|
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x3c).c_str());
|
||||||
|
|
||||||
|
j_item["xml"] =
|
||||||
|
unicode_to_utf8((wchar_t *)READ_WSTRING(begin_addr, 0x384).c_str());
|
||||||
|
|
||||||
|
j_sns["data"].push_back(j_item);
|
||||||
|
begin_addr += 0xB48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string jstr = j_sns.dump() + '\n';
|
||||||
|
InnerMessageStruct *inner_msg = new InnerMessageStruct;
|
||||||
|
inner_msg->buffer = new char[jstr.size() + 1];
|
||||||
|
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
|
||||||
|
inner_msg->length = jstr.size();
|
||||||
|
HANDLE thread = CreateThread(
|
||||||
|
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
|
||||||
|
if (thread) {
|
||||||
|
CloseHandle(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief hook implement
|
/// @brief hook implement
|
||||||
_declspec(naked) void handle_sync_msg() {
|
_declspec(naked) void handle_sync_msg() {
|
||||||
__asm {
|
__asm {
|
||||||
@ -190,6 +243,23 @@ _declspec(naked) void handle_sync_msg() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief hook sns msg implement
|
||||||
|
_declspec(naked) void handle_sns_msg() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH [ESP + 0x24]
|
||||||
|
CALL OnSnsTimeLineMsg
|
||||||
|
ADD ESP, 0x4
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL kSnsMsgNextAddress
|
||||||
|
JMP kSnsMsgJmpBackAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief hook any address address+0x5
|
/// @brief hook any address address+0x5
|
||||||
/// @param port 端口
|
/// @param port 端口
|
||||||
/// @return 成功返回1,已经hook返回2,失败返回-1
|
/// @return 成功返回1,已经hook返回2,失败返回-1
|
||||||
@ -210,6 +280,14 @@ int HookRecvMsg(char* client_ip,int port) {
|
|||||||
kReceMsgJmpBackAddress = hook_recv_msg_addr + 0x5;
|
kReceMsgJmpBackAddress = hook_recv_msg_addr + 0x5;
|
||||||
HookAnyAddress(hook_recv_msg_addr, (LPVOID)handle_sync_msg,
|
HookAnyAddress(hook_recv_msg_addr, (LPVOID)handle_sync_msg,
|
||||||
kOriginReceMsgAsmCode);
|
kOriginReceMsgAsmCode);
|
||||||
|
|
||||||
|
DWORD hook_sns_msg_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
|
||||||
|
kSnsMsgNextAddress = kWeChatWinBase + WX_SNS_HOOK_NEXT_OFFSET;
|
||||||
|
kSnsMsgJmpBackAddress = hook_sns_msg_addr + 0x5;
|
||||||
|
HookAnyAddress(hook_sns_msg_addr, (LPVOID)handle_sns_msg,
|
||||||
|
kOriginSnsMsgAsmCode);
|
||||||
|
|
||||||
|
|
||||||
kMessageHooked = TRUE;
|
kMessageHooked = TRUE;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -218,7 +296,9 @@ int UnHookRecvMsg() {
|
|||||||
kServerPort = 0;
|
kServerPort = 0;
|
||||||
if (!kMessageHooked) return 2;
|
if (!kMessageHooked) return 2;
|
||||||
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
|
DWORD hook_recv_msg_addr = kWeChatWinBase + WX_RECV_MSG_HOOK_OFFSET;
|
||||||
|
DWORD hook_sns_addr = kWeChatWinBase + WX_SNS_HOOK_OFFSET;
|
||||||
UnHookAnyAddress(hook_recv_msg_addr, kOriginReceMsgAsmCode);
|
UnHookAnyAddress(hook_recv_msg_addr, kOriginReceMsgAsmCode);
|
||||||
|
UnHookAnyAddress(hook_sns_addr, kOriginSnsMsgAsmCode);
|
||||||
kMessageHooked = FALSE;
|
kMessageHooked = FALSE;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
68
src/sns.cc
Normal file
68
src/sns.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "sns.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "wechat_data.h"
|
||||||
|
using namespace std;
|
||||||
|
#define WX_SNS_DATA_MGR_OFFSET 0xac66a0
|
||||||
|
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x12e46c0
|
||||||
|
#define WX_SNS_TIME_LINE_MGR_OFFSET 0x128e6a0
|
||||||
|
#define WX_SNS_TRY_GET_FIRST_PAGE_SCENE_OFFSET 0x12ff300
|
||||||
|
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x12e4760
|
||||||
|
|
||||||
|
int GetFirstPage() {
|
||||||
|
int success = -1;
|
||||||
|
DWORD base = GetWeChatWinBase();
|
||||||
|
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
|
||||||
|
DWORD get_first_page_addr = base + WX_SNS_GET_FIRST_PAGE_OFFSET;
|
||||||
|
|
||||||
|
DWORD time_line_mgr_addr = base + WX_SNS_TIME_LINE_MGR_OFFSET;
|
||||||
|
DWORD get_first_page_scene_addr = base + WX_SNS_TRY_GET_FIRST_PAGE_SCENE_OFFSET;
|
||||||
|
char buff[0xB44] = {};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL sns_data_mgr_addr
|
||||||
|
PUSH 0x1
|
||||||
|
LEA ECX,buff
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_first_page_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
// __asm {
|
||||||
|
// PUSHAD
|
||||||
|
// CALL time_line_mgr_addr
|
||||||
|
// PUSH 0x1
|
||||||
|
// MOV ECX,EAX
|
||||||
|
// CALL get_first_page_scene_addr
|
||||||
|
// MOV success, EAX
|
||||||
|
// POPAD
|
||||||
|
// }
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GetNextPage(ULONG64 sns_id) {
|
||||||
|
int success = -1;
|
||||||
|
DWORD base = GetWeChatWinBase();
|
||||||
|
DWORD sns_data_mgr_addr = base + WX_SNS_DATA_MGR_OFFSET;
|
||||||
|
DWORD get_next_page_addr = base + WX_SNS_GET_NEXT_PAGE_OFFSET;
|
||||||
|
VectorInner temp = {};
|
||||||
|
__asm{
|
||||||
|
PUSHAD
|
||||||
|
CALL sns_data_mgr_addr
|
||||||
|
LEA ECX,temp
|
||||||
|
PUSH ECX
|
||||||
|
MOV EBX,dword ptr [sns_id + 0x4]
|
||||||
|
PUSH EBX
|
||||||
|
MOV EDI,dword ptr [sns_id ]
|
||||||
|
PUSH EDI
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_next_page_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user