first commit
This commit is contained in:
commit
9351dac281
2 changed files with 233 additions and 0 deletions
230
go-ps.go
Normal file
230
go-ps.go
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
// https://github.com/mitchellh/go-ps/blob/master/process_windows.go
|
||||||
|
// With addition from me on querying using NTDLL and not just kernel32
|
||||||
|
|
||||||
|
package ps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows API functions
|
||||||
|
var (
|
||||||
|
modKernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
procCloseHandle = modKernel32.NewProc("CloseHandle")
|
||||||
|
procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot")
|
||||||
|
procProcess32First = modKernel32.NewProc("Process32FirstW")
|
||||||
|
procProcess32Next = modKernel32.NewProc("Process32NextW")
|
||||||
|
|
||||||
|
// NTDLL
|
||||||
|
modNtDll = windows.NewLazySystemDLL("ntdll.dll")
|
||||||
|
procNtQuerySystemInformation = modNtDll.NewProc("NtQuerySystemInformation")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Some constants from the Windows API
|
||||||
|
const (
|
||||||
|
ERROR_NO_MORE_FILES = 0x12
|
||||||
|
MAX_PATH = 260
|
||||||
|
|
||||||
|
SystemProcessInformation = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
// PROCESSENTRY32 is the Windows API structure that contains a process's
|
||||||
|
// information.
|
||||||
|
type PROCESSENTRY32 struct {
|
||||||
|
Size uint32
|
||||||
|
CntUsage uint32
|
||||||
|
ProcessID uint32
|
||||||
|
DefaultHeapID uintptr
|
||||||
|
ModuleID uint32
|
||||||
|
CntThreads uint32
|
||||||
|
ParentProcessID uint32
|
||||||
|
PriorityClassBase int32
|
||||||
|
Flags uint32
|
||||||
|
ExeFile [MAX_PATH]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowsProcess is an implementation of Process for Windows.
|
||||||
|
type WindowsProcess struct {
|
||||||
|
pid int
|
||||||
|
ppid int
|
||||||
|
exe string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SYSTEM_PROCESS_INFORMATION struct {
|
||||||
|
NextEntryOffset uint32
|
||||||
|
NumberOfThreads uint32
|
||||||
|
Reserved1 [3]uint64
|
||||||
|
CreateTime int64
|
||||||
|
UserTime int64
|
||||||
|
KernelTime int64
|
||||||
|
ImageName windows.NTUnicodeString
|
||||||
|
BasePriority int32
|
||||||
|
UniqueProcessID uintptr
|
||||||
|
InheritedFromUniqueProcessID uintptr
|
||||||
|
HandleCount uint32
|
||||||
|
SessionID uint32
|
||||||
|
PageDirectoryBase uintptr
|
||||||
|
PeakVirtualSize uint64
|
||||||
|
VirtualSize uint64
|
||||||
|
PageFaultCount uint32
|
||||||
|
PeakWorkingSetSize uint64
|
||||||
|
WorkingSetSize uint64
|
||||||
|
QuotaPeakPagedPoolUsage uint64
|
||||||
|
QuotaPagedPoolUsage uint64
|
||||||
|
QuotaPeakNonPagedPoolUsage uint64
|
||||||
|
QuotaNonPagedPoolUsage uint64
|
||||||
|
PagefileUsage uint64
|
||||||
|
PeakPagefileUsage uint64
|
||||||
|
PrivatePageCount uint64
|
||||||
|
Reserved2 [6]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ps provides an API for finding and listing processes in a platform-agnostic
|
||||||
|
// way.
|
||||||
|
//
|
||||||
|
// NOTE: If you're reading these docs online via GoDocs or some other system,
|
||||||
|
// you might only see the Unix docs. This project makes heavy use of
|
||||||
|
// platform-specific implementations. We recommend reading the source if you
|
||||||
|
// are interested.
|
||||||
|
|
||||||
|
// Process is the generic interface that is implemented on every platform
|
||||||
|
// and provides common operations for processes.
|
||||||
|
type Process interface {
|
||||||
|
// Pid is the process ID for this process.
|
||||||
|
Pid() int
|
||||||
|
|
||||||
|
// PPid is the parent process ID for this process.
|
||||||
|
PPid() int
|
||||||
|
|
||||||
|
// Executable name running this process. This is not a path to the
|
||||||
|
// executable.
|
||||||
|
Executable() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processes returns all processes.
|
||||||
|
//
|
||||||
|
// This of course will be a point-in-time snapshot of when this method was
|
||||||
|
// called. Some operating systems don't provide snapshot capability of the
|
||||||
|
// process table, in which case the process table returned might contain
|
||||||
|
// ephemeral entities that happened to be running when this was called.
|
||||||
|
func Processes(method string) ([]Process, error) {
|
||||||
|
if method == "k32" {
|
||||||
|
return processes32()
|
||||||
|
} else if method == "ntdll" {
|
||||||
|
return processesNTDLL()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProcess looks up a single process by pid.
|
||||||
|
//
|
||||||
|
// Process will be nil and error will be nil if a matching process is
|
||||||
|
// not found.
|
||||||
|
func FindProcess(pid int) (Process, error) {
|
||||||
|
return findProcess(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *WindowsProcess) Pid() int {
|
||||||
|
return p.pid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *WindowsProcess) PPid() int {
|
||||||
|
return p.ppid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *WindowsProcess) Executable() string {
|
||||||
|
return p.exe
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess {
|
||||||
|
// Find when the string ends for decoding
|
||||||
|
end := 0
|
||||||
|
for {
|
||||||
|
if e.ExeFile[end] == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
|
||||||
|
return &WindowsProcess{
|
||||||
|
pid: int(e.ProcessID),
|
||||||
|
ppid: int(e.ParentProcessID),
|
||||||
|
exe: syscall.UTF16ToString(e.ExeFile[:end]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findProcess(pid int) (Process, error) {
|
||||||
|
ps, err := processes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range ps {
|
||||||
|
if p.Pid() == pid {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processesk32() ([]Process, error) {
|
||||||
|
handle, _, _ := procCreateToolhelp32Snapshot.Call(
|
||||||
|
0x00000002,
|
||||||
|
0)
|
||||||
|
if handle < 0 {
|
||||||
|
return nil, syscall.GetLastError()
|
||||||
|
}
|
||||||
|
defer procCloseHandle.Call(handle)
|
||||||
|
|
||||||
|
var entry PROCESSENTRY32
|
||||||
|
entry.Size = uint32(unsafe.Sizeof(entry))
|
||||||
|
ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
return nil, fmt.Errorf("Error retrieving process info.")
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]Process, 0, 50)
|
||||||
|
for {
|
||||||
|
results = append(results, newWindowsProcess(&entry))
|
||||||
|
|
||||||
|
ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry)))
|
||||||
|
if ret == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processesNTDLL() ([]SYSTEM_PROCESS_INFORMATION, error) {
|
||||||
|
var buffer [1024 * 1024]byte
|
||||||
|
var returnLength uint32
|
||||||
|
|
||||||
|
r1, _, err := procNtQuerySystemInformation.Call(
|
||||||
|
uintptr(SystemProcessInformation),
|
||||||
|
uintptr(unsafe.Pointer(&buffer[0])),
|
||||||
|
uintptr(len(buffer)),
|
||||||
|
uintptr(unsafe.Pointer(&returnLength)),
|
||||||
|
)
|
||||||
|
if r1 != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var processes []SYSTEM_PROCESS_INFORMATION
|
||||||
|
offset := 0
|
||||||
|
for {
|
||||||
|
spi := (*SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(&buffer[offset]))
|
||||||
|
processes = append(processes, *spi)
|
||||||
|
if spi.NextEntryOffset == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
offset += int(spi.NextEntryOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return processes, nil
|
||||||
|
}
|
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module git.postblue.info/chris/go-ps
|
||||||
|
|
||||||
|
go 1.21.6
|
Loading…
Reference in a new issue