From 4eab2a2414975c61cb5b452def1ac62fe8792adb Mon Sep 17 00:00:00 2001 From: hugy <504650082@qq.com> Date: Sat, 4 Mar 2023 11:30:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=8B=E8=BD=BD=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E9=99=84=E4=BB=B6=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 41 +++++++++++ src/api.cc | 8 ++ src/api.h | 1 + src/common.cc | 2 +- src/download.cc | 183 ++++++++++++++++++++++++++++++++++++++++++++++ src/download.h | 5 ++ src/wechat_data.h | 147 +++++++++++++++++++++++++++++++++++++ 7 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 src/download.cc create mode 100644 src/download.h diff --git a/README.md b/README.md index b22233b..70272e9 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ vcpkg 53.朋友圈首页 54.朋友圈下一页 55.获取联系人或者群名称 +56.获取消息附件(图片,视频,文件) ### 接口文档: @@ -1464,6 +1465,46 @@ vcpkg +#### 56.获取消息附件** +###### 接口功能 +> 根据消息id,下载消息附件(图片,视频,文件) + +###### 接口地址 +> [/api/?type=56](/api/?type=56) + +###### HTTP请求方式 +> POST JSON + +###### 请求参数 +|参数|必选|类型|说明| +|---|---|---|---| +|msgId |true |string| 消息id | + + + +###### 返回字段 +|返回字段|字段类型|说明 | +|---|---|---| +|code|int|返回状态,0成功, 非0失败| +|result|string|成功提示| + + + +###### 接口示例 +入参: +``` javascript +{ + "msgId": 3224560917391784099 + +} + +``` +响应: +``` javascript +{"code":0,"result":"OK"} +``` + + #### 感谢 https://github.com/ljc545w/ComWeChatRobot diff --git a/src/api.cc b/src/api.cc index ae13bef..4183138 100644 --- a/src/api.cc +++ b/src/api.cc @@ -23,6 +23,7 @@ #include "confirm_receipt.h" #include "sns.h" #include "search_contact.h" +#include "download.h" #pragma comment(lib, "ws2_32.lib") using namespace std; @@ -652,6 +653,13 @@ void api_handle(mg_http_message *hm, struct mg_connection *c, string &ret) { ret = ret_data.dump(); break; } + case WECHAT_ATTACH_DOWNLOAD:{ + ULONG64 msg_id = get_http_param_ulong64(hm, j_param, "msgId", is_post); + int success = DoDownloadTask(msg_id); + json ret_data = {{"code", success}, {"result", "OK"}}; + ret = ret_data.dump(); + break; + } default: break; } diff --git a/src/api.h b/src/api.h index 94b9c50..3b44f4a 100644 --- a/src/api.h +++ b/src/api.h @@ -70,6 +70,7 @@ typedef enum WECHAT_HTTP_APISTag WECHAT_SNS_GET_FIRST_PAGE, WECHAT_SNS_GET_NEXT_PAGE, WECHAT_CONTACT_NAME, + WECHAT_ATTACH_DOWNLOAD, } WECHAT_HTTP_APIS, *PWECHAT_HTTP_APIS; diff --git a/src/common.cc b/src/common.cc index e60a3a1..d3e0ce1 100644 --- a/src/common.cc +++ b/src/common.cc @@ -126,7 +126,7 @@ string Wstring2String(wstring wstr) { BOOL FindOrCreateDirectoryW(const wchar_t *path) { WIN32_FIND_DATAW fd; HANDLE hFind = ::FindFirstFileW(path, &fd); - if (hFind != INVALID_HANDLE_VALUE) { + if (hFind != INVALID_HANDLE_VALUE && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { FindClose(hFind); return true; } diff --git a/src/download.cc b/src/download.cc new file mode 100644 index 0000000..f22a6d0 --- /dev/null +++ b/src/download.cc @@ -0,0 +1,183 @@ +#include "pch.h" +#include "download.h" + +#include "common.h" +#include "get_db_handle.h" + +#include "wechat_data.h" + +#define WX_NEW_CHAT_MSG_OFFSET 0x70e2a0 +#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x7ae310 +#define WX_PUSH_ATTACH_TASK_OFFSET 0x7c94a0 +#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x6f5370 +#define WX_FREE_CHAT_MSG_OFFSET 0x6f4ea0 +#define WX_CHAT_MGR_OFFSET 0x732660 +#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xb54950 +#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc11140 +#define WX_APP_MSG_INFO_OFFSET 0x7571d0 +#define WX_GET_APP_MSG_XML_OFFSET 0xddef80 +#define WX_FREE_APP_MSG_INFO_OFFSET 0x73d820 +#define WX_PUSH_THUMB_TASK_OFFSET 0x7c93a0 +#define WX_VIDEO_MGR_OFFSET 0x7c7300 +#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xcc6d80 + +using namespace std; + +int DoDownloadTask(ULONG64 msg_id) { + int success = -1; + int db_index = 0; + int local_id = GetLocalIdByMsgId(msg_id, db_index); + if (local_id < 1) { + return -2; + } + + char chat_msg[0x2C4] = {0}; + DWORD base = GetWeChatWinBase(); + DWORD new_chat_msg_addr = base + WX_NEW_CHAT_MSG_OFFSET; + DWORD get_chat_mgr_addr = base + WX_CHAT_MGR_OFFSET; + DWORD pre_download_mgr_addr = base + WX_GET_PRE_DOWNLOAD_MGR_OFFSET; + DWORD push_attach_task_addr = base + WX_PUSH_ATTACH_TASK_OFFSET; + DWORD free_addr = base + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET; + DWORD get_by_local_Id_addr = base + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET; + DWORD get_current_data_path_addr = base + WX_GET_CURRENT_DATA_PATH_OFFSET; + DWORD free_app_msg_info_addr = base + WX_FREE_APP_MSG_INFO_OFFSET; + DWORD push_thumb_task_addr = base + WX_PUSH_THUMB_TASK_OFFSET; + DWORD video_mgr_addr = base + WX_VIDEO_MGR_OFFSET; + DWORD download_video_image_addr = base + WX_VIDEO_MGR_OFFSET; + + WeChatString current_data_path; + + __asm { + PUSHAD + PUSHFD + LEA ECX,current_data_path + CALL get_current_data_path_addr + + LEA ECX,chat_msg + CALL new_chat_msg_addr + + CALL get_chat_mgr_addr + PUSH dword ptr [db_index] + LEA ECX,chat_msg + PUSH dword ptr [local_id] + CALL get_by_local_Id_addr + ADD ESP,0x8 + POPFD + POPAD + } + wstring save_path = L""; + wstring thumb_path = L""; + if (current_data_path.length > 0) { + save_path += current_data_path.ptr; + save_path += L"wxhelper"; + } else { + return -1; + } + + if (!FindOrCreateDirectoryW(save_path.c_str())) { + return -3; + } + DWORD type = *(DWORD *)(chat_msg + 0x38); + wchar_t *content = *(wchar_t **)(chat_msg + 0x70); + + switch (type) { + case 0x3: { + save_path += L"\\image"; + if (!FindOrCreateDirectoryW(save_path.c_str())) { + return -3; + } + save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png"; + break; + } + case 0x3E: + case 0x2B: { + save_path += L"\\video"; + if (!FindOrCreateDirectoryW(save_path.c_str())) { + return -3; + } + thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg"; + save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4"; + + break; + } + case 0x31: { + save_path += L"\\file"; + wcout << save_path << endl; + if (!FindOrCreateDirectoryW(save_path.c_str())) { + return -3; + } + char xml_app_msg[0xC80] = {0}; + DWORD new_app_msg_addr = base + WX_APP_MSG_INFO_OFFSET; + DWORD get_xml_addr = base + WX_GET_APP_MSG_XML_OFFSET; + WeChatString w_content(content); + + __asm { + PUSHAD + PUSHFD + LEA ECX,xml_app_msg + CALL new_app_msg_addr + PUSH 0x1 + LEA EAX,w_content + PUSH EAX + LEA ECX,xml_app_msg + CALL get_xml_addr + MOV success,EAX + LEA ECX,xml_app_msg + CALL free_app_msg_info_addr + POPFD + POPAD + } + if (success != 1) { + return -4; + } + WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44); + save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" + + wstring(file_name->ptr, file_name->length); + break; + } + default: + break; + } + WeChatString w_save_path(save_path); + WeChatString w_thumb_path(thumb_path); + int temp =1; + memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path)); + memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path)); + memcpy(&chat_msg[0x290], &temp, sizeof(temp)); + // note: the image has been downloaded and will not be downloaded again + // use low-level method + // this function does not work, need to modify chatmsg. + // if (type == 0x3E || type == 0x2B){ + // __asm{ + // PUSHAD + // PUSHFD + // CALL video_mgr_addr + // LEA ECX,chat_msg + // PUSH ECX + // MOV ECX,EAX + // CALL download_video_image_addr + // POPFD + // POPAD + // } + // } + + __asm { + PUSHAD + PUSHFD + CALL pre_download_mgr_addr + PUSH 0x1 + PUSH 0x0 + LEA ECX,chat_msg + PUSH ECX + MOV ECX,EAX + CALL push_attach_task_addr + MOV success,EAX + LEA ECX,chat_msg + PUSH 0x0 + CALL free_addr + POPFD + POPAD + } + + return success; +} \ No newline at end of file diff --git a/src/download.h b/src/download.h new file mode 100644 index 0000000..fcd15b9 --- /dev/null +++ b/src/download.h @@ -0,0 +1,5 @@ +#ifndef DOWNLOAD_H_ +#define DOWNLOAD_H_ + +int DoDownloadTask(ULONG64 msg_id); +#endif \ No newline at end of file diff --git a/src/wechat_data.h b/src/wechat_data.h index f15b8e3..cf4f997 100644 --- a/src/wechat_data.h +++ b/src/wechat_data.h @@ -186,4 +186,151 @@ struct AtInner{ DWORD finsh; DWORD end; }; + +struct ChatMsg { + DWORD **field0_0x0; + DWORD field1_0x4; + ULONG64 sequence; + DWORD field3_0x10; + DWORD field4_0x14; + ULONG64 msgSequence; + DWORD localId; + DWORD field7_0x24; + DWORD field8_0x28; + DWORD field9_0x2c; + ULONG64 msgId; + DWORD type; + DWORD isSendMsg; + DWORD msgStatus; + DWORD timestamp; + WeChatString talker; + DWORD field16_0x5c; + DWORD field17_0x60; + DWORD field18_0x64; + DWORD field19_0x68; + DWORD field20_0x6c; + WeChatString content; + DWORD field22_0x84; + DWORD field23_0x88; + DWORD field24_0x8c; + DWORD field25_0x90; + DWORD field26_0x94; + DWORD field27_0x98; + DWORD field28_0x9c; + DWORD field29_0xa0; + DWORD field30_0xa4; + DWORD field31_0xa8; + DWORD field32_0xac; + DWORD field33_0xb0; + DWORD field34_0xb4; + DWORD field35_0xb8; + DWORD field36_0xbc; + DWORD field37_0xc0; + DWORD field38_0xc4; + DWORD field39_0xc8; + DWORD field40_0xcc; + DWORD field41_0xd0; + DWORD field42_0xd4; + DWORD field43_0xd8; + DWORD field44_0xdc; + DWORD field45_0xe0; + DWORD field46_0xe4; + DWORD field47_0xe8; + DWORD field48_0xec; + DWORD field49_0xf0; + DWORD field50_0xf4; + DWORD field51_0xf8; + DWORD field52_0xfc; + DWORD field53_0x100; + DWORD field54_0x104; + DWORD field55_0x108; + DWORD field56_0x10c; + DWORD field57_0x110; + DWORD field58_0x114; + DWORD field59_0x118; + DWORD field60_0x11c; + DWORD field61_0x120; + DWORD field62_0x124; + DWORD field63_0x128; + DWORD field64_0x12c; + DWORD field65_0x130; + DWORD field66_0x134; + DWORD field67_0x138; + DWORD field68_0x13c; + DWORD field69_0x140; + DWORD field70_0x144; + DWORD field71_0x148; + DWORD field72_0x14c; + DWORD field73_0x150; + DWORD field74_0x154; + DWORD field75_0x158; + DWORD field76_0x15c; + DWORD field77_0x160; + DWORD field78_0x164; + DWORD field79_0x168; + DWORD field80_0x16c; + DWORD field81_0x170; + WeChatString fromGroup; + WeChatString sign; + WeChatString thumbPath; + WeChatString path; + DWORD field86_0x1c4; + DWORD field87_0x1c8; + DWORD field88_0x1cc; + DWORD field89_0x1d0; + DWORD field90_0x1d4; + DWORD field91_0x1d8; + DWORD field92_0x1dc; + DWORD field93_0x1e0; + DWORD field94_0x1e4; + DWORD field95_0x1e8; + DWORD field96_0x1ec; + WeChatString signature; + DWORD field98_0x204; + DWORD field99_0x208; + DWORD field100_0x20c; + DWORD field101_0x210; + DWORD field102_0x214; + DWORD field103_0x218; + DWORD field104_0x21c; + DWORD field105_0x220; + DWORD field106_0x224; + DWORD field107_0x228; + DWORD field108_0x22c; + DWORD field109_0x230; + DWORD field110_0x234; + DWORD field111_0x238; + DWORD field112_0x23c; + DWORD field113_0x240; + DWORD field114_0x244; + DWORD field115_0x248; + DWORD field116_0x24c; + DWORD field117_0x250; + DWORD field118_0x254; + DWORD field119_0x258; + DWORD field120_0x25c; + DWORD field121_0x260; + DWORD field122_0x264; + DWORD field123_0x268; + DWORD field124_0x26c; + DWORD field125_0x270; + DWORD field126_0x274; + DWORD field127_0x278; + DWORD field128_0x27c; + DWORD field129_0x280; + DWORD field130_0x284; + DWORD field131_0x288; + DWORD field132_0x28c; + DWORD field133_0x290; + DWORD field134_0x294; + DWORD field135_0x298; + DWORD field136_0x29c; + DWORD field137_0x2a0; + DWORD field138_0x2a4; + DWORD field139_0x2a8; + DWORD field140_0x2ac; + DWORD field141_0x2b0; + int field142_0x2b4; +}; + #endif