Skip to content

Instantly share code, notes, and snippets.

@NaniteFactory
Created September 9, 2020 11:21
Show Gist options
  • Save NaniteFactory/7396f1928998190c423faee9f84acf09 to your computer and use it in GitHub Desktop.
Save NaniteFactory/7396f1928998190c423faee9f84acf09 to your computer and use it in GitHub Desktop.
kill all processes in windows
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