mirror of
https://github.com/ttttupup/wxhelper.git
synced 2024-11-23 02:39:25 +08:00
Merge pull request #250 from ttttupup/dev-3.9.5.81
feat:新增发送公众号消息,下载附件,图片解码,获取语音,发送自定义表情
This commit is contained in:
commit
212613e3b6
315
doc/3.9.5.81.md
315
doc/3.9.5.81.md
@ -1366,3 +1366,318 @@ enableHttp=0时,使用ip,port的tcp服务回传消息。
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 27.发送公众号消息**
|
||||
###### 接口功能
|
||||
> 自定义发送公众号消息
|
||||
|
||||
###### 接口地址
|
||||
> [/api/forwardPublicMsg](/api/forwardPublicMsg)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|appName|string|公众号id,消息内容里的appname|
|
||||
|userName|string|公众号昵称,消息内容里的username|
|
||||
|title|string|链接地址,消息内容里的title|
|
||||
|url|string|链接地址,消息内容里的url|
|
||||
|thumbUrl|string|缩略图地址,消息内容里的thumburl|
|
||||
|digest|string|摘要,消息内容里的digest|
|
||||
|wxid|string|wxid|
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"appName": "快手",
|
||||
"userName": "gh_271633",
|
||||
"title": "PC硬件、数码产品彻底反转",
|
||||
"url": "http://mp.weixin.qq.com/s?__biz=Mzg3MzYg==&mid=22440&idx=1&sn=bd8e8b0d9f2753f3c340&chksm=ced16f2ff9a6e639cc9bb76631ff03487f86486f0f29fcf9f8bed754354cb20eda31cc894a56&scene=0&xtrack=1#rd",
|
||||
"thumbUrl": "https://mmbiz.qpic.cn/sz__jpg/tpzwaqMCicQyEkpxmpmmP9KgoBHiciamYhqZ0ff4kNlozxgRq4AtEzibo4iaw/640?wxtype=jpeg&wxfrom=0",
|
||||
"digest": "这谁顶得住?",
|
||||
"wxid": "filehelper"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 28.转发公众号消息**
|
||||
###### 接口功能
|
||||
> 转发公众号消息
|
||||
|
||||
###### 接口地址
|
||||
> [/api/forwardPublicMsgByMsgId](/api/forwardPublicMsgByMsgId)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|msgId|number|msgId|
|
||||
|wxid|string|wxid|
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"msgId": 8871595889497690337,
|
||||
"wxid": "filehelper"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 29.下载附件**
|
||||
###### 接口功能
|
||||
> 下载附件,保存在微信文件目录下 wxid_xxx/wxhelper 目录下
|
||||
|
||||
###### 接口地址
|
||||
> [/api/downloadAttach](/api/downloadAttach)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|msgId|number|msgId|
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"msgId": 887159588949767
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 30.解码图片**
|
||||
###### 接口功能
|
||||
> 解码图片
|
||||
|
||||
###### 接口地址
|
||||
> [/api/decodeImage](/api/decodeImage)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|filePath|string|待解码图片地址|
|
||||
|storeDir|string|解码后图片的存储目录|
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"filePath": "C:\\886206666148161980131.dat",
|
||||
"storeDir":"C:\\test"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 31.获取语音**
|
||||
###### 接口功能
|
||||
> 获取语音,SILK v3格式,可自行转换mp3格式
|
||||
|
||||
###### 接口地址
|
||||
> [/api/getVoiceByMsgId](/api/getVoiceByMsgId)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|msgId|number|消息id|
|
||||
|storeDir|string|语音的存储目录|
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"msgId":78804324411226,
|
||||
"storeDir":"c:\\test"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 32.发送图片**
|
||||
###### 接口功能
|
||||
> 发送图片
|
||||
|
||||
###### 接口地址
|
||||
> [/api/sendImagesMsg](/api/sendImagesMsg)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|wxid|string|wxid|
|
||||
|imagePath|string|图片路径|
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"wxid":"filehelper",
|
||||
"imagePath":"C:\\test.png"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
#### 33.发送自定义表情**
|
||||
###### 接口功能
|
||||
> 发送自定义表情
|
||||
|
||||
###### 接口地址
|
||||
> [/api/sendCustomEmotion](/api/sendCustomEmotion)
|
||||
|
||||
###### HTTP请求方式
|
||||
> POST JSON
|
||||
|
||||
###### 请求参数
|
||||
|参数|必选|类型|说明|
|
||||
|---|---|---|---|
|
||||
|wxid|string|wxid|
|
||||
|filePath|string|表情路径,可以直接查询CustomEmotion表的MD5字段,路径规则见下面示例|
|
||||
|
||||
|
||||
###### 返回字段
|
||||
|返回字段|字段类型|说明 |
|
||||
|---|---|---|
|
||||
|code|int|返回状态,大于0成功, -1失败|
|
||||
|msg|string|成功提示|
|
||||
|data|object|null|
|
||||
|
||||
###### 接口示例
|
||||
|
||||
入参:
|
||||
``` javascript
|
||||
|
||||
{
|
||||
"wxid":"filehelper",
|
||||
"filePath":"C:\\wechatDir\\WeChat Files\\wxid_123\\FileStorage\\CustomEmotion\\8F\\8F6423BC2E69188DCAC797E279C81DE9"
|
||||
}
|
||||
|
||||
```
|
||||
响应:
|
||||
``` javascript
|
||||
{
|
||||
"code": 1,
|
||||
"data": {},
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
@ -395,6 +395,98 @@ def sendAtText():
|
||||
|
||||
print(response.text)
|
||||
|
||||
def forwardPublicMsg():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/forwardPublicMsg"
|
||||
|
||||
payload = json.dumps({
|
||||
"appName": "",
|
||||
"userName": "",
|
||||
"title": "",
|
||||
"url": "",
|
||||
"thumbUrl": "",
|
||||
"digest": "",
|
||||
"wxid": "filehelper"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def forwardPublicMsgByMsgId():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/forwardPublicMsgByMsgId"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 123,
|
||||
"wxid": "filehelper"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
def downloadAttach():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/downloadAttach"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 123
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def decodeImage():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/decodeImage"
|
||||
|
||||
payload = json.dumps({
|
||||
"filePath": "C:\\66664816980131.dat",
|
||||
"storeDir": "C:\\test"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
def getVoiceByMsgId():
|
||||
print("modify param ")
|
||||
raise RuntimeError("modify param then deleted me")
|
||||
url = "127.0.0.1:19088/api/getVoiceByMsgId"
|
||||
|
||||
payload = json.dumps({
|
||||
"msgId": 7880439644200,
|
||||
"storeDir": "c:\\test"
|
||||
})
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
print(response.text)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
checkLogin()
|
||||
|
11
src/hooks.cc
11
src/hooks.cc
@ -78,7 +78,7 @@ VOID CALLBACK SendMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context,
|
||||
goto clean;
|
||||
}
|
||||
char recv_buf[1024] = {0};
|
||||
ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
|
||||
ret = send(client_socket, jstr.c_str(), static_cast<int>(jstr.size()) , 0);
|
||||
if (ret < 0) {
|
||||
SPDLOG_ERROR("socket send fail ,ret:{}", ret);
|
||||
goto clean;
|
||||
@ -125,9 +125,10 @@ void HandleSyncMsg(INT64 param1, INT64 param2, INT64 param3) {
|
||||
msg["toUser"] = Utils::ReadSKBuiltinString(*(INT64 *)(param2 + 0x28));
|
||||
msg["content"] = Utils::ReadSKBuiltinString(*(INT64 *)(param2 + 0x30));
|
||||
msg["signature"] = Utils::ReadWeChatStr(*(INT64 *)(param2 + 0x48));
|
||||
msg["msgId"] = *(INT64 *)(param2 + 0x58);
|
||||
msg["msgSequence"] = *(DWORD *)(param2 + 0x20);
|
||||
msg["fromUserName"] = Utils::ReadWeChatStr(*(INT64 *)(param2 + 0x50));
|
||||
msg["msgId"] = *(INT64 *)(param2 + 0x60);
|
||||
msg["msgSequence"] = *(DWORD *)(param2 + 0x5C);
|
||||
msg["createTime"] = *(DWORD *)(param2 + 0x58);
|
||||
msg["displayFullContent"] = Utils::ReadWeChatStr(*(INT64 *)(param2 + 0x50));
|
||||
DWORD type = *(DWORD *)(param2 + 0x24);
|
||||
msg["type"] = type;
|
||||
if (type == 3) {
|
||||
@ -288,7 +289,7 @@ int UnHookSyncMsg() {
|
||||
DetourAttach(&(PVOID &)R_Log, &HandlePrintLog);
|
||||
LONG ret = DetourTransactionCommit();
|
||||
if (ret == NO_ERROR) {
|
||||
kMsgHookFlag = true;
|
||||
kLogHookFlag = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace wxhelper {
|
||||
}
|
||||
|
||||
// Send request
|
||||
int content_length = data.post_data.size();
|
||||
size_t content_length = data.post_data.size();
|
||||
mg_printf(c,
|
||||
"POST %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
|
@ -484,8 +484,9 @@ std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
} else if (mg_http_match_uri(hm, "/api/getContactProfile")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
common::ContactProfileInner profile;
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->GetContactByWxid(
|
||||
wxid, profile);
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->GetContactByWxid(wxid,
|
||||
profile);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
if (success == 1) {
|
||||
@ -498,7 +499,67 @@ std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
}
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
|
||||
} else if (mg_http_match_uri(hm, "/api/downloadAttach")) {
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->DoDownloadTask(msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/forwardPublicMsg")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring appname = GetWStringParam(j_param, "appName");
|
||||
std::wstring username = GetWStringParam(j_param, "userName");
|
||||
std::wstring title = GetWStringParam(j_param, "title");
|
||||
std::wstring url = GetWStringParam(j_param, "url");
|
||||
std::wstring thumburl = GetWStringParam(j_param, "thumbUrl");
|
||||
std::wstring digest = GetWStringParam(j_param, "digest");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ForwardPublicMsg(
|
||||
wxid, title, url, thumburl, username, appname, digest);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/forwardPublicMsgByMsgId")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->ForwardPublicMsgByMsgId(
|
||||
wxid, msg_id);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/decodeImage")) {
|
||||
std::wstring file_path = GetWStringParam(j_param, "filePath");
|
||||
std::wstring store_dir = GetWStringParam(j_param, "storeDir");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->DecodeImage(
|
||||
file_path, store_dir);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/getVoiceByMsgId")) {
|
||||
UINT64 msg_id = GetUINT64Param(j_param, "msgId");
|
||||
std::wstring store_dir = GetWStringParam(j_param, "storeDir");
|
||||
INT64 success = wxhelper::GlobalContext::GetInstance().mgr->GetVoiceByDB(
|
||||
msg_id, store_dir);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else if (mg_http_match_uri(hm, "/api/sendCustomEmotion")) {
|
||||
std::wstring wxid = GetWStringParam(j_param, "wxid");
|
||||
std::wstring file_path = GetWStringParam(j_param, "filePath");
|
||||
INT64 success =
|
||||
wxhelper::GlobalContext::GetInstance().mgr->SendCustomEmotion(file_path,
|
||||
wxid);
|
||||
nlohmann::json ret_data = {
|
||||
{"code", success}, {"msg", "success"}, {"data", {}}};
|
||||
ret = ret_data.dump();
|
||||
return ret;
|
||||
} else {
|
||||
nlohmann::json ret_data = {
|
||||
{"code", 200}, {"data", {}}, {"msg", "not support url"}};
|
||||
|
312
src/manager.cc
312
src/manager.cc
@ -4,6 +4,9 @@
|
||||
#include "export.h"
|
||||
#include "wechat_function.h"
|
||||
#include "db.h"
|
||||
#include "lz4.h"
|
||||
#include "base64.h"
|
||||
#include "tinyxml2.h"
|
||||
|
||||
namespace offset = wxhelper::V3_9_5_81::offset;
|
||||
namespace prototype = wxhelper::V3_9_5_81::prototype;
|
||||
@ -783,4 +786,313 @@ INT64 Manager::GetContactByWxid(const std::wstring &wxid,
|
||||
free_contact(contact);
|
||||
return success;
|
||||
}
|
||||
|
||||
INT64 Manager::DoDownloadTask(UINT64 msg_id) {
|
||||
INT64 success = -1;
|
||||
UINT64 get_by_local_id_addr = base_addr_ + offset::kGetMgrByPrefixLocalId;
|
||||
func::__GetMgrByPrefixLocalId get_by_local_id =
|
||||
(func::__GetMgrByPrefixLocalId)get_by_local_id_addr;
|
||||
|
||||
UINT64 get_chat_mgr_addr = base_addr_ + offset::kGetChatMgr;
|
||||
func::__GetChatMgr get_chat_mgr = (func::__GetChatMgr)get_chat_mgr_addr;
|
||||
|
||||
UINT64 free_chat_msg_addr = base_addr_ + offset::kFreeChatMsg;
|
||||
func::__FreeChatMsg free_chat_msg = (func::__FreeChatMsg)free_chat_msg_addr;
|
||||
|
||||
UINT64 new_chat_msg_addr = base_addr_ + offset::kChatMsgInstanceCounter;
|
||||
func::__NewChatMsg new_chat_msg = (func::__NewChatMsg)new_chat_msg_addr;
|
||||
|
||||
UINT64 get_current_data_path_addr = base_addr_ + offset::kGetCurrentDataPath;
|
||||
func::__GetCurrentDataPath GetCurrentDataPath =
|
||||
(func::__GetCurrentDataPath)get_current_data_path_addr;
|
||||
|
||||
UINT64 new_app_msg_info_addr = base_addr_ + offset::kNewAppMsgInfo;
|
||||
func::__NewAppMsgInfo new_app_msg_info =
|
||||
(func::__NewAppMsgInfo)new_app_msg_info_addr;
|
||||
|
||||
UINT64 free_app_msg_info_addr = base_addr_ + offset::kFreeAppMsgInfo;
|
||||
func::__FreeAppMsgInfo free_app_msg_info =
|
||||
(func::__NewAppMsgInfo)free_app_msg_info_addr;
|
||||
|
||||
UINT64 xml_to_app_info_addr = base_addr_ + offset::kParseAppMsgXml;
|
||||
func::__ParseAppMsgXml xml_to_app_info =
|
||||
(func::__ParseAppMsgXml)xml_to_app_info_addr;
|
||||
|
||||
UINT64 get_pre_download_mgr_addr = base_addr_ + offset::kGetPreDownLoadMgr;
|
||||
func::__GetPreDownLoadMgr get_pre_download_mgr =
|
||||
(func::__GetPreDownLoadMgr)get_pre_download_mgr_addr;
|
||||
|
||||
UINT64 push_attach_task_addr = base_addr_ + offset::kPushAttachTask;
|
||||
func::__PushAttachTask push_attach_task =
|
||||
(func::__PushAttachTask)push_attach_task_addr;
|
||||
|
||||
INT64 index = 0;
|
||||
INT64 local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, index);
|
||||
if (local_id <= 0 || index >> 32 == 0) {
|
||||
success = -2;
|
||||
return success;
|
||||
}
|
||||
char *chat_msg = Utils::WxHeapAlloc<char>(0x460);
|
||||
LARGE_INTEGER l;
|
||||
l.HighPart = index >> 32;
|
||||
l.LowPart = (DWORD)local_id;
|
||||
UINT64 p_chat_msg = new_chat_msg(reinterpret_cast<UINT64>(chat_msg));
|
||||
|
||||
get_chat_mgr();
|
||||
get_by_local_id(l.QuadPart, p_chat_msg);
|
||||
|
||||
std::wstring save_path = L"";
|
||||
std::wstring thumb_path = L"";
|
||||
|
||||
prototype::WeChatString current_data_path;
|
||||
GetCurrentDataPath(reinterpret_cast<ULONG_PTR>(¤t_data_path));
|
||||
|
||||
if (current_data_path.length > 0) {
|
||||
save_path += current_data_path.ptr;
|
||||
save_path += L"wxhelper";
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return -3;
|
||||
}
|
||||
INT64 type = *(INT64 *)(chat_msg + 0x38);
|
||||
wchar_t *content = *(wchar_t **)(chat_msg + 0x88);
|
||||
DWORD len = *(DWORD *)(chat_msg + 0x94);
|
||||
std::wstring tmp_content(content, len);
|
||||
prototype::WeChatString *we_content = BuildWechatString(tmp_content);
|
||||
|
||||
switch (type) {
|
||||
case 0x3: {
|
||||
save_path += L"\\image";
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return -3;
|
||||
}
|
||||
thumb_path = save_path + L"\\" + std::to_wstring(msg_id) + L"_t.dat";
|
||||
save_path = save_path + L"\\" + std::to_wstring(msg_id) + L".dat";
|
||||
break;
|
||||
}
|
||||
case 0x3E:
|
||||
case 0x2B: {
|
||||
save_path += L"\\video";
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return -3;
|
||||
}
|
||||
thumb_path = save_path + L"\\" + std::to_wstring(msg_id) + L".jpg";
|
||||
save_path = save_path + L"\\" + std::to_wstring(msg_id) + L".mp4";
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x31: {
|
||||
save_path += L"\\file";
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return -3;
|
||||
}
|
||||
char *p_xml_app_msg = Utils::WxHeapAlloc<char>(0x3000);
|
||||
UINT64 xml_msg =
|
||||
new_app_msg_info(reinterpret_cast<UINT64>(p_xml_app_msg));
|
||||
UINT64 result =
|
||||
xml_to_app_info(xml_msg, reinterpret_cast<UINT64>(we_content), 1);
|
||||
if (result != 1) {
|
||||
return -4;
|
||||
}
|
||||
std::wstring file_name = Utils::ReadWstring(xml_msg + 0x70);
|
||||
save_path =
|
||||
save_path + L"\\" + std::to_wstring(msg_id) + L"_" + file_name;
|
||||
free_app_msg_info(xml_msg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prototype::WeChatString *we_save_path = BuildWechatString(save_path);
|
||||
prototype::WeChatString *we_thumb_path = BuildWechatString(thumb_path);
|
||||
int temp = 1;
|
||||
memcpy(chat_msg + 0x280, we_thumb_path, sizeof(prototype::WeChatString));
|
||||
memcpy(chat_msg + 0x2A0, we_save_path, sizeof(prototype::WeChatString));
|
||||
memcpy(chat_msg + 0x40C, &temp, sizeof(temp));
|
||||
UINT64 mgr = get_pre_download_mgr();
|
||||
success = push_attach_task(mgr, p_chat_msg, 0, 1);
|
||||
free_chat_msg(p_chat_msg);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
INT64 Manager::ForwardPublicMsg(const std::wstring &wxid,
|
||||
const std::wstring &title,
|
||||
const std::wstring &url,
|
||||
const std::wstring &thumb_url,
|
||||
const std::wstring &sender_id,
|
||||
const std::wstring &sender_name,
|
||||
const std::wstring &digest) {
|
||||
INT64 success = -1;
|
||||
UINT64 new_item_addr = base_addr_ + offset::kNewMMReaderItem;
|
||||
func::__NewMMReaderItem new_item = (func::__NewMMReaderItem)new_item_addr;
|
||||
|
||||
UINT64 free_item_addr = base_addr_ + offset::kFreeMMReaderItem;
|
||||
func::__FreeMMReaderItem free_item = (func::__FreeMMReaderItem)free_item_addr;
|
||||
|
||||
UINT64 get_app_msg_mgr_addr = base_addr_ + offset::kGetAppMsgMgr;
|
||||
func::__GetAppMsgMgr get_app_mgr = (func::__GetAppMsgMgr)get_app_msg_mgr_addr;
|
||||
|
||||
UINT64 forward_public_msg_addr = base_addr_ + offset::kForwordPublicMsg;
|
||||
func::__ForwordPublicMsg forward_public_msg =
|
||||
(func::__ForwordPublicMsg)forward_public_msg_addr;
|
||||
|
||||
char *p_item = Utils::WxHeapAlloc<char>(0x3E4);
|
||||
new_item(reinterpret_cast<UINT64>(p_item));
|
||||
prototype::WeChatString *to_user = BuildWechatString(wxid);
|
||||
prototype::WeChatString *p_title = BuildWechatString(title);
|
||||
prototype::WeChatString *p_url = BuildWechatString(url);
|
||||
prototype::WeChatString *p_thumburl = BuildWechatString(thumb_url);
|
||||
prototype::WeChatString *p_sender_id = BuildWechatString(sender_id);
|
||||
prototype::WeChatString *p_name = BuildWechatString(sender_name);
|
||||
prototype::WeChatString *p_digest = BuildWechatString(digest);
|
||||
|
||||
memcpy(p_item + 0x8, p_title, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0x48, p_url, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0xB0, p_thumburl, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0xF0, p_digest, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0x2A0, p_sender_id, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0x2C0, p_name, sizeof(prototype::WeChatString));
|
||||
memcpy(p_item + 0x2C0, p_name, sizeof(prototype::WeChatString));
|
||||
|
||||
UINT64 mgr = get_app_mgr();
|
||||
success = forward_public_msg(mgr, reinterpret_cast<UINT64>(to_user),
|
||||
reinterpret_cast<UINT64>(p_item));
|
||||
free_item(reinterpret_cast<UINT64>(p_item));
|
||||
return success;
|
||||
}
|
||||
|
||||
INT64 Manager::ForwardPublicMsgByMsgId(const std::wstring &wxid,
|
||||
UINT64 msg_id) {
|
||||
INT64 success = -1;
|
||||
std::string compress_content =
|
||||
DB::GetInstance().GetPublicMsgCompressContentByMsgId(msg_id);
|
||||
if (compress_content.empty()) {
|
||||
SPDLOG_INFO("Get compressContent is null from PublicMsg.db");
|
||||
return -3;
|
||||
}
|
||||
|
||||
std::string decode = base64_decode(compress_content);
|
||||
size_t len = decode.size();
|
||||
const char *src = decode.c_str();
|
||||
size_t dst_len = (len << 8);
|
||||
char *dst = new char[dst_len];
|
||||
|
||||
int decompress_len = LZ4_decompress_safe_partial(
|
||||
src, dst, static_cast<int>(len), static_cast<int>(dst_len), static_cast<int>(dst_len));
|
||||
if (decompress_len < 0) {
|
||||
SPDLOG_INFO("decompress content size :{}", decompress_len);
|
||||
return -1;
|
||||
}
|
||||
tinyxml2::XMLDocument doc;
|
||||
if (doc.Parse(dst, decompress_len - 1) != 0) {
|
||||
SPDLOG_INFO("tinyxml2 parse error");
|
||||
return -2;
|
||||
}
|
||||
const char *title = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("title")
|
||||
->GetText();
|
||||
const char *digest = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("des")
|
||||
->GetText();
|
||||
|
||||
const char *url = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("mmreader")
|
||||
->FirstChildElement("category")
|
||||
->FirstChildElement("item")
|
||||
->FirstChildElement("url")
|
||||
->GetText();
|
||||
const char *thumb_url = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("thumburl")
|
||||
->GetText();
|
||||
const char *user_name = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("mmreader")
|
||||
->FirstChildElement("publisher")
|
||||
->FirstChildElement("username")
|
||||
->GetText();
|
||||
|
||||
const char *nickname = doc.FirstChildElement("msg")
|
||||
->FirstChildElement("appmsg")
|
||||
->FirstChildElement("mmreader")
|
||||
->FirstChildElement("publisher")
|
||||
->FirstChildElement("nickname")
|
||||
->GetText();
|
||||
|
||||
std::string s_title(title);
|
||||
std::string s_digest(digest);
|
||||
std::string s_url(url);
|
||||
std::string s_thumburl(thumb_url);
|
||||
std::string s_user_name(user_name);
|
||||
std::string s_nickname(nickname);
|
||||
|
||||
std::wstring ws_title = Utils::UTF8ToWstring(s_title);
|
||||
std::wstring ws_digest = Utils::UTF8ToWstring(s_digest);
|
||||
std::wstring ws_url = Utils::UTF8ToWstring(s_url);
|
||||
std::wstring ws_thumb_url = Utils::UTF8ToWstring(s_thumburl);
|
||||
std::wstring ws_user_name = Utils::UTF8ToWstring(s_user_name);
|
||||
std::wstring ws_nickname = Utils::UTF8ToWstring(s_nickname);
|
||||
success = ForwardPublicMsg(wxid, ws_title, ws_url, ws_thumb_url, ws_user_name,
|
||||
ws_nickname, ws_digest);
|
||||
return success;
|
||||
}
|
||||
|
||||
INT64 Manager::DecodeImage(const std::wstring &file_path, const std::wstring &save_dir) {
|
||||
return Utils::DecodeImage(file_path.c_str(), save_dir.c_str());
|
||||
}
|
||||
|
||||
INT64 Manager::GetVoiceByDB(ULONG64 msg_id, const std::wstring& dir) {
|
||||
INT64 success = -1;
|
||||
std::string buff = DB::GetInstance().GetVoiceBuffByMsgId(msg_id);
|
||||
if (buff.size() == 0) {
|
||||
success = 0;
|
||||
return success;
|
||||
}
|
||||
std::wstring save_path = dir;
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
success = -2;
|
||||
return success;
|
||||
}
|
||||
save_path = save_path + L"\\" + std::to_wstring(msg_id) + L".amr";
|
||||
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||
SPDLOG_ERROR("GetVoiceByDB save path invalid");
|
||||
return success;
|
||||
}
|
||||
DWORD bytes_write = 0;
|
||||
std::string decode = base64_decode(buff);
|
||||
WriteFile(file_handle, (LPCVOID)decode.c_str(), static_cast<DWORD>(decode.size()) , &bytes_write, 0);
|
||||
CloseHandle(file_handle);
|
||||
success = 1;
|
||||
return success;
|
||||
}
|
||||
|
||||
INT64 Manager::SendCustomEmotion(const std::wstring &file_path,
|
||||
const std::wstring &wxid) {
|
||||
INT64 success = -1;
|
||||
UINT64 get_custom_smiley_mgr_addr = base_addr_ + offset::kGetCustomSmileyMgr;
|
||||
func::__GetCustomSmileyMgr get_custom_smiley_mgr =
|
||||
(func::__GetCustomSmileyMgr)get_custom_smiley_mgr_addr;
|
||||
UINT64 send_custom_emotion_addr = base_addr_ + offset::kSendCustomEmotion;
|
||||
func::__SendCustomEmotion send_custom_emotion =
|
||||
(func::__SendCustomEmotion)send_custom_emotion_addr;
|
||||
prototype::WeChatString *path = BuildWechatString(file_path);
|
||||
prototype::WeChatString *recv = BuildWechatString(wxid);
|
||||
INT64 *temp = Utils::WxHeapAlloc<INT64>(0x20);
|
||||
memset(temp, 0, 0x20);
|
||||
UINT64 mgr = get_custom_smiley_mgr();
|
||||
success = send_custom_emotion(
|
||||
mgr, reinterpret_cast<UINT64>(path), reinterpret_cast<UINT64>(temp),
|
||||
reinterpret_cast<UINT64>(recv), 2, reinterpret_cast<UINT64>(temp), 0,
|
||||
reinterpret_cast<UINT64>(temp));
|
||||
return success;
|
||||
}
|
||||
} // namespace wxhelper
|
@ -43,6 +43,19 @@ class Manager {
|
||||
std::wstring GetContactOrChatRoomNickname(const std::wstring& wxid);
|
||||
INT64 GetContactByWxid(const std::wstring& wxid,
|
||||
common::ContactProfileInner& profile);
|
||||
INT64 DoDownloadTask(UINT64 msg_id);
|
||||
INT64 ForwardPublicMsg(const std::wstring& wxid, const std::wstring& title,
|
||||
const std::wstring& url, const std::wstring& thumb_url,
|
||||
const std::wstring& sender_id,
|
||||
const std::wstring& sender_name,
|
||||
const std::wstring& digest);
|
||||
INT64 ForwardPublicMsgByMsgId(const std::wstring& wxid, UINT64 msg_id);
|
||||
|
||||
INT64 DecodeImage(const std::wstring& file_path,
|
||||
const std::wstring& save_dir);
|
||||
INT64 GetVoiceByDB(ULONG64 msg_id, const std::wstring& dir);
|
||||
INT64 SendCustomEmotion(const std::wstring& file_path,
|
||||
const std::wstring& wxid);
|
||||
|
||||
private:
|
||||
UINT64 base_addr_;
|
||||
|
79
src/utils.cc
79
src/utils.cc
@ -319,4 +319,83 @@ std::string Utils::ReadWstringThenConvert(INT64 addr){
|
||||
std::wstring wstr = ReadWstring(addr);
|
||||
return WstringToUTF8(wstr);
|
||||
}
|
||||
|
||||
INT64 Utils::DecodeImage(const wchar_t* file_path,const wchar_t* save_dir){
|
||||
std::wstring save_path(save_dir);
|
||||
std::wstring orign_file_path(file_path);
|
||||
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT64 pos_begin = orign_file_path.find_last_of(L"\\") + 1;
|
||||
INT64 pos_end = orign_file_path.find_last_of(L".");
|
||||
std::wstring file_name =
|
||||
orign_file_path.substr(pos_begin, pos_end - pos_begin);
|
||||
HANDLE h_origin_file =
|
||||
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
char buffer[BUFSIZE] = {0};
|
||||
DWORD bytes_read = 0;
|
||||
DWORD bytes_write = 0;
|
||||
unsigned char magic_head[4] = {0};
|
||||
std::wstring suffix;
|
||||
short key = 0;
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
memcpy(magic_head, buffer, 3);
|
||||
} else {
|
||||
CloseHandle(h_origin_file);
|
||||
return 0;
|
||||
}
|
||||
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
|
||||
key = magic_head[0] ^ JPEG0;
|
||||
suffix = L".jpg";
|
||||
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
|
||||
key = magic_head[0] ^ PNG1;
|
||||
suffix = L".png";
|
||||
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
|
||||
key = magic_head[0] ^ GIF0;
|
||||
suffix = L".gif";
|
||||
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
|
||||
key = magic_head[0] ^ BMP0;
|
||||
suffix = L".bmp";
|
||||
} else {
|
||||
key = -1;
|
||||
suffix = L".dat";
|
||||
}
|
||||
std::wstring save_img_path = save_path + L"\\" + file_name + suffix;
|
||||
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (save_img == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i] ^= key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||
if (key > 0) {
|
||||
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||
buffer[i] ^= key;
|
||||
}
|
||||
}
|
||||
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == BUFSIZE);
|
||||
CloseHandle(h_origin_file);
|
||||
CloseHandle(save_img);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace wxhelper
|
@ -58,6 +58,8 @@ class Utils {
|
||||
static std::wstring ReadWstring(INT64 addr);
|
||||
static std::string ReadWstringThenConvert(INT64 addr);
|
||||
|
||||
static INT64 DecodeImage(const wchar_t* file_path,const wchar_t* save_dir);
|
||||
|
||||
template <typename T1, typename T2>
|
||||
static std::vector<T1> split(T1 str, T2 letter) {
|
||||
std::vector<T1> arr;
|
||||
|
@ -112,7 +112,7 @@ struct SqlResult {
|
||||
|
||||
struct InnerMessageStruct {
|
||||
char *buffer;
|
||||
int length;
|
||||
INT64 length;
|
||||
~InnerMessageStruct() {
|
||||
if (this->buffer != NULL) {
|
||||
delete[] this->buffer;
|
||||
@ -264,6 +264,16 @@ typedef UINT64 (*__AddFavFromImage)(UINT64,UINT64,UINT64);
|
||||
typedef UINT64 (*__GetContact)(UINT64,UINT64,UINT64);
|
||||
typedef UINT64 (*__NewContact)(UINT64);
|
||||
typedef UINT64 (*__FreeContact)(UINT64);
|
||||
typedef UINT64 (*__NewMMReaderItem)(UINT64);
|
||||
typedef UINT64 (*__FreeMMReaderItem)(UINT64);
|
||||
typedef UINT64 (*__ForwordPublicMsg)(UINT64,UINT64,UINT64);
|
||||
typedef UINT64 (*__NewAppMsgInfo)(UINT64);
|
||||
typedef UINT64 (*__FreeAppMsgInfo)(UINT64);
|
||||
typedef UINT64 (*__ParseAppMsgXml)(UINT64,UINT64,UINT64);
|
||||
typedef UINT64 (*__GetPreDownLoadMgr)();
|
||||
typedef UINT64 (*__PushAttachTask)(UINT64,UINT64,UINT64,UINT64);
|
||||
typedef UINT64 (*__GetCustomSmileyMgr)();
|
||||
typedef UINT64 (*__SendCustomEmotion)(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64);
|
||||
|
||||
|
||||
} // namespace function
|
||||
@ -384,6 +394,16 @@ const UINT64 kAddFavFromImage = 0x160b920;
|
||||
const UINT64 kGetContact = 0xEA5F90;
|
||||
const UINT64 kNewContact = 0x1212e40;
|
||||
const UINT64 kFreeContact = 0x12134e0;
|
||||
const UINT64 kNewMMReaderItem = 0x8c79a0;
|
||||
const UINT64 kFreeMMReaderItem = 0x8c6da0;
|
||||
const UINT64 kForwordPublicMsg = 0xddc6c0;
|
||||
const UINT64 kParseAppMsgXml = 0x11b0a70;
|
||||
const UINT64 kNewAppMsgInfo = 0x91a550;
|
||||
const UINT64 kFreeAppMsgInfo = 0x8fd1a0;
|
||||
const UINT64 kGetPreDownLoadMgr = 0x9996f0;
|
||||
const UINT64 kPushAttachTask = 0x9c0080;
|
||||
const UINT64 kGetCustomSmileyMgr = 0x915c00;
|
||||
const UINT64 kSendCustomEmotion = 0xec0a40;
|
||||
|
||||
} // namespace offset
|
||||
} // namespace V3_9_5_81
|
||||
|
Loading…
Reference in New Issue
Block a user