tgstation-server  4.4.0
The /tg/station 13 server suite
WindowsProcessFeatures.cs
Go to the documentation of this file.
2 using Microsoft.Extensions.Logging;
3 using System;
4 using System.Diagnostics;
5 using System.IO;
6 using System.Linq;
7 using System.Management;
8 using System.Threading;
9 using System.Threading.Tasks;
10 
11 namespace Tgstation.Server.Host.System
12 {
15  {
19  readonly ILogger<WindowsProcessFeatures> logger;
20 
25  public WindowsProcessFeatures(ILogger<WindowsProcessFeatures> logger)
26  {
27  this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
28  }
29 
31  public void ResumeProcess(global::System.Diagnostics.Process process)
32  {
33  if (process == null)
34  throw new ArgumentNullException(nameof(process));
35 
36  try
37  {
38  foreach (ProcessThread thread in process.Threads)
39  {
40  var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, (uint)thread.Id);
41  if (pOpenThread == IntPtr.Zero)
42  continue;
43 
44  if (NativeMethods.ResumeThread(pOpenThread) == UInt32.MaxValue)
45  throw new Win32Exception();
46 
47  NativeMethods.CloseHandle(pOpenThread);
48  }
49 
50  logger.LogTrace("Resumed PID {0}", process.Id);
51  }
52  catch (Exception e)
53  {
54  logger.LogError(e, "Failed to resume PID {0}!", process.Id);
55  throw;
56  }
57  }
58 
60  public void SuspendProcess(global::System.Diagnostics.Process process)
61  {
62  if (process == null)
63  throw new ArgumentNullException(nameof(process));
64 
65  try
66  {
67  foreach (ProcessThread thread in process.Threads)
68  {
69  var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, (uint)thread.Id);
70  if (pOpenThread == IntPtr.Zero)
71  continue;
72 
73  if (NativeMethods.SuspendThread(pOpenThread) == UInt32.MaxValue)
74  throw new Win32Exception();
75 
76  NativeMethods.CloseHandle(pOpenThread);
77  }
78 
79  logger.LogTrace("Suspended PID {0}", process.Id);
80  }
81  catch (Exception e)
82  {
83  logger.LogError(e, "Failed to suspend PID {0}!", process.Id);
84  throw;
85  }
86  }
87 
89  public Task<string> GetExecutingUsername(global::System.Diagnostics.Process process, CancellationToken cancellationToken)
90  {
91  string query = $"SELECT * FROM Win32_Process WHERE ProcessId = {process?.Id ?? throw new ArgumentNullException(nameof(process))}";
92  using var searcher = new ManagementObjectSearcher(query);
93  foreach (ManagementObject obj in searcher.Get())
94  {
95  var argList = new string[] { String.Empty, String.Empty };
96  var returnString = obj.InvokeMethod(
97  "GetOwner",
98  argList)
99  ?.ToString();
100 
101  if (!Int32.TryParse(returnString, out var returnVal))
102  return Task.FromResult($"BAD RETURN PARSE: {returnString}");
103 
104  if (returnVal == 0)
105  {
106  // return DOMAIN\user
107  string owner = argList.Last() + "\\" + argList.First();
108  return Task.FromResult(owner);
109  }
110  }
111 
112  return Task.FromResult("NO OWNER");
113  }
114 
116  public Task CreateDump(global::System.Diagnostics.Process process, string outputFile, CancellationToken cancellationToken)
117  => Task.Factory.StartNew(
118  () =>
119  {
120  using var fileStream = new FileStream(outputFile, FileMode.CreateNew);
122  process.Handle,
123  (uint)process.Id,
124  fileStream.SafeFileHandle,
125  NativeMethods.MiniDumpType.WithDataSegs
126  | NativeMethods.MiniDumpType.WithFullMemory
127  | NativeMethods.MiniDumpType.WithHandleData
128  | NativeMethods.MiniDumpType.WithThreadInfo
129  | NativeMethods.MiniDumpType.WithUnloadedModules,
130  IntPtr.Zero,
131  IntPtr.Zero,
132  IntPtr.Zero))
133  throw new Win32Exception();
134  },
135  cancellationToken,
136  TaskCreationOptions.LongRunning,
137  TaskScheduler.Current);
138  }
139 }
static bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, MiniDumpType dumpType, IntPtr expParam, IntPtr userStreamParam, IntPtr callbackParam)
See https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwrite...
static uint ResumeThread(IntPtr hThread)
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms685086(v=vs.85).aspx ...
readonly ILogger< WindowsProcessFeatures > logger
The ILogger<TCategoryName> for the WindowsProcessFeatures.
MiniDumpType
See https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_type...
void SuspendProcess(global::System.Diagnostics.Process process)
Suspend a given process .
WindowsProcessFeatures(ILogger< WindowsProcessFeatures > logger)
Initializes a new instance of the WindowsProcessFeatures .
void ResumeProcess(global::System.Diagnostics.Process process)
Resume a given suspended Process.
Task< string > GetExecutingUsername(global::System.Diagnostics.Process process, CancellationToken cancellationToken)
Get the name of the user executing a given process .
static bool CloseHandle(IntPtr hObject)
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx ...
Native Windows methods used by the code.
ThreadAccess
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx ...
static uint SuspendThread(IntPtr hThread)
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686345(v=vs.85).aspx ...
Abstraction for suspending and resuming processes.
static IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId)
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335(v=vs.85).aspx ...