Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDK相对完整的多开支持 #241

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .editorconfig
Empty file.
111 changes: 86 additions & 25 deletions WeChatFerry/sdk/sdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,29 @@
#include "injector.h"
#include "sdk.h"
#include "util.h"
#include <string>
#include <vector>

static BOOL injected = false;
static HANDLE wcProcess = NULL;
static HMODULE spyBase = NULL;
static WCHAR spyDllPath[MAX_PATH] = { 0 };
using namespace std;

struct WxProcessInfo
{
DWORD pid;
HANDLE wcProcess;
HMODULE spyBase;
bool injected;
WCHAR spyDllPath[MAX_PATH];
WxProcessInfo(DWORD pid)
{
this->pid = pid;
this->wcProcess = NULL;
this->spyBase = NULL;
this->injected = false;
this->spyDllPath[0] = 0;
}
};

static vector<WxProcessInfo> wxProcess;

static int GetDllPath(bool debug, wchar_t *dllPath)
{
Expand All @@ -31,60 +49,103 @@ static int GetDllPath(bool debug, wchar_t *dllPath)
return 0;
}

int WxInitSDK(bool debug, int port)
int WxInitSDK(bool debug, int port, int index)
{
int status = 0;
DWORD wcPid = 0;
int status = 0;

if (index < 0) {
clearAllSDK();
DWORD wcPid = 0;
status = OpenWeChat(&wcPid);
if (status != 0) {
MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0);
return status;
}
Sleep(2000); // 等待微信打开
wxProcess.push_back(WxProcessInfo(wcPid));
index = 0;
}

status = GetDllPath(debug, spyDllPath);
if (status != 0) {
return status;
if (index + 1 > wxProcess.size()) {
MessageBox(NULL, L"参数错误: index >= wxProcess.size", L"WxInitSDK", 0);
return -1;
}

status = OpenWeChat(&wcPid);
if (status != 0) {
MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0);
status = GetDllPath(debug, wxProcess[index].spyDllPath);
if (status != 0)
{
return status;
}

if (!IsProcessX64(wcPid)) {
if (!IsProcessX64(wxProcess[index].pid)) {
MessageBox(NULL, L"只支持 64 位微信", L"WxInitSDK", 0);
return -1;
}

Sleep(2000); // 等待微信打开
wcProcess = InjectDll(wcPid, spyDllPath, &spyBase);
if (wcProcess == NULL) {
wxProcess[index].wcProcess = InjectDll(wxProcess[index].pid, wxProcess[index].spyDllPath, &wxProcess[index].spyBase);
if (wxProcess[index].wcProcess == NULL) {
MessageBox(NULL, L"注入失败", L"WxInitSDK", 0);
return -1;
}

PortPath_t pp = { 0 };
pp.port = port;
PortPath_t pp = {0};
pp.port = port;
sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str());

if (!CallDllFuncEx(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) {
if (!CallDllFuncEx(wxProcess[index].wcProcess, wxProcess[index].spyDllPath, wxProcess[index].spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) {
MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0);
return -1;
}

injected = true;
wxProcess[index].injected = true;
return 0;
}

int WxDestroySDK()
int WxDestroySDK(int index)
{
if (!injected) {
if (index + 1 > wxProcess.size()) {
MessageBox(NULL, L"参数错误: index >= wxProcess.size", L"WxInitSDK", 0);
return -1;
}

if (!wxProcess[index].injected) {
return -1;
}

if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL)) {
if (!CallDllFunc(wxProcess[index].wcProcess, wxProcess[index].spyDllPath, wxProcess[index].spyBase, "CleanupSpy", NULL)) {
return -2;
}

if (!EjectDll(wcProcess, spyBase)) {
if (!EjectDll(wxProcess[index].wcProcess, wxProcess[index].spyBase)) {
return -3; // TODO: Unify error codes
}

wxProcess[index].injected = false;
wxProcess[index].spyBase = NULL;
wxProcess[index].wcProcess = NULL;

return 0;
}

int EnumWeChatProcess()
{
clearAllSDK();
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32 = {sizeof(PROCESSENTRY32)};
while (Process32Next(hSnapshot, &pe32)) {
std::wstring strProcess = pe32.szExeFile;
if (strProcess == WECHAREXE) {
wxProcess.push_back(WxProcessInfo(pe32.th32ProcessID));
}
}
CloseHandle(hSnapshot);
return (int)wxProcess.size();
}

void clearAllSDK()
{
for (int i = 0; i < wxProcess.size(); i++) {
WxDestroySDK(i);
}
wxProcess.clear();
}
1 change: 1 addition & 0 deletions WeChatFerry/sdk/sdk.def
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
EXPORTS
WxInitSDK
WxDestroySDK
EnumWeChatProcess
6 changes: 4 additions & 2 deletions WeChatFerry/sdk/sdk.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#pragma once

int WxInitSDK(bool debug, int port);
int WxDestroySDK();
int WxInitSDK(bool debug, int port, int index=-1);
int WxDestroySDK(int index=0);
int EnumWeChatProcess();
void clearAllSDK();
6 changes: 5 additions & 1 deletion WeChatFerry/spy/rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,11 @@ int RpcStopServer()
nng_close(msgSock);
// UnListenMessage();
lIsRunning = false;
Sleep(1000);
HANDLE hThread = OpenThread(THREAD_TERMINATE, FALSE, lThreadId);
if (hThread) {
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
LOG_INFO("Server stoped.");
}
#if ENABLE_WX_LOG
Expand Down
19 changes: 16 additions & 3 deletions clients/python/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from threading import Thread
from time import sleep

from wcferry import Wcf
from wcferry import Wcf, enumWeChatProcess

logging.basicConfig(level='DEBUG', format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
LOG = logging.getLogger("Demo")
Expand Down Expand Up @@ -82,7 +82,20 @@ def main():


if __name__ == "__main__":
wcf = main()
# wcf = main()

# 一直运行
wcf.keep_running()
# wcf.keep_running()

count = enumWeChatProcess()
print(count)

port = 8180
for index in range(count):
print(index)
wcf = Wcf(debug=False, block=False, processIndex=index, port=port) # 默认连接本地服务
port +=10
LOG.info(f"已经登录: {True if wcf.is_login() else False}")
LOG.info(f"wxid: {wcf.get_self_wxid()}")
wcf.send_text("Hello world.", "filehelper")
wcf = None
2 changes: 1 addition & 1 deletion clients/python/wcferry/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-

from wcferry.client import Wcf, __version__
from wcferry.client import Wcf, __version__, enumWeChatProcess
from wcferry.wxmsg import WxMsg
20 changes: 15 additions & 5 deletions clients/python/wcferry/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Wcf():
contacts (list): 联系人缓存,调用 `get_contacts` 后更新
"""

def __init__(self, host: str = None, port: int = 10086, debug: bool = True, block: bool = True) -> None:
def __init__(self, host: str = None, port: int = 10086, debug: bool = True, block: bool = True, processIndex: int=-1) -> None:
self._local_mode = False
self._is_running = False
self._is_receiving_msg = False
Expand All @@ -78,9 +78,13 @@ def __init__(self, host: str = None, port: int = 10086, debug: bool = True, bloc
self._local_mode = True
self.host = "127.0.0.1"
self.sdk = ctypes.cdll.LoadLibrary(f"{self._wcf_root}/sdk.dll")
if self.sdk.WxInitSDK(debug, port) != 0:
if self.sdk.WxInitSDK(debug, port, processIndex) != 0:
self.LOG.error("初始化失败!")
os._exit(-1)
if processIndex == -1:
self.processIndex = 0
else:
self.processIndex = processIndex

self.cmd_url = f"tcp://{self.host}:{self.port}"

Expand Down Expand Up @@ -121,9 +125,10 @@ def cleanup(self) -> None:
return

self.disable_recv_msg()
self.msg_socket.close() # 退出前关闭通信通道, 与init配套
self.cmd_socket.close()

if self._local_mode and self.sdk and self.sdk.WxDestroySDK() != 0:
if self._local_mode and self.sdk and self.sdk.WxDestroySDK(self.processIndex) != 0:
self.LOG.error("退出失败!")

self._is_running = False
Expand Down Expand Up @@ -528,7 +533,7 @@ def listening_msg():
self.msgQ.put(WxMsg(rsp.wxmsg))

# 退出前关闭通信通道
self.msg_socket.close()
# self.msg_socket.close()

if self._is_receiving_msg:
return True
Expand Down Expand Up @@ -565,7 +570,7 @@ def listening_msg():
else:
callback(WxMsg(rsp.wxmsg))
# 退出前关闭通信通道
self.msg_socket.close()
# self.msg_socket.close()

if self._is_receiving_msg:
return True
Expand Down Expand Up @@ -959,3 +964,8 @@ def get_alias_in_chatroom(self, wxid: str, roomid: str) -> str:
return member.name if member.name else nickname

return ""

def enumWeChatProcess():
"""列出所有的微信进程"""
dll = ctypes.cdll.LoadLibrary(os.path.abspath(os.path.dirname(__file__)) + "/sdk.dll")
return dll.EnumWeChatProcess()