|
|
|
@ -12,16 +12,16 @@ import (
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
"syscall"
|
|
|
|
|
"time"
|
|
|
|
|
"unicode/utf16"
|
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
|
|
|
|
|
|
"github.com/shirou/gopsutil/v4/cpu"
|
|
|
|
|
"github.com/shirou/gopsutil/v4/internal/common"
|
|
|
|
|
"github.com/shirou/gopsutil/v4/net"
|
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Signal = syscall.Signal
|
|
|
|
@ -245,7 +245,7 @@ func pidsWithContext(ctx context.Context) ([]int32, error) {
|
|
|
|
|
// inspired by https://gist.github.com/henkman/3083408
|
|
|
|
|
// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
|
|
|
|
|
var ret []int32
|
|
|
|
|
var read uint32
|
|
|
|
|
var read uint32 = 0
|
|
|
|
|
var psSize uint32 = 1024
|
|
|
|
|
const dwordSize uint32 = 4
|
|
|
|
|
|
|
|
|
@ -288,10 +288,10 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
|
|
|
|
|
return false, err
|
|
|
|
|
}
|
|
|
|
|
h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
|
|
|
|
|
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
|
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
if errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
|
|
|
|
|
if err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
@ -330,7 +330,7 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) {
|
|
|
|
|
|
|
|
|
|
exe, err := p.ExeWithContext(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("could not get Name: %w", err)
|
|
|
|
|
return "", fmt.Errorf("could not get Name: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filepath.Base(exe), nil
|
|
|
|
@ -370,7 +370,7 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
|
|
|
|
|
func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
|
|
|
|
|
cmdline, err := getProcessCommandLine(p.Pid)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("could not get CommandLine: %w", err)
|
|
|
|
|
return "", fmt.Errorf("could not get CommandLine: %s", err)
|
|
|
|
|
}
|
|
|
|
|
return cmdline, nil
|
|
|
|
|
}
|
|
|
|
@ -380,33 +380,13 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return parseCmdline(cmdline)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseCmdline(cmdline string) ([]string, error) {
|
|
|
|
|
cmdlineptr, err := windows.UTF16PtrFromString(cmdline)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var argc int32
|
|
|
|
|
argvptr, err := windows.CommandLineToArgv(cmdlineptr, &argc)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer windows.LocalFree(windows.Handle(uintptr(unsafe.Pointer(argvptr))))
|
|
|
|
|
|
|
|
|
|
argv := make([]string, argc)
|
|
|
|
|
for i, v := range (*argvptr)[:argc] {
|
|
|
|
|
argv[i] = windows.UTF16ToString((*v)[:])
|
|
|
|
|
}
|
|
|
|
|
return argv, nil
|
|
|
|
|
return strings.Split(cmdline, " "), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
|
|
|
|
|
ru, err := getRusage(p.Pid)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, fmt.Errorf("could not get CreationDate: %w", err)
|
|
|
|
|
return 0, fmt.Errorf("could not get CreationDate: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ru.CreationTime.Nanoseconds() / 1000000, nil
|
|
|
|
@ -414,7 +394,7 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
|
|
|
|
|
|
|
|
|
|
func (p *Process) CwdWithContext(_ context.Context) (string, error) {
|
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
|
|
|
|
|
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
|
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
|
return "", nil
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
@ -652,17 +632,7 @@ func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExSta
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
|
|
|
|
|
mem, err := getMemoryInfo(p.Pid)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret := &PageFaultsStat{
|
|
|
|
|
// Since Windows does not distinguish between Major and Minor faults, all faults are treated as Major
|
|
|
|
|
MajorFaults: uint64(mem.PageFaultCount),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
|
return nil, common.ErrNotImplementedError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
|
|
|
|
@ -852,9 +822,9 @@ func (p *Process) KillWithContext(ctx context.Context) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
|
|
|
|
|
envVars, err := getProcessEnvironmentVariables(ctx, p.Pid)
|
|
|
|
|
envVars, err := getProcessEnvironmentVariables(p.Pid, ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("could not get environment variables: %w", err)
|
|
|
|
|
return nil, fmt.Errorf("could not get environment variables: %s", err)
|
|
|
|
|
}
|
|
|
|
|
return envVars, nil
|
|
|
|
|
}
|
|
|
|
@ -874,7 +844,7 @@ func (p *Process) setPpid(ppid int32) {
|
|
|
|
|
p.parent = ppid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getFromSnapProcess(pid int32) (int32, int32, string, error) { //nolint:unparam //FIXME
|
|
|
|
|
func getFromSnapProcess(pid int32) (int32, int32, string, error) {
|
|
|
|
|
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, 0, "", err
|
|
|
|
@ -902,7 +872,7 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
|
|
|
|
|
|
|
|
|
|
pids, err := PidsWithContext(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return out, fmt.Errorf("could not get Processes %w", err)
|
|
|
|
|
return out, fmt.Errorf("could not get Processes %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, pid := range pids {
|
|
|
|
@ -993,13 +963,13 @@ func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32,
|
|
|
|
|
|
|
|
|
|
buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
|
|
|
|
|
return rtlUserProcessParameters32{}, errors.New("cannot read process PEB")
|
|
|
|
|
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB")
|
|
|
|
|
}
|
|
|
|
|
peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
|
|
|
|
|
userProcessAddress := uint64(peb.ProcessParameters)
|
|
|
|
|
buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
|
|
|
|
|
return rtlUserProcessParameters32{}, errors.New("cannot read user process parameters")
|
|
|
|
|
return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters")
|
|
|
|
|
}
|
|
|
|
|
return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
|
|
|
|
|
}
|
|
|
|
@ -1012,13 +982,13 @@ func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64,
|
|
|
|
|
|
|
|
|
|
buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
|
|
|
|
|
return rtlUserProcessParameters64{}, errors.New("cannot read process PEB")
|
|
|
|
|
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB")
|
|
|
|
|
}
|
|
|
|
|
peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
|
|
|
|
|
userProcessAddress := peb.ProcessParameters
|
|
|
|
|
buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
|
|
|
|
|
if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
|
|
|
|
|
return rtlUserProcessParameters64{}, errors.New("cannot read user process parameters")
|
|
|
|
|
return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters")
|
|
|
|
|
}
|
|
|
|
|
return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
|
|
|
|
|
}
|
|
|
|
@ -1068,9 +1038,9 @@ func is32BitProcess(h windows.Handle) bool {
|
|
|
|
|
return procIs32Bits
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getProcessEnvironmentVariables(ctx context.Context, pid int32) ([]string, error) {
|
|
|
|
|
func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) {
|
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
|
|
|
|
|
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
|
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
@ -1154,7 +1124,7 @@ func (p *processReader) Read(buf []byte) (int, error) {
|
|
|
|
|
|
|
|
|
|
func getProcessCommandLine(pid int32) (string, error) {
|
|
|
|
|
h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
|
|
|
|
|
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
|
|
|
|
|
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
|
|
|
|
|
return "", nil
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|