diff --git a/python/demo.py b/python/demo.py
index e5c9e12..aac393b 100644
--- a/python/demo.py
+++ b/python/demo.py
@@ -51,7 +51,12 @@ def main():
LOG.info(f"Tables:\n{wcf.get_tables('db')}")
LOG.info(f"Results:\n{wcf.query_sql('MicroMsg.db', 'SELECT * FROM Contact LIMIT 1;')}")
- # wcf.accept_new_friend("v3", "v4") # 需要真正的 V3、V4 信息
+ # 需要真正的 V3、V4 信息
+ # wcf.accept_new_friend("v3", "v4")
+
+ # 填写正确的群 ID 和成员 wxid
+ # ret = wcf.add_chatroom_members("chatroom id", "wxid1,wxid2,wxid3,...")
+ # LOG.info(f"add_chatroom_members: {ret}")
# 一直运行
wcf.keep_running()
diff --git a/python/wcferry/client.py b/python/wcferry/client.py
index f0fe8d3..35f8e6f 100644
--- a/python/wcferry/client.py
+++ b/python/wcferry/client.py
@@ -70,7 +70,7 @@ class Wcf():
cmd = f"{WCF_ROOT}/wcf.exe start {'debug' if debug else ''}"
if os.system(cmd) != 0:
self.LOG.error("初始化失败!")
- return
+ exit(-1)
# 连接 RPC
self.cmd_socket = pynng.Pair1() # Client --> Server,发送消息
@@ -358,3 +358,12 @@ class Wcf():
friends.append(cnt)
return friends
+
+ def add_chatroom_members(self, roomid: str, wxids: str) -> int:
+ """添加群成员"""
+ req = wcf_pb2.Request()
+ req.func = wcf_pb2.FUNC_ADD_ROOM_MEMBERS # FUNC_ADD_ROOM_MEMBERS
+ req.m.roomid = roomid
+ req.m.wxids = wxids
+ rsp = self._send_request(req)
+ return rsp.status
diff --git a/rpc/proto/wcf.proto b/rpc/proto/wcf.proto
index 0410d0a..b68bb61 100644
--- a/rpc/proto/wcf.proto
+++ b/rpc/proto/wcf.proto
@@ -35,6 +35,7 @@ enum Functions {
FUNC_DISABLE_RECV_TXT = 0x40;
FUNC_EXEC_DB_QUERY = 0x50;
FUNC_ACCEPT_FRIEND = 0x51;
+ FUNC_ADD_ROOM_MEMBERS = 0x52;
}
message Request
@@ -48,6 +49,7 @@ message Request
PathMsg file = 5;
DbQuery query = 6;
Verification v = 7;
+ AddMembers m = 8;
}
}
@@ -137,3 +139,9 @@ message Verification
string v3 = 1;
string v4 = 2;
}
+
+message AddMembers
+{
+ string roomid = 1; // 要加的群ID
+ string wxids = 2; // 要加群的人列表,逗号分隔
+}
diff --git a/spy/Spy.vcxproj b/spy/Spy.vcxproj
index abcb135..764898b 100644
--- a/spy/Spy.vcxproj
+++ b/spy/Spy.vcxproj
@@ -75,6 +75,7 @@
true
$(ProjectName)_debug
+ true
false
@@ -224,6 +225,7 @@ C:\Tools\nanopb\protoc --nanopb_out=. wcf.proto
+
@@ -243,6 +245,7 @@ C:\Tools\nanopb\protoc --nanopb_out=. wcf.proto
+
diff --git a/spy/Spy.vcxproj.filters b/spy/Spy.vcxproj.filters
index 8a4b8e1..ccdf03c 100644
--- a/spy/Spy.vcxproj.filters
+++ b/spy/Spy.vcxproj.filters
@@ -75,6 +75,9 @@
nnrpc
+
+ 头文件
+
@@ -125,6 +128,9 @@
nnrpc
+
+ 源文件
+
diff --git a/spy/add_chatroom_member.cpp b/spy/add_chatroom_member.cpp
new file mode 100644
index 0000000..28bbcda
--- /dev/null
+++ b/spy/add_chatroom_member.cpp
@@ -0,0 +1,70 @@
+#include "framework.h"
+#include
+
+#include "add_chatroom_member.h"
+#include "load_calls.h"
+#include "log.h"
+#include "util.h"
+
+using namespace std;
+
+extern WxCalls_t g_WxCalls;
+extern DWORD g_WeChatWinDllAddr;
+
+typedef struct MemberList {
+ DWORD start;
+ DWORD end1;
+ DWORD end2;
+} MemberList_t;
+
+int AddChatroomMember(string roomid, string wxids)
+{
+ int rv = 0;
+ DWORD addRoomMemberCall1 = g_WeChatWinDllAddr + g_WxCalls.arm.call1;
+ DWORD addRoomMemberCall2 = g_WeChatWinDllAddr + g_WxCalls.arm.call2;
+ DWORD addRoomMemberCall3 = g_WeChatWinDllAddr + g_WxCalls.arm.call3;
+
+ TextStruct_t txtRoomid = { 0 };
+ wstring wsRoomid = String2Wstring(roomid);
+ txtRoomid.text = (wchar_t *)wsRoomid.c_str();
+ txtRoomid.size = wsRoomid.size();
+ txtRoomid.capacity = wsRoomid.capacity();
+
+ vector vMembers;
+ vector vTxtMembers;
+ if (!wxids.empty()) {
+ wstringstream wss(String2Wstring(wxids));
+ while (wss.good()) {
+ wstring wstr;
+ getline(wss, wstr, L',');
+ vMembers.push_back(wstr);
+ TextStruct_t txtMember = { 0 };
+ txtMember.text = (wchar_t *)vMembers.back().c_str();
+ txtMember.size = vMembers.back().size();
+ txtMember.capacity = vMembers.back().capacity();
+ vTxtMembers.push_back(txtMember);
+ }
+ }
+
+ LOG_DEBUG("Adding {} members[{}] to {}", vTxtMembers.size(), wxids.c_str(), roomid.c_str());
+ __asm {
+ pushad;
+ pushfd;
+ call addRoomMemberCall1;
+ sub esp, 0x14;
+ mov esi, eax;
+ mov ecx, esp;
+ lea eax, txtRoomid;
+ push eax;
+ call addRoomMemberCall2;
+ lea edi, vTxtMembers
+ push edi;
+ mov ecx, esi;
+ call addRoomMemberCall3;
+ mov rv, eax;
+ popfd;
+ popad;
+ }
+
+ return rv;
+}
diff --git a/spy/add_chatroom_member.h b/spy/add_chatroom_member.h
new file mode 100644
index 0000000..eacb825
--- /dev/null
+++ b/spy/add_chatroom_member.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include
+#include
+
+int AddChatroomMember(std::string roomid, std::string wxids);
diff --git a/spy/load_calls.cpp b/spy/load_calls.cpp
index be4ace1..5efe9a5 100644
--- a/spy/load_calls.cpp
+++ b/spy/load_calls.cpp
@@ -19,7 +19,8 @@ WxCalls_t wxCalls = {
/* Exec Sql:
Exec, base, start, end, slot, name*/
{ 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 },
- { 0x771980, 0x2AE8D0, 0x1EE40E0 } // Accept New Friend application
+ { 0x771980, 0x2AE8D0, 0x1EE40E0 }, // Accept New Friend application
+ { 0xE29F0, 0x771980, 0x43D8D0 } // Add chatroom members
};
int LoadCalls(const wchar_t *version, WxCalls_t *calls)
diff --git a/spy/rpc_server.cpp b/spy/rpc_server.cpp
index 2cdd2ed..b8c1c1a 100644
--- a/spy/rpc_server.cpp
+++ b/spy/rpc_server.cpp
@@ -17,6 +17,7 @@
#include "wcf.pb.h"
#include "accept_new_friend.h"
+#include "add_chatroom_member.h"
#include "exec_sql.h"
#include "get_contacts.h"
#include "log.h"
@@ -383,6 +384,28 @@ bool func_accept_friend(char *v3, char *v4, uint8_t *out, size_t *len)
return true;
}
+bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len)
+{
+ Response rsp = Response_init_default;
+ rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS;
+ rsp.which_msg = Response_status_tag;
+ rsp.msg.status = 0;
+
+ rsp.msg.status = AddChatroomMember(roomid, wxids);
+ if (rsp.msg.status != 1) {
+ LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status);
+ }
+
+ pb_ostream_t stream = pb_ostream_from_buffer(out, *len);
+ if (!pb_encode(&stream, Response_fields, &rsp)) {
+ LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream));
+ return false;
+ }
+ *len = stream.bytes_written;
+
+ return true;
+}
+
static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len)
{
bool ret = false;
@@ -461,6 +484,11 @@ static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len
ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, out, out_len);
break;
}
+ case Functions_FUNC_ADD_ROOM_MEMBERS: {
+ LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]");
+ ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len);
+ break;
+ }
default: {
LOG_ERROR("[UNKNOW FUNCTION]");
break;
diff --git a/spy/spy_types.h b/spy/spy_types.h
index 5bb9373..cfd6989 100644
--- a/spy/spy_types.h
+++ b/spy/spy_types.h
@@ -53,6 +53,12 @@ typedef struct NewFriend {
DWORD handle;
} NewFriend_t;
+typedef struct RoomMember {
+ DWORD call1;
+ DWORD call2;
+ DWORD call3;
+} RoomMember_t;
+
typedef struct WxCalls {
DWORD login; // 登录状态
UserInfoCall_t ui; // 用户信息
@@ -63,7 +69,7 @@ typedef struct WxCalls {
Contact_t contact; // 获取联系人
Sql_t sql; // 执行 SQL
NewFriend_t anf; // 通过好友申请
-
+ RoomMember_t arm; // 添加群成员
} WxCalls_t;
typedef struct TextStruct {