sing-box/common/process/searcher_windows.go
2025-01-30 19:43:36 +08:00

62 lines
1.4 KiB
Go

package process
import (
"context"
"net/netip"
"syscall"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/winiphlpapi"
"golang.org/x/sys/windows"
)
var _ Searcher = (*windowsSearcher)(nil)
type windowsSearcher struct{}
func NewSearcher(_ Config) (Searcher, error) {
err := initWin32API()
if err != nil {
return nil, E.Cause(err, "init win32 api")
}
return &windowsSearcher{}, nil
}
func initWin32API() error {
return winiphlpapi.LoadExtendedTable()
}
func (s *windowsSearcher) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
pid, err := winiphlpapi.FindPid(network, source)
if err != nil {
return nil, err
}
path, err := getProcessPath(pid)
if err != nil {
return &Info{ProcessID: pid, UserId: -1}, err
}
return &Info{ProcessID: pid, ProcessPath: path, UserId: -1}, nil
}
func getProcessPath(pid uint32) (string, error) {
switch pid {
case 0:
return ":System Idle Process", nil
case 4:
return ":System", nil
}
handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
if err != nil {
return "", err
}
defer windows.CloseHandle(handle)
size := uint32(syscall.MAX_LONG_PATH)
buf := make([]uint16, syscall.MAX_LONG_PATH)
err = windows.QueryFullProcessImageName(handle, 0, &buf[0], &size)
if err != nil {
return "", err
}
return windows.UTF16ToString(buf[:size]), nil
}