• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Aldaviva / Unfucked / 28753990451

05 Jul 2026 08:14PM UTC coverage: 43.937% (-0.4%) from 44.313%
28753990451

push

github

Aldaviva
Added Process.CommandLine and .CommandLineSplit extension properties to get the command line (filename and arguments) of a process not started by this process

666 of 1901 branches covered (35.03%)

3 of 40 new or added lines in 2 files covered. (7.5%)

1 existing line in 1 file now uncovered.

1163 of 2647 relevant lines covered (43.94%)

176.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Windows/Windows/WindowsProcesses.cs
1
using Microsoft.Win32.SafeHandles;
2
using System.Buffers;
3
using System.ComponentModel;
4
using System.Diagnostics;
5
using System.Diagnostics.CodeAnalysis;
6
using System.Diagnostics.Contracts;
7
using System.Runtime.InteropServices;
8
using System.Security.Principal;
9
using System.Text;
10

11
namespace Unfucked.Windows;
12

13
/// <summary>
14
/// Methods that make it easier to work with processes and arguments.
15
/// </summary>
16
public static class WindowsProcesses {
17

18
    /// <summary>
19
    /// Split a single command-line string into a sequence of individual arguments using Windows rules.
20
    /// </summary>
21
    /// <param name="commandLine">A command-line string, possibly consisting of multiple arguments, escaping, and quotation marks.</param>
22
    /// <returns>An enumerable of the individual arguments in <paramref name="commandLine"/>, unescaped and unquoted.</returns>
23
    /// <remarks>
24
    /// By Mike Schwörer: <see href="https://stackoverflow.com/a/64236441/979493" />
25
    /// </remarks>
26
    [ExcludeFromCodeCoverage]
27
    [Pure]
28
    public static IEnumerable<string> CommandLineToEnumerable(string commandLine) {
29
        StringBuilder result = new();
30

31
        bool quoted     = false;
32
        bool escaped    = false;
33
        bool started    = false;
34
        bool allowcaret = false;
35
        for (int i = 0; i < commandLine.Length; i++) {
36
            char chr = commandLine[i];
37

38
            if (chr == '^' && !quoted) {
39
                if (allowcaret) {
40
                    result.Append(chr);
41
                    started    = true;
42
                    escaped    = false;
43
                    allowcaret = false;
44
                } else if (i + 1 < commandLine.Length && commandLine[i + 1] == '^') {
45
                    allowcaret = true;
46
                } else if (i + 1 == commandLine.Length) {
47
                    result.Append(chr);
48
                    started = true;
49
                    escaped = false;
50
                }
51
            } else if (escaped) {
52
                result.Append(chr);
53
                started = true;
54
                escaped = false;
55
            } else if (chr == '"') {
56
                quoted  = !quoted;
57
                started = true;
58
            } else if (chr == '\\' && i + 1 < commandLine.Length && commandLine[i + 1] == '"') {
59
                escaped = true;
60
            } else if (chr == ' ' && !quoted) {
61
                if (started) yield return result.ToString();
62
                result.Clear();
63
                started = false;
64
            } else {
65
                result.Append(chr);
66
                started = true;
67
            }
68
        }
69

70
        if (started) yield return result.ToString();
71
    }
72

73
    /// <summary>
74
    /// <para>Gets the process that started a given child process.</para>
75
    /// <para>Windows only.</para>
76
    /// </summary>
77
    /// <param name="pid">The child process ID of which you want to find the parent, or <c>null</c> to get the parent of the current process.</param>
78
    /// <returns>The parent process of the child process that has the given <paramref name="pid"/>, or <c>null</c> if the process cannot be found (possibly because it already exited). Remember to <see cref="IDisposable.Dispose"/> the returned value.</returns>
79
    /// <inheritdoc cref="get_Parent" path="/remarks" />
80
    [ExcludeFromCodeCoverage]
81
    [Pure]
82
    public static Process? GetParentProcess(int? pid = null) {
83
        using Process process = pid.HasValue ? Process.GetProcessById(pid.Value) : Process.GetCurrentProcess();
84
        return process.Parent;
85
    }
86

87
    // ReSharper disable once ParameterTypeCanBeEnumerable.Local (Avoid double enumeration heuristic)
88
    private static IEnumerable<Process> GetDescendantProcesses(Process ancestor, Process[] allProcesses) =>
89
        allProcesses.SelectMany(descendant => {
×
90
            bool isDescendantOfParent = false;
×
91
            try {
×
NEW
92
                using Process? descendantParent = descendant.Parent;
×
93
                isDescendantOfParent = descendantParent?.Id == ancestor.Id;
×
94
            } catch (Exception e) when (e is not OutOfMemoryException) {
×
95
                //leave isDescendentOfParent false
×
96
            }
×
97

×
98
            return isDescendantOfParent ? new[] { descendant }.Concat(GetDescendantProcesses(descendant, allProcesses)) : [];
×
99
        });
×
100

101
    private sealed class ProcessIdEqualityComparer: IEqualityComparer<Process> {
102

103
        public static readonly ProcessIdEqualityComparer Instance = new();
×
104

105
        public bool Equals(Process? x, Process? y) => ReferenceEquals(x, y) || (x is not null && y is not null && x.GetType() == y.GetType() && x.Id == y.Id);
×
106

107
        public int GetHashCode(Process obj) => obj.Id;
×
108

109
    }
110

111
    extension(Process process) {
112

113
        /// <summary>
114
        /// <para>List all currently running processes that were started by the current process, including transitively to an unlimited depth.</para>
115
        /// <para>Windows only.</para>
116
        /// </summary>
117
        /// <returns>List of processes which were started by either this process, one of its children, grandchildren, or further to an unlimited depth. Remember to <see cref="IDisposable.Dispose"/> all of these <see cref="Process"/> instances.</returns>
118
        [Pure]
119
        public IEnumerable<Process> Descendants {
120
            get {
NEW
121
                Process[] allProcesses = Process.GetProcesses();
×
122

123
                //eagerly find child processes, because once we start killing processes, their parent PIDs won't mean anything anymore
NEW
124
                List<Process> descendants = GetDescendantProcesses(process, allProcesses).ToList();
×
125

NEW
126
                foreach (Process nonDescendant in allProcesses.Except(descendants, ProcessIdEqualityComparer.Instance)) {
×
NEW
127
                    nonDescendant.Dispose();
×
128
                }
129

NEW
130
                return descendants;
×
131
            }
132
        }
133

134
        /// <summary>
135
        /// <para>Gets the process that started a given child process.</para>
136
        /// <para>Windows only.</para>
137
        /// </summary>
138
        /// <returns>The parent process of this process. Remember to <see cref="IDisposable.Dispose"/> the returned value.</returns>
139
        /// <remarks>
140
        /// <para>By Simon Mourier: <see href="https://stackoverflow.com/a/3346055/979493"/></para>
141
        /// </remarks>
142
        [ExcludeFromCodeCoverage]
143
        public Process? Parent {
144
            get {
145
                try {
NEW
146
                    if (0 != NtQueryInformationProcess(process.Handle, 0, out ProcessBasicInformation basicInfo, Marshal.SizeOf<ProcessBasicInformation>(), out int _)) {
×
NEW
147
                        return null;
×
148
                    }
149

NEW
150
                    return Process.GetProcessById((int) basicInfo.InheritedFromUniqueProcessId.ToUInt32());
×
NEW
151
                } catch (ArgumentException) {
×
152
                    // not found
NEW
153
                    return null;
×
NEW
154
                } catch (InvalidOperationException) {
×
155
                    // child process already exited
NEW
156
                    return null;
×
157
                }
NEW
158
            }
×
159
        }
160

161
        /// <summary>Suspend (pause) or resume the process, or check if it is currently suspended.</summary>
162
        public bool Suspended {
163
            get {
NEW
164
                uint returnCode = NtQueryInformationProcess(process.Handle, ProcessInfoClass.ProcessBasicInformation, out ProcessExtendedBasicInformation info,
×
NEW
165
                    Marshal.SizeOf<ProcessExtendedBasicInformation>(), out int _);
×
NEW
166
                return returnCode == 0 && (info.Flags & ProcessExtendedBasicInformation.ProcessFlags.IsFrozen) != 0;
×
167
            }
168
            set {
NEW
169
                if (value) {
×
NEW
170
                    NtSuspendProcess(process.Handle);
×
171
                } else {
NEW
172
                    NtResumeProcess(process.Handle);
×
173
                }
NEW
174
            }
×
175
        }
176

177
        /// <summary>
178
        /// Determine whether a process is running elevated (as Administrator) or not.
179
        /// </summary>
180
        /// <returns><c>true</c> if <paramref name="process"/> is running elevated, or <c>false</c> if it is unelevated</returns>
181
        /// <exception cref="Win32Exception">failed to open handle to <paramref name="process"/>, possibly due to privileges.</exception>
182
        /// <remarks>
183
        /// By John Smith: <see href="https://stackoverflow.com/a/55079599/979493"/>
184
        /// </remarks>
185
        public bool Elevated {
186
            get {
187
                const uint maximumAllowed = 0x2000000;
188

NEW
189
                if (!OpenProcessToken(process.Handle, maximumAllowed, out nint token)) {
×
NEW
190
                    throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
×
191
                }
192

193
                try {
NEW
194
                    using WindowsIdentity identity  = new(token);
×
NEW
195
                    WindowsPrincipal      principal = new(identity);
×
NEW
196
                    return principal.IsInRole(WindowsBuiltInRole.Administrator)
×
NEW
197
                        || principal.IsInRole(0x200); //Domain Administrator
×
198
                } finally {
NEW
199
                    CloseHandle(token);
×
NEW
200
                }
×
NEW
201
            }
×
202
        }
203

204
        /// <summary>
205
        /// <para>Get the command line that started the given process. This includes the program filename and all arguments.</para>
206
        /// <para>Unlike <see cref="ProcessStartInfo.Arguments"/>, this succeeds for processes that were not started by the current process, and it contains the program filename instead of just the arguments.</para>
207
        /// <para>To get an enumerable of each token instead of one big string, use <see cref="CommandLineSplit"/>.</para>
208
        /// </summary>
209
        public string CommandLine {
210
            get {
NEW
211
                byte[] resultBuffer = ArrayPool<byte>.Shared.Rent(16 + 2 * 8191 + 1);
×
212
                try {
NEW
213
                    return 0 == NtQueryInformationProcess(process.Handle, ProcessInfoClass.ProcessCommandLineInformation, resultBuffer, resultBuffer.Length, out int _) ?
×
NEW
214
                        Encoding.Unicode.GetString(resultBuffer, 16, BitConverter.ToInt16(resultBuffer, 2)) : string.Empty;
×
215
                } finally {
NEW
216
                    ArrayPool<byte>.Shared.Return(resultBuffer);
×
NEW
217
                }
×
NEW
218
            }
×
219
        }
220

221
        /// <summary>
222
        /// <para>Get a sequence of the command-line tokens that started the given process. This includes the program filename and all arguments.</para>
223
        /// <para>Unlike <see cref="ProcessStartInfo.Arguments"/>, this succeeds for processes that were not started by the current process, and it contains the program filename instead of just the arguments.</para>
224
        /// <para>To get one big string instead of a sequence of each token, use <see cref="CommandLine"/>.</para>
225
        /// </summary>
NEW
226
        public IEnumerable<string> CommandLineSplit => CommandLineToEnumerable(process.CommandLine);
×
227

228
    }
229

230
    [DllImport("ntdll.dll", SetLastError = true)]
231
    private static extern uint NtQueryInformationProcess(IntPtr process, ProcessInfoClass query, out ProcessExtendedBasicInformation result, int inputSize, out int resultSize);
232

233
    [DllImport("ntdll.dll", SetLastError = true)]
234
    private static extern uint NtQueryInformationProcess(IntPtr process, ProcessInfoClass query, out ProcessBasicInformation result, int inputSize, out int resultSize);
235

236
    [DllImport("ntdll.dll", SetLastError = true)]
237
    private static extern uint NtQueryInformationProcess(IntPtr process, ProcessInfoClass query, byte[] result, int inputSize, out int resultSize);
238

239
    [StructLayout(LayoutKind.Sequential)]
240
    private struct ProcessExtendedBasicInformation {
241

242
        public UIntPtr                 Size;
243
        public ProcessBasicInformation BasicInfo;
244
        public ProcessFlags            Flags;
245

246
        [Flags]
247
        public enum ProcessFlags: uint {
248

249
            /*IS_PROTECTED_PROCESS    = 1 << 0,
250
            IS_WOW64_PROCESS        = 1 << 1,
251
            IS_PROCESS_DELETING     = 1 << 2,
252
            IS_CROSS_SESSION_CREATE = 1 << 3,*/
253
            IsFrozen = 1 << 4,
254
            /*IS_BACKGROUND           = 1 << 5,
255
            IS_STRONGLY_NAMED       = 1 << 6,
256
            IS_SECURE_PROCESS       = 1 << 7,
257
            IS_SUBSYSTEM_PROCESS    = 1 << 8,
258
            SPARE_BITS              = 1 << 9*/
259

260
        }
261

262
    }
263

264
    [StructLayout(LayoutKind.Sequential)]
265
    private struct ProcessBasicInformation {
266

267
        public uint    ExitStatus;
268
        public IntPtr  PebBaseAddress;
269
        public UIntPtr AffinityMask;
270
        public int     BasePriority;
271
        public UIntPtr UniqueProcessId;
272
        public UIntPtr InheritedFromUniqueProcessId;
273

274
    }
275

276
    private enum ProcessInfoClass: uint {
277

278
        ProcessBasicInformation = 0x00,
279

280
        /*PROCESS_QUOTA_LIMITS                               = 0x01,
281
        PROCESS_IO_COUNTERS                                = 0x02,
282
        PROCESS_VM_COUNTERS                                = 0x03,
283
        PROCESS_TIMES                                      = 0x04,
284
        PROCESS_BASE_PRIORITY                              = 0x05,
285
        PROCESS_RAISE_PRIORITY                             = 0x06,
286
        PROCESS_DEBUG_PORT                                 = 0x07,
287
        PROCESS_EXCEPTION_PORT                             = 0x08,
288
        PROCESS_ACCESS_TOKEN                               = 0x09,
289
        PROCESS_LDT_INFORMATION                            = 0x0A,
290
        PROCESS_LDT_SIZE                                   = 0x0B,
291
        PROCESS_DEFAULT_HARD_ERROR_MODE                    = 0x0C,
292
        PROCESS_IO_PORT_HANDLERS                           = 0x0D,
293
        PROCESS_POOLED_USAGE_AND_LIMITS                    = 0x0E,
294
        PROCESS_WORKING_SET_WATCH                          = 0x0F,
295
        PROCESS_USER_MODE_IOPL                             = 0x10,
296
        PROCESS_ENABLE_ALIGNMENT_FAULT_FIXUP               = 0x11,
297
        PROCESS_PRIORITY_CLASS                             = 0x12,
298
        PROCESS_WX86_INFORMATION                           = 0x13,
299
        PROCESS_HANDLE_COUNT                               = 0x14,
300
        PROCESS_AFFINITY_MASK                              = 0x15,
301
        PROCESS_PRIORITY_BOOST                             = 0x16,
302
        PROCESS_DEVICE_MAP                                 = 0x17,
303
        PROCESS_SESSION_INFORMATION                        = 0x18,
304
        PROCESS_FOREGROUND_INFORMATION                     = 0x19,
305
        PROCESS_WOW64_INFORMATION                          = 0x1A,
306
        PROCESS_IMAGE_FILE_NAME                            = 0x1B,
307
        PROCESS_LUID_DEVICE_MAPS_ENABLED                   = 0x1C,
308
        PROCESS_BREAK_ON_TERMINATION                       = 0x1D,
309
        PROCESS_DEBUG_OBJECT_HANDLE                        = 0x1E,
310
        PROCESS_DEBUG_FLAGS                                = 0x1F,
311
        PROCESS_HANDLE_TRACING                             = 0x20,
312
        PROCESS_IO_PRIORITY                                = 0x21,
313
        PROCESS_EXECUTE_FLAGS                              = 0x22,
314
        PROCESS_RESOURCE_MANAGEMENT                        = 0x23,
315
        PROCESS_COOKIE                                     = 0x24,
316
        PROCESS_IMAGE_INFORMATION                          = 0x25,
317
        PROCESS_CYCLE_TIME                                 = 0x26,
318
        PROCESS_PAGE_PRIORITY                              = 0x27,
319
        PROCESS_INSTRUMENTATION_CALLBACK                   = 0x28,
320
        PROCESS_THREAD_STACK_ALLOCATION                    = 0x29,
321
        PROCESS_WORKING_SET_WATCH_EX                       = 0x2A,
322
        PROCESS_IMAGE_FILE_NAME_WIN32                      = 0x2B,
323
        PROCESS_IMAGE_FILE_MAPPING                         = 0x2C,
324
        PROCESS_AFFINITY_UPDATE_MODE                       = 0x2D,
325
        PROCESS_MEMORY_ALLOCATION_MODE                     = 0x2E,
326
        PROCESS_GROUP_INFORMATION                          = 0x2F,
327
        PROCESS_TOKEN_VIRTUALIZATION_ENABLED               = 0x30,
328
        PROCESS_CONSOLE_HOST_PROCESS                       = 0x31,
329
        PROCESS_WINDOW_INFORMATION                         = 0x32,
330
        PROCESS_HANDLE_INFORMATION                         = 0x33,
331
        PROCESS_MITIGATION_POLICY                          = 0x34,
332
        PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION         = 0x35,
333
        PROCESS_HANDLE_CHECKING_MODE                       = 0x36,
334
        PROCESS_KEEP_ALIVE_COUNT                           = 0x37,
335
        PROCESS_REVOKE_FILE_HANDLES                        = 0x38,
336
        PROCESS_WORKING_SET_CONTROL                        = 0x39,
337
        PROCESS_HANDLE_TABLE                               = 0x3A,
338
        PROCESS_CHECK_STACK_EXTENTS_MODE                   = 0x3B,*/
339
        ProcessCommandLineInformation = 0x3C,
340
        /*PROCESS_PROTECTION_INFORMATION                     = 0x3D,
341
        PROCESS_MEMORY_EXHAUSTION                          = 0x3E,
342
        PROCESS_FAULT_INFORMATION                          = 0x3F,
343
        PROCESS_TELEMETRY_ID_INFORMATION                   = 0x40,
344
        PROCESS_COMMIT_RELEASE_INFORMATION                 = 0x41,
345
        PROCESS_DEFAULT_CPU_SETS_INFORMATION               = 0x42,
346
        PROCESS_ALLOWED_CPU_SETS_INFORMATION               = 0x43,
347
        PROCESS_SUBSYSTEM_PROCESS                          = 0x44,
348
        PROCESS_JOB_MEMORY_INFORMATION                     = 0x45,
349
        PROCESS_IN_PRIVATE                                 = 0x46,
350
        PROCESS_RAISE_UM_EXCEPTION_ON_INVALID_HANDLE_CLOSE = 0x47,
351
        PROCESS_IUM_CHALLENGE_RESPONSE                     = 0x48,
352
        PROCESS_CHILD_PROCESS_INFORMATION                  = 0x49,
353
        PROCESS_HIGH_GRAPHICS_PRIORITY_INFORMATION         = 0x4A,
354
        PROCESS_SUBSYSTEM_INFORMATION                      = 0x4B,
355
        PROCESS_ENERGY_VALUES                              = 0x4C,
356
        PROCESS_ACTIVITY_THROTTLE_STATE                    = 0x4D,
357
        PROCESS_ACTIVITY_THROTTLE_POLICY                   = 0x4E,
358
        PROCESS_WIN32_K_SYSCALL_FILTER_INFORMATION         = 0x4F,
359
        PROCESS_DISABLE_SYSTEM_ALLOWED_CPU_SETS            = 0x50,
360
        PROCESS_WAKE_INFORMATION                           = 0x51,
361
        PROCESS_ENERGY_TRACKING_STATE                      = 0x52,
362
        PROCESS_MANAGE_WRITES_TO_EXECUTABLE_MEMORY         = 0x53,
363
        PROCESS_CAPTURE_TRUSTLET_LIVE_DUMP                 = 0x54,
364
        PROCESS_TELEMETRY_COVERAGE                         = 0x55,
365
        PROCESS_ENCLAVE_INFORMATION                        = 0x56,
366
        PROCESS_ENABLE_READ_WRITE_VM_LOGGING               = 0x57,
367
        PROCESS_UPTIME_INFORMATION                         = 0x58,
368
        PROCESS_IMAGE_SECTION                              = 0x59,
369
        PROCESS_DEBUG_AUTH_INFORMATION                     = 0x5A,
370
        PROCESS_SYSTEM_RESOURCE_MANAGEMENT                 = 0x5B,
371
        PROCESS_SEQUENCE_NUMBER                            = 0x5C,
372
        PROCESS_LOADER_DETOUR                              = 0x5D,
373
        PROCESS_SECURITY_DOMAIN_INFORMATION                = 0x5E,
374
        PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION       = 0x5F,
375
        PROCESS_ENABLE_LOGGING                             = 0x60,
376
        PROCESS_LEAP_SECOND_INFORMATION                    = 0x61,
377
        PROCESS_FIBER_SHADOW_STACK_ALLOCATION              = 0x62,
378
        PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION         = 0x63,
379
        MAX_PROCESS_INFO_CLASS                             = 0x64*/
380

381
    }
382

383
    [DllImport("ntdll.dll")]
384
    private static extern IntPtr NtSuspendProcess(IntPtr processHandle);
385

386
    [DllImport("ntdll.dll")]
387
    private static extern IntPtr NtResumeProcess(IntPtr processHandle);
388

389
    /// <summary>
390
    /// <para>Call this on a child process if you want it to detach from the console and ignore Ctrl+C, because your parent console process will handle that signal.</para>
391
    /// <para>Strangely, in Windows console applications, pressing Ctrl+C in the terminal will send the signal to every attached descendant in the terminal's process tree, not just the top-most child running directly in the terminal.</para>
392
    /// <para>This is necessary if you have custom Ctrl+C handling in your parent (using <see cref="Console.CancelKeyPress"/>), and don't want the child to ignore that and exit on the first Ctrl+C anyway.</para>
393
    /// <para>The best way to solve this is by the child not attaching to the console in the first place, or detaching with <c>FreeConsole()</c>, but this is not possible if you can't make code changes to the child program. The second-best way to solve this is by specifying a <c>dwCreationFlags</c> of <c>DETACHED_PROCESS (0x8)</c> when calling <c>CreateProcess</c>, but these flags are insufficiently customizable when wrapped by .NET's <see cref="ProcessStartInfo"/> (API cliff).</para>
394
    /// <para>This technique injects a thread into the child process that calls <c>FreeConsole</c>, which is better than copying and reimplementing all of <see cref="Process.Start()"/> from the .NET BCL repository.</para>
395
    /// </summary>
396
    /// <param name="process"></param>
397
    public static void DetachFromConsole(this Process process) {
398
        int targetPid = process.Id;
×
399
        int selfPid;
400
#if NET5_0_OR_GREATER
401
        selfPid = Environment.ProcessId;
402
#else
403
        using Process selfProcess = Process.GetCurrentProcess();
404
        selfPid = selfProcess.Id;
405
#endif
406

407
        if (targetPid == selfPid) {
×
408
            FreeConsole();
×
409
        } else {
410
            // https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
411
            using SafeProcessHandle safeProcessHandle = OpenProcess(ProcessSecurityAndAccessRight.ProcessCreateThread, false, targetPid);
×
412

413
            IntPtr methodAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeConsole");
×
414
            CreateRemoteThread(safeProcessHandle, IntPtr.Zero, 0, methodAddr, IntPtr.Zero, 0, IntPtr.Zero);
×
415
        }
416
    }
×
417

418
    [Flags]
419
    private enum ProcessSecurityAndAccessRight: uint {
420

421
        ProcessCreateThread = 0x2,
422

423
        /*PROCESS_QUERY_INFORMATION = 0x400,
424
        PROCESS_VM_OPERATION      = 0x8,
425
        PROCESS_VM_WRITE          = 0x20,
426
        PROCESS_VM_READ = 0x10*/
427

428
    }
429

430
    [DllImport("kernel32.dll")]
431
    [return: MarshalAs(UnmanagedType.Bool)]
432
    private static extern bool FreeConsole();
433

434
    [DllImport("kernel32.dll")]
435
    private static extern SafeProcessHandle OpenProcess(ProcessSecurityAndAccessRight dwDesiredAccess, bool bInheritHandle, int dwProcessId);
436

437
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
438
    private static extern IntPtr GetModuleHandle(string lpModuleName);
439

440
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
441
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
442

443
    [DllImport("kernel32.dll")]
444
    private static extern IntPtr CreateRemoteThread(SafeProcessHandle hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags,
445
                                                    IntPtr lpThreadId);
446

447
    [DllImport("advapi32.dll", SetLastError = true)]
448
    [return: MarshalAs(UnmanagedType.Bool)]
449
    private static extern bool OpenProcessToken(nint processHandle, uint desiredAccess, out nint tokenHandle);
450

451
    [DllImport("kernel32.dll", SetLastError = true)]
452
    [return: MarshalAs(UnmanagedType.Bool)]
453
    private static extern bool CloseHandle(nint hObject);
454

455
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc