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 {