github.com/elastic/gosigar@v0.14.3/sys/windows/syscall_windows.go (about)

     1  package windows
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"syscall"
     7  	"time"
     8  	"unsafe"
     9  
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  var (
    14  	sizeofUint32                  = 4
    15  	sizeofProcessEntry32          = uint32(unsafe.Sizeof(ProcessEntry32{}))
    16  	sizeofProcessMemoryCountersEx = uint32(unsafe.Sizeof(ProcessMemoryCountersEx{}))
    17  	sizeofMemoryStatusEx          = uint32(unsafe.Sizeof(MemoryStatusEx{}))
    18  )
    19  
    20  // Process-specific access rights. Others are declared in the syscall package.
    21  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx
    22  const (
    23  	PROCESS_QUERY_LIMITED_INFORMATION uint32 = 0x1000
    24  	PROCESS_VM_READ                   uint32 = 0x0010
    25  )
    26  
    27  // error codes for GetVolumeInformation function
    28  const (
    29  	ERROR_INVALID_FUNCTION syscall.Errno = 1
    30  	ERROR_NOT_READY        syscall.Errno = 21
    31  )
    32  
    33  // SizeOfRtlUserProcessParameters gives the size
    34  // of the RtlUserProcessParameters struct.
    35  const SizeOfRtlUserProcessParameters = unsafe.Sizeof(RtlUserProcessParameters{})
    36  
    37  // MAX_PATH is the maximum length for a path in Windows.
    38  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
    39  const MAX_PATH = 260
    40  
    41  // DriveType represents a type of drive (removable, fixed, CD-ROM, RAM disk, or
    42  // network drive).
    43  type DriveType uint32
    44  
    45  // Drive types as returned by GetDriveType.
    46  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364939(v=vs.85).aspx
    47  const (
    48  	DRIVE_UNKNOWN DriveType = iota
    49  	DRIVE_NO_ROOT_DIR
    50  	DRIVE_REMOVABLE
    51  	DRIVE_FIXED
    52  	DRIVE_REMOTE
    53  	DRIVE_CDROM
    54  	DRIVE_RAMDISK
    55  )
    56  
    57  // UnicodeString is Go's equivalent for the _UNICODE_STRING struct.
    58  type UnicodeString struct {
    59  	Size          uint16
    60  	MaximumLength uint16
    61  	Buffer        uintptr
    62  }
    63  
    64  // RtlUserProcessParameters is Go's equivalent for the
    65  // _RTL_USER_PROCESS_PARAMETERS struct.
    66  // A few undocumented fields are exposed.
    67  type RtlUserProcessParameters struct {
    68  	Reserved1              [16]byte
    69  	Reserved2              [5]uintptr
    70  	CurrentDirectoryPath   UnicodeString
    71  	CurrentDirectoryHandle uintptr
    72  	DllPath                UnicodeString
    73  	ImagePathName          UnicodeString
    74  	CommandLine            UnicodeString
    75  }
    76  
    77  func (dt DriveType) String() string {
    78  	names := map[DriveType]string{
    79  		DRIVE_UNKNOWN:     "unknown",
    80  		DRIVE_NO_ROOT_DIR: "invalid",
    81  		DRIVE_REMOVABLE:   "removable",
    82  		DRIVE_FIXED:       "fixed",
    83  		DRIVE_REMOTE:      "remote",
    84  		DRIVE_CDROM:       "cdrom",
    85  		DRIVE_RAMDISK:     "ramdisk",
    86  	}
    87  
    88  	name, found := names[dt]
    89  	if !found {
    90  		return "unknown DriveType value"
    91  	}
    92  	return name
    93  }
    94  
    95  // Flags that can be used with CreateToolhelp32Snapshot.
    96  const (
    97  	TH32CS_INHERIT      uint32 = 0x80000000 // Indicates that the snapshot handle is to be inheritable.
    98  	TH32CS_SNAPHEAPLIST uint32 = 0x00000001 // Includes all heaps of the process specified in th32ProcessID in the snapshot.
    99  	TH32CS_SNAPMODULE   uint32 = 0x00000008 // Includes all modules of the process specified in th32ProcessID in the snapshot.
   100  	TH32CS_SNAPMODULE32 uint32 = 0x00000010 // Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit process.
   101  	TH32CS_SNAPPROCESS  uint32 = 0x00000002 // Includes all processes in the system in the snapshot.
   102  	TH32CS_SNAPTHREAD   uint32 = 0x00000004 // Includes all threads in the system in the snapshot.
   103  )
   104  
   105  // ProcessEntry32 is an equivalent representation of PROCESSENTRY32 in the
   106  // Windows API. It contains a process's information. Do not modify or reorder.
   107  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684839(v=vs.85).aspx
   108  type ProcessEntry32 struct {
   109  	size              uint32
   110  	CntUsage          uint32
   111  	ProcessID         uint32
   112  	DefaultHeapID     uintptr
   113  	ModuleID          uint32
   114  	CntThreads        uint32
   115  	ParentProcessID   uint32
   116  	PriorityClassBase int32
   117  	Flags             uint32
   118  	exeFile           [MAX_PATH]uint16
   119  }
   120  
   121  // ExeFile returns the name of the executable file for the process. It does
   122  // not contain the full path.
   123  func (p ProcessEntry32) ExeFile() string {
   124  	return syscall.UTF16ToString(p.exeFile[:])
   125  }
   126  
   127  func (p ProcessEntry32) String() string {
   128  	return fmt.Sprintf("{CntUsage:%v ProcessID:%v DefaultHeapID:%v ModuleID:%v "+
   129  		"CntThreads:%v ParentProcessID:%v PriorityClassBase:%v Flags:%v ExeFile:%v",
   130  		p.CntUsage, p.ProcessID, p.DefaultHeapID, p.ModuleID, p.CntThreads,
   131  		p.ParentProcessID, p.PriorityClassBase, p.Flags, p.ExeFile())
   132  }
   133  
   134  // MemoryStatusEx is an equivalent representation of MEMORYSTATUSEX in the
   135  // Windows API. It contains information about the current state of both physical
   136  // and virtual memory, including extended memory.
   137  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770
   138  type MemoryStatusEx struct {
   139  	length               uint32
   140  	MemoryLoad           uint32
   141  	TotalPhys            uint64
   142  	AvailPhys            uint64
   143  	TotalPageFile        uint64
   144  	AvailPageFile        uint64
   145  	TotalVirtual         uint64
   146  	AvailVirtual         uint64
   147  	AvailExtendedVirtual uint64
   148  }
   149  
   150  // ProcessMemoryCountersEx is an equivalent representation of
   151  // PROCESS_MEMORY_COUNTERS_EX in the Windows API.
   152  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684874(v=vs.85).aspx
   153  type ProcessMemoryCountersEx struct {
   154  	cb                         uint32
   155  	PageFaultCount             uint32
   156  	PeakWorkingSetSize         uintptr
   157  	WorkingSetSize             uintptr
   158  	QuotaPeakPagedPoolUsage    uintptr
   159  	QuotaPagedPoolUsage        uintptr
   160  	QuotaPeakNonPagedPoolUsage uintptr
   161  	QuotaNonPagedPoolUsage     uintptr
   162  	PagefileUsage              uintptr
   163  	PeakPagefileUsage          uintptr
   164  	PrivateUsage               uintptr
   165  }
   166  
   167  // GetLogicalDriveStrings returns a list of drives in the system.
   168  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364975(v=vs.85).aspx
   169  func GetLogicalDriveStrings() ([]string, error) {
   170  	// Determine the size of the buffer required to receive all drives.
   171  	bufferLength, err := _GetLogicalDriveStringsW(0, nil)
   172  	if err != nil {
   173  		return nil, errors.Wrap(err, "GetLogicalDriveStringsW failed to get buffer length")
   174  	}
   175  	if bufferLength < 0 {
   176  		return nil, errors.New("GetLogicalDriveStringsW returned an invalid buffer length")
   177  	}
   178  
   179  	buffer := make([]uint16, bufferLength)
   180  	_, err = _GetLogicalDriveStringsW(uint32(len(buffer)), &buffer[0])
   181  	if err != nil {
   182  		return nil, errors.Wrap(err, "GetLogicalDriveStringsW failed")
   183  	}
   184  
   185  	return UTF16SliceToStringSlice(buffer), nil
   186  }
   187  
   188  // GetAccessPaths returns the list of access paths for volumes in the system.
   189  func GetAccessPaths() ([]string, error) {
   190  	volumes, err := GetVolumes()
   191  	if err != nil {
   192  		return nil, errors.Wrap(err, "GetVolumes failed")
   193  	}
   194  
   195  	var paths []string
   196  	for _, volumeName := range volumes {
   197  		volumePaths, err := GetVolumePathsForVolume(volumeName)
   198  		if err != nil {
   199  			return nil, errors.Wrapf(err, "failed to get list of access paths for volume '%s'", volumeName)
   200  		}
   201  		if len(volumePaths) == 0 {
   202  			continue
   203  		}
   204  
   205  		// Get only the first path
   206  		paths = append(paths, volumePaths[0])
   207  	}
   208  
   209  	return paths, nil
   210  }
   211  
   212  // GetVolumes returs the list of volumes in the system.
   213  // https://docs.microsoft.com/es-es/windows/desktop/api/fileapi/nf-fileapi-findfirstvolumew
   214  func GetVolumes() ([]string, error) {
   215  	buffer := make([]uint16, MAX_PATH+1)
   216  
   217  	var volumes []string
   218  
   219  	h, err := _FindFirstVolume(&buffer[0], uint32(len(buffer)))
   220  	if err != nil {
   221  		return nil, errors.Wrap(err, "FindFirstVolumeW failed")
   222  	}
   223  	defer _FindVolumeClose(h)
   224  
   225  	for {
   226  		volumes = append(volumes, syscall.UTF16ToString(buffer))
   227  
   228  		err = _FindNextVolume(h, &buffer[0], uint32(len(buffer)))
   229  		if err != nil {
   230  			if errors.Cause(err) == syscall.ERROR_NO_MORE_FILES {
   231  				break
   232  			}
   233  			return nil, errors.Wrap(err, "FindNextVolumeW failed")
   234  		}
   235  	}
   236  
   237  	return volumes, nil
   238  }
   239  
   240  // GetVolumePathsForVolume returns the list of volume paths for a volume.
   241  // https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-getvolumepathnamesforvolumenamew
   242  func GetVolumePathsForVolume(volumeName string) ([]string, error) {
   243  	var length uint32
   244  	err := _GetVolumePathNamesForVolumeName(volumeName, nil, 0, &length)
   245  	if errors.Cause(err) != syscall.ERROR_MORE_DATA {
   246  		return nil, errors.Wrap(err, "GetVolumePathNamesForVolumeNameW failed to get needed buffer length")
   247  	}
   248  	if length == 0 {
   249  		// Not mounted, no paths, that's ok
   250  		return nil, nil
   251  	}
   252  
   253  	buffer := make([]uint16, length*(MAX_PATH+1))
   254  	err = _GetVolumePathNamesForVolumeName(volumeName, &buffer[0], length, &length)
   255  	if err != nil {
   256  		return nil, errors.Wrap(err, "GetVolumePathNamesForVolumeNameW failed")
   257  	}
   258  
   259  	return UTF16SliceToStringSlice(buffer), nil
   260  }
   261  
   262  // GlobalMemoryStatusEx retrieves information about the system's current usage
   263  // of both physical and virtual memory.
   264  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx
   265  func GlobalMemoryStatusEx() (MemoryStatusEx, error) {
   266  	memoryStatusEx := MemoryStatusEx{length: sizeofMemoryStatusEx}
   267  	err := _GlobalMemoryStatusEx(&memoryStatusEx)
   268  	if err != nil {
   269  		return MemoryStatusEx{}, errors.Wrap(err, "GlobalMemoryStatusEx failed")
   270  	}
   271  
   272  	return memoryStatusEx, nil
   273  }
   274  
   275  // GetProcessMemoryInfo retrieves information about the memory usage of the
   276  // specified process.
   277  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683219(v=vs.85).aspx
   278  func GetProcessMemoryInfo(handle syscall.Handle) (ProcessMemoryCountersEx, error) {
   279  	processMemoryCountersEx := ProcessMemoryCountersEx{cb: sizeofProcessMemoryCountersEx}
   280  	err := _GetProcessMemoryInfo(handle, &processMemoryCountersEx, processMemoryCountersEx.cb)
   281  	if err != nil {
   282  		return ProcessMemoryCountersEx{}, errors.Wrap(err, "GetProcessMemoryInfo failed")
   283  	}
   284  
   285  	return processMemoryCountersEx, nil
   286  }
   287  
   288  // GetProcessImageFileName Retrieves the name of the executable file for the
   289  // specified process.
   290  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx
   291  func GetProcessImageFileName(handle syscall.Handle) (string, error) {
   292  	buffer := make([]uint16, MAX_PATH)
   293  	_, err := _GetProcessImageFileName(handle, &buffer[0], uint32(len(buffer)))
   294  	if err != nil {
   295  		return "", errors.Wrap(err, "GetProcessImageFileName failed")
   296  	}
   297  
   298  	return syscall.UTF16ToString(buffer), nil
   299  }
   300  
   301  // GetSystemTimes retrieves system timing information. On a multiprocessor
   302  // system, the values returned are the sum of the designated times across all
   303  // processors. The returned kernel time does not include the system idle time.
   304  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx
   305  func GetSystemTimes() (idle, kernel, user time.Duration, err error) {
   306  	var idleTime, kernelTime, userTime syscall.Filetime
   307  	err = _GetSystemTimes(&idleTime, &kernelTime, &userTime)
   308  	if err != nil {
   309  		return 0, 0, 0, errors.Wrap(err, "GetSystemTimes failed")
   310  	}
   311  
   312  	idle = FiletimeToDuration(&idleTime)
   313  	kernel = FiletimeToDuration(&kernelTime) // Kernel time includes idle time so we subtract it out.
   314  	user = FiletimeToDuration(&userTime)
   315  
   316  	return idle, kernel - idle, user, nil
   317  }
   318  
   319  // FiletimeToDuration converts a Filetime to a time.Duration. Do not use this
   320  // method to convert a Filetime to an actual clock time, for that use
   321  // Filetime.Nanosecond().
   322  func FiletimeToDuration(ft *syscall.Filetime) time.Duration {
   323  	n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
   324  	return time.Duration(n * 100)
   325  }
   326  
   327  // GetDriveType Determines whether a disk drive is a removable, fixed, CD-ROM,
   328  // RAM disk, or network drive. A trailing backslash is required on the
   329  // rootPathName.
   330  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364939
   331  func GetDriveType(rootPathName string) (DriveType, error) {
   332  	rootPathNamePtr, err := syscall.UTF16PtrFromString(rootPathName)
   333  	if err != nil {
   334  		return DRIVE_UNKNOWN, errors.Wrapf(err, "UTF16PtrFromString failed for rootPathName=%v", rootPathName)
   335  	}
   336  
   337  	dt, err := _GetDriveType(rootPathNamePtr)
   338  	if err != nil {
   339  		return DRIVE_UNKNOWN, errors.Wrapf(err, "GetDriveType failed for rootPathName=%v", rootPathName)
   340  	}
   341  
   342  	return dt, nil
   343  }
   344  
   345  // GetFilesystemType returns file system type information at the given root path.
   346  // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw
   347  func GetFilesystemType(rootPathName string) (string, error) {
   348  	rootPathNamePtr, err := syscall.UTF16PtrFromString(rootPathName)
   349  	var systemType = "unavailable"
   350  	if err != nil {
   351  		return "", errors.Wrapf(err, "UTF16PtrFromString failed for rootPathName=%v", rootPathName)
   352  	}
   353  	buffer := make([]uint16, MAX_PATH+1)
   354  	// _GetVolumeInformation will fail for external drives like CD-ROM or other type with error codes as ERROR_NOT_READY. ERROR_INVALID_FUNCTION, ERROR_INVALID_PARAMETER, etc., these types of errors will be ignored
   355  	success, err := _GetVolumeInformation(rootPathNamePtr, nil, 0, nil, nil, nil, &buffer[0], MAX_PATH)
   356  	if success {
   357  		systemType = strings.ToLower(syscall.UTF16ToString(buffer))
   358  	}
   359  	return systemType, nil
   360  }
   361  
   362  // EnumProcesses retrieves the process identifier for each process object in the
   363  // system. This function can return a max of 65536 PIDs. If there are more
   364  // processes than that then this will not return them all.
   365  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682629(v=vs.85).aspx
   366  func EnumProcesses() ([]uint32, error) {
   367  	enumProcesses := func(size int) ([]uint32, error) {
   368  		var (
   369  			pids         = make([]uint32, size)
   370  			sizeBytes    = len(pids) * sizeofUint32
   371  			bytesWritten uint32
   372  		)
   373  
   374  		err := _EnumProcesses(&pids[0], uint32(sizeBytes), &bytesWritten)
   375  
   376  		pidsWritten := int(bytesWritten) / sizeofUint32
   377  		if int(bytesWritten)%sizeofUint32 != 0 || pidsWritten > len(pids) {
   378  			return nil, errors.Errorf("EnumProcesses returned an invalid bytesWritten value of %v", bytesWritten)
   379  		}
   380  		pids = pids[:pidsWritten]
   381  
   382  		return pids, err
   383  	}
   384  
   385  	// Retry the EnumProcesses call with larger arrays if needed.
   386  	size := 2048
   387  	var pids []uint32
   388  	for tries := 0; tries < 5; tries++ {
   389  		var err error
   390  		pids, err = enumProcesses(size)
   391  		if err != nil {
   392  			return nil, errors.Wrap(err, "EnumProcesses failed")
   393  		}
   394  
   395  		if len(pids) < size {
   396  			break
   397  		}
   398  
   399  		// Increase the size the pids array and retry the enumProcesses call
   400  		// because the array wasn't large enough to hold all of the processes.
   401  		size *= 2
   402  	}
   403  
   404  	return pids, nil
   405  }
   406  
   407  // GetDiskFreeSpaceEx retrieves information about the amount of space that is
   408  // available on a disk volume, which is the total amount of space, the total
   409  // amount of free space, and the total amount of free space available to the
   410  // user that is associated with the calling thread.
   411  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
   412  func GetDiskFreeSpaceEx(directoryName string) (freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64, err error) {
   413  	directoryNamePtr, err := syscall.UTF16PtrFromString(directoryName)
   414  	if err != nil {
   415  		return 0, 0, 0, errors.Wrapf(err, "UTF16PtrFromString failed for directoryName=%v", directoryName)
   416  	}
   417  
   418  	err = _GetDiskFreeSpaceEx(directoryNamePtr, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)
   419  	if err != nil {
   420  		return 0, 0, 0, err
   421  	}
   422  
   423  	return freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes, nil
   424  }
   425  
   426  // CreateToolhelp32Snapshot takes a snapshot of the specified processes, as well
   427  // as the heaps, modules, and threads used by these processes.
   428  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682489(v=vs.85).aspx
   429  func CreateToolhelp32Snapshot(flags, pid uint32) (syscall.Handle, error) {
   430  	h, err := _CreateToolhelp32Snapshot(flags, pid)
   431  	if err != nil {
   432  		return syscall.InvalidHandle, err
   433  	}
   434  	if h == syscall.InvalidHandle {
   435  		return syscall.InvalidHandle, syscall.GetLastError()
   436  	}
   437  
   438  	return h, nil
   439  }
   440  
   441  // Process32First retrieves information about the first process encountered in a
   442  // system snapshot.
   443  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684834
   444  func Process32First(handle syscall.Handle) (ProcessEntry32, error) {
   445  	processEntry32 := ProcessEntry32{size: sizeofProcessEntry32}
   446  	err := _Process32First(handle, &processEntry32)
   447  	if err != nil {
   448  		return ProcessEntry32{}, errors.Wrap(err, "Process32First failed")
   449  	}
   450  
   451  	return processEntry32, nil
   452  }
   453  
   454  // Process32Next retrieves information about the next process recorded in a
   455  // system snapshot. When there are no more processes to iterate then
   456  // syscall.ERROR_NO_MORE_FILES is returned (use errors.Cause() to unwrap).
   457  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684836
   458  func Process32Next(handle syscall.Handle) (ProcessEntry32, error) {
   459  	processEntry32 := ProcessEntry32{size: sizeofProcessEntry32}
   460  	err := _Process32Next(handle, &processEntry32)
   461  	if err != nil {
   462  		return ProcessEntry32{}, errors.Wrap(err, "Process32Next failed")
   463  	}
   464  
   465  	return processEntry32, nil
   466  }
   467  
   468  // UTF16SliceToStringSlice converts slice of uint16 containing a list of UTF16
   469  // strings to a slice of strings.
   470  func UTF16SliceToStringSlice(buffer []uint16) []string {
   471  	// Split the uint16 slice at null-terminators.
   472  	var startIdx int
   473  	var stringsUTF16 [][]uint16
   474  	for i, value := range buffer {
   475  		if value == 0 {
   476  			stringsUTF16 = append(stringsUTF16, buffer[startIdx:i])
   477  			startIdx = i + 1
   478  		}
   479  	}
   480  
   481  	// Convert the utf16 slices to strings.
   482  	result := make([]string, 0, len(stringsUTF16))
   483  	for _, stringUTF16 := range stringsUTF16 {
   484  		if len(stringUTF16) > 0 {
   485  			result = append(result, syscall.UTF16ToString(stringUTF16))
   486  		}
   487  	}
   488  
   489  	return result
   490  }
   491  
   492  func GetUserProcessParams(handle syscall.Handle, pbi ProcessBasicInformation) (params RtlUserProcessParameters, err error) {
   493  	const is32bitProc = unsafe.Sizeof(uintptr(0)) == 4
   494  
   495  	// Offset of params field within PEB structure.
   496  	// This structure is different in 32 and 64 bit.
   497  	paramsOffset := 0x20
   498  	if is32bitProc {
   499  		paramsOffset = 0x10
   500  	}
   501  
   502  	// Read the PEB from the target process memory
   503  	pebSize := paramsOffset + 8
   504  	peb := make([]byte, pebSize)
   505  	nRead, err := ReadProcessMemory(handle, pbi.PebBaseAddress, peb)
   506  	if err != nil {
   507  		return params, err
   508  	}
   509  	if nRead != uintptr(pebSize) {
   510  		return params, errors.Errorf("PEB: short read (%d/%d)", nRead, pebSize)
   511  	}
   512  
   513  	// Get the RTL_USER_PROCESS_PARAMETERS struct pointer from the PEB
   514  	paramsAddr := *(*uintptr)(unsafe.Pointer(&peb[paramsOffset]))
   515  
   516  	// Read the RTL_USER_PROCESS_PARAMETERS from the target process memory
   517  	paramsBuf := make([]byte, SizeOfRtlUserProcessParameters)
   518  	nRead, err = ReadProcessMemory(handle, paramsAddr, paramsBuf)
   519  	if err != nil {
   520  		return params, err
   521  	}
   522  	if nRead != uintptr(SizeOfRtlUserProcessParameters) {
   523  		return params, errors.Errorf("RTL_USER_PROCESS_PARAMETERS: short read (%d/%d)", nRead, SizeOfRtlUserProcessParameters)
   524  	}
   525  
   526  	params = *(*RtlUserProcessParameters)(unsafe.Pointer(&paramsBuf[0]))
   527  	return params, nil
   528  }
   529  
   530  // ReadProcessUnicodeString returns a zero-terminated UTF-16 string from another
   531  // process's memory.
   532  func ReadProcessUnicodeString(handle syscall.Handle, s *UnicodeString) ([]byte, error) {
   533  	// Allocate an extra UTF-16 null character at the end in case the read string
   534  	// is not terminated.
   535  	extra := 2
   536  	if s.Size&1 != 0 {
   537  		extra = 3 // If size is odd, need 3 nulls to terminate.
   538  	}
   539  	buf := make([]byte, int(s.Size)+extra)
   540  	nRead, err := ReadProcessMemory(handle, s.Buffer, buf[:s.Size])
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	if nRead != uintptr(s.Size) {
   545  		return nil, errors.Errorf("unicode string: short read: (%d/%d)", nRead, s.Size)
   546  	}
   547  	return buf, nil
   548  }
   549  
   550  // ByteSliceToStringSlice uses CommandLineToArgv API to split an UTF-16 command
   551  // line string into a list of parameters.
   552  func ByteSliceToStringSlice(utf16 []byte) ([]string, error) {
   553  	n := len(utf16)
   554  	// Discard odd byte
   555  	if n&1 != 0 {
   556  		n--
   557  		utf16 = utf16[:n]
   558  	}
   559  	if n == 0 {
   560  		return nil, nil
   561  	}
   562  	terminated := false
   563  	for i := 0; i < n && !terminated; i += 2 {
   564  		terminated = utf16[i] == 0 && utf16[i+1] == 0
   565  	}
   566  	if !terminated {
   567  		// Append a null uint16 at the end if terminator is missing
   568  		utf16 = append(utf16, 0, 0)
   569  	}
   570  	var numArgs int32
   571  	argsWide, err := syscall.CommandLineToArgv((*uint16)(unsafe.Pointer(&utf16[0])), &numArgs)
   572  	if err != nil {
   573  		return nil, err
   574  	}
   575  
   576  	// Free memory allocated for CommandLineToArgvW arguments.
   577  	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(argsWide)))
   578  
   579  	args := make([]string, numArgs)
   580  	for idx := range args {
   581  		args[idx] = syscall.UTF16ToString(argsWide[idx][:])
   582  	}
   583  	return args, nil
   584  }
   585  
   586  // ReadProcessMemory reads from another process memory. The Handle needs to have
   587  // the PROCESS_VM_READ right.
   588  // A zero-byte read is a no-op, no error is returned.
   589  func ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, dest []byte) (numRead uintptr, err error) {
   590  	n := len(dest)
   591  	if n == 0 {
   592  		return 0, nil
   593  	}
   594  	if err = _ReadProcessMemory(handle, baseAddress, uintptr(unsafe.Pointer(&dest[0])), uintptr(n), &numRead); err != nil {
   595  		return 0, err
   596  	}
   597  	return numRead, nil
   598  }
   599  
   600  func GetTickCount64() (uptime uint64, err error) {
   601  	if uptime, err = _GetTickCount64(); err != nil {
   602  		return 0, err
   603  	}
   604  	return uptime, nil
   605  }
   606  
   607  // Windows API calls
   608  //sys   _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx
   609  //sys   _GetLogicalDriveStringsW(bufferLength uint32, buffer *uint16) (length uint32, err error) = kernel32.GetLogicalDriveStringsW
   610  //sys   _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCountersEx, cb uint32) (err error) = psapi.GetProcessMemoryInfo
   611  //sys   _GetProcessImageFileName(handle syscall.Handle, outImageFileName *uint16, size uint32) (length uint32, err error) = psapi.GetProcessImageFileNameW
   612  //sys   _GetSystemTimes(idleTime *syscall.Filetime, kernelTime *syscall.Filetime, userTime *syscall.Filetime) (err error) = kernel32.GetSystemTimes
   613  //sys   _GetDriveType(rootPathName *uint16) (dt DriveType, err error) = kernel32.GetDriveTypeW
   614  //sys   _GetVolumeInformation(rootPathName *uint16, volumeName *uint16, volumeNameSize uint32, volumeSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemName *uint16, fileSystemNameSize uint32) (success bool, err error) [true] = kernel32.GetVolumeInformationW
   615  //sys   _EnumProcesses(processIds *uint32, sizeBytes uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
   616  //sys   _GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailable *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) = kernel32.GetDiskFreeSpaceExW
   617  //sys   _Process32First(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) = kernel32.Process32FirstW
   618  //sys   _Process32Next(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) = kernel32.Process32NextW
   619  //sys   _CreateToolhelp32Snapshot(flags uint32, processID uint32) (handle syscall.Handle, err error) = kernel32.CreateToolhelp32Snapshot
   620  //sys   _NtQuerySystemInformation(systemInformationClass uint32, systemInformation *byte, systemInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) = ntdll.NtQuerySystemInformation
   621  //sys   _NtQueryInformationProcess(processHandle syscall.Handle, processInformationClass uint32, processInformation *byte, processInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) = ntdll.NtQueryInformationProcess
   622  //sys   _LookupPrivilegeName(systemName string, luid *int64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
   623  //sys   _LookupPrivilegeValue(systemName string, name string, luid *int64) (err error) = advapi32.LookupPrivilegeValueW
   624  //sys   _AdjustTokenPrivileges(token syscall.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
   625  //sys   _FindFirstVolume(volumeName *uint16, size uint32) (handle syscall.Handle, err error) = kernel32.FindFirstVolumeW
   626  //sys  _FindNextVolume(handle syscall.Handle, volumeName *uint16, size uint32) (err error) = kernel32.FindNextVolumeW
   627  //sys  _FindVolumeClose(handle syscall.Handle) (err error) = kernel32.FindVolumeClose
   628  //sys  _GetVolumePathNamesForVolumeName(volumeName string, buffer *uint16, bufferSize uint32, length *uint32) (err error) = kernel32.GetVolumePathNamesForVolumeNameW
   629  //sys  _ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, buffer uintptr, size uintptr, numRead *uintptr) (err error) = kernel32.ReadProcessMemory
   630  //sys  _GetTickCount64() (uptime uint64, err error) = kernel32.GetTickCount64