github.com/iDigitalFlame/xmt@v0.5.4/device/winapi/proc_snap.go (about)

     1  //go:build windows && snap
     2  // +build windows,snap
     3  
     4  // Copyright (C) 2020 - 2023 iDigitalFlame
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    18  //
    19  
    20  package winapi
    21  
    22  import "unsafe"
    23  
    24  // ThreadEntry32 matches the THREADENTRY32 struct
    25  //
    26  //	https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-threadentry32
    27  //
    28  //	typedef struct tagTHREADENTRY32 {
    29  //	  DWORD dwSize;
    30  //	  DWORD cntUsage;
    31  //	  DWORD th32ThreadID;
    32  //	  DWORD th32OwnerProcessID;
    33  //	  LONG  tpBasePri;
    34  //	  LONG  tpDeltaPri;
    35  //	  DWORD dwFlags;
    36  //	} THREADENTRY32;
    37  //
    38  // DO NOT REORDER
    39  type ThreadEntry32 struct {
    40  	Size           uint32
    41  	Usage          uint32
    42  	ThreadID       uint32
    43  	OwnerProcessID uint32
    44  	BasePri        int32
    45  	DeltaPri       int32
    46  	Flags          uint32
    47  }
    48  
    49  // ProcessEntry32 matches the PROCESSENTRY32 struct
    50  //
    51  //	https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32
    52  //
    53  //	typedef struct tagPROCESSENTRY32 {
    54  //	  DWORD     dwSize;
    55  //	  DWORD     cntUsage;
    56  //	  DWORD     th32ProcessID;
    57  //	  ULONG_PTR th32DefaultHeapID;
    58  //	  DWORD     th32ModuleID;
    59  //	  DWORD     cntThreads;
    60  //	  DWORD     th32ParentProcessID;
    61  //	  LONG      pcPriClassBase;
    62  //	  DWORD     dwFlags;
    63  //	  CHAR      szExeFile[MAX_PATH];
    64  //	} PROCESSENTRY32;
    65  //
    66  // DO NOT REORDER
    67  type ProcessEntry32 struct {
    68  	Size            uint32
    69  	Usage           uint32
    70  	ProcessID       uint32
    71  	DefaultHeapID   uintptr
    72  	ModuleID        uint32
    73  	Threads         uint32
    74  	ParentProcessID uint32
    75  	PriClassBase    int32
    76  	Flags           uint32
    77  	ExeFile         [260]uint16
    78  }
    79  
    80  // EnumProcesses attempts to reterive the list of currently running Processes
    81  // and will call the supplied function with an entry for each Process.
    82  //
    83  // The user supplied function can return an error that if non-nil, will stop
    84  // Process iteration immediately and will be returned by this function.
    85  //
    86  // Callers can return the special 'winapi.ErrNoMoreFiles' error that will stop
    87  // iteration but will cause this function to return nil. This can be used to
    88  // stop iteration without errors if needed.
    89  //
    90  // This function is affected by the 'snap' buildtag, which if supplied will use
    91  // the 'CreateToolhelp32Snapshot' API function instead of the default
    92  // 'NtQuerySystemInformation' API function.
    93  func EnumProcesses(f func(ProcessEntry) error) error {
    94  	// 0x2 - TH32CS_SNAPPROCESS
    95  	h, err := CreateToolhelp32Snapshot(0x2, 0)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	var e ProcessEntry32
   100  	e.Size = uint32(unsafe.Sizeof(e))
   101  	for err = Process32First(h, &e); err == nil; err = Process32Next(h, &e) {
   102  		err = f(ProcessEntry{
   103  			Name:    UTF16ToString(e.ExeFile[:]),
   104  			PID:     e.ProcessID,
   105  			PPID:    e.ParentProcessID,
   106  			Threads: e.Threads,
   107  			session: -1,
   108  		})
   109  		if err != nil {
   110  			break
   111  		}
   112  	}
   113  	if CloseHandle(h); err != nil && err != ErrNoMoreFiles {
   114  		return err
   115  	}
   116  	return nil
   117  }
   118  
   119  // Thread32Next Windows API Call
   120  //
   121  //	Retrieves information about the next thread of any process encountered in
   122  //	the system memory snapshot.
   123  //
   124  // https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-thread32next
   125  //
   126  // NOTE: This function is only avaliable if the "snap" build tag is used. To work
   127  // around this restriction, use the higher level 'EnumThreads' function.
   128  func Thread32Next(h uintptr, e *ThreadEntry32) error {
   129  	r, _, err := syscallN(funcThread32Next.address(), h, uintptr(unsafe.Pointer(e)))
   130  	if r == 0 {
   131  		return unboxError(err)
   132  	}
   133  	return nil
   134  }
   135  
   136  // Thread32First Windows API Call
   137  //
   138  //	Retrieves information about the first thread of any process encountered in
   139  //	a system snapshot.
   140  //
   141  // https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-thread32first
   142  //
   143  // NOTE: This function is only avaliable if the "snap" build tag is used. To work
   144  // around this restriction, use the higher level 'EnumThreads' function.
   145  func Thread32First(h uintptr, e *ThreadEntry32) error {
   146  	r, _, err := syscallN(funcThread32First.address(), h, uintptr(unsafe.Pointer(e)))
   147  	if r == 0 {
   148  		return unboxError(err)
   149  	}
   150  	return nil
   151  }
   152  
   153  // Process32Next Windows API Call
   154  //
   155  //	Retrieves information about the next process recorded in a system snapshot.
   156  //
   157  // https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32nextw
   158  //
   159  // NOTE: This function is only avaliable if the "snap" build tag is used. To work
   160  // around this restriction, use the higher level 'EnumProcesses' function.
   161  func Process32Next(h uintptr, e *ProcessEntry32) error {
   162  	r, _, err := syscallN(funcProcess32Next.address(), h, uintptr(unsafe.Pointer(e)))
   163  	if r == 0 {
   164  		return unboxError(err)
   165  	}
   166  	return nil
   167  }
   168  
   169  // Process32First Windows API Call
   170  //
   171  //	Retrieves information about the next process recorded in a system snapshot.
   172  //
   173  // https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next
   174  //
   175  // NOTE: This function is only avaliable if the "snap" build tag is used. To work
   176  // around this restriction, use the higher level 'EnumProcesses' function.
   177  func Process32First(h uintptr, e *ProcessEntry32) error {
   178  	r, _, err := syscallN(funcProcess32First.address(), h, uintptr(unsafe.Pointer(e)))
   179  	if r == 0 {
   180  		return unboxError(err)
   181  	}
   182  	return nil
   183  }
   184  
   185  // EnumThreads attempts to reterive the list of currently running Process Threads
   186  // and will call the supplied function with an entry for each Thread that matches
   187  // the supplied Process ID.
   188  //
   189  // The user supplied function can return an error that if non-nil, will stop
   190  // Thread iteration immediately and will be returned by this function.
   191  //
   192  // Callers can return the special 'winapi.ErrNoMoreFiles' error that will stop
   193  // iteration but will cause this function to return nil. This can be used to
   194  // stop iteration without errors if needed.
   195  //
   196  // This function is affected by the 'snap' buildtag, which if supplied will use
   197  // the 'CreateToolhelp32Snapshot' API function instead of the default
   198  // 'NtQuerySystemInformation' API function.
   199  func EnumThreads(pid uint32, f func(ThreadEntry) error) error {
   200  	// 0x4 - TH32CS_SNAPTHREAD
   201  	h, err := CreateToolhelp32Snapshot(0x4, 0)
   202  	if err != nil {
   203  		return err
   204  	}
   205  	var t ThreadEntry32
   206  	t.Size = uint32(unsafe.Sizeof(t))
   207  	for err = Thread32First(h, &t); err == nil; err = Thread32Next(h, &t) {
   208  		if t.OwnerProcessID != pid {
   209  			continue
   210  		}
   211  		if err = f(ThreadEntry{TID: t.ThreadID, PID: t.OwnerProcessID}); err != nil {
   212  			break
   213  		}
   214  	}
   215  	if CloseHandle(h); err != nil && err != ErrNoMoreFiles {
   216  		return err
   217  	}
   218  	return nil
   219  }
   220  
   221  // CreateToolhelp32Snapshot Windows API Call
   222  //
   223  //	Takes a snapshot of the specified processes, as well as the heaps, modules,
   224  //	and threads used by these processes.
   225  //
   226  // https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot
   227  //
   228  // NOTE: This function is only avaliable if the "snap" build tag is used. To work
   229  // around this restriction, use the higher level 'EnumProcesses' or 'EnumThreads'
   230  // functions.
   231  func CreateToolhelp32Snapshot(flags, pid uint32) (uintptr, error) {
   232  	r, _, err := syscallN(funcCreateToolhelp32Snapshot.address(), uintptr(flags), uintptr(pid))
   233  	if r == invalid {
   234  		return 0, unboxError(err)
   235  	}
   236  	return r, nil
   237  }