1
2
3 package process
4
5 import (
6 "bufio"
7 "context"
8 "errors"
9 "fmt"
10 "io"
11 "os"
12 "reflect"
13 "strings"
14 "syscall"
15 "time"
16 "unicode/utf16"
17 "unsafe"
18
19 "github.com/shirou/gopsutil/cpu"
20 "github.com/shirou/gopsutil/internal/common"
21 "github.com/shirou/gopsutil/net"
22 "golang.org/x/sys/windows"
23 )
24
25 var (
26 modntdll = windows.NewLazySystemDLL("ntdll.dll")
27 procNtResumeProcess = modntdll.NewProc("NtResumeProcess")
28 procNtSuspendProcess = modntdll.NewProc("NtSuspendProcess")
29
30 modpsapi = windows.NewLazySystemDLL("psapi.dll")
31 procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
32 procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW")
33
34 advapi32 = windows.NewLazySystemDLL("advapi32.dll")
35 procLookupPrivilegeValue = advapi32.NewProc("LookupPrivilegeValueW")
36 procAdjustTokenPrivileges = advapi32.NewProc("AdjustTokenPrivileges")
37
38 procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW")
39 procGetPriorityClass = common.Modkernel32.NewProc("GetPriorityClass")
40 procGetProcessIoCounters = common.Modkernel32.NewProc("GetProcessIoCounters")
41 procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
42
43 processorArchitecture uint
44 )
45
46 const processQueryInformation = windows.PROCESS_QUERY_LIMITED_INFORMATION
47
48 type SystemProcessInformation struct {
49 NextEntryOffset uint64
50 NumberOfThreads uint64
51 Reserved1 [48]byte
52 Reserved2 [3]byte
53 UniqueProcessID uintptr
54 Reserved3 uintptr
55 HandleCount uint64
56 Reserved4 [4]byte
57 Reserved5 [11]byte
58 PeakPagefileUsage uint64
59 PrivatePageCount uint64
60 Reserved6 [6]uint64
61 }
62
63 type systemProcessorInformation struct {
64 ProcessorArchitecture uint16
65 ProcessorLevel uint16
66 ProcessorRevision uint16
67 Reserved uint16
68 ProcessorFeatureBits uint16
69 }
70
71 type systemInfo struct {
72 wProcessorArchitecture uint16
73 wReserved uint16
74 dwPageSize uint32
75 lpMinimumApplicationAddress uintptr
76 lpMaximumApplicationAddress uintptr
77 dwActiveProcessorMask uintptr
78 dwNumberOfProcessors uint32
79 dwProcessorType uint32
80 dwAllocationGranularity uint32
81 wProcessorLevel uint16
82 wProcessorRevision uint16
83 }
84
85
86 type MemoryInfoExStat struct {
87 }
88
89 type MemoryMapsStat struct {
90 }
91
92
93
94 type ioCounters struct {
95 ReadOperationCount uint64
96 WriteOperationCount uint64
97 OtherOperationCount uint64
98 ReadTransferCount uint64
99 WriteTransferCount uint64
100 OtherTransferCount uint64
101 }
102
103 type processBasicInformation32 struct {
104 Reserved1 uint32
105 PebBaseAddress uint32
106 Reserved2 uint32
107 Reserved3 uint32
108 UniqueProcessId uint32
109 Reserved4 uint32
110 }
111
112 type processBasicInformation64 struct {
113 Reserved1 uint64
114 PebBaseAddress uint64
115 Reserved2 uint64
116 Reserved3 uint64
117 UniqueProcessId uint64
118 Reserved4 uint64
119 }
120
121 type processEnvironmentBlock32 struct {
122 Reserved1 [2]uint8
123 BeingDebugged uint8
124 Reserved2 uint8
125 Reserved3 [2]uint32
126 Ldr uint32
127 ProcessParameters uint32
128
129 }
130
131 type processEnvironmentBlock64 struct {
132 Reserved1 [2]uint8
133 BeingDebugged uint8
134 Reserved2 uint8
135 _ [4]uint8
136 Reserved3 [2]uint64
137 Ldr uint64
138 ProcessParameters uint64
139
140 }
141
142 type rtlUserProcessParameters32 struct {
143 Reserved1 [16]uint8
144 ConsoleHandle uint32
145 ConsoleFlags uint32
146 StdInputHandle uint32
147 StdOutputHandle uint32
148 StdErrorHandle uint32
149 CurrentDirectoryPathNameLength uint16
150 _ uint16
151 CurrentDirectoryPathAddress uint32
152 CurrentDirectoryHandle uint32
153 DllPathNameLength uint16
154 _ uint16
155 DllPathAddress uint32
156 ImagePathNameLength uint16
157 _ uint16
158 ImagePathAddress uint32
159 CommandLineLength uint16
160 _ uint16
161 CommandLineAddress uint32
162 EnvironmentAddress uint32
163
164 }
165
166 type rtlUserProcessParameters64 struct {
167 Reserved1 [16]uint8
168 ConsoleHandle uint64
169 ConsoleFlags uint64
170 StdInputHandle uint64
171 StdOutputHandle uint64
172 StdErrorHandle uint64
173 CurrentDirectoryPathNameLength uint16
174 _ uint16
175 _ uint32
176 CurrentDirectoryPathAddress uint64
177 CurrentDirectoryHandle uint64
178 DllPathNameLength uint16
179 _ uint16
180 _ uint32
181 DllPathAddress uint64
182 ImagePathNameLength uint16
183 _ uint16
184 _ uint32
185 ImagePathAddress uint64
186 CommandLineLength uint16
187 _ uint16
188 _ uint32
189 CommandLineAddress uint64
190 EnvironmentAddress uint64
191
192 }
193
194 type winLUID struct {
195 LowPart winDWord
196 HighPart winLong
197 }
198
199
200 type winLUIDAndAttributes struct {
201 Luid winLUID
202 Attributes winDWord
203 }
204
205
206 type winTokenPriviledges struct {
207 PrivilegeCount winDWord
208 Privileges [1]winLUIDAndAttributes
209 }
210
211 type winLong int32
212 type winDWord uint32
213
214 func init() {
215 var systemInfo systemInfo
216
217 procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo)))
218 processorArchitecture = uint(systemInfo.wProcessorArchitecture)
219
220
221 handle, err := syscall.GetCurrentProcess()
222 if err != nil {
223 return
224 }
225
226 var token syscall.Token
227 err = syscall.OpenProcessToken(handle, 0x0028, &token)
228 if err != nil {
229 return
230 }
231 defer token.Close()
232
233 tokenPriviledges := winTokenPriviledges{PrivilegeCount: 1}
234 lpName := syscall.StringToUTF16("SeDebugPrivilege")
235 ret, _, _ := procLookupPrivilegeValue.Call(
236 0,
237 uintptr(unsafe.Pointer(&lpName[0])),
238 uintptr(unsafe.Pointer(&tokenPriviledges.Privileges[0].Luid)))
239 if ret == 0 {
240 return
241 }
242
243 tokenPriviledges.Privileges[0].Attributes = 0x00000002
244
245 procAdjustTokenPrivileges.Call(
246 uintptr(token),
247 0,
248 uintptr(unsafe.Pointer(&tokenPriviledges)),
249 uintptr(unsafe.Sizeof(tokenPriviledges)),
250 0,
251 0)
252 }
253
254 func pidsWithContext(ctx context.Context) ([]int32, error) {
255
256
257 var ret []int32
258 var read uint32 = 0
259 var psSize uint32 = 1024
260 const dwordSize uint32 = 4
261
262 for {
263 ps := make([]uint32, psSize)
264 if err := windows.EnumProcesses(ps, &read); err != nil {
265 return nil, err
266 }
267 if uint32(len(ps)) == read {
268 psSize += 1024
269 continue
270 }
271 for _, pid := range ps[:read/dwordSize] {
272 ret = append(ret, int32(pid))
273 }
274 return ret, nil
275
276 }
277
278 }
279
280 func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) {
281 if pid == 0 {
282 return true, nil
283 }
284 if pid < 0 {
285 return false, fmt.Errorf("invalid pid %v", pid)
286 }
287 if pid%4 != 0 {
288
289
290 pids, err := PidsWithContext(ctx)
291 if err != nil {
292 return false, err
293 }
294 for _, i := range pids {
295 if i == pid {
296 return true, err
297 }
298 }
299 return false, err
300 }
301 const STILL_ACTIVE = 259
302 h, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
303 if err == windows.ERROR_ACCESS_DENIED {
304 return true, nil
305 }
306 if err == windows.ERROR_INVALID_PARAMETER {
307 return false, nil
308 }
309 if err != nil {
310 return false, err
311 }
312 defer syscall.CloseHandle(syscall.Handle(h))
313 var exitCode uint32
314 err = windows.GetExitCodeProcess(h, &exitCode)
315 return exitCode == STILL_ACTIVE, err
316 }
317
318 func (p *Process) PpidWithContext(ctx context.Context) (int32, error) {
319
320 cachedPpid := p.getPpid()
321 if cachedPpid != 0 {
322 return cachedPpid, nil
323 }
324
325 ppid, _, _, err := getFromSnapProcess(p.Pid)
326 if err != nil {
327 return 0, err
328 }
329
330
331 p.setPpid(ppid)
332
333 return ppid, nil
334 }
335
336 func (p *Process) NameWithContext(ctx context.Context) (string, error) {
337 ppid, _, name, err := getFromSnapProcess(p.Pid)
338 if err != nil {
339 return "", fmt.Errorf("could not get Name: %s", err)
340 }
341
342
343 p.parent = ppid
344 if 0 == p.getPpid() {
345 p.setPpid(ppid)
346 }
347
348 return name, nil
349 }
350
351 func (p *Process) TgidWithContext(ctx context.Context) (int32, error) {
352 return 0, common.ErrNotImplementedError
353 }
354
355 func (p *Process) ExeWithContext(ctx context.Context) (string, error) {
356 c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
357 if err != nil {
358 return "", err
359 }
360 defer windows.CloseHandle(c)
361 buf := make([]uint16, syscall.MAX_LONG_PATH)
362 size := uint32(syscall.MAX_LONG_PATH)
363 if err := procQueryFullProcessImageNameW.Find(); err == nil {
364 ret, _, err := procQueryFullProcessImageNameW.Call(
365 uintptr(c),
366 uintptr(0),
367 uintptr(unsafe.Pointer(&buf[0])),
368 uintptr(unsafe.Pointer(&size)))
369 if ret == 0 {
370 return "", err
371 }
372 return windows.UTF16ToString(buf[:]), nil
373 }
374
375 ret, _, err := procGetProcessImageFileNameW.Call(uintptr(c), uintptr(unsafe.Pointer(&buf[0])), uintptr(size))
376 if ret == 0 {
377 return "", err
378 }
379 return common.ConvertDOSPath(windows.UTF16ToString(buf[:])), nil
380 }
381
382 func (p *Process) CmdlineWithContext(_ context.Context) (string, error) {
383 cmdline, err := getProcessCommandLine(p.Pid)
384 if err != nil {
385 return "", fmt.Errorf("could not get CommandLine: %s", err)
386 }
387 return cmdline, nil
388 }
389
390 func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) {
391 cmdline, err := p.CmdlineWithContext(ctx)
392 if err != nil {
393 return nil, err
394 }
395 return strings.Split(cmdline, " "), nil
396 }
397
398 func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
399 ru, err := getRusage(p.Pid)
400 if err != nil {
401 return 0, fmt.Errorf("could not get CreationDate: %s", err)
402 }
403
404 return ru.CreationTime.Nanoseconds() / 1000000, nil
405 }
406
407 func (p *Process) CwdWithContext(_ context.Context) (string, error) {
408 h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
409 if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
410 return "", nil
411 }
412 if err != nil {
413 return "", err
414 }
415 defer syscall.CloseHandle(syscall.Handle(h))
416
417 procIs32Bits := is32BitProcess(h)
418
419 if procIs32Bits {
420 userProcParams, err := getUserProcessParams32(h)
421 if err != nil {
422 return "", err
423 }
424 if userProcParams.CurrentDirectoryPathNameLength > 0 {
425 cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))
426 if len(cwd) != int(userProcParams.CurrentDirectoryPathAddress) {
427 return "", errors.New("cannot read current working directory")
428 }
429
430 return convertUTF16ToString(cwd), nil
431 }
432 } else {
433 userProcParams, err := getUserProcessParams64(h)
434 if err != nil {
435 return "", err
436 }
437 if userProcParams.CurrentDirectoryPathNameLength > 0 {
438 cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
439 if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
440 return "", errors.New("cannot read current working directory")
441 }
442
443 return convertUTF16ToString(cwd), nil
444 }
445 }
446
447
448 return "", nil
449 }
450
451 func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {
452 ppid, err := p.PpidWithContext(ctx)
453 if err != nil {
454 return nil, fmt.Errorf("could not get ParentProcessID: %s", err)
455 }
456
457 return NewProcessWithContext(ctx, ppid)
458 }
459
460 func (p *Process) StatusWithContext(ctx context.Context) (string, error) {
461 return "", common.ErrNotImplementedError
462 }
463
464 func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) {
465 return false, common.ErrNotImplementedError
466 }
467
468 func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
469 pid := p.Pid
470 c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
471 if err != nil {
472 return "", err
473 }
474 defer windows.CloseHandle(c)
475
476 var token syscall.Token
477 err = syscall.OpenProcessToken(syscall.Handle(c), syscall.TOKEN_QUERY, &token)
478 if err != nil {
479 return "", err
480 }
481 defer token.Close()
482 tokenUser, err := token.GetTokenUser()
483 if err != nil {
484 return "", err
485 }
486
487 user, domain, _, err := tokenUser.User.Sid.LookupAccount("")
488 return domain + "\\" + user, err
489 }
490
491 func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) {
492 return nil, common.ErrNotImplementedError
493 }
494
495 func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) {
496 return nil, common.ErrNotImplementedError
497 }
498
499 func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) {
500 return nil, common.ErrNotImplementedError
501 }
502
503 func (p *Process) TerminalWithContext(ctx context.Context) (string, error) {
504 return "", common.ErrNotImplementedError
505 }
506
507
508
509
510 var priorityClasses = map[int]int32{
511 0x00008000: 10,
512 0x00004000: 6,
513 0x00000080: 13,
514 0x00000040: 4,
515 0x00000020: 8,
516 0x00000100: 24,
517 }
518
519 func (p *Process) NiceWithContext(ctx context.Context) (int32, error) {
520 c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
521 if err != nil {
522 return 0, err
523 }
524 defer windows.CloseHandle(c)
525 ret, _, err := procGetPriorityClass.Call(uintptr(c))
526 if ret == 0 {
527 return 0, err
528 }
529 priority, ok := priorityClasses[int(ret)]
530 if !ok {
531 return 0, fmt.Errorf("unknown priority class %v", ret)
532 }
533 return priority, nil
534 }
535
536 func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) {
537 return 0, common.ErrNotImplementedError
538 }
539
540 func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) {
541 return nil, common.ErrNotImplementedError
542 }
543
544 func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) {
545 return nil, common.ErrNotImplementedError
546 }
547
548 func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) {
549 c, err := windows.OpenProcess(processQueryInformation, false, uint32(p.Pid))
550 if err != nil {
551 return nil, err
552 }
553 defer windows.CloseHandle(c)
554 var ioCounters ioCounters
555 ret, _, err := procGetProcessIoCounters.Call(uintptr(c), uintptr(unsafe.Pointer(&ioCounters)))
556 if ret == 0 {
557 return nil, err
558 }
559 stats := &IOCountersStat{
560 ReadCount: ioCounters.ReadOperationCount,
561 ReadBytes: ioCounters.ReadTransferCount,
562 WriteCount: ioCounters.WriteOperationCount,
563 WriteBytes: ioCounters.WriteTransferCount,
564 }
565
566 return stats, nil
567 }
568
569 func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) {
570 return nil, common.ErrNotImplementedError
571 }
572
573 func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) {
574 return 0, common.ErrNotImplementedError
575 }
576
577 func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) {
578 ppid, ret, _, err := getFromSnapProcess(p.Pid)
579 if err != nil {
580 return 0, err
581 }
582
583
584 p.parent = ppid
585 if 0 == p.getPpid() {
586 p.setPpid(ppid)
587 }
588
589 return ret, nil
590 }
591
592 func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) {
593 return nil, common.ErrNotImplementedError
594 }
595
596 func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) {
597 sysTimes, err := getProcessCPUTimes(p.Pid)
598 if err != nil {
599 return nil, err
600 }
601
602
603
604
605
606
607
608
609
610
611 user := float64(sysTimes.UserTime.HighDateTime)*429.4967296 + float64(sysTimes.UserTime.LowDateTime)*1e-7
612 kernel := float64(sysTimes.KernelTime.HighDateTime)*429.4967296 + float64(sysTimes.KernelTime.LowDateTime)*1e-7
613
614 return &cpu.TimesStat{
615 User: user,
616 System: kernel,
617 }, nil
618 }
619
620 func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) {
621 return nil, common.ErrNotImplementedError
622 }
623
624 func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) {
625 mem, err := getMemoryInfo(p.Pid)
626 if err != nil {
627 return nil, err
628 }
629
630 ret := &MemoryInfoStat{
631 RSS: uint64(mem.WorkingSetSize),
632 VMS: uint64(mem.PagefileUsage),
633 }
634
635 return ret, nil
636 }
637
638 func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) {
639 return nil, common.ErrNotImplementedError
640 }
641
642 func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) {
643 return nil, common.ErrNotImplementedError
644 }
645
646 func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) {
647 out := []*Process{}
648 snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(0))
649 if err != nil {
650 return out, err
651 }
652 defer windows.CloseHandle(snap)
653 var pe32 windows.ProcessEntry32
654 pe32.Size = uint32(unsafe.Sizeof(pe32))
655 if err := windows.Process32First(snap, &pe32); err != nil {
656 return out, err
657 }
658 for {
659 if pe32.ParentProcessID == uint32(p.Pid) {
660 p, err := NewProcessWithContext(ctx, int32(pe32.ProcessID))
661 if err == nil {
662 out = append(out, p)
663 }
664 }
665 if err = windows.Process32Next(snap, &pe32); err != nil {
666 break
667 }
668 }
669 return out, nil
670 }
671
672 func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) {
673 files := make([]OpenFilesStat, 0)
674 fileExists := make(map[string]bool)
675
676 process, err := windows.OpenProcess(common.ProcessQueryInformation, false, uint32(p.Pid))
677 if err != nil {
678 return nil, err
679 }
680
681 buffer := make([]byte, 1024)
682 var size uint32
683
684 st := common.CallWithExpandingBuffer(
685 func() common.NtStatus {
686 return common.NtQuerySystemInformation(
687 common.SystemExtendedHandleInformationClass,
688 &buffer[0],
689 uint32(len(buffer)),
690 &size,
691 )
692 },
693 &buffer,
694 &size,
695 )
696 if st.IsError() {
697 return nil, st.Error()
698 }
699
700 handlesList := (*common.SystemExtendedHandleInformation)(unsafe.Pointer(&buffer[0]))
701 handles := make([]common.SystemExtendedHandleTableEntryInformation, int(handlesList.NumberOfHandles))
702 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&handles))
703 hdr.Data = uintptr(unsafe.Pointer(&handlesList.Handles[0]))
704
705 currentProcess, err := windows.GetCurrentProcess()
706 if err != nil {
707 return nil, err
708 }
709
710 for _, handle := range handles {
711 var file uintptr
712 if int32(handle.UniqueProcessId) != p.Pid {
713 continue
714 }
715 if windows.DuplicateHandle(process, windows.Handle(handle.HandleValue), currentProcess, (*windows.Handle)(&file),
716 0, true, windows.DUPLICATE_SAME_ACCESS) != nil {
717 continue
718 }
719 fileType, _ := windows.GetFileType(windows.Handle(file))
720 if fileType != windows.FILE_TYPE_DISK {
721 continue
722 }
723
724 var fileName string
725 ch := make(chan struct{})
726
727 go func() {
728 var buf [syscall.MAX_LONG_PATH]uint16
729 n, err := windows.GetFinalPathNameByHandle(windows.Handle(file), &buf[0], syscall.MAX_LONG_PATH, 0)
730 if err != nil {
731 return
732 }
733
734 fileName = string(utf16.Decode(buf[:n]))
735 ch <- struct{}{}
736 }()
737
738 select {
739 case <-time.NewTimer(100 * time.Millisecond).C:
740 continue
741 case <-ch:
742 fileInfo, _ := os.Stat(fileName)
743 if fileInfo.IsDir() {
744 continue
745 }
746
747 if _, exists := fileExists[fileName]; !exists {
748 files = append(files, OpenFilesStat{
749 Path: fileName,
750 Fd: uint64(file),
751 })
752 fileExists[fileName] = true
753 }
754 case <-ctx.Done():
755 return files, ctx.Err()
756 }
757 }
758
759 return files, nil
760 }
761
762 func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) {
763 return net.ConnectionsPidWithContext(ctx, "all", p.Pid)
764 }
765
766 func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) {
767 return nil, common.ErrNotImplementedError
768 }
769
770 func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) {
771 return nil, common.ErrNotImplementedError
772 }
773
774 func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) {
775 return nil, common.ErrNotImplementedError
776 }
777
778 func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
779 return common.ErrNotImplementedError
780 }
781
782 func (p *Process) SuspendWithContext(ctx context.Context) error {
783 c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
784 if err != nil {
785 return err
786 }
787 defer windows.CloseHandle(c)
788
789 r1, _, _ := procNtSuspendProcess.Call(uintptr(c))
790 if r1 != 0 {
791
792 return fmt.Errorf("NtStatus='0x%.8X'", r1)
793 }
794
795 return nil
796 }
797
798 func (p *Process) ResumeWithContext(ctx context.Context) error {
799 c, err := windows.OpenProcess(windows.PROCESS_SUSPEND_RESUME, false, uint32(p.Pid))
800 if err != nil {
801 return err
802 }
803 defer windows.CloseHandle(c)
804
805 r1, _, _ := procNtResumeProcess.Call(uintptr(c))
806 if r1 != 0 {
807
808 return fmt.Errorf("NtStatus='0x%.8X'", r1)
809 }
810
811 return nil
812 }
813
814 func (p *Process) TerminateWithContext(ctx context.Context) error {
815 proc, err := windows.OpenProcess(windows.PROCESS_TERMINATE, false, uint32(p.Pid))
816 if err != nil {
817 return err
818 }
819 err = windows.TerminateProcess(proc, 0)
820 windows.CloseHandle(proc)
821 return err
822 }
823
824 func (p *Process) KillWithContext(ctx context.Context) error {
825 process, err := os.FindProcess(int(p.Pid))
826 if err != nil {
827 return err
828 }
829 return process.Kill()
830 }
831
832 func (p *Process) EnvironWithContext(ctx context.Context) ([]string, error) {
833 envVars, err := getProcessEnvironmentVariables(p.Pid, ctx)
834 if err != nil {
835 return nil, fmt.Errorf("could not get environment variables: %s", err)
836 }
837 return envVars, nil
838 }
839
840
841 func (p *Process) getPpid() int32 {
842 p.parentMutex.RLock()
843 defer p.parentMutex.RUnlock()
844 return p.parent
845 }
846
847
848
849 func (p *Process) setPpid(ppid int32) {
850 p.parentMutex.Lock()
851 defer p.parentMutex.Unlock()
852 p.parent = ppid
853 }
854
855 func getFromSnapProcess(pid int32) (int32, int32, string, error) {
856 snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
857 if err != nil {
858 return 0, 0, "", err
859 }
860 defer windows.CloseHandle(snap)
861 var pe32 windows.ProcessEntry32
862 pe32.Size = uint32(unsafe.Sizeof(pe32))
863 if err = windows.Process32First(snap, &pe32); err != nil {
864 return 0, 0, "", err
865 }
866 for {
867 if pe32.ProcessID == uint32(pid) {
868 szexe := windows.UTF16ToString(pe32.ExeFile[:])
869 return int32(pe32.ParentProcessID), int32(pe32.Threads), szexe, nil
870 }
871 if err = windows.Process32Next(snap, &pe32); err != nil {
872 break
873 }
874 }
875 return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
876 }
877
878 func ProcessesWithContext(ctx context.Context) ([]*Process, error) {
879 out := []*Process{}
880
881 pids, err := PidsWithContext(ctx)
882 if err != nil {
883 return out, fmt.Errorf("could not get Processes %s", err)
884 }
885
886 for _, pid := range pids {
887 p, err := NewProcessWithContext(ctx, pid)
888 if err != nil {
889 continue
890 }
891 out = append(out, p)
892 }
893
894 return out, nil
895 }
896
897 func getRusage(pid int32) (*windows.Rusage, error) {
898 var CPU windows.Rusage
899
900 c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
901 if err != nil {
902 return nil, err
903 }
904 defer windows.CloseHandle(c)
905
906 if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil {
907 return nil, err
908 }
909
910 return &CPU, nil
911 }
912
913 func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) {
914 var mem PROCESS_MEMORY_COUNTERS
915 c, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
916 if err != nil {
917 return mem, err
918 }
919 defer windows.CloseHandle(c)
920 if err := getProcessMemoryInfo(c, &mem); err != nil {
921 return mem, err
922 }
923
924 return mem, err
925 }
926
927 func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) {
928 r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem)))
929 if r1 == 0 {
930 if e1 != 0 {
931 err = error(e1)
932 } else {
933 err = syscall.EINVAL
934 }
935 }
936 return
937 }
938
939 type SYSTEM_TIMES struct {
940 CreateTime syscall.Filetime
941 ExitTime syscall.Filetime
942 KernelTime syscall.Filetime
943 UserTime syscall.Filetime
944 }
945
946 func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) {
947 var times SYSTEM_TIMES
948
949 h, err := windows.OpenProcess(processQueryInformation, false, uint32(pid))
950 if err != nil {
951 return times, err
952 }
953 defer windows.CloseHandle(h)
954
955 err = syscall.GetProcessTimes(
956 syscall.Handle(h),
957 ×.CreateTime,
958 ×.ExitTime,
959 ×.KernelTime,
960 ×.UserTime,
961 )
962
963 return times, err
964 }
965
966 func getUserProcessParams32(handle windows.Handle) (rtlUserProcessParameters32, error) {
967 pebAddress, err := queryPebAddress(syscall.Handle(handle), true)
968 if err != nil {
969 return rtlUserProcessParameters32{}, fmt.Errorf("cannot locate process PEB: %w", err)
970 }
971
972 buf := readProcessMemory(syscall.Handle(handle), true, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock32{})))
973 if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock32{})) {
974 return rtlUserProcessParameters32{}, fmt.Errorf("cannot read process PEB")
975 }
976 peb := (*processEnvironmentBlock32)(unsafe.Pointer(&buf[0]))
977 userProcessAddress := uint64(peb.ProcessParameters)
978 buf = readProcessMemory(syscall.Handle(handle), true, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters32{})))
979 if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters32{})) {
980 return rtlUserProcessParameters32{}, fmt.Errorf("cannot read user process parameters")
981 }
982 return *(*rtlUserProcessParameters32)(unsafe.Pointer(&buf[0])), nil
983 }
984
985 func getUserProcessParams64(handle windows.Handle) (rtlUserProcessParameters64, error) {
986 pebAddress, err := queryPebAddress(syscall.Handle(handle), false)
987 if err != nil {
988 return rtlUserProcessParameters64{}, fmt.Errorf("cannot locate process PEB: %w", err)
989 }
990
991 buf := readProcessMemory(syscall.Handle(handle), false, pebAddress, uint(unsafe.Sizeof(processEnvironmentBlock64{})))
992 if len(buf) != int(unsafe.Sizeof(processEnvironmentBlock64{})) {
993 return rtlUserProcessParameters64{}, fmt.Errorf("cannot read process PEB")
994 }
995 peb := (*processEnvironmentBlock64)(unsafe.Pointer(&buf[0]))
996 userProcessAddress := peb.ProcessParameters
997 buf = readProcessMemory(syscall.Handle(handle), false, userProcessAddress, uint(unsafe.Sizeof(rtlUserProcessParameters64{})))
998 if len(buf) != int(unsafe.Sizeof(rtlUserProcessParameters64{})) {
999 return rtlUserProcessParameters64{}, fmt.Errorf("cannot read user process parameters")
1000 }
1001 return *(*rtlUserProcessParameters64)(unsafe.Pointer(&buf[0])), nil
1002 }
1003
1004 func is32BitProcess(h windows.Handle) bool {
1005 const (
1006 PROCESSOR_ARCHITECTURE_INTEL = 0
1007 PROCESSOR_ARCHITECTURE_ARM = 5
1008 PROCESSOR_ARCHITECTURE_ARM64 = 12
1009 PROCESSOR_ARCHITECTURE_IA64 = 6
1010 PROCESSOR_ARCHITECTURE_AMD64 = 9
1011 )
1012
1013 var procIs32Bits bool
1014 switch processorArchitecture {
1015 case PROCESSOR_ARCHITECTURE_INTEL:
1016 fallthrough
1017 case PROCESSOR_ARCHITECTURE_ARM:
1018 procIs32Bits = true
1019 case PROCESSOR_ARCHITECTURE_ARM64:
1020 fallthrough
1021 case PROCESSOR_ARCHITECTURE_IA64:
1022 fallthrough
1023 case PROCESSOR_ARCHITECTURE_AMD64:
1024 var wow64 uint
1025
1026 ret, _, _ := common.ProcNtQueryInformationProcess.Call(
1027 uintptr(h),
1028 uintptr(common.ProcessWow64Information),
1029 uintptr(unsafe.Pointer(&wow64)),
1030 uintptr(unsafe.Sizeof(wow64)),
1031 uintptr(0),
1032 )
1033 if int(ret) >= 0 {
1034 if wow64 != 0 {
1035 procIs32Bits = true
1036 }
1037 } else {
1038
1039 if unsafe.Sizeof(wow64) == 4 {
1040 procIs32Bits = true
1041 }
1042 }
1043
1044 default:
1045
1046 if unsafe.Sizeof(processorArchitecture) == 8 {
1047 procIs32Bits = false
1048 } else {
1049 procIs32Bits = true
1050 }
1051 }
1052 return procIs32Bits
1053 }
1054
1055 func getProcessEnvironmentVariables(pid int32, ctx context.Context) ([]string, error) {
1056 h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
1057 if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
1058 return nil, nil
1059 }
1060 if err != nil {
1061 return nil, err
1062 }
1063 defer syscall.CloseHandle(syscall.Handle(h))
1064
1065 procIs32Bits := is32BitProcess(h)
1066
1067 var processParameterBlockAddress uint64
1068
1069 if procIs32Bits {
1070 peb, err := getUserProcessParams32(h)
1071 if err != nil {
1072 return nil, err
1073 }
1074 processParameterBlockAddress = uint64(peb.EnvironmentAddress)
1075 } else {
1076 peb, err := getUserProcessParams64(h)
1077 if err != nil {
1078 return nil, err
1079 }
1080 processParameterBlockAddress = peb.EnvironmentAddress
1081 }
1082 envvarScanner := bufio.NewScanner(&processReader{
1083 processHandle: h,
1084 is32BitProcess: procIs32Bits,
1085 offset: processParameterBlockAddress,
1086 })
1087 envvarScanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
1088 if atEOF && len(data) == 0 {
1089 return 0, nil, nil
1090 }
1091
1092 for i := 0; i < len(data)-1; i += 2 {
1093 if data[i] == 0 && data[i+1] == 0 {
1094 return i + 2, data[0:i], nil
1095 }
1096 }
1097 if atEOF {
1098 return len(data), data, nil
1099 }
1100
1101 return 0, nil, nil
1102 })
1103 var envVars []string
1104 for envvarScanner.Scan() {
1105 entry := envvarScanner.Bytes()
1106 if len(entry) == 0 {
1107 break
1108 }
1109 envVars = append(envVars, convertUTF16ToString(entry))
1110 select {
1111 case <-ctx.Done():
1112 break
1113 default:
1114 continue
1115 }
1116 }
1117 if err := envvarScanner.Err(); err != nil {
1118 return nil, err
1119 }
1120 return envVars, nil
1121 }
1122
1123 type processReader struct {
1124 processHandle windows.Handle
1125 is32BitProcess bool
1126 offset uint64
1127 }
1128
1129 func (p *processReader) Read(buf []byte) (int, error) {
1130 processMemory := readProcessMemory(syscall.Handle(p.processHandle), p.is32BitProcess, p.offset, uint(len(buf)))
1131 if len(processMemory) == 0 {
1132 return 0, io.EOF
1133 }
1134 copy(buf, processMemory)
1135 p.offset += uint64(len(processMemory))
1136 return len(processMemory), nil
1137 }
1138
1139 func getProcessCommandLine(pid int32) (string, error) {
1140 h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(pid))
1141 if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
1142 return "", nil
1143 }
1144 if err != nil {
1145 return "", err
1146 }
1147 defer syscall.CloseHandle(syscall.Handle(h))
1148
1149 procIs32Bits := is32BitProcess(h)
1150
1151 if procIs32Bits {
1152 userProcParams, err := getUserProcessParams32(h)
1153 if err != nil {
1154 return "", err
1155 }
1156 if userProcParams.CommandLineLength > 0 {
1157 cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CommandLineAddress), uint(userProcParams.CommandLineLength))
1158 if len(cmdLine) != int(userProcParams.CommandLineLength) {
1159 return "", errors.New("cannot read cmdline")
1160 }
1161
1162 return convertUTF16ToString(cmdLine), nil
1163 }
1164 } else {
1165 userProcParams, err := getUserProcessParams64(h)
1166 if err != nil {
1167 return "", err
1168 }
1169 if userProcParams.CommandLineLength > 0 {
1170 cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CommandLineAddress, uint(userProcParams.CommandLineLength))
1171 if len(cmdLine) != int(userProcParams.CommandLineLength) {
1172 return "", errors.New("cannot read cmdline")
1173 }
1174
1175 return convertUTF16ToString(cmdLine), nil
1176 }
1177 }
1178
1179
1180 return "", nil
1181 }
1182
1183 func convertUTF16ToString(src []byte) string {
1184 srcLen := len(src) / 2
1185
1186 codePoints := make([]uint16, srcLen)
1187
1188 srcIdx := 0
1189 for i := 0; i < srcLen; i++ {
1190 codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx+1])<<8
1191 srcIdx += 2
1192 }
1193 return syscall.UTF16ToString(codePoints)
1194 }
1195
View as plain text