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 }