searcher_windows.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package process
  2. import (
  3. "context"
  4. "net/netip"
  5. "syscall"
  6. E "github.com/sagernet/sing/common/exceptions"
  7. "github.com/sagernet/sing/common/winiphlpapi"
  8. "golang.org/x/sys/windows"
  9. )
  10. var _ Searcher = (*windowsSearcher)(nil)
  11. type windowsSearcher struct{}
  12. func NewSearcher(_ Config) (Searcher, error) {
  13. err := initWin32API()
  14. if err != nil {
  15. return nil, E.Cause(err, "init win32 api")
  16. }
  17. return &windowsSearcher{}, nil
  18. }
  19. func initWin32API() error {
  20. return winiphlpapi.LoadExtendedTable()
  21. }
  22. func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
  23. pid, err := winiphlpapi.FindPid(network, source)
  24. if err != nil {
  25. return nil, err
  26. }
  27. path, err := getProcessPath(pid)
  28. if err != nil {
  29. return &Info{ProcessID: pid, UserId: -1}, err
  30. }
  31. return &Info{ProcessID: pid, ProcessPath: path, UserId: -1}, nil
  32. }
  33. func getProcessPath(pid uint32) (string, error) {
  34. switch pid {
  35. case 0:
  36. return ":System Idle Process", nil
  37. case 4:
  38. return ":System", nil
  39. }
  40. handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
  41. if err != nil {
  42. return "", err
  43. }
  44. defer windows.CloseHandle(handle)
  45. size := uint32(syscall.MAX_LONG_PATH)
  46. buf := make([]uint16, syscall.MAX_LONG_PATH)
  47. err = windows.QueryFullProcessImageName(handle, 0, &buf[0], &size)
  48. if err != nil {
  49. return "", err
  50. }
  51. return windows.UTF16ToString(buf[:size]), nil
  52. }