Created
September 9, 2020 11:21
-
-
Save NaniteFactory/7396f1928998190c423faee9f84acf09 to your computer and use it in GitHub Desktop.
kill all processes in windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"os/exec" | |
"strconv" | |
"strings" | |
"syscall" | |
"unsafe" | |
"golang.org/x/sys/windows" | |
) | |
var silent bool | |
func init() { | |
flag.BoolVar(&silent, "silent", false, "Allows the program to return as soon as it's done showing and asking nothing.") | |
flag.Parse() | |
} | |
func main() { | |
if silent { | |
log.SetOutput(ioutil.Discard) | |
} | |
// list processes | |
procs, err := processes() | |
if err != nil { | |
log.Println("Cannot list processes:", err) | |
return | |
} | |
for _, p := range procs { | |
log.Printf("[%v] of [%v] \"%v\"\r\n", p.ProcessID, p.ParentProcessID, p.Exe) | |
} | |
// get key input | |
if !silent { | |
var input string | |
log.Println("Proceed? (y/n)") | |
LoopScan: | |
for _, err := fmt.Scanln(&input); ; _, err = fmt.Scanln(&input) { | |
if err == nil { | |
switch strings.ToLower(input) { | |
case "y": | |
break LoopScan | |
case "n": | |
return | |
default: | |
// Do nothing. | |
} | |
} | |
log.Println("Proceed? (y/n)") | |
} | |
} | |
// kill processes | |
pidSkip := int(windows.GetCurrentProcessId()) | |
nameSkip := map[string]struct{}{"winlogon.exe": {}} | |
for i := range procs { | |
p := procs[len(procs)-1-i] | |
if p.ProcessID == pidSkip { | |
pidSkip = p.ParentProcessID | |
log.Printf("Skipped closing parent process: [%v] \"%v\"\r\n", p.ProcessID, p.Exe) | |
continue | |
} | |
if _, ok := nameSkip[p.Exe]; ok { | |
log.Printf("Skipped closing special task: [%v] \"%v\"\r\n", p.ProcessID, p.Exe) | |
continue | |
} | |
if err := exec.Command("taskkill", "/pid", strconv.Itoa(p.ProcessID)).Run(); err != nil { | |
log.Printf("Stubborn process: [%v] \"%v\" %v\r\n", p.ProcessID, p.Exe, err) | |
// fallback: IsProcessCritical() TerminateProcess() of win32api | |
hProcess, err := windows.OpenProcess(windows.PROCESS_TERMINATE|windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(p.ProcessID)) | |
if err != nil { | |
log.Printf("Cannot open process: [%v] \"%v\" %v\r\n", p.ProcessID, p.Exe, err) | |
continue | |
} | |
isCritical, err := isProcessCritical(hProcess) | |
if err != nil { | |
log.Printf("Cannot determine whether the specified process is critical: [%v] \"%v\" %v\r\n", p.ProcessID, p.Exe, err) | |
continue | |
} | |
if isCritical { | |
log.Printf("Skipping critical process: [%v] \"%v\"\r\n", p.ProcessID, p.Exe) | |
continue | |
} | |
if err := windows.TerminateProcess(hProcess, uint32(syscall.SIGKILL)); err != nil { | |
log.Printf("Cannot terminate process: [%v] \"%v\" %v\r\n", p.ProcessID, p.Exe, err) | |
continue | |
} | |
windows.CloseHandle(hProcess) | |
log.Printf("Forcefully terminated process: [%v] \"%v\"\r\n", p.ProcessID, p.Exe) | |
continue | |
} | |
log.Printf("Gracefully closed task: [%v] \"%v\"\r\n", p.ProcessID, p.Exe) | |
continue | |
} | |
// complete | |
if !silent { | |
log.Println("Press enter to exit...") | |
fmt.Scanln() | |
} | |
} | |
// WindowsProcess is an implementation of Process for Windows. | |
type WindowsProcess struct { | |
ProcessID int | |
ParentProcessID int | |
Exe string | |
} | |
func newWindowsProcess(e *windows.ProcessEntry32) WindowsProcess { | |
// Find when the string ends for decoding | |
end := 0 | |
for { | |
if e.ExeFile[end] == 0 { | |
break | |
} | |
end++ | |
} | |
return WindowsProcess{ | |
ProcessID: int(e.ProcessID), | |
ParentProcessID: int(e.ParentProcessID), | |
Exe: syscall.UTF16ToString(e.ExeFile[:end]), | |
} | |
} | |
func processes() ([]WindowsProcess, error) { | |
hSnapshot, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) | |
if err != nil { | |
return nil, err | |
} | |
defer windows.CloseHandle(hSnapshot) | |
var entry windows.ProcessEntry32 | |
entry.Size = uint32(unsafe.Sizeof(entry)) | |
// get the first process | |
err = windows.Process32First(hSnapshot, &entry) | |
if err != nil { | |
return nil, err | |
} | |
ret := make([]WindowsProcess, 0, 50) | |
for { | |
ret = append(ret, newWindowsProcess(&entry)) | |
if err := windows.Process32Next(hSnapshot, &entry); err != nil { | |
// windows sends ERROR_NO_MORE_FILES on last process | |
if err == syscall.ERROR_NO_MORE_FILES { | |
return ret, nil | |
} | |
return nil, err | |
} | |
} | |
} | |
// if explorer := findProcessByName(procs, "explorer.exe"); explorer != nil { | |
// log.Println(explorer.ProcessID) | |
// } | |
func findProcessByName(processes []WindowsProcess, name string) *WindowsProcess { | |
for _, p := range processes { | |
if strings.ToLower(p.Exe) == strings.ToLower(name) { | |
return &p | |
} | |
} | |
return nil | |
} | |
var procIsProcessCritical = syscall.NewLazyDLL("kernel32.dll").NewProc("IsProcessCritical") | |
func isProcessCritical(hProcess windows.Handle) (ret bool, err error) { | |
var holder uintptr | |
r1, _, e1 := procIsProcessCritical.Call(uintptr(hProcess), uintptr(unsafe.Pointer(&holder))) | |
if r1 == 0 { // r1 is false (func errored) | |
return false, e1 | |
} | |
return holder != 0, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment