Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created December 17, 2016 17:00
Show Gist options
  • Save jordanorelli/3227b67c165ca649ec7eb2a979ef671f to your computer and use it in GitHub Desktop.
Save jordanorelli/3227b67c165ca649ec7eb2a979ef671f to your computer and use it in GitHub Desktop.
watch process creation and termination on windows
package main
import (
"fmt"
"time"
"os"
"sort"
"io"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
invalidHandle = ^uintptr(0) // INVALID_HANDLE_VALUE in windows.h
maxPath = 260 // MAX_PATH in windows.h
FALSE = 0
TRUE = 1
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
createSnapshot = kernel32.NewProc("CreateToolhelp32Snapshot")
firstProcess = kernel32.NewProc("Process32FirstW")
nextProcess = kernel32.NewProc("Process32NextW")
closeHandle = kernel32.NewProc("CloseHandle")
)
type processTable struct {
byPid map[uint32]*processEntry32
byName map[string]*processEntry32
entries [1024]processEntry32
numEntries int
}
func (t *processTable) clear() {
*t = processTable{
byPid: make(map[uint32]*processEntry32),
byName: make(map[string]*processEntry32),
}
}
func (t *processTable) display(w io.Writer, label string) {
fmt.Fprintf(w, "########################################################################################\n");
fmt.Fprintf(w, "\n%s\n\n", label)
fmt.Fprintf(w, "Pid\tParent\tName\n");
fmt.Fprintf(w, "----------------------------------------------------------------------------------------\n");
pids := make([]int, 0, t.numEntries)
for pid, _ := range t.byPid {
pids = append(pids, int(pid))
}
sort.Ints(pids)
for _, pid := range pids {
p := t.byPid[uint32(pid)]
fmt.Fprintf(w, "%d\t%d\t%s\n", p.pid, p.parent, p.exe())
}
fmt.Fprintf(w, "----------------------------------------------------------------------------------------\n");
fmt.Fprintf(w, "Total Processes: %d\n", t.numEntries)
}
type processEntry32 struct {
size uint32
usage uint32
pid uint32
heapID uintptr
moduleID uint32
threads uint32
parent uint32
priority int32
flags uint32
exeFile [260]uint16
}
func (p *processEntry32) exe() string {
for i := 0; i < 259; i++ {
if p.exeFile[i] == 0 && p.exeFile[i+1] == 0 {
return string(utf16.Decode(p.exeFile[:i]))
}
}
return string(utf16.Decode(p.exeFile[:260]))
}
func fillProcessTable(t *processTable) {
t.clear()
h, _, err := createSnapshot.Call(2, 0)
if h == invalidHandle {
panic(err)
}
defer closeHandle.Call(h)
entry := &t.entries[t.numEntries]
entry.size = uint32(unsafe.Sizeof(*entry))
ok, _, err := firstProcess.Call(h, uintptr(unsafe.Pointer(entry)))
if ok == FALSE {
panic(err)
}
t.numEntries++
t.byPid[entry.pid] = entry
t.byName[entry.exe()] = entry
for {
entry := &t.entries[t.numEntries]
entry.size = uint32(unsafe.Sizeof(*entry))
ok, _, err = nextProcess.Call(h, uintptr(unsafe.Pointer(entry)))
if ok == FALSE {
if err == syscall.ERROR_NO_MORE_FILES {
break
}
panic(err)
}
t.numEntries++
t.byPid[entry.pid] = entry
t.byName[entry.exe()] = entry
}
}
func delta(prev, cur *processTable) (*processTable, *processTable) {
added, removed := new(processTable), new(processTable)
added.clear()
removed.clear()
for pid, entry := range cur.byPid {
if prev.byPid[pid] == nil {
dupe := &added.entries[added.numEntries]
added.numEntries++
*dupe = *entry
added.byPid[pid] = dupe
added.byName[entry.exe()] = dupe
}
}
for pid, entry := range prev.byPid {
if cur.byPid[pid] == nil {
dupe := &removed.entries[removed.numEntries]
removed.numEntries++
*dupe = *entry
removed.byPid[pid] = dupe
removed.byName[entry.exe()] = dupe
}
}
return added, removed
}
func main() {
prev := new(processTable)
prev.clear()
fillProcessTable(prev)
prev.display(os.Stdout, "Initial Process Table")
cur := new(processTable)
cur.clear()
for range time.Tick(time.Second) {
fillProcessTable(cur)
added, removed := delta(prev, cur)
if added.numEntries > 0 {
for pid, entry := range added.byPid {
fmt.Fprintf(os.Stdout, "+ %d %s\n", pid, entry.exe())
}
}
if removed.numEntries > 0 {
for pid, entry := range removed.byPid {
fmt.Fprintf(os.Stdout, "- %d %s\n", pid, entry.exe())
}
}
prev, cur = cur, prev
cur.clear()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment