From 17aff3b6aa16fb3642fd949dd91b506455eb6f88 Mon Sep 17 00:00:00 2001 From: hugy <504650082@qq.com> Date: Thu, 27 Jul 2023 21:18:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=82=80=E8=AF=B7=E5=85=A5=E7=BE=A4?= =?UTF-8?q?=EF=BC=8Chook=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/3.9.5.81.md | 129 +++++++++++++++++++++++++++++++++++- source/injector.cc | 14 +++- src/hooks.cc | 69 +++++++++++++++++++ src/hooks.h | 4 ++ src/http_server_callback.cc | 22 ++++++ src/manager.cc | 22 ++++++ src/manager.h | 2 + src/wechat_function.h | 3 + 8 files changed, 263 insertions(+), 2 deletions(-) diff --git a/doc/3.9.5.81.md b/doc/3.9.5.81.md index 5c6899a..8958bfc 100644 --- a/doc/3.9.5.81.md +++ b/doc/3.9.5.81.md @@ -815,7 +815,7 @@ enableHttp=0时,使用ip,port的tcp服务回传消息。 { - "msgId":8005736725060623215, + "msgId":8005736725060623215, "chatRoomId":"12345678@chatroom" } ``` @@ -826,4 +826,131 @@ enableHttp=0时,使用ip,port的tcp服务回传消息。 "data": null, "msg": "success" } +``` + +#### 16.邀请入群** +###### 接口功能 +> 邀请入群,(40人以上的群需要使用邀请入群) + +###### 接口地址 +> [/api/InviteMemberToChatRoom](/api/InviteMemberToChatRoom) + +###### HTTP请求方式 +> POST JSON + +###### 请求参数 +|参数|必选|类型|说明| +|---|---|---|---| +|memberIds |true |string| wxid,用,分隔 | +|chatRoomId |true |string| 群id | + + +###### 返回字段 +|返回字段|字段类型|说明 | +|---|---|---| +|code|int|返回状态,1成功, -1失败| +|msg|string|成功提示| +|data|object|null| + + +###### 接口示例 + +入参: +``` javascript + + +{ + "memberIds":"wxid_123,wxid_12341", + "chatRoomId":"12345678@chatroom" +} +``` +响应: +``` javascript +{ + "code": 1, + "data": null, + "msg": "success" +} +``` + + +#### 16.hook日志** +###### 接口功能 +> hook微信日志,输出在wechat安装目录的logs目录下 + +###### 接口地址 +> [/api/hookLog](/api/hookLog) + +###### HTTP请求方式 +> POST JSON + +###### 请求参数 +|参数|必选|类型|说明| +|---|---|---|---| + + + +###### 返回字段 +|返回字段|字段类型|说明 | +|---|---|---| +|code|int|返回状态,0成功, -1失败| +|msg|string|成功提示| +|data|object|null| + + +###### 接口示例 + +入参: +``` javascript + + + +``` +响应: +``` javascript +{ + "code": 0, + "data": null, + "msg": "success" +} +``` + +#### 18.取消hook日志** +###### 接口功能 +> 取消hook日志 + +###### 接口地址 +> [/api/unhookLog](/api/unhookLog) + +###### HTTP请求方式 +> POST JSON + +###### 请求参数 +|参数|必选|类型|说明| +|---|---|---|---| + + + +###### 返回字段 +|返回字段|字段类型|说明 | +|---|---|---| +|code|int|返回状态,0成功, -1失败| +|msg|string|成功提示| +|data|object|null| + + +###### 接口示例 + +入参: +``` javascript + + +``` +响应: +``` javascript +{ + "code": 0, + "data": null, + "msg": "success" +} ``` \ No newline at end of file diff --git a/source/injector.cc b/source/injector.cc index c009272..8dcd67c 100644 --- a/source/injector.cc +++ b/source/injector.cc @@ -933,7 +933,10 @@ int InjectDll(wchar_t* szPName, wchar_t* szDllPath) result = 1; } else - { + { + DWORD dErrorCode = GetLastError(); + printf("dll inject fail"); + printf("error code : %d ", dErrorCode); VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE); CloseHandle(hProcess); result = 0; @@ -941,6 +944,9 @@ int InjectDll(wchar_t* szPName, wchar_t* szDllPath) } else { + DWORD dErrorCode = GetLastError(); + printf("dll inject fail.VirtualAllocEx method fail."); + printf("error code : %d ", dErrorCode); CloseHandle(hProcess); result = 0; } @@ -986,6 +992,9 @@ int InjectDllByPid(unsigned int pid, wchar_t* szDllPath) } else { + DWORD dErrorCode = GetLastError(); + printf("dll inject fail"); + printf("error code : %d ", dErrorCode); VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE); CloseHandle(hProcess); result = 0; @@ -993,6 +1002,9 @@ int InjectDllByPid(unsigned int pid, wchar_t* szDllPath) } else { + DWORD dErrorCode = GetLastError(); + printf("dll inject fail.VirtualAllocEx method fail."); + printf("error code : %d ", dErrorCode); CloseHandle(hProcess); result = 0; } diff --git a/src/hooks.cc b/src/hooks.cc index 06b2305..4387a42 100644 --- a/src/hooks.cc +++ b/src/hooks.cc @@ -16,12 +16,19 @@ static int kServerPort = 19099; static bool kMsgHookFlag = false; static char kServerIp[16] = "127.0.0.1"; static bool kEnableHttp = false; +static bool kLogHookFlag = false; static UINT64 (*R_DoAddMsg)(UINT64, UINT64, UINT64) = (UINT64(*)( UINT64, UINT64, UINT64))(Utils::GetWeChatWinBase() + offset::kDoAddMsg); +static UINT64 (*R_Log)(UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, + UINT64, UINT64, UINT64, UINT64, UINT64) = + (UINT64(*)(UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, UINT64, + UINT64, UINT64, UINT64, + UINT64))(Utils::GetWeChatWinBase() + offset::kHookLog); + VOID CALLBACK SendMsgCallback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK Work) { common::InnerMessageStruct *msg = (common::InnerMessageStruct *)context; @@ -140,6 +147,26 @@ void HandleSyncMsg(INT64 param1, INT64 param2, INT64 param3) { R_DoAddMsg(param1,param2,param3); } +UINT64 HandlePrintLog(UINT64 param1, UINT64 param2, UINT64 param3, UINT64 param4, + UINT64 param5, UINT64 param6, UINT64 param7, UINT64 param8, + UINT64 param9, UINT64 param10, UINT64 param11, + UINT64 param12) { + UINT64 p = R_Log(param1, param2, param3, param4, param5, param6, param7, param8, param9, + param10, param11, param12); +if(p== 0 || p == 1){ + return p; +} + char *msg = (char *)p; + if (msg != NULL) { + // INT64 size = *(INT64 *)(p - 0x8); + std::string str(msg); + std::wstring ws = Utils::UTF8ToWstring(str); + std::string out = Utils::WstringToAnsi(ws, CP_ACP); + spdlog::info("wechat log:{}", out); + } + return p; +} + int HookSyncMsg(std::string client_ip, int port, std::string url, uint64_t timeout, bool enable) { if (kMsgHookFlag) { @@ -196,5 +223,47 @@ int UnHookSyncMsg() { return ret; } + int HookLog() { + if (kLogHookFlag) { + SPDLOG_INFO("log hook already called"); + return 2; + } + + UINT64 base = Utils::GetWeChatWinBase(); + if (!base) { + SPDLOG_INFO("base addr is null"); + return -1; + } + + DetourRestoreAfterWith(); + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + UINT64 do_add_msg_addr = base + offset::kHookLog; + DetourAttach(&(PVOID &)R_Log, &HandlePrintLog); + LONG ret = DetourTransactionCommit(); + if (ret == NO_ERROR) { + kMsgHookFlag = true; + } + return ret; + } + + int UnHookLog() { + if (!kLogHookFlag) { + kLogHookFlag = false; + SPDLOG_INFO("hook log reset"); + return NO_ERROR; + } + UINT64 base = Utils::GetWeChatWinBase(); + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + UINT64 do_add_msg_addr = base + offset::kHookLog; + DetourDetach(&(PVOID &)R_Log, &HandlePrintLog); + LONG ret = DetourTransactionCommit(); + if (ret == NO_ERROR) { + kLogHookFlag = false; + } + return ret; + } + } // namespace hooks } // namespace wxhelper \ No newline at end of file diff --git a/src/hooks.h b/src/hooks.h index d952f12..f99444f 100644 --- a/src/hooks.h +++ b/src/hooks.h @@ -10,6 +10,10 @@ int HookSyncMsg(std::string client_ip, int port, std::string url, uint64_t timeo int UnHookSyncMsg(); +int HookLog(); + +int UnHookLog(); + } // namespace hooks } // namespace wxhelper #endif \ No newline at end of file diff --git a/src/http_server_callback.cc b/src/http_server_callback.cc index 9b4dd4b..f4f1b7e 100644 --- a/src/http_server_callback.cc +++ b/src/http_server_callback.cc @@ -358,6 +358,28 @@ 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/InviteMemberToChatRoom")) { + std::wstring room_id = GetWStringParam(j_param, "chatRoomId"); + std::vector wxids = GetArrayParam(j_param, "memberIds"); + INT64 success = + wxhelper::GlobalContext::GetInstance().mgr->InviteMemberToChatRoom( + room_id, wxids); + nlohmann::json ret_data = { + {"code", success}, {"msg", "success"}, {"data", {}}}; + ret = ret_data.dump(); + return ret; + } else if (mg_http_match_uri(hm, "/api/hookLog")) { + int success = wxhelper::hooks::HookLog(); + nlohmann::json ret_data = { + {"code", success}, {"msg", "success"}, {"data", {}}}; + ret = ret_data.dump(); + return ret; + } else if (mg_http_match_uri(hm, "/api/unhookLog")) { + int success = wxhelper::hooks::UnHookLog(); + 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 19a285d..5fa99ec 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -530,4 +530,26 @@ INT64 Manager::RemoveTopMsg(const std::wstring &room_id, ULONG64 msg_id) { reinterpret_cast(chat_room_id)); return success; } + +INT64 Manager::InviteMemberToChatRoom(const std::wstring &room_id, + const std::vector &wxids) { + INT64 success = -1; + UINT64 invite_addr = base_addr_ + offset::kInviteMember; + func::__InviteMemberToChatRoom invite = + (func::__InviteMemberToChatRoom)invite_addr; + const wchar_t *w_room = room_id.c_str(); + prototype::WeChatString *chat_room_id = BuildWechatString(room_id); + std::vector wxid_list; + common::VectorInner *list = (common::VectorInner *)&wxid_list; + INT64 head = (INT64)&list->start; + for (int i = 0; i < wxids.size(); i++) { + prototype::WeChatString id(wxids[i]); + wxid_list.push_back(id); + } + UINT64 temp[2] = {0}; + success = invite(reinterpret_cast(w_room), head, + reinterpret_cast(chat_room_id), + reinterpret_cast(&temp)); + return success; +} } // namespace wxhelper \ No newline at end of file diff --git a/src/manager.h b/src/manager.h index 2dba73d..1a5edb9 100644 --- a/src/manager.h +++ b/src/manager.h @@ -27,6 +27,8 @@ class Manager { common::ChatRoomMemberInner& member); INT64 SetTopMsg(ULONG64 msg_id); INT64 RemoveTopMsg(const std::wstring& room_id,ULONG64 msg_id); + INT64 InviteMemberToChatRoom(const std::wstring& room_id, + const std::vector& wxids); private: UINT64 base_addr_; diff --git a/src/wechat_function.h b/src/wechat_function.h index 26ee6b3..028a80b 100644 --- a/src/wechat_function.h +++ b/src/wechat_function.h @@ -235,6 +235,7 @@ typedef UINT64 (*__FreeChatRoom)(UINT64); typedef UINT64 (*__DoTopMsg)(UINT64,UINT64); typedef UINT64 (*__RemoveTopMsg)(UINT64,UINT64,UINT64); +typedef UINT64 (*__InviteMemberToChatRoom)(UINT64,UINT64,UINT64,UINT64); } // namespace function namespace prototype { @@ -334,6 +335,8 @@ const UINT64 kFreeChatRoom = 0x11fe030; const UINT64 kTopMsg = 0xa5e4f0; const UINT64 kRemoveTopMsg = 0xe787b0; +const UINT64 kInviteMember = 0xe63650; +const UINT64 kHookLog = 0x1304e60; } // namespace offset } // namespace V3_9_5_81