process_windows.go 33 KB

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