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(¶msBuf[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