protected override void Dispose(bool disposing) { _stdinReadHandle.Dispose(); _stdinWriteHandle.Dispose(); _stdoutReadHandle.Dispose(); _stdoutWriteHandle.Dispose(); _stderrReadHandle.Dispose(); _stderrWriteHandle.Dispose(); if (_processHandle != null) { _processHandle.Dispose(); } base.Dispose(disposing); }
private Win32Process(NativeMethods.PROCESS_INFORMATION pi, StreamWriter stdin, StreamReader stdout, StreamReader stderror) { StandardInput = stdin; StandardOutput = stdout; StandardError = stderror; _hasExited = false; _exitCodeLock = new object(); Id = pi.dwProcessId; MainThreadId = pi.dwThreadId; _processHandle = new SafeProcessHandle(pi.hProcess, true); var wait = new ProcessWaitHandle(_processHandle); _registeredWait = ThreadPool.RegisterWaitForSingleObject(wait, (o, t) => { _registeredWait.Unregister(wait); SetExitState(); Exited?.Invoke(this, EventArgs.Empty); _processHandle.Dispose(); wait.Dispose(); }, null, -1, true); _disposable .Add(() => _registeredWait.Unregister(wait)) .Add(_processHandle) .Add(wait); }
/// <summary> /// Instructs the Process component to wait the specified number of milliseconds for the associated process to exit. /// </summary> private bool WaitForExitCore(int milliseconds) { SafeProcessHandle handle = null; try { handle = GetProcessHandle(Interop.Advapi32.ProcessOptions.SYNCHRONIZE, false); if (handle.IsInvalid) { return(true); } using (Interop.Kernel32.ProcessWaitHandle processWaitHandle = new Interop.Kernel32.ProcessWaitHandle(handle)) { return(_signaled = processWaitHandle.WaitOne(milliseconds)); } } finally { // If we have a hard timeout, we cannot wait for the streams if (_output != null && milliseconds == Timeout.Infinite) { _output.WaitUtilEOF(); } if (_error != null && milliseconds == Timeout.Infinite) { _error.WaitUtilEOF(); } handle?.Dispose(); } }
public static SafeProcessHandle OpenProcess(int processId, int access, bool throwIfExited) { SafeProcessHandle processHandle = Interop.Kernel32.OpenProcess(access, false, processId); int result = Marshal.GetLastWin32Error(); if (!processHandle.IsInvalid) { return(processHandle); } processHandle.Dispose(); if (processId == 0) { throw new Win32Exception(Interop.Errors.ERROR_ACCESS_DENIED); } // If the handle is invalid because the process has exited, only throw an exception if throwIfExited is true. // Assume the process is still running if the error was ERROR_ACCESS_DENIED for better performance if (result != Interop.Errors.ERROR_ACCESS_DENIED && !IsProcessRunning(processId)) { if (throwIfExited) { throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, processId.ToString())); } else { return(SafeProcessHandle.InvalidHandle); } } throw new Win32Exception(result); }
internal static void KillTree(int processIdTokill) { using (Process process = Process.GetProcessById(processIdTokill)) { DateTime startTime = process.StartTime; SafeProcessHandle handle = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processIdTokill); if (!handle.IsInvalid) { try { process.Kill(); List <Tuple <int, SafeProcessHandle> > childProcessIds = GetChildProcessIds(processIdTokill, startTime); try { foreach (Tuple <int, SafeProcessHandle> tuple in childProcessIds) { KillTree(tuple.Item1); } } finally { foreach (Tuple <int, SafeProcessHandle> tuple2 in childProcessIds) { tuple2.Item2.Dispose(); } } } finally { handle.Dispose(); } } } }
[Fact, PlatformSpecific(PlatformID.Windows), OuterLoop] // Requires admin privileges public void TestUserCredentialsPropertiesOnWindows() { string username = "******", password = "******"; try { Interop.NetUserAdd(username, password); } catch (Exception exc) { Console.Error.WriteLine("TestUserCredentialsPropertiesOnWindows: NetUserAdd failed: {0}", exc.Message); return; // test is irrelevant if we can't add a user } Process p = CreateProcessLong(); p.StartInfo.LoadUserProfile = true; p.StartInfo.UserName = username; p.StartInfo.PasswordInClearText = password; SafeProcessHandle handle = null; try { p.Start(); if (Interop.OpenProcessToken(p.SafeHandle, 0x8u, out handle)) { SecurityIdentifier sid; if (Interop.ProcessTokenToSid(handle, out sid)) { string actualUserName = sid.Translate(typeof(NTAccount)).ToString(); int indexOfDomain = actualUserName.IndexOf('\\'); if (indexOfDomain != -1) { actualUserName = actualUserName.Substring(indexOfDomain + 1); } bool isProfileLoaded = GetNamesOfUserProfiles().Any(profile => profile.Equals(username)); Assert.Equal(username, actualUserName); Assert.True(isProfileLoaded); } } } finally { if (handle != null) { handle.Dispose(); } if (!p.HasExited) { p.Kill(); } Interop.NetUserDel(null, username); Assert.True(p.WaitForExit(WaitInMS)); } }
public bool CloseHandle() { if (!IsHandleClosed) { using (SafeProcessHandle processHandle = NativeMethods.OpenProcess(ProcessAccessRights.PROCESS_ALL_ACCESS, false, SourceProcess)) { if (!processHandle.IsInvalid) { SafeObjectHandle objectHandle = null; if (NativeMethods.DuplicateHandle(processHandle.DangerousGetHandle(), SourceHandle, IntPtr.Zero, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_CLOSE_SOURCE)) { NativeMethods.CloseHandle(processHandle.DangerousGetHandle()); processHandle.Dispose(); IsHandleClosed = true; } } } } return(IsHandleClosed); }
internal static void KillTree(int processIdTokill) { using (Process process = Process.GetProcessById(processIdTokill)) { DateTime startTime = process.StartTime; SafeProcessHandle handle = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processIdTokill); if (!handle.IsInvalid) { try { process.Kill(); List <KeyValuePair <int, SafeProcessHandle> > childProcessIds = GetChildProcessIds(processIdTokill, startTime); try { foreach (KeyValuePair <int, SafeProcessHandle> pair in childProcessIds) { KillTree(pair.Key); } } finally { foreach (KeyValuePair <int, SafeProcessHandle> pair2 in childProcessIds) { pair2.Value.Dispose(); } } } finally { handle.Dispose(); } } } }
/// <summary> /// Returns the parent process id for the specified process. /// Returns zero if it cannot be gotten for some reason. /// </summary> internal static int GetParentProcessId(int processId) { int ParentID = 0; SafeProcessHandle hProcess = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processId); if (!hProcess.IsInvalid) { try { // UNDONE: NtQueryInformationProcess will fail if we are not elevated and other process is. Advice is to change to use ToolHelp32 API's // For now just return zero and worst case we will not kill some children. PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); int pSize = 0; if (0 == NtQueryInformationProcess(hProcess, PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, pbi.Size, ref pSize)) { ParentID = (int)pbi.InheritedFromUniqueProcessId; } } finally { hProcess.Dispose(); } } return(ParentID); }
public void Dispose() { if (!isDisposed) { isDisposed = true; CloseStreams(); ClosePipes(); proc?.Dispose(); } }
public void Dispose() { foreach (var peInstance in _peInstances) { peInstance.Value.Dispose(); } Process.Dispose(); Handle.Dispose(); }
/// <summary> /// Releases resources associated to this object. /// </summary> public void Dispose() { if (!_isDisposed) { _processHandle.Dispose(); _waitHandle.Dispose(); _standardInput?.Dispose(); _standardOutput?.Dispose(); _standardError?.Dispose(); _isDisposed = true; } }
public void Dispose() { if (safeProcessHandle != null) { safeProcessHandle.Dispose(); } if (standardOutput != null) { standardOutput.Dispose(); } if (standardError != null) { standardError.Dispose(); } }
/// <summary> /// Returns an array of all the immediate child processes by id. /// NOTE: The IntPtr in the tuple is the handle of the child process. CloseHandle MUST be called on this. /// </summary> private static List <KeyValuePair <int, SafeProcessHandle> > GetChildProcessIds(int parentProcessId, DateTime parentStartTime) { List <KeyValuePair <int, SafeProcessHandle> > myChildren = new List <KeyValuePair <int, SafeProcessHandle> >(); foreach (Process possibleChildProcess in Process.GetProcesses()) { using (possibleChildProcess) { // Hold the child process handle open so that children cannot die and restart with a different parent after we've started looking at it. // This way, any handle we pass back is guaranteed to be one of our actual children. SafeProcessHandle childHandle = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, possibleChildProcess.Id); if (childHandle.IsInvalid) { continue; } bool keepHandle = false; try { if (possibleChildProcess.StartTime > parentStartTime) { int childParentProcessId = GetParentProcessId(possibleChildProcess.Id); if (childParentProcessId != 0) { if (parentProcessId == childParentProcessId) { // Add this one myChildren.Add(new KeyValuePair <int, SafeProcessHandle>(possibleChildProcess.Id, childHandle)); keepHandle = true; } } } } finally { if (!keepHandle) { childHandle.Dispose(); } } } } return(myChildren); }
private List <(Process Process, SafeProcessHandle Handle)> GetProcessHandlePairs(Func <Process, Process, bool> predicate) { var results = new List <(Process Process, SafeProcessHandle Handle)>(); foreach (Process p in GetProcesses()) { SafeProcessHandle h = SafeGetHandle(p); if (!h.IsInvalid && predicate(this, p)) { results.Add((p, h)); } else { p.Dispose(); h.Dispose(); } } return(results);
public void Dispose() { _processHandle.Dispose(); _exitedWaitHandle.Dispose(); if (!_isPseudoConsoleDisposed) { // This will terminate the process tree (unless we are on Windows 1809). _pseudoConsole?.Dispose(); if (WindowsVersion.NeedsWorkaroundForWindows1809) { // Should always succeed. Kill(); } _isPseudoConsoleDisposed = true; } }
/// <summary> /// Calls <see cref="CreateProcessAsUserW"/> and safely stores the obtained handles. /// </summary> /// <param name="userToken">Token to impersonate the external process</param> /// <param name="createFlags">Flags used to create the external process</param> /// <param name="startupInfo">Startup information used to create the external process</param> /// <returns><c>true</c> if the call to <see cref="CreateProcessAsUserW"/> was successful; otherwise <c>false</c></returns> private bool SafeCreateProcessAsUserW(IntPtr userToken, CreateProcessFlags createFlags, StartupInfo startupInfo) { _processHandle = new SafeProcessHandle(); var threadHandle = new SafeThreadHandle(); bool success; // The following is necessary to make sure that processInformation.hProcess and processInformation.hThread // are safely stored in the respective SafeHandle classes. It is, unfortunately, not possible to define // processInformation.hProcess and processInformation.hThread as SafeHandles and use processInformation // as an out parameter, because the unmanaged code is not able to create these objects. We therefore use // IntPtr and ensure in the following that the IntPtrs are stored in SafeHandle objects immediately after // they have been obtained. // For details see here: https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ProcessInformation processInformation; success = CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out processInformation); if (success) { _processHandle.InitialSetHandle(processInformation.hProcess); threadHandle.InitialSetHandle(processInformation.hThread); _processId = processInformation.dwProcessId; } } // We don't need the threadHandle and therefore immediately dispose it. threadHandle.Dispose(); if (success) { return(true); } _processHandle.Dispose(); var error = Marshal.GetLastWin32Error(); _debugLogger.Error("AsyncImpersonationProcess ({0}): Cannot start process. ErrorCode: {1} ({2})", StartInfo.FileName, error, new Win32Exception(error).Message); return(false); }
/// <summary> /// Assigns a process to an existing job object. /// </summary> /// <param name="processHandle">A handle to the process to associate with the job object. The handle /// must have PROCESS_SET_QUOTA and PROCESS_TERMINATE access rights.</param> public void AssignProcess(SafeProcessHandle processHandle) { if (processHandle == null) { throw new ArgumentNullException(nameof(processHandle)); } if ((processHandle.IsClosed) || (processHandle.IsInvalid)) { throw new ArgumentException(Resources.ProcessHandleClosedOrInvalid); } CheckDisposed(); SafeProcessHandle newProcessHandle = null; try { if (!Interop.Kernel32.DuplicateHandle(Interop.Kernel32.GetCurrentProcessIntPtr(), processHandle, Interop.Kernel32.GetCurrentProcessIntPtr(), out newProcessHandle, Interop.ProcessAccess.SetQuota | Interop.ProcessAccess.Terminate, false, 0)) { throw Errors.Win32Error(); } if (!Interop.Kernel32.AssignProcessToJobObject(Handle, newProcessHandle)) { throw Errors.Win32Error(); } } finally { newProcessHandle?.Dispose(); } }
internal static int GetParentProcessId(int processId) { int inheritedFromUniqueProcessId = 0; SafeProcessHandle hProcess = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processId); if (!hProcess.IsInvalid) { try { PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION(); int pSize = 0; if (-1 != NtQueryInformationProcess(hProcess, PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, pbi.Size, ref pSize)) { inheritedFromUniqueProcessId = pbi.InheritedFromUniqueProcessId; } } finally { hProcess.Dispose(); } } return(inheritedFromUniqueProcessId); }
internal static List <KeyValuePair <int, SafeProcessHandle> > GetChildProcessIds(int parentProcessId, DateTime parentStartTime) { List <KeyValuePair <int, SafeProcessHandle> > list = new List <KeyValuePair <int, SafeProcessHandle> >(); foreach (Process process in Process.GetProcesses()) { using (process) { SafeProcessHandle handle = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, process.Id); if (!handle.IsInvalid) { bool flag = false; try { if (process.StartTime > parentStartTime) { int num2 = GetParentProcessId(process.Id); if ((num2 != 0) && (parentProcessId == num2)) { list.Add(new KeyValuePair <int, SafeProcessHandle>(process.Id, handle)); flag = true; } } } finally { if (!flag) { handle.Dispose(); } } } } } return(list); }
private IntPtr GetAbsoluteFunctionAddress(SafeProcessHandle hProcess, IntPtr hModule, string functionName) { var moduleInfo = GetModuleInfo(hProcess, hModule); DataDirectory exportDir = GetDataDirectory(ReadPage(hProcess, moduleInfo.BaseOfDll), 0); var buffer = new byte[exportDir.Size]; if (!Interop.Kernel32.ReadProcessMemory( hProcess, moduleInfo.BaseOfDll + (int)exportDir.Rva, buffer, new UIntPtr((uint)buffer.Length), out UIntPtr bytesRead) || bytesRead.ToUInt32() != buffer.Length) { throw new Win32Exception("Failed to read export table from memory of module."); } // We no longer need the process handle, so close it. hProcess.Dispose(); return(new IntPtr(moduleInfo.BaseOfDll.ToInt64() + GetFunctionAddress(buffer, exportDir.Rva, functionName).ToInt64())); }
/// <devdoc> /// <para> /// Frees any resources associated with this component. /// </para> /// </devdoc> public void Close() { if (Associated) { if (_haveProcessHandle) { // We need to lock to ensure we don't run concurrently with CompletionCallback. // Without this lock we could reset _raisedOnExited which causes CompletionCallback to // raise the Exited event a second time for the same process. lock (this) { // This sets _waitHandle to null which causes CompletionCallback to not emit events. StopWatchingForExit(); } _processHandle.Dispose(); _processHandle = null; _haveProcessHandle = false; } _haveProcessId = false; _isRemoteMachine = false; _machineName = "."; _raisedOnExited = false; // Only call close on the streams if the user cannot have a reference on them. // If they are referenced it is the user's responsibility to dispose of them. try { if (_standardOutput != null && (_outputStreamReadMode == StreamReadMode.AsyncMode || _outputStreamReadMode == StreamReadMode.Undefined)) { if (_outputStreamReadMode == StreamReadMode.AsyncMode) { _output.CancelOperation(); } _standardOutput.Close(); } if (_standardError != null && (_errorStreamReadMode == StreamReadMode.AsyncMode || _errorStreamReadMode == StreamReadMode.Undefined)) { if (_errorStreamReadMode == StreamReadMode.AsyncMode) { _error.CancelOperation(); } _standardError.Close(); } if (_standardInput != null && !_standardInputAccessed) { _standardInput.Close(); } } finally { _standardOutput = null; _standardInput = null; _standardError = null; _output = null; _error = null; CloseCore(); Refresh(); } } }
private static ProcessModuleCollection GetModules(int processId, bool firstModuleOnly) { // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(HResults.E_FAIL, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, true); bool succeeded = Interop.Kernel32.EnumProcessModules(processHandle, null, 0, out int needed); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. if (!succeeded) { if (!Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool sourceProcessIsWow64)) { throw new Win32Exception(); } if (!Interop.Kernel32.IsWow64Process(processHandle, out bool targetProcessIsWow64)) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.Errors.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } EnumProcessModulesUntilSuccess(processHandle, null, 0, out needed); } int modulesCount = needed / IntPtr.Size; IntPtr[] moduleHandles = new IntPtr[modulesCount]; while (true) { int size = needed; EnumProcessModulesUntilSuccess(processHandle, moduleHandles, size, out needed); if (size == needed) { break; } if (needed > size && needed / IntPtr.Size > modulesCount) { modulesCount = needed / IntPtr.Size; moduleHandles = new IntPtr[modulesCount]; } } var modules = new ProcessModuleCollection(firstModuleOnly ? 1 : modulesCount); char[] chars = ArrayPool <char> .Shared.Rent(1024); try { for (int i = 0; i < modulesCount; i++) { if (i > 0) { // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. if (firstModuleOnly) { break; } } IntPtr moduleHandle = moduleHandles[i]; Interop.Kernel32.NtModuleInfo ntModuleInfo; if (!Interop.Kernel32.GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo)) { HandleLastWin32Error(); continue; } var module = new ProcessModule() { ModuleMemorySize = ntModuleInfo.SizeOfImage, EntryPointAddress = ntModuleInfo.EntryPoint, BaseAddress = ntModuleInfo.BaseOfDll }; int length = Interop.Kernel32.GetModuleBaseName(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleLastWin32Error(); continue; } module.ModuleName = new string(chars, 0, length); length = Interop.Kernel32.GetModuleFileNameEx(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleLastWin32Error(); continue; } module.FileName = (length >= 4 && chars[0] == '\\' && chars[1] == '\\' && chars[2] == '?' && chars[3] == '\\') ? new string(chars, 4, length - 4) : new string(chars, 0, length); modules.Add(module); } } finally { ArrayPool <char> .Shared.Return(chars); } return(modules); } finally { if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }
private static ModuleInfo[] GetModuleInfos(int processId, bool firstModuleOnly) { Contract.Ensures(Contract.Result <ModuleInfo[]>().Length >= 1); // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(Interop.EFail, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.PROCESS_QUERY_INFORMATION | Interop.PROCESS_VM_READ, true); IntPtr[] moduleHandles = new IntPtr[64]; GCHandle moduleHandlesArrayHandle = new GCHandle(); int moduleCount = 0; for (; ;) { bool enumResult = false; try { moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned); enumResult = Interop.mincore.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. // // Also, EnumProcessModules is not a reliable method to get the modules for a process. // If OS loader is touching module information, this method might fail and copy part of the data. // This is no easy solution to this problem. The only reliable way to fix this is to // suspend all the threads in target process. Of course we don't want to do this in Process class. // So we just to try avoid the race by calling the same method 50 (an arbitary number) times. // if (!enumResult) { bool sourceProcessIsWow64 = false; bool targetProcessIsWow64 = false; SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle; try { hCurProcess = ProcessManager.OpenProcess(unchecked ((int)Interop.mincore.GetCurrentProcessId()), Interop.PROCESS_QUERY_INFORMATION, true); bool wow64Ret; wow64Ret = Interop.mincore.IsWow64Process(hCurProcess, ref sourceProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } wow64Ret = Interop.mincore.IsWow64Process(processHandle, ref targetProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } } finally { if (hCurProcess != SafeProcessHandle.InvalidHandle) { hCurProcess.Dispose(); } } // If the failure wasn't due to Wow64, try again. for (int i = 0; i < 50; i++) { enumResult = Interop.mincore.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); if (enumResult) { break; } Thread.Sleep(1); } } } finally { moduleHandlesArrayHandle.Free(); } if (!enumResult) { throw new Win32Exception(); } moduleCount /= IntPtr.Size; if (moduleCount <= moduleHandles.Length) { break; } moduleHandles = new IntPtr[moduleHandles.Length * 2]; } List <ModuleInfo> moduleInfos = new List <ModuleInfo>(); int ret; for (int i = 0; i < moduleCount; i++) { try { ModuleInfo moduleInfo = new ModuleInfo(); IntPtr moduleHandle = moduleHandles[i]; Interop.NtModuleInfo ntModuleInfo = new Interop.NtModuleInfo(); if (!Interop.mincore.GetModuleInformation(processHandle, moduleHandle, ntModuleInfo, Marshal.SizeOf(ntModuleInfo))) { throw new Win32Exception(); } moduleInfo._sizeOfImage = ntModuleInfo.SizeOfImage; moduleInfo._entryPoint = ntModuleInfo.EntryPoint; moduleInfo._baseOfDll = ntModuleInfo.BaseOfDll; StringBuilder baseName = new StringBuilder(1024); ret = Interop.mincore.GetModuleBaseName(processHandle, moduleHandle, baseName, baseName.Capacity * 2); if (ret == 0) { throw new Win32Exception(); } moduleInfo._baseName = baseName.ToString(); StringBuilder fileName = new StringBuilder(1024); ret = Interop.mincore.GetModuleFileNameEx(processHandle, moduleHandle, fileName, fileName.Capacity * 2); if (ret == 0) { throw new Win32Exception(); } moduleInfo._fileName = fileName.ToString(); if (moduleInfo._fileName != null && moduleInfo._fileName.Length >= 4 && moduleInfo._fileName.StartsWith(@"\\?\", StringComparison.Ordinal)) { moduleInfo._fileName = moduleInfo._fileName.Substring(4); } moduleInfos.Add(moduleInfo); } catch (Win32Exception e) { if (e.NativeErrorCode == Interop.ERROR_INVALID_HANDLE || e.NativeErrorCode == Interop.ERROR_PARTIAL_COPY) { // It's possible that another thread casued this module to become // unloaded (e.g FreeLibrary was called on the module). Ignore it and // move on. } else { throw; } } // // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. // if (firstModuleOnly) { break; } } ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count]; moduleInfos.CopyTo(temp, 0); return(temp); } finally { #if FEATURE_TRACESWITCH Debug.WriteLineIf(Process._processTracing.TraceVerbose, "Process - CloseHandle(process)"); #endif if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }
private static ProcessModuleCollection GetModules(int processId, bool firstModuleOnly) { // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(Interop.Errors.EFail, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, true); IntPtr[] moduleHandles = new IntPtr[64]; GCHandle moduleHandlesArrayHandle = new GCHandle(); int moduleCount = 0; for (;;) { bool enumResult = false; try { moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned); enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. // // Also, EnumProcessModules is not a reliable method to get the modules for a process. // If OS loader is touching module information, this method might fail and copy part of the data. // This is no easy solution to this problem. The only reliable way to fix this is to // suspend all the threads in target process. Of course we don't want to do this in Process class. // So we just to try avoid the race by calling the same method 50 (an arbitrary number) times. // if (!enumResult) { bool sourceProcessIsWow64 = false; bool targetProcessIsWow64 = false; SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle; try { hCurProcess = ProcessManager.OpenProcess(unchecked ((int)Interop.Kernel32.GetCurrentProcessId()), Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION, true); bool wow64Ret; wow64Ret = Interop.Kernel32.IsWow64Process(hCurProcess, ref sourceProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } wow64Ret = Interop.Kernel32.IsWow64Process(processHandle, ref targetProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.Errors.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } } finally { if (hCurProcess != SafeProcessHandle.InvalidHandle) { hCurProcess.Dispose(); } } // If the failure wasn't due to Wow64, try again. for (int i = 0; i < 50; i++) { enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); if (enumResult) { break; } Thread.Sleep(1); } } } finally { moduleHandlesArrayHandle.Free(); } if (!enumResult) { throw new Win32Exception(); } moduleCount /= IntPtr.Size; if (moduleCount <= moduleHandles.Length) { break; } moduleHandles = new IntPtr[moduleHandles.Length * 2]; } var modules = new ProcessModuleCollection(firstModuleOnly ? 1 : moduleCount); char[] chars = new char[1024]; for (int i = 0; i < moduleCount; i++) { if (i > 0) { // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. if (firstModuleOnly) { break; } } IntPtr moduleHandle = moduleHandles[i]; Interop.Kernel32.NtModuleInfo ntModuleInfo; if (!Interop.Kernel32.GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo)) { HandleError(); continue; } var module = new ProcessModule() { ModuleMemorySize = ntModuleInfo.SizeOfImage, EntryPointAddress = ntModuleInfo.EntryPoint, BaseAddress = ntModuleInfo.BaseOfDll }; int length = Interop.Kernel32.GetModuleBaseName(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.ModuleName = new string(chars, 0, length); length = Interop.Kernel32.GetModuleFileNameEx(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.FileName = (length >= 4 && chars[0] == '\\' && chars[1] == '\\' && chars[2] == '?' && chars[3] == '\\') ? new string(chars, 4, length - 4) : new string(chars, 0, length); modules.Add(module); } return(modules); } finally { if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }
/// <summary>Starts the process using the supplied start info.</summary> /// <param name="startInfo">The start info with which to start the process.</param> private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) { // See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points: // * The handles are duplicated as non-inheritable before they are passed to CreateProcess so // that the child process can not close them // * CreateProcess allows you to redirect all or none of the standard IO handles, so we use // GetStdHandle for the handles that are not being redirected var commandLine = new ValueStringBuilder(stackalloc char[256]); BuildCommandLine(startInfo, ref commandLine); Interop.Kernel32.STARTUPINFO startupInfo = default; Interop.Kernel32.PROCESS_INFORMATION processInfo = default; Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = default; SafeProcessHandle procSH = new SafeProcessHandle(); // handles used in parent process SafeFileHandle?parentInputPipeHandle = null; SafeFileHandle?childInputPipeHandle = null; SafeFileHandle?parentOutputPipeHandle = null; SafeFileHandle?childOutputPipeHandle = null; SafeFileHandle?parentErrorPipeHandle = null; SafeFileHandle?childErrorPipeHandle = null; // Take a global lock to synchronize all redirect pipe handle creations and CreateProcess // calls. We do not want one process to inherit the handles created concurrently for another // process, as that will impact the ownership and lifetimes of those handles now inherited // into multiple child processes. lock (s_createProcessLock) { try { startupInfo.cb = sizeof(Interop.Kernel32.STARTUPINFO); // set up the streams if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError) { if (startInfo.RedirectStandardInput) { CreatePipe(out parentInputPipeHandle, out childInputPipeHandle, true); } else { childInputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false); } if (startInfo.RedirectStandardOutput) { CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false); } else { childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false); } if (startInfo.RedirectStandardError) { CreatePipe(out parentErrorPipeHandle, out childErrorPipeHandle, false); } else { childErrorPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false); } startupInfo.hStdInput = childInputPipeHandle.DangerousGetHandle(); startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle(); startupInfo.hStdError = childErrorPipeHandle.DangerousGetHandle(); startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES; } // set up the creation flags parameter int creationFlags = 0; if (startInfo.CreateNoWindow) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW; } // set up the environment block parameter string?environmentBlock = null; if (startInfo._environmentVariables != null) { creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT; environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables !); } string?workingDirectory = startInfo.WorkingDirectory; if (workingDirectory.Length == 0) { workingDirectory = null; } bool retVal; int errorCode = 0; if (startInfo.UserName.Length != 0) { if (startInfo.Password != null && startInfo.PasswordInClearText != null) { throw new ArgumentException(SR.CantSetDuplicatePassword); } Interop.Advapi32.LogonFlags logonFlags = (Interop.Advapi32.LogonFlags) 0; if (startInfo.LoadUserProfile) { logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE; } fixed(char *passwordInClearTextPtr = startInfo.PasswordInClearText ?? string.Empty) fixed(char *environmentBlockPtr = environmentBlock) fixed(char *commandLinePtr = &commandLine.GetPinnableReference(terminate: true)) { IntPtr passwordPtr = (startInfo.Password != null) ? Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password) : IntPtr.Zero; try { retVal = Interop.Advapi32.CreateProcessWithLogonW( startInfo.UserName, startInfo.Domain, (passwordPtr != IntPtr.Zero) ? passwordPtr : (IntPtr)passwordInClearTextPtr, logonFlags, null, // we don't need this since all the info is in commandLine commandLinePtr, creationFlags, (IntPtr)environmentBlockPtr, workingDirectory, ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } finally { if (passwordPtr != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr); } } } } else { fixed(char *environmentBlockPtr = environmentBlock) fixed(char *commandLinePtr = &commandLine.GetPinnableReference(terminate: true)) { retVal = Interop.Kernel32.CreateProcess( null, // we don't need this since all the info is in commandLine commandLinePtr, // pointer to the command line string ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle ref unused_SecAttrs, // address to thread security attributes. true, // handle inheritance flag creationFlags, // creation flags (IntPtr)environmentBlockPtr, // pointer to new environment block workingDirectory, // pointer to current directory name ref startupInfo, // pointer to STARTUPINFO ref processInfo // pointer to PROCESS_INFORMATION ); if (!retVal) { errorCode = Marshal.GetLastWin32Error(); } } } if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != new IntPtr(-1)) { Marshal.InitHandle(procSH, processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != new IntPtr(-1)) { Interop.Kernel32.CloseHandle(processInfo.hThread); } if (!retVal) { string nativeErrorMessage = errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH ? SR.InvalidApplication : GetErrorMessage(errorCode); throw CreateExceptionForErrorStartingProcess(nativeErrorMessage, errorCode, startInfo.FileName, workingDirectory); } } catch { parentInputPipeHandle?.Dispose(); parentOutputPipeHandle?.Dispose(); parentErrorPipeHandle?.Dispose(); procSH.Dispose(); throw; } finally { childInputPipeHandle?.Dispose(); childOutputPipeHandle?.Dispose(); childErrorPipeHandle?.Dispose(); } } if (startInfo.RedirectStandardInput) { Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP()); _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle !, FileAccess.Write, 4096, false), enc, 4096); _standardInput.AutoFlush = true; } if (startInfo.RedirectStandardOutput) { Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle !, FileAccess.Read, 4096, false), enc, true, 4096); } if (startInfo.RedirectStandardError) { Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); _standardError = new StreamReader(new FileStream(parentErrorPipeHandle !, FileAccess.Read, 4096, false), enc, true, 4096); } commandLine.Dispose(); if (procSH.IsInvalid) { procSH.Dispose(); return(false); } SetProcessHandle(procSH); SetProcessId((int)processInfo.dwProcessId); return(true); }
public void Dispose() { target.Dispose(); hProcess.Dispose(); }
/// <summary> /// Calls <see cref="CreateProcessAsUserW"/> and safely stores the obtained handles. /// </summary> /// <param name="userToken">Token to impersonate the external process</param> /// <param name="createFlags">Flags used to create the external process</param> /// <param name="startupInfo">Startup information used to create the external process</param> /// <returns><c>true</c> if the call to <see cref="CreateProcessAsUserW"/> was successful; otherwise <c>false</c></returns> private bool SafeCreateProcessAsUserW(IntPtr userToken, CreateProcessFlags createFlags, StartupInfo startupInfo) { _processHandle = new SafeProcessHandle(); var threadHandle = new SafeThreadHandle(); bool success; // The following is necessary to make sure that processInformation.hProcess and processInformation.hThread // are safely stored in the respective SafeHandle classes. It is, unfortunately, not possible to define // processInformation.hProcess and processInformation.hThread as SafeHandles and use processInformation // as an out parameter, because the unmanaged code is not able to create these objects. We therefore use // IntPtr and ensure in the following that the IntPtrs are stored in SafeHandle objects immediately after // they have been obtained. // For details see here: https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions(v=vs.110).aspx RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ProcessInformation processInformation; success = CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out processInformation); if (success) { _processHandle.InitialSetHandle(processInformation.hProcess); threadHandle.InitialSetHandle(processInformation.hThread); _processId = processInformation.dwProcessId; } } // We don't need the threadHandle and therefore immediately dispose it. threadHandle.Dispose(); if (success) return true; _processHandle.Dispose(); var error = Marshal.GetLastWin32Error(); _debugLogger.Error("AsyncImpersonationProcess ({0}): Cannot start process. ErrorCode: {1} ({2})", StartInfo.FileName, error, new Win32Exception(error).Message); return false; }
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported)), PlatformSpecific(TestPlatforms.Windows), OuterLoop] // Uses P/Invokes, Requires admin privileges public void TestUserCredentialsPropertiesOnWindows() { // [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Unit test dummy credentials.")] string username = "******", password = "******"; try { Interop.NetUserAdd(username, password); } catch (Exception exc) { Console.Error.WriteLine("TestUserCredentialsPropertiesOnWindows: NetUserAdd failed: {0}", exc.Message); return; // test is irrelevant if we can't add a user } bool hasStarted = false; SafeProcessHandle handle = null; Process p = null; try { p = CreateProcessLong(); p.StartInfo.LoadUserProfile = true; p.StartInfo.UserName = username; p.StartInfo.PasswordInClearText = password; hasStarted = p.Start(); if (Interop.OpenProcessToken(p.SafeHandle, 0x8u, out handle)) { SecurityIdentifier sid; if (Interop.ProcessTokenToSid(handle, out sid)) { string actualUserName = sid.Translate(typeof(NTAccount)).ToString(); int indexOfDomain = actualUserName.IndexOf('\\'); if (indexOfDomain != -1) { actualUserName = actualUserName.Substring(indexOfDomain + 1); } bool isProfileLoaded = GetNamesOfUserProfiles().Any(profile => profile.Equals(username)); Assert.Equal(username, actualUserName); Assert.True(isProfileLoaded); } } } finally { IEnumerable <uint> collection = new uint[] { 0 /* NERR_Success */, 2221 /* NERR_UserNotFound */ }; Assert.Contains <uint>(Interop.NetUserDel(null, username), collection); if (handle != null) { handle.Dispose(); } if (hasStarted) { p.Kill(); Assert.True(p.WaitForExit(WaitInMS)); } } }
public void Dispose() { processHandle?.Dispose(); tokenSource.Dispose(); GC.SuppressFinalize(this); }
public void Dispose() { _processHandle.Dispose(); }