github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/process/process_windows.go (about)

     1  //go:build windows
     2  // +build windows
     3  
     4  package process
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  	"syscall"
    13  	"unsafe"
    14  
    15  	"github.com/gofiber/fiber/v2/internal/gopsutil/common"
    16  	cpu "github.com/gofiber/fiber/v2/internal/gopsutil/cpu"
    17  	net "github.com/gofiber/fiber/v2/internal/gopsutil/net"
    18  	"golang.org/x/sys/windows"
    19  )
    20  
    21  var (
    22  	modntdll             = windows.NewLazySystemDLL("ntdll.dll")
    23  	procNtResumeProcess  = modntdll.NewProc("NtResumeProcess")
    24  	procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
    25  
    26  	modpsapi                     = windows.NewLazySystemDLL("psapi.dll")
    27  	procGetProcessMemoryInfo     = modpsapi.NewProc("GetProcessMemoryInfo")
    28  	procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW")
    29  
    30  	advapi32                  = windows.NewLazySystemDLL("advapi32.dll")
    31  	procLookupPrivilegeValue  = advapi32.NewProc("LookupPrivilegeValueW")
    32  	procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
    33  
    34  	procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW")
    35  	procGetPriorityClass           = common.Modkernel32.NewProc("GetPriorityClass")
    36  	procGetProcessIoCounters       = common.Modkernel32.NewProc("GetProcessIoCounters")
    37  	procGetNativeSystemInfo        = common.Modkernel32.NewProc("GetNativeSystemInfo")
    38  
    39  	processorArchitecture uint
    40  )
    41  
    42  type SystemProcessInformation struct {
    43  	NextEntryOffset   uint64
    44  	NumberOfThreads   uint64
    45  	Reserved1         [48]byte
    46  	Reserved2         [3]byte
    47  	UniqueProcessID   uintptr
    48  	Reserved3         uintptr
    49  	HandleCount       uint64
    50  	Reserved4         [4]byte
    51  	Reserved5         [11]byte
    52  	PeakPagefileUsage uint64
    53  	PrivatePageCount  uint64
    54  	Reserved6         [6]uint64
    55  }
    56  
    57  type systemProcessorInformation struct {
    58  	ProcessorArchitecture uint16
    59  	ProcessorLevel        uint16
    60  	ProcessorRevision     uint16
    61  	Reserved              uint16
    62  	ProcessorFeatureBits  uint16
    63  }
    64  
    65  type systemInfo struct {
    66  	wProcessorArchitecture      uint16
    67  	wReserved                   uint16
    68  	dwPageSize                  uint32
    69  	lpMinimumApplicationAddress uintptr
    70  	lpMaximumApplicationAddress uintptr
    71  	dwActiveProcessorMask       uintptr
    72  	dwNumberOfProcessors        uint32
    73  	dwProcessorType             uint32
    74  	dwAllocationGranularity     uint32
    75  	wProcessorLevel             uint16
    76  	wProcessorRevision          uint16
    77  }
    78  
    79  // Memory_info_ex is different between OSes
    80  type MemoryInfoExStat struct {
    81  }
    82  
    83  type MemoryMapsStat struct {
    84  }
    85  
    86  // ioCounters is an equivalent representation of IO_COUNTERS in the Windows API.
    87  // https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters
    88  type ioCounters struct {
    89  	ReadOperationCount  uint64
    90  	WriteOperationCount uint64
    91  	OtherOperationCount uint64
    92  	ReadTransferCount   uint64
    93  	WriteTransferCount  uint64
    94  	OtherTransferCount  uint64
    95  }
    96  
    97  type processBasicInformation32 struct {
    98  	Reserved1       uint32
    99  	PebBaseAddress  uint32
   100  	Reserved2       uint32
   101  	Reserved3       uint32
   102  	UniqueProcessId uint32
   103  	Reserved4       uint32
   104  }
   105  
   106  type processBasicInformation64 struct {
   107  	Reserved1       uint64
   108  	PebBaseAddress  uint64
   109  	Reserved2       uint64
   110  	Reserved3       uint64
   111  	UniqueProcessId uint64
   112  	Reserved4       uint64
   113  }
   114  
   115  type winLUID struct {
   116  	LowPart  winDWord
   117  	HighPart winLong
   118  }
   119  
   120  // LUID_AND_ATTRIBUTES
   121  type winLUIDAndAttributes struct {
   122  	Luid       winLUID
   123  	Attributes winDWord
   124  }
   125  
   126  // TOKEN_PRIVILEGES
   127  type winTokenPriviledges struct {
   128  	PrivilegeCount winDWord
   129  	Privileges     [1]winLUIDAndAttributes
   130  }
   131  
   132  type winLong int32
   133  type winDWord uint32
   134  
   135  func init() {
   136  	var systemInfo systemInfo
   137  
   138  	procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
   139  	processorArchitecture = uint(systemInfo.wProcessorArchitecture)
   140  
   141  	// enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119
   142  	handle, err := syscall.GetCurrentProcess()
   143  	if err != nil {
   144  		return
   145  	}
   146  
   147  	var token syscall.Token
   148  	err = syscall.OpenProcessToken(handle, 0x0028, &token)
   149  	if err != nil {
   150  		return
   151  	}
   152  	defer token.Close()
   153  
   154  	tokenPriviledges := winTokenPriviledges{PrivilegeCount: 1}
   155  	lpName := syscall.StringToUTF16("SeDebugPrivilege")
   156  	ret, _, _ := procLookupPrivilegeValue.Call(
   157  		0,
   158  		uintptr(unsafe.Pointer(&lpName[0])),
   159  		uintptr(unsafe.Pointer(&tokenPriviledges.Privileges[0].Luid)))
   160  	if ret == 0 {
   161  		return
   162  	}
   163  
   164  	tokenPriviledges.Privileges[0].Attributes = 0x00000002 // SE_PRIVILEGE_ENABLED
   165  
   166  	procAdjustTokenPrivileges.Call(
   167  		uintptr(token),
   168  		0,
   169  		uintptr(unsafe.Pointer(&tokenPriviledges)),
   170  		uintptr(unsafe.Sizeof(tokenPriviledges)),
   171  		0,
   172  		0)
   173  }
   174  
   175  func pidsWithContext(ctx context.Context) ([]int32, error) {
   176  	// inspired by https://gist.github.com/henkman/3083408
   177  	// and https://github.com/giampaolo/psutil/blob/1c3a15f637521ba5c0031283da39c733fda53e4c/psutil/arch/windows/process_info.c#L315-L329
   178  	var ret []int32
   179  	var read uint32 = 0
   180  	var psSize uint32 = 1024
   181  	const dwordSize uint32 = 4
   182  
   183  	for {
   184  		ps := make([]uint32, psSize)
   185  		if err := windows.EnumProcesses(ps, &read); err != nil {
   186  			return nil, err
   187  		}
   188  		if uint32(len(ps)) == read { // ps buffer was too small to host every results, retry with a bigger one
   189  			psSize += 1024
   190  			continue
   191  		}
   192  		for _, pid := range ps[:read/dwordSize] {
   193  			ret = append(ret, int32(pid))
   194  		}
   195  		return ret, nil
   196  
   197  	}
   198  
   199  }
   200  
   201  func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
   202  	if pid == 0 { // special case for pid 0 System Idle Process
   203  		return true, nil
   204  	}
   205  	if pid < 0 {
   206  		return false, fmt.Errorf("invalid pid %v", pid)
   207  	}
   208  	if pid%4 != 0 {
   209  		// OpenProcess will succeed even on non-existing pid here https://devblogs.microsoft.com/oldnewthing/20080606-00/?p=22043
   210  		// so we list every pid just to be sure and be future-proof
   211  		pids, err := PidsWithContext(ctx)
   212  		if err != nil {
   213  			return false, err
   214  		}
   215  		for _, i := range pids {
   216  			if i == pid {
   217  				return true, err
   218  			}
   219  		}
   220  		return false, err
   221  	}
   222  	const STILL_ACTIVE = 259 // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
   223  	h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
   224  	if err == windows.ERROR_ACCESS_DENIED {
   225  		return true, nil
   226  	}
   227  	if err == windows.ERROR_INVALID_PARAMETER {
   228  		return false, nil
   229  	}
   230  	if err != nil {
   231  		return false, err
   232  	}
   233  	defer syscall.CloseHandle(syscall.Handle(h))
   234  	var exitCode uint32
   235  	err = windows.GetExitCodeProcess(h, &exitCode)
   236  	return exitCode == STILL_ACTIVE, err
   237  }
   238  
   239  func (p *Process) Ppid() (int32, error) {
   240  	return p.PpidWithContext(context.Background())
   241  }
   242  
   243  func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
   244  	ppid, _, _, err := getFromSnapProcess(p.Pid)
   245  	if err != nil {
   246  		return 0, err
   247  	}
   248  	return ppid, nil
   249  }
   250  
   251  func (p *Process) Name() (string, error) {
   252  	return p.NameWithContext(context.Background())
   253  }
   254  
   255  func (p *Process) NameWithContext(ctx context.Context) (string, error) {
   256  	_, _, name, err := getFromSnapProcess(p.Pid)
   257  	if err != nil {
   258  		return "", fmt.Errorf("could not get Name: %s", err)
   259  	}
   260  	return name, nil
   261  }
   262  
   263  func (p *Process) Tgid() (int32, error) {
   264  	return 0, common.ErrNotImplementedError
   265  }
   266  
   267  func (p *Process) Exe() (string, error) {
   268  	return p.ExeWithContext(context.Background())
   269  }
   270  
   271  func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
   272  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(p.Pid))
   273  	if err != nil {
   274  		return "", err
   275  	}
   276  	defer windows.CloseHandle(c)
   277  	buf := make([]uint16, syscall.MAX_LONG_PATH)
   278  	size := uint32(syscall.MAX_LONG_PATH)
   279  	if err := procQueryFullProcessImageNameW.Find(); err == nil { // Vista+
   280  		ret, _, err := procQueryFullProcessImageNameW.Call(
   281  			uintptr(c),
   282  			uintptr(0),
   283  			uintptr(unsafe.Pointer(&buf[0])),
   284  			uintptr(unsafe.Pointer(&size)))
   285  		if ret == 0 {
   286  			return "", err
   287  		}
   288  		return windows.UTF16ToString(buf[:]), nil
   289  	}
   290  	// XP fallback
   291  	ret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size))
   292  	if ret == 0 {
   293  		return "", err
   294  	}
   295  	return common.ConvertDOSPath(windows.UTF16ToString(buf[:])), nil
   296  }
   297  
   298  func (p *Process) Cmdline() (string, error) {
   299  	return p.CmdlineWithContext(context.Background())
   300  }
   301  
   302  func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
   303  	cmdline, err := getProcessCommandLine(p.Pid)
   304  	if err != nil {
   305  		return "", fmt.Errorf("could not get CommandLine: %s", err)
   306  	}
   307  	return cmdline, nil
   308  }
   309  
   310  // CmdlineSlice returns the command line arguments of the process as a slice with each
   311  // element being an argument. This merely returns the CommandLine informations passed
   312  // to the process split on the 0x20 ASCII character.
   313  func (p *Process) CmdlineSlice() ([]string, error) {
   314  	return p.CmdlineSliceWithContext(context.Background())
   315  }
   316  
   317  func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
   318  	cmdline, err := p.CmdlineWithContext(ctx)
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	return strings.Split(cmdline, " "), nil
   323  }
   324  
   325  func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
   326  	ru, err := getRusage(p.Pid)
   327  	if err != nil {
   328  		return 0, fmt.Errorf("could not get CreationDate: %s", err)
   329  	}
   330  
   331  	return ru.CreationTime.Nanoseconds() / 1000000, nil
   332  }
   333  
   334  func (p *Process) Cwd() (string, error) {
   335  	return p.CwdWithContext(context.Background())
   336  }
   337  
   338  func (p *Process) CwdWithContext(ctx context.Context) (string, error) {
   339  	return "", common.ErrNotImplementedError
   340  }
   341  func (p *Process) Parent() (*Process, error) {
   342  	return p.ParentWithContext(context.Background())
   343  }
   344  
   345  func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
   346  	ppid, err := p.PpidWithContext(ctx)
   347  	if err != nil {
   348  		return nil, fmt.Errorf("could not get ParentProcessID: %s", err)
   349  	}
   350  
   351  	return NewProcess(ppid)
   352  }
   353  func (p *Process) Status() (string, error) {
   354  	return p.StatusWithContext(context.Background())
   355  }
   356  
   357  func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
   358  	return "", common.ErrNotImplementedError
   359  }
   360  
   361  func (p *Process) Foreground() (bool, error) {
   362  	return p.ForegroundWithContext(context.Background())
   363  }
   364  
   365  func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
   366  	return false, common.ErrNotImplementedError
   367  }
   368  
   369  func (p *Process) Username() (string, error) {
   370  	return p.UsernameWithContext(context.Background())
   371  }
   372  
   373  func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
   374  	pid := p.Pid
   375  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
   376  	if err != nil {
   377  		return "", err
   378  	}
   379  	defer windows.CloseHandle(c)
   380  
   381  	var token syscall.Token
   382  	err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)
   383  	if err != nil {
   384  		return "", err
   385  	}
   386  	defer token.Close()
   387  	tokenUser, err := token.GetTokenUser()
   388  	if err != nil {
   389  		return "", err
   390  	}
   391  
   392  	user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
   393  	return domain + "\\" + user, err
   394  }
   395  
   396  func (p *Process) Uids() ([]int32, error) {
   397  	return p.UidsWithContext(context.Background())
   398  }
   399  
   400  func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
   401  	var uids []int32
   402  
   403  	return uids, common.ErrNotImplementedError
   404  }
   405  func (p *Process) Gids() ([]int32, error) {
   406  	return p.GidsWithContext(context.Background())
   407  }
   408  
   409  func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
   410  	var gids []int32
   411  	return gids, common.ErrNotImplementedError
   412  }
   413  
   414  func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
   415  	var groups []int32
   416  	return groups, common.ErrNotImplementedError
   417  }
   418  func (p *Process) Terminal() (string, error) {
   419  	return p.TerminalWithContext(context.Background())
   420  }
   421  
   422  func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
   423  	return "", common.ErrNotImplementedError
   424  }
   425  
   426  // priorityClasses maps a win32 priority class to its WMI equivalent Win32_Process.Priority
   427  // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass
   428  // https://docs.microsoft.com/en-us/windows/desktop/cimwin32prov/win32-process
   429  var priorityClasses = map[int]int32{
   430  	0x00008000: 10, // ABOVE_NORMAL_PRIORITY_CLASS
   431  	0x00004000: 6,  // BELOW_NORMAL_PRIORITY_CLASS
   432  	0x00000080: 13, // HIGH_PRIORITY_CLASS
   433  	0x00000040: 4,  // IDLE_PRIORITY_CLASS
   434  	0x00000020: 8,  // NORMAL_PRIORITY_CLASS
   435  	0x00000100: 24, // REALTIME_PRIORITY_CLASS
   436  }
   437  
   438  // Nice returns priority in Windows
   439  func (p *Process) Nice() (int32, error) {
   440  	return p.NiceWithContext(context.Background())
   441  }
   442  
   443  func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
   444  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(p.Pid))
   445  	if err != nil {
   446  		return 0, err
   447  	}
   448  	defer windows.CloseHandle(c)
   449  	ret, _, err := procGetPriorityClass.Call(uintptr(c))
   450  	if ret == 0 {
   451  		return 0, err
   452  	}
   453  	priority, ok := priorityClasses[int(ret)]
   454  	if !ok {
   455  		return 0, fmt.Errorf("unknown priority class %v", ret)
   456  	}
   457  	return priority, nil
   458  }
   459  func (p *Process) IOnice() (int32, error) {
   460  	return p.IOniceWithContext(context.Background())
   461  }
   462  
   463  func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
   464  	return 0, common.ErrNotImplementedError
   465  }
   466  func (p *Process) Rlimit() ([]RlimitStat, error) {
   467  	return p.RlimitWithContext(context.Background())
   468  }
   469  
   470  func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
   471  	var rlimit []RlimitStat
   472  
   473  	return rlimit, common.ErrNotImplementedError
   474  }
   475  func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) {
   476  	return p.RlimitUsageWithContext(context.Background(), gatherUsed)
   477  }
   478  
   479  func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
   480  	var rlimit []RlimitStat
   481  
   482  	return rlimit, common.ErrNotImplementedError
   483  }
   484  
   485  func (p *Process) IOCounters() (*IOCountersStat, error) {
   486  	return p.IOCountersWithContext(context.Background())
   487  }
   488  
   489  func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
   490  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(p.Pid))
   491  	if err != nil {
   492  		return nil, err
   493  	}
   494  	defer windows.CloseHandle(c)
   495  	var ioCounters ioCounters
   496  	ret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&ioCounters)))
   497  	if ret == 0 {
   498  		return nil, err
   499  	}
   500  	stats := &IOCountersStat{
   501  		ReadCount:  ioCounters.ReadOperationCount,
   502  		ReadBytes:  ioCounters.ReadTransferCount,
   503  		WriteCount: ioCounters.WriteOperationCount,
   504  		WriteBytes: ioCounters.WriteTransferCount,
   505  	}
   506  
   507  	return stats, nil
   508  }
   509  func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
   510  	return p.NumCtxSwitchesWithContext(context.Background())
   511  }
   512  
   513  func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
   514  	return nil, common.ErrNotImplementedError
   515  }
   516  func (p *Process) NumFDs() (int32, error) {
   517  	return p.NumFDsWithContext(context.Background())
   518  }
   519  
   520  func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
   521  	return 0, common.ErrNotImplementedError
   522  }
   523  func (p *Process) NumThreads() (int32, error) {
   524  	return p.NumThreadsWithContext(context.Background())
   525  }
   526  
   527  func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
   528  	_, ret, _, err := getFromSnapProcess(p.Pid)
   529  	if err != nil {
   530  		return 0, err
   531  	}
   532  	return ret, nil
   533  }
   534  func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) {
   535  	return p.ThreadsWithContext(context.Background())
   536  }
   537  
   538  func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
   539  	ret := make(map[int32]*cpu.TimesStat)
   540  	return ret, common.ErrNotImplementedError
   541  }
   542  func (p *Process) Times() (*cpu.TimesStat, error) {
   543  	return p.TimesWithContext(context.Background())
   544  }
   545  
   546  func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
   547  	sysTimes, err := getProcessCPUTimes(p.Pid)
   548  	if err != nil {
   549  		return nil, err
   550  	}
   551  
   552  	// User and kernel times are represented as a FILETIME structure
   553  	// which contains a 64-bit value representing the number of
   554  	// 100-nanosecond intervals since January 1, 1601 (UTC):
   555  	// http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
   556  	// To convert it into a float representing the seconds that the
   557  	// process has executed in user/kernel mode I borrowed the code
   558  	// below from psutil's _psutil_windows.c, and in turn from Python's
   559  	// Modules/posixmodule.c
   560  
   561  	user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
   562  	kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
   563  
   564  	return &cpu.TimesStat{
   565  		User:   user,
   566  		System: kernel,
   567  	}, nil
   568  }
   569  func (p *Process) CPUAffinity() ([]int32, error) {
   570  	return p.CPUAffinityWithContext(context.Background())
   571  }
   572  
   573  func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
   574  	return nil, common.ErrNotImplementedError
   575  }
   576  func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
   577  	return p.MemoryInfoWithContext(context.Background())
   578  }
   579  
   580  func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
   581  	mem, err := getMemoryInfo(p.Pid)
   582  	if err != nil {
   583  		return nil, err
   584  	}
   585  
   586  	ret := &MemoryInfoStat{
   587  		RSS: uint64(mem.WorkingSetSize),
   588  		VMS: uint64(mem.PagefileUsage),
   589  	}
   590  
   591  	return ret, nil
   592  }
   593  func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
   594  	return p.MemoryInfoExWithContext(context.Background())
   595  }
   596  
   597  func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
   598  	return nil, common.ErrNotImplementedError
   599  }
   600  
   601  func (p *Process) PageFaults() (*PageFaultsStat, error) {
   602  	return p.PageFaultsWithContext(context.Background())
   603  }
   604  
   605  func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
   606  	return nil, common.ErrNotImplementedError
   607  }
   608  
   609  func (p *Process) Children() ([]*Process, error) {
   610  	return p.ChildrenWithContext(context.Background())
   611  }
   612  
   613  func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
   614  	out := []*Process{}
   615  	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0))
   616  	if err != nil {
   617  		return out, err
   618  	}
   619  	defer windows.CloseHandle(snap)
   620  	var pe32 windows.ProcessEntry32
   621  	pe32.Size = uint32(unsafe.Sizeof(pe32))
   622  	if err := windows.Process32First(snap, &pe32); err != nil {
   623  		return out, err
   624  	}
   625  	for {
   626  		if pe32.ParentProcessID == uint32(p.Pid) {
   627  			p, err := NewProcess(int32(pe32.ProcessID))
   628  			if err == nil {
   629  				out = append(out, p)
   630  			}
   631  		}
   632  		if err = windows.Process32Next(snap, &pe32); err != nil {
   633  			break
   634  		}
   635  	}
   636  	return out, nil
   637  }
   638  
   639  func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
   640  	return p.OpenFilesWithContext(context.Background())
   641  }
   642  
   643  func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
   644  	return nil, common.ErrNotImplementedError
   645  }
   646  
   647  func (p *Process) Connections() ([]net.ConnectionStat, error) {
   648  	return p.ConnectionsWithContext(context.Background())
   649  }
   650  
   651  func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
   652  	return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
   653  }
   654  
   655  func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) {
   656  	return p.ConnectionsMaxWithContext(context.Background(), max)
   657  }
   658  
   659  func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
   660  	return []net.ConnectionStat{}, common.ErrNotImplementedError
   661  }
   662  
   663  func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
   664  	return p.NetIOCountersWithContext(context.Background(), pernic)
   665  }
   666  
   667  func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
   668  	return nil, common.ErrNotImplementedError
   669  }
   670  
   671  func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
   672  	return p.MemoryMapsWithContext(context.Background(), grouped)
   673  }
   674  
   675  func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
   676  	var ret []MemoryMapsStat
   677  	return &ret, common.ErrNotImplementedError
   678  }
   679  
   680  func (p *Process) SendSignal(sig windows.Signal) error {
   681  	return p.SendSignalWithContext(context.Background(), sig)
   682  }
   683  
   684  func (p *Process) SendSignalWithContext(ctx context.Context, sig windows.Signal) error {
   685  	return common.ErrNotImplementedError
   686  }
   687  
   688  func (p *Process) Suspend() error {
   689  	return p.SuspendWithContext(context.Background())
   690  }
   691  
   692  func (p *Process) SuspendWithContext(ctx context.Context) error {
   693  	c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
   694  	if err != nil {
   695  		return err
   696  	}
   697  	defer windows.CloseHandle(c)
   698  
   699  	r1, _, _ := procNtSuspendProcess.Call(uintptr(unsafe.Pointer(c)))
   700  	if r1 != 0 {
   701  		// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
   702  		return fmt.Errorf("NtStatus='0x%.8X'", r1)
   703  	}
   704  
   705  	return nil
   706  }
   707  
   708  func (p *Process) Resume() error {
   709  	return p.ResumeWithContext(context.Background())
   710  }
   711  
   712  func (p *Process) ResumeWithContext(ctx context.Context) error {
   713  	c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
   714  	if err != nil {
   715  		return err
   716  	}
   717  	defer windows.CloseHandle(c)
   718  
   719  	r1, _, _ := procNtResumeProcess.Call(uintptr(unsafe.Pointer(c)))
   720  	if r1 != 0 {
   721  		// See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
   722  		return fmt.Errorf("NtStatus='0x%.8X'", r1)
   723  	}
   724  
   725  	return nil
   726  }
   727  
   728  func (p *Process) Terminate() error {
   729  	return p.TerminateWithContext(context.Background())
   730  }
   731  
   732  func (p *Process) TerminateWithContext(ctx context.Context) error {
   733  	proc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid))
   734  	if err != nil {
   735  		return err
   736  	}
   737  	err = windows.TerminateProcess(proc, 0)
   738  	windows.CloseHandle(proc)
   739  	return err
   740  }
   741  
   742  func (p *Process) Kill() error {
   743  	return p.KillWithContext(context.Background())
   744  }
   745  
   746  func (p *Process) KillWithContext(ctx context.Context) error {
   747  	process := os.Process{Pid: int(p.Pid)}
   748  	return process.Kill()
   749  }
   750  
   751  func getFromSnapProcess(pid int32) (int32, int32, string, error) {
   752  	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
   753  	if err != nil {
   754  		return 0, 0, "", err
   755  	}
   756  	defer windows.CloseHandle(snap)
   757  	var pe32 windows.ProcessEntry32
   758  	pe32.Size = uint32(unsafe.Sizeof(pe32))
   759  	if err = windows.Process32First(snap, &pe32); err != nil {
   760  		return 0, 0, "", err
   761  	}
   762  	for {
   763  		if pe32.ProcessID == uint32(pid) {
   764  			szexe := windows.UTF16ToString(pe32.ExeFile[:])
   765  			return int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil
   766  		}
   767  		if err = windows.Process32Next(snap, &pe32); err != nil {
   768  			break
   769  		}
   770  	}
   771  	return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
   772  }
   773  
   774  // Get processes
   775  func Processes() ([]*Process, error) {
   776  	return ProcessesWithContext(context.Background())
   777  }
   778  
   779  func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
   780  	out := []*Process{}
   781  
   782  	pids, err := PidsWithContext(ctx)
   783  	if err != nil {
   784  		return out, fmt.Errorf("could not get Processes %s", err)
   785  	}
   786  
   787  	for _, pid := range pids {
   788  		p, err := NewProcess(pid)
   789  		if err != nil {
   790  			continue
   791  		}
   792  		out = append(out, p)
   793  	}
   794  
   795  	return out, nil
   796  }
   797  
   798  func getRusage(pid int32) (*windows.Rusage, error) {
   799  	var CPU windows.Rusage
   800  
   801  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
   802  	if err != nil {
   803  		return nil, err
   804  	}
   805  	defer windows.CloseHandle(c)
   806  
   807  	if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
   808  		return nil, err
   809  	}
   810  
   811  	return &CPU, nil
   812  }
   813  
   814  func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
   815  	var mem PROCESS_MEMORY_COUNTERS
   816  	c, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
   817  	if err != nil {
   818  		return mem, err
   819  	}
   820  	defer windows.CloseHandle(c)
   821  	if err := getProcessMemoryInfo(c, &mem); err != nil {
   822  		return mem, err
   823  	}
   824  
   825  	return mem, err
   826  }
   827  
   828  func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
   829  	r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
   830  	if r1 == 0 {
   831  		if e1 != 0 {
   832  			err = error(e1)
   833  		} else {
   834  			err = syscall.EINVAL
   835  		}
   836  	}
   837  	return
   838  }
   839  
   840  type SYSTEM_TIMES struct {
   841  	CreateTime syscall.Filetime
   842  	ExitTime   syscall.Filetime
   843  	KernelTime syscall.Filetime
   844  	UserTime   syscall.Filetime
   845  }
   846  
   847  func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
   848  	var times SYSTEM_TIMES
   849  
   850  	h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
   851  	if err != nil {
   852  		return times, err
   853  	}
   854  	defer windows.CloseHandle(h)
   855  
   856  	err = syscall.GetProcessTimes(
   857  		syscall.Handle(h),
   858  		&times.CreateTime,
   859  		&times.ExitTime,
   860  		&times.KernelTime,
   861  		&times.UserTime,
   862  	)
   863  
   864  	return times, err
   865  }
   866  
   867  func is32BitProcess(procHandle syscall.Handle) bool {
   868  	var wow64 uint
   869  
   870  	ret, _, _ := common.ProcNtQueryInformationProcess.Call(
   871  		uintptr(procHandle),
   872  		uintptr(common.ProcessWow64Information),
   873  		uintptr(unsafe.Pointer(&wow64)),
   874  		uintptr(unsafe.Sizeof(wow64)),
   875  		uintptr(0),
   876  	)
   877  	if int(ret) >= 0 {
   878  		if wow64 != 0 {
   879  			return true
   880  		}
   881  	} else {
   882  		//if the OS does not support the call, we fallback into the bitness of the app
   883  		if unsafe.Sizeof(wow64) == 4 {
   884  			return true
   885  		}
   886  	}
   887  	return false
   888  }
   889  
   890  func getProcessCommandLine(pid int32) (string, error) {
   891  	h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.PROCESS_VM_READ, false, uint32(pid))
   892  	if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
   893  		return "", nil
   894  	}
   895  	if err != nil {
   896  		return "", err
   897  	}
   898  	defer syscall.CloseHandle(syscall.Handle(h))
   899  
   900  	const (
   901  		PROCESSOR_ARCHITECTURE_INTEL = 0
   902  		PROCESSOR_ARCHITECTURE_ARM   = 5
   903  		PROCESSOR_ARCHITECTURE_ARM64 = 12
   904  		PROCESSOR_ARCHITECTURE_IA64  = 6
   905  		PROCESSOR_ARCHITECTURE_AMD64 = 9
   906  	)
   907  
   908  	procIs32Bits := true
   909  	switch processorArchitecture {
   910  	case PROCESSOR_ARCHITECTURE_INTEL:
   911  		fallthrough
   912  	case PROCESSOR_ARCHITECTURE_ARM:
   913  		procIs32Bits = true
   914  
   915  	case PROCESSOR_ARCHITECTURE_ARM64:
   916  		fallthrough
   917  	case PROCESSOR_ARCHITECTURE_IA64:
   918  		fallthrough
   919  	case PROCESSOR_ARCHITECTURE_AMD64:
   920  		procIs32Bits = is32BitProcess(syscall.Handle(h))
   921  
   922  	default:
   923  		//for other unknown platforms, we rely on process platform
   924  		if unsafe.Sizeof(processorArchitecture) == 8 {
   925  			procIs32Bits = false
   926  		}
   927  	}
   928  
   929  	pebAddress := queryPebAddress(syscall.Handle(h), procIs32Bits)
   930  	if pebAddress == 0 {
   931  		return "", errors.New("cannot locate process PEB")
   932  	}
   933  
   934  	if procIs32Bits {
   935  		buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress+uint64(16), 4)
   936  		if len(buf) != 4 {
   937  			return "", errors.New("cannot locate process user parameters")
   938  		}
   939  		userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24)
   940  
   941  		//read CommandLine field from PRTL_USER_PROCESS_PARAMETERS
   942  		remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(64), 8)
   943  		if len(remoteCmdLine) != 8 {
   944  			return "", errors.New("cannot read cmdline field")
   945  		}
   946  
   947  		//remoteCmdLine is actually a UNICODE_STRING32
   948  		//the first two bytes has the length
   949  		cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8)
   950  		if cmdLineLength > 0 {
   951  			//and, at offset 4, is the pointer to the buffer
   952  			bufferAddress := uint32(remoteCmdLine[4]) | (uint32(remoteCmdLine[5]) << 8) |
   953  				(uint32(remoteCmdLine[6]) << 16) | (uint32(remoteCmdLine[7]) << 24)
   954  
   955  			cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(bufferAddress), cmdLineLength)
   956  			if len(cmdLine) != int(cmdLineLength) {
   957  				return "", errors.New("cannot read cmdline")
   958  			}
   959  
   960  			return convertUTF16ToString(cmdLine), nil
   961  		}
   962  	} else {
   963  		buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress+uint64(32), 8)
   964  		if len(buf) != 8 {
   965  			return "", errors.New("cannot locate process user parameters")
   966  		}
   967  		userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) |
   968  			(uint64(buf[4]) << 32) | (uint64(buf[5]) << 40) | (uint64(buf[6]) << 48) | (uint64(buf[7]) << 56)
   969  
   970  		//read CommandLine field from PRTL_USER_PROCESS_PARAMETERS
   971  		remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(112), 16)
   972  		if len(remoteCmdLine) != 16 {
   973  			return "", errors.New("cannot read cmdline field")
   974  		}
   975  
   976  		//remoteCmdLine is actually a UNICODE_STRING64
   977  		//the first two bytes has the length
   978  		cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8)
   979  		if cmdLineLength > 0 {
   980  			//and, at offset 8, is the pointer to the buffer
   981  			bufferAddress := uint64(remoteCmdLine[8]) | (uint64(remoteCmdLine[9]) << 8) |
   982  				(uint64(remoteCmdLine[10]) << 16) | (uint64(remoteCmdLine[11]) << 24) |
   983  				(uint64(remoteCmdLine[12]) << 32) | (uint64(remoteCmdLine[13]) << 40) |
   984  				(uint64(remoteCmdLine[14]) << 48) | (uint64(remoteCmdLine[15]) << 56)
   985  
   986  			cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, bufferAddress, cmdLineLength)
   987  			if len(cmdLine) != int(cmdLineLength) {
   988  				return "", errors.New("cannot read cmdline")
   989  			}
   990  
   991  			return convertUTF16ToString(cmdLine), nil
   992  		}
   993  	}
   994  
   995  	//if we reach here, we have no command line
   996  	return "", nil
   997  }
   998  
   999  func convertUTF16ToString(src []byte) string {
  1000  	srcLen := len(src) / 2
  1001  
  1002  	codePoints := make([]uint16, srcLen)
  1003  
  1004  	srcIdx := 0
  1005  	for i := 0; i < srcLen; i++ {
  1006  		codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8
  1007  		srcIdx += 2
  1008  	}
  1009  	return syscall.UTF16ToString(codePoints)
  1010  }