Compare commits

..
Author SHA1 Message Date
hugy 1268d37a57 feat: 建群 2023-07-29 10:03:59 +08:00
hugy 17aff3b6aa feat: 邀请入群,hook日志 2023-07-27 21:18:42 +08:00
hugy 7e06eaf4e4 fix: 消除警告 2023-07-22 09:17:20 +08:00
hugy b996a9d91c feat: 群消息置顶 2023-07-22 09:13:50 +08:00
9 changed files with 484 additions and 2 deletions
+257
View File
@@ -736,4 +736,261 @@ enableHttp=0时,使用ip,port的tcp服务回传消息。
},
"msg": "success"
}
```
#### 14.置顶群消息**
###### 接口功能
> 置顶群消息,需要群主权限
###### 接口地址
> [/api/topMsg](/api/topMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|msgId |true |string| 消息id |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功, -1失败|
|msg|string|成功提示|
|data|object|null|
###### 接口示例
入参:
``` javascript
{
"msgId":8005736725060623215
}
```
响应:
``` javascript
{
"code": 1,
"data": null,
"msg": "success"
}
```
#### 15.移除置顶群消息**
###### 接口功能
> 移除置顶群消息,需要群主权限
###### 接口地址
> [/api/removeTopMsg](/api/removeTopMsg)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|msgId |true |string| 消息id |
|chatRoomId |true |string| 群id |
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,1成功, -1失败|
|msg|string|成功提示|
|data|object|null|
###### 接口示例
入参:
``` javascript
{
"msgId":8005736725060623215,
"chatRoomId":"12345678@chatroom"
}
```
响应:
``` javascript
{
"code": 1,
"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"
}
```
#### 17.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"
}
```
#### 19.建群**
###### 接口功能
> 建群(不建议使用,容易被封,测试期间被封了,无法保证效果)
###### 接口地址
> [/api/createChatRoom](/api/createChatRoom)
###### HTTP请求方式
> POST JSON
###### 请求参数
|参数|必选|类型|说明|
|---|---|---|---|
|memberIds|string|群成员id,以,分割|
###### 返回字段
|返回字段|字段类型|说明 |
|---|---|---|
|code|int|返回状态,0成功, -1失败|
|msg|string|成功提示|
|data|object|null|
###### 接口示例
入参:
``` javascript
```
响应:
``` javascript
{
"code": 1,
"data": null,
"msg": "success"
}
```
+13 -1
View File
@@ -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;
}
+2 -1
View File
@@ -344,6 +344,7 @@ std::vector<void *> DB::GetDbHandles() {
msg0_db.db_name = (wchar_t *)(*(UINT64 *)(db_addr));
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x8);
msg0_db.handle = msg0_db_addr;
msg0_db.extrainfo = *(UINT64 *)(*(UINT64 *)(db_addr + 0x28) + 0x1E8);
ExecuteSQL(msg0_db_addr,
"select * from sqlite_master where type=\"table\";",
(UINT64)GetDbInfo, &msg0_db);
@@ -458,7 +459,7 @@ std::vector<std::string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
wchar_t dbname[20] = {0};
for (int i = 0;; i++) {
swprintf_s(dbname, L"MSG%d.db", i);
DWORD handle = GetDbHandleByDbName(dbname);
UINT64 handle = GetDbHandleByDbName(dbname);
if (handle == 0) {
// LOG(INFO) << "MSG db handle is null";
return {};
+69
View File
@@ -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
+4
View File
@@ -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
+47
View File
@@ -341,6 +341,53 @@ 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/topMsg")) {
INT64 msg_id = GetINT64Param(j_param, "msgId");
INT64 success =
wxhelper::GlobalContext::GetInstance().mgr->SetTopMsg(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/removeTopMsg")) {
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
INT64 msg_id = GetINT64Param(j_param, "msgId");
INT64 success =
wxhelper::GlobalContext::GetInstance().mgr->RemoveTopMsg(room_id,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/InviteMemberToChatRoom")) {
std::wstring room_id = GetWStringParam(j_param, "chatRoomId");
std::vector<std::wstring> 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 if (mg_http_match_uri(hm, "/api/createChatRoom")) {
std::vector<std::wstring> wxids = GetArrayParam(j_param, "memberIds");
INT64 success =
wxhelper::GlobalContext::GetInstance().mgr->CreateChatRoom(wxids);
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"}};
+73
View File
@@ -3,6 +3,7 @@
#include "export.h"
#include "wechat_function.h"
#include "db.h"
namespace offset = wxhelper::V3_9_5_81::offset;
namespace prototype = wxhelper::V3_9_5_81::prototype;
@@ -500,4 +501,76 @@ INT64 Manager::GetMemberFromChatRoom(const std::wstring &room_id,
free_chat_room(addr);
return success;
}
INT64 Manager::SetTopMsg(ULONG64 msg_id) {
INT64 success = -1;
UINT64 top_addr = base_addr_ + offset::kTopMsg;
func::__DoTopMsg top_msg = (func::__DoTopMsg)top_addr;
INT64 index = 0;
INT64 local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, index);
if (local_id <= 0 || index >> 32 == 0) {
success = -2;
return success;
}
LARGE_INTEGER l;
l.HighPart = index >> 32;
l.LowPart = (DWORD)local_id;
UINT64 ptr = reinterpret_cast<UINT64>(&l);
success = top_msg(ptr, 1);
return success;
}
INT64 Manager::RemoveTopMsg(const std::wstring &room_id, ULONG64 msg_id) {
INT64 success = -1;
UINT64 remove_addr = base_addr_ + offset::kRemoveTopMsg;
func::__RemoveTopMsg remove_top_msg = (func::__RemoveTopMsg)remove_addr;
prototype::WeChatString *chat_room_id = BuildWechatString(room_id);
const wchar_t *w_room = room_id.c_str();
success = remove_top_msg(reinterpret_cast<UINT64>(w_room), msg_id,
reinterpret_cast<UINT64>(chat_room_id));
return success;
}
INT64 Manager::InviteMemberToChatRoom(const std::wstring &room_id,
const std::vector<std::wstring> &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<prototype::WeChatString> 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<UINT64>(w_room), head,
reinterpret_cast<UINT64>(chat_room_id),
reinterpret_cast<UINT64>(&temp));
return success;
}
INT64 Manager::CreateChatRoom(const std::vector<std::wstring>& wxids){
INT64 success = -1;
UINT64 get_chat_room_mgr_addr = base_addr_ + offset::kChatRoomMgr;
UINT64 create_chat_room_addr = base_addr_ + offset::kCreateChatRoom;
func::__GetChatRoomMgr get_chat_room_mgr =
(func::__GetChatRoomMgr)get_chat_room_mgr_addr;
func::__CreateChatRoom create_chat_room =
(func::__CreateChatRoom)create_chat_room_addr;
std::vector<prototype::WeChatString> 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);
}
INT64 end = list->end;
UINT64 mgr = get_chat_room_mgr();
success = create_chat_room(mgr, head, end);
return success;
}
} // namespace wxhelper
+5
View File
@@ -25,6 +25,11 @@ class Manager {
const std::vector<std::wstring>& members);
INT64 GetMemberFromChatRoom(const std::wstring& room_id,
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<std::wstring>& wxids);
INT64 CreateChatRoom(const std::vector<std::wstring>& wxids);
private:
UINT64 base_addr_;
+14
View File
@@ -233,6 +233,12 @@ typedef UINT64 (*__GetMemberFromChatRoom)(UINT64,UINT64,UINT64);
typedef UINT64 (*__NewChatRoom)(UINT64);
typedef UINT64 (*__FreeChatRoom)(UINT64);
typedef UINT64 (*__DoTopMsg)(UINT64,UINT64);
typedef UINT64 (*__RemoveTopMsg)(UINT64,UINT64,UINT64);
typedef UINT64 (*__InviteMemberToChatRoom)(UINT64,UINT64,UINT64,UINT64);
typedef UINT64 (*__CreateChatRoom)(UINT64,UINT64,UINT64);
} // namespace function
namespace prototype {
@@ -329,6 +335,14 @@ const UINT64 kDelMemberFromChatRoom = 0xe64290;
const UINT64 kGetMemberFromChatRoom = 0xe74de0;
const UINT64 kNewChatRoom = 0x11fde50;
const UINT64 kFreeChatRoom = 0x11fe030;
const UINT64 kTopMsg = 0xa5e4f0;
const UINT64 kRemoveTopMsg = 0xe787b0;
const UINT64 kInviteMember = 0xe63650;
const UINT64 kHookLog = 0x1304e60;
const UINT64 kCreateChatRoom = 0xe63340;
} // namespace offset
} // namespace V3_9_5_81