diff --git a/doc/3.9.5.81.md b/doc/3.9.5.81.md index b3718a9..4cbe307 100644 --- a/doc/3.9.5.81.md +++ b/doc/3.9.5.81.md @@ -1672,6 +1672,63 @@ enableHttp=0时,使用ip,port的tcp服务回传消息。 "filePath":"C:\\wechatDir\\WeChat Files\\wxid_123\\FileStorage\\CustomEmotion\\8F\\8F6423BC2E69188DCAC797E279C81DE9" } +``` +响应: +``` javascript +{ + "code": 1, + "data": {}, + "msg": "success" +} +``` + + +#### 34.发送小程序** +###### 接口功能 +> 发送小程序(待完善,不稳定),相关参数可以参考示例的滴滴小程序的内容自行组装。 + +###### 接口地址 +> [/api/sendCustomEmotion](/api/sendApplet) + +###### HTTP请求方式 +> POST JSON + +###### 请求参数 +|参数|必选|类型|说明| +|---|---|---|---| +|wxid|string|接收人wxid| +|waidConcat|string|app的wxid与回调信息之类绑定的拼接字符串,伪造的数据可以随意| +|appletWxid|string|app的wxid| +|jsonParam|string|相关参数| +|headImgUrl|string|头像url| +|mainImg|string|主图的本地路径,需要在小程序的临时目录下| +|indexPage|string|小程序的跳转页面| + + + +###### 返回字段 +|返回字段|字段类型|说明 | +|---|---|---| +|code|int|返回状态,大于0成功, -1失败| +|msg|string|成功提示| +|data|object|null| + +###### 接口示例 + +入参: +``` javascript + +{ +"wxid":"filehelper", +"waidConcat":"wxaf35009675aa0b2a_118", +"waid":"wxaf35009675aa0b2a", +"appletWxid":"gh_7a5c4141778f@app", +"jsonParam":"{\"current_path\":\"home/pages/index.html\",\"current_title\":\"\",\"image_url\":\"https://ut-static.udache.com/webx/mini-pics/U7mDFxU2yh-2-r1BJ-J0X.png\",\"scene\":1001,\"scene_note\":\"\",\"sessionId\":\"SessionId@1672284921_1#1692848476899\"}", +"headImgUrl":"http://mmbiz.qpic.cn/sz_mmbiz_png/9n47wQlh4dH8afD9dQ9uQicibRm5mYz3lawXCLMjmnzFicribH51qsFYxjzPEcTGHGmgX4lkAkQ3jznia8UDEtqsX1w/640?wx_fmt=png&wxfrom=200", +"mainImg":"C:\\wxid_123123\\Applet\\wxaf35009675aa0b2a\\temp\\2.png", +"indexPage":"pages/index/index.html" +} + ``` 响应: ``` javascript diff --git a/src/http_server_callback.cc b/src/http_server_callback.cc index f9ddaf0..1d81a6f 100644 --- a/src/http_server_callback.cc +++ b/src/http_server_callback.cc @@ -560,6 +560,31 @@ std::string HttpDispatch(struct mg_connection *c, struct mg_http_message *hm) { {"code", success}, {"msg", "success"}, {"data", {}}}; ret = ret_data.dump(); return ret; + } else if (mg_http_match_uri(hm, "/api/sendApplet")) { + std::wstring wxid = GetWStringParam(j_param, "wxid"); + std::wstring waid_concat = GetWStringParam(j_param, "waidConcat"); + std::string waid = GetStringParam(j_param, "waid"); + std::string app_wxid = GetStringParam(j_param, "appletWxid"); + std::string json_param = GetStringParam(j_param, "jsonParam"); + std::string head_url = GetStringParam(j_param, "headImgUrl"); + std::string main_img = GetStringParam(j_param, "mainImg"); + std::string index_page = GetStringParam(j_param, "indexPage"); + + std::wstring waid_w = wxhelper::Utils::UTF8ToWstring(waid); + + INT64 success = wxhelper::GlobalContext::GetInstance().mgr->SendApplet( + wxid, waid_concat, waid_w, waid, app_wxid, json_param, head_url, + main_img, index_page); + nlohmann::json ret_data = { + {"code", success}, {"msg", "success"}, {"data", {}}}; + ret = ret_data.dump(); + return ret; + } else if (mg_http_match_uri(hm, "/api/test")) { + INT64 success = wxhelper::GlobalContext::GetInstance().mgr->Test(); + 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"}}; diff --git a/src/manager.cc b/src/manager.cc index be22fa6..46605cf 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -28,7 +28,19 @@ prototype::WeChatString * BuildWechatString(const std::wstring &ws){ return p; } -Manager::Manager(UINT64 base) : base_addr_(base) {} +prototype::WeChatStr * BuildWechatStr(const std::string &str){ + prototype::WeChatStr *p = Utils::WxHeapAlloc( + sizeof(prototype::WeChatStr)); + char *p_chat_room_id = Utils::WxHeapAlloc(str.size() + 1); + memcpy(p_chat_room_id, str.c_str(), str.size() + 1); + p->ptr = p_chat_room_id; + p->len = static_cast(str.size()); + p->maxlen = static_cast(str.size()); + p->buf = NULL; + return p; +} + +Manager::Manager(UINT64 base) : base_addr_(base),js_api_addr_(0) {} Manager::~Manager() {} INT64 Manager::CheckLogin() { INT64 success = -1; @@ -1095,4 +1107,124 @@ INT64 Manager::SendCustomEmotion(const std::wstring &file_path, reinterpret_cast(temp)); return success; } -} // namespace wxhelper \ No newline at end of file + +INT64 Manager::SendApplet(const std::wstring &recv_wxid, + const std::wstring &waid_suff, + const std::wstring &waid_w, const std::string &waid_s, + const std::string &wa_wxid, + const std::string &json_param, + const std::string &head_image, + const std::string &big_image, + const std::string &index_page) { + INT64 success = -1; + if (js_api_addr_ == 0) { + auto vec2 = Utils::QWordScan(base_addr_ + 0x32D1318, 0x1000, 0x8); + for (int i = 0; i < vec2.size(); i++) { + INT64 ptr = vec2.at(i); + if (*(INT64 *)ptr == base_addr_ + 0x32D1318) { + js_api_addr_ = ptr; + break; + } + } + } + if (js_api_addr_ == 0) { + success = -2; + return success; + } + + UINT64 share_app_msg_addr = base_addr_ + offset::kNewJsApiShareAppMessage; + func::__JsApiShareAppMessage share_app_msg = + (func::__JsApiShareAppMessage)share_app_msg_addr; + + UINT64 init_addr = base_addr_ + offset::kInitJsConfig; + func::__InitJsConfig init = (func::__InitJsConfig)init_addr; + + UINT64 send_applet_addr = base_addr_ + offset::kSendApplet; + func::__SendApplet send_applet = (func::__SendApplet)send_applet_addr; + + UINT64 get_by_waid_addr = base_addr_ + offset::kGetAppInfoByWaid; + func::__GetAppInfoByWaid get_app_info = + (func::__GetAppInfoByWaid)get_by_waid_addr; + + UINT64 copy_app_req_addr = base_addr_ + offset::kCopyShareAppMessageRequest; + func::__CopyShareAppMessageRequest copy_app_req = + (func::__CopyShareAppMessageRequest)copy_app_req_addr; + + UINT64 new_wa_msg_addr = base_addr_ + offset::kNewWAUpdatableMsgInfo; + func::__NewWAUpdatableMsgInfo new_wa_msg = + (func::__NewWAUpdatableMsgInfo)new_wa_msg_addr; + + UINT64 free_wa_msg_addr = base_addr_ + offset::kFreeWAUpdatableMsgInfo; + func::__FreeWAUpdatableMsgInfo free_wa_msg = + (func::__FreeWAUpdatableMsgInfo)free_wa_msg_addr; + + std::vector *temp = + Utils::WxHeapAlloc>(0x20); + // std::vector* temp = new + // std::vector(); + common::VectorInner *list = (common::VectorInner *)temp; + + prototype::WeChatString *member = BuildWechatString(recv_wxid); + + list->head = reinterpret_cast(member); + list->start = reinterpret_cast(member); + list->finsh = reinterpret_cast(member) + 0x20; + list->end = reinterpret_cast(member) + 0x20; + + INT64 head = reinterpret_cast(&(list->start)); + + prototype::WeChatString *waid_cat = BuildWechatString(waid_suff); + prototype::WeChatString *waid = BuildWechatString(waid_w); + + prototype::WeChatString *waid_2 = BuildWechatString(waid_suff); + + prototype::WeChatStr *waid_str = BuildWechatStr(waid_s); + prototype::WeChatStr *app_wxid = BuildWechatStr(wa_wxid); + prototype::WeChatStr *json_str = BuildWechatStr(json_param); + prototype::WeChatStr *head_image_url = BuildWechatStr(head_image); + prototype::WeChatStr *image = BuildWechatStr(big_image); + prototype::WeChatStr *index = BuildWechatStr(index_page); + + UINT64 app_msg = js_api_addr_; + + UINT64 data = *(UINT64 *)(app_msg + 0x8); + char *share_req = Utils::WxHeapAlloc(0x2000); + + char *mid_ptr = Utils::WxHeapAlloc(0x18); + memcpy(mid_ptr, &share_req, sizeof(INT64)); + memcpy(mid_ptr + 0x8, &share_req, sizeof(INT64)); + memcpy(mid_ptr + 0x10, &share_req, sizeof(INT64)); + + memcpy((void *)data, mid_ptr, 0x18); + + memcpy(share_req, (void *)(app_msg + 0x8), sizeof(UINT64)); + memcpy(share_req + 0x8, (void *)(app_msg + 0x8), sizeof(UINT64)); + memcpy(share_req + 0x10, (void *)(app_msg + 0x8), sizeof(UINT64)); + memcpy(share_req + 0x20, waid_2, sizeof(prototype::WeChatString)); + memcpy(share_req + 0x48, waid_str, sizeof(prototype::WeChatStr)); + memcpy(share_req + 0x98, app_wxid, sizeof(prototype::WeChatStr)); + memcpy(share_req + 0xF8, json_str, sizeof(prototype::WeChatStr)); + memcpy(share_req + 0x178, head_image_url, sizeof(prototype::WeChatStr)); + memcpy(share_req + 0x198, image, sizeof(prototype::WeChatStr)); + memcpy(share_req + 0x1c0, index, sizeof(prototype::WeChatStr)); + + success = send_applet(app_msg, reinterpret_cast(waid_cat), head, 0); + + return success; +} + +INT64 Manager::Test() { + auto vec = Utils::QWordScan(base_addr_ + 0x32D1318, 0x1, L"WeChatWin.dll"); + for (int i = 0; i < vec.size(); i++) { + INT64 re = vec.at(i); + SPDLOG_INFO("scan result :{},{}", i, re); + } + + auto vec2 = Utils::QWordScan(base_addr_ + 0x32D1318, 0x1000, 0x8); + for (int i = 0; i < vec2.size(); i++) { + INT64 re = vec2.at(i); + SPDLOG_INFO("scan2 result :{},{}", i, re); + } + return 1; +} +} // namespace wxhelper diff --git a/src/manager.h b/src/manager.h index 2dbf77c..eea98f4 100644 --- a/src/manager.h +++ b/src/manager.h @@ -56,9 +56,16 @@ class Manager { INT64 GetVoiceByDB(ULONG64 msg_id, const std::wstring& dir); INT64 SendCustomEmotion(const std::wstring& file_path, const std::wstring& wxid); - + INT64 Manager::SendApplet( + const std::wstring& recv_wxid, const std::wstring& waid_suff, + const std::wstring& waid_w, const std::string& waid_s, + const std::string& wa_wxid, const std::string& json_param, + const std::string& head_image, const std::string& big_image, + const std::string& index_page); + INT64 Test(); private: UINT64 base_addr_; + UINT64 js_api_addr_; }; } // namespace wxhelper diff --git a/src/utils.cc b/src/utils.cc index 106adc0..2623312 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -1,6 +1,7 @@ #include "pch.h" #include "utils.h" #include +#include #define BUFSIZE 1024 #define JPEG0 0xFF #define JPEG1 0xD8 @@ -398,4 +399,62 @@ INT64 Utils::DecodeImage(const wchar_t* file_path,const wchar_t* save_dir){ return 1; } +std::vector Utils::QWordScan(INT64 value, int align, + const wchar_t *module) { + MODULEINFO module_info; + std::vector result; + if (GetModuleInformation(GetCurrentProcess(), GetModuleHandleW(module), + &module_info, sizeof(module_info))) { + auto start = static_cast(module_info.lpBaseOfDll); + const auto end = start + module_info.SizeOfImage - 0x8; + + auto current_addr = start; + while (current_addr < end) { + if (*(INT64*)current_addr == value) { + result.push_back(reinterpret_cast(current_addr)); + } + start += align; + current_addr = start; + } + } + return result; +} + +std::vector Utils::QWordScan(INT64 value, INT64 start,int align) { + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + std::vector result; + INT64 min_addr = + reinterpret_cast(sys_info.lpMinimumApplicationAddress); + INT64 max_addr = + reinterpret_cast(sys_info.lpMaximumApplicationAddress); + const INT64 page_size = sys_info.dwPageSize; + min_addr = min_addr > start ? min_addr : start; + + auto current_addr = min_addr; + MEMORY_BASIC_INFORMATION mem_info = {}; + HANDLE handle = GetCurrentProcess(); + while (current_addr < max_addr) { + VirtualQueryEx(handle, reinterpret_cast(current_addr), &mem_info, + sizeof(MEMORY_BASIC_INFORMATION)); + + if ((INT64)mem_info.RegionSize <= 0) { + break; + } + INT64 region_size = mem_info.RegionSize; + if ((mem_info.State & MEM_COMMIT) == MEM_COMMIT && + (mem_info.Protect & PAGE_GUARD) != PAGE_GUARD && + (mem_info.Protect & PAGE_NOACCESS) != PAGE_NOACCESS) { + for (INT64 i = 0; i < region_size; i += align) { + if (value == *(INT64 *)current_addr) { + result.push_back(current_addr); + } + current_addr += align; + } + } else { + current_addr += region_size; + } + } + return result; +} } // namespace wxhelper \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index 56e6023..26a7d80 100644 --- a/src/utils.h +++ b/src/utils.h @@ -60,6 +60,10 @@ class Utils { static INT64 DecodeImage(const wchar_t* file_path,const wchar_t* save_dir); + static std::vector QWordScan(INT64 value, int align, + const wchar_t *module); + + static std::vector QWordScan(INT64 value, INT64 start,int align); template static std::vector split(T1 str, T2 letter) { std::vector arr; diff --git a/src/wechat_function.h b/src/wechat_function.h index ac53f83..aa78d6d 100644 --- a/src/wechat_function.h +++ b/src/wechat_function.h @@ -274,6 +274,14 @@ typedef UINT64 (*__GetPreDownLoadMgr)(); typedef UINT64 (*__PushAttachTask)(UINT64,UINT64,UINT64,UINT64); typedef UINT64 (*__GetCustomSmileyMgr)(); typedef UINT64 (*__SendCustomEmotion)(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); +typedef UINT64 (*__JsApiShareAppMessage)(UINT64); +typedef UINT64 (*__InitJsConfig)(UINT64,UINT64); +typedef UINT64 (*__SendApplet)(UINT64,UINT64,UINT64,UINT64); +typedef UINT64 (*__SendAppletSecond)(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); +typedef UINT64 (*__GetAppInfoByWaid)(UINT64,UINT64); +typedef UINT64 (*__CopyShareAppMessageRequest)(UINT64,UINT64); +typedef UINT64 (*__NewWAUpdatableMsgInfo)(UINT64); +typedef UINT64 (*__FreeWAUpdatableMsgInfo)(UINT64); } // namespace function @@ -313,6 +321,26 @@ struct WeChatString { } }; +struct WeChatStr{ + char * ptr; + INT64 buf; + INT64 len; + INT64 maxlen; + + WeChatStr(const char* p) { + ptr = (char *)p; + buf = 0; + len = strlen(p); + maxlen = len | 0xF; + } + WeChatStr() { + ptr = NULL; + buf = 0; + len = 0; + maxlen = 0xF; + } +}; + } // namespace prototype namespace offset { const UINT64 kGetAccountServiceMgr = 0x8c1230; @@ -404,6 +432,14 @@ const UINT64 kGetPreDownLoadMgr = 0x9996f0; const UINT64 kPushAttachTask = 0x9c0080; const UINT64 kGetCustomSmileyMgr = 0x915c00; const UINT64 kSendCustomEmotion = 0xec0a40; +const UINT64 kNewJsApiShareAppMessage = 0x13be1a0; +const UINT64 kInitJsConfig = 0x137bc00; +const UINT64 kSendApplet = 0x13c0920; +const UINT64 kSendAppletSecond = 0x13c1150; +const UINT64 kGetAppInfoByWaid = 0x13c5790; +const UINT64 kCopyShareAppMessageRequest = 0x13c0670; +const UINT64 kNewWAUpdatableMsgInfo = 0x919ca0; +const UINT64 kFreeWAUpdatableMsgInfo = 0x8fc230; } // namespace offset } // namespace V3_9_5_81