diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt
index fd8dbff53..0188763bd 100644
--- a/trunk/CHANGELOG.txt
+++ b/trunk/CHANGELOG.txt
@@ -7,6 +7,7 @@ Process Hacker
* KProcessHacker can now bypass all handle-opening protections
* Ability to set handle flags such as protect-from-close and inherit
* Better highlighting
+ * Terminator test: TD1 (debugs a process and closes the debug object)
* Terminator test: TT3 (TT1 is now completely user-mode)
* Shows function file and line numbers where available
* FIXED:
diff --git a/trunk/ProcessHacker.Native/Api/Enums.cs b/trunk/ProcessHacker.Native/Api/Enums.cs
index 0d5279042..26485b397 100644
--- a/trunk/ProcessHacker.Native/Api/Enums.cs
+++ b/trunk/ProcessHacker.Native/Api/Enums.cs
@@ -102,6 +102,12 @@ namespace ProcessHacker.Native.Api
CreateIgnoreSystemDefault = 0x80000000
}
+ [Flags]
+ public enum DebugObjectFlags : uint
+ {
+ KillOnClose = 0x1
+ }
+
public enum DepFlags : uint
{
Disable = 0x00000000,
diff --git a/trunk/ProcessHacker.Native/Api/Functions.cs b/trunk/ProcessHacker.Native/Api/Functions.cs
index 401d14ff8..2d8e66595 100644
--- a/trunk/ProcessHacker.Native/Api/Functions.cs
+++ b/trunk/ProcessHacker.Native/Api/Functions.cs
@@ -93,6 +93,28 @@ namespace ProcessHacker.Native.Api
#endregion
+ #region Debugging
+
+ [DllImport("kernel32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DebugActiveProcess(
+ [In] int Pid
+ );
+
+ [DllImport("kernel32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DebugActiveProcessStop(
+ [In] int Pid
+ );
+
+ [DllImport("kernel32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DebugSetProcessKillOnExit(
+ [In] bool KillOnExit
+ );
+
+ #endregion
+
#region Error Handling
[DllImport("ntdll.dll")]
@@ -493,6 +515,20 @@ namespace ProcessHacker.Native.Api
[In] IntPtr ThreadHandle
);
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern int NtAlertResumeThread(
+ [In] IntPtr ThreadHandle,
+ [Out] [Optional] out int PreviousSuspendCount
+ );
+
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern int NtCreateDebugObject(
+ [Out] out IntPtr DebugObjectHandle,
+ [In] DebugObjectAccess DesiredAccess,
+ [In] [Optional] IntPtr ObjectAttributes,
+ [In] DebugObjectFlags Flags
+ );
+
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtCreateProcess(
[Out] out IntPtr ProcessHandle,
@@ -516,6 +552,12 @@ namespace ProcessHacker.Native.Api
[In] [Optional] IntPtr FileHandle
);
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern int NtDebugActiveProcess(
+ [In] IntPtr ProcessHandle,
+ [In] IntPtr DebugObjectHandle
+ );
+
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtDuplicateObject(
[In] IntPtr SourceProcessHandle,
@@ -529,7 +571,7 @@ namespace ProcessHacker.Native.Api
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtGetNextProcess(
- [In] IntPtr ProcessHandle,
+ [In] [Optional] IntPtr ProcessHandle,
[In] ProcessAccess DesiredAccess,
[In] int HandleAttributes,
[In] int Flags,
@@ -538,11 +580,12 @@ namespace ProcessHacker.Native.Api
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtGetNextThread(
- [In] IntPtr ProcessHandle,
- [In] ProcessAccess DesiredAccess,
+ [In] [Optional] IntPtr ProcessHandle,
+ [In] [Optional] IntPtr ThreadHandle,
+ [In] ThreadAccess DesiredAccess,
[In] int HandleAttributes,
[In] int Flags,
- [Out] out int NewProcessHandle
+ [Out] out IntPtr NewThreadHandle
);
[DllImport("ntdll.dll", SetLastError = true)]
@@ -559,6 +602,12 @@ namespace ProcessHacker.Native.Api
[Out] [Optional] out int DataWritten
);
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern int NtRemoveProcessDebug(
+ [In] IntPtr ProcessHandle,
+ [In] IntPtr DebugObjectHandle
+ );
+
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtResumeProcess(
[In] IntPtr ProcessHandle
@@ -569,6 +618,15 @@ namespace ProcessHacker.Native.Api
[In] IntPtr ProcessHandle
);
+ [DllImport("ntdll.dll", SetLastError = true)]
+ public static extern int NtQueueApcThread(
+ [In] IntPtr ThreadHandle,
+ [In] IntPtr ApcRoutine,
+ [In] [Optional] IntPtr ApcArgument1,
+ [In] [Optional] IntPtr ApcArgument2,
+ [In] [Optional] IntPtr ApcArgument3
+ );
+
[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtQuerySection(
[In] IntPtr SectionHandle,
@@ -935,18 +993,6 @@ namespace ProcessHacker.Native.Api
[In] int ProcessId
);
- [DllImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool DebugActiveProcess(
- [In] int Pid
- );
-
- [DllImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool DebugActiveProcessStop(
- [In] int Pid
- );
-
[DllImport("psapi.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumProcessModules(
diff --git a/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs b/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs
new file mode 100644
index 000000000..d6ba7a603
--- /dev/null
+++ b/trunk/ProcessHacker.Native/Objects/DebugObjectHandle.cs
@@ -0,0 +1,53 @@
+/*
+ * Process Hacker -
+ * debug object handle
+ *
+ * Copyright (C) 2009 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ProcessHacker.Native.Api;
+using ProcessHacker.Native.Security;
+
+namespace ProcessHacker.Native.Objects
+{
+ public class DebugObjectHandle : Win32Handle
+ {
+ public static DebugObjectHandle Create(DebugObjectAccess access, DebugObjectFlags flags)
+ {
+ int status;
+ IntPtr handle;
+
+ if ((status = Win32.NtCreateDebugObject(
+ out handle,
+ access,
+ IntPtr.Zero,
+ flags
+ )) < 0)
+ Win32.ThrowLastError(status);
+
+ return new DebugObjectHandle(handle, true);
+ }
+
+ private DebugObjectHandle(IntPtr handle, bool owned)
+ : base(handle, owned)
+ { }
+ }
+}
diff --git a/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs b/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs
index 744057b9a..6cd5b9b5c 100644
--- a/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/DesktopHandle.cs
@@ -1,4 +1,26 @@
-using System;
+/*
+ * Process Hacker -
+ * desktop handle
+ *
+ * Copyright (C) 2009 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+using System;
using System.Collections.Generic;
using System.Text;
using ProcessHacker.Native.Api;
diff --git a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
index fc9fa9a6c..ea628d9f4 100644
--- a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
@@ -185,13 +185,15 @@ namespace ProcessHacker.Native.Objects
public enum JobObjectInformationClass : int
{
JobObjectBasicAccountingInformation = 1,
- JobObjectBasicLimitInformation = 2,
- JobObjectBasicProcessIdList = 3,
- JobObjectBasicUIRestrictions = 4,
- JobObjectSecurityLimitInformation = 5,
- JobObjectBasicAndIoAccountingInformation = 8,
- JobObjectExtendedLimitInformation = 9,
- JobObjectGroupInformation = 11
+ JobObjectBasicLimitInformation,
+ JobObjectBasicProcessIdList,
+ JobObjectBasicUIRestrictions,
+ JobObjectSecurityLimitInformation,
+ JobObjectEndOfJobTimeInformation,
+ JobObjectAssociateCompletionPortInformation,
+ JobObjectBasicAndIoAccountingInformation,
+ JobObjectExtendedLimitInformation,
+ JobObjectJobSetInformation
}
[Flags]
diff --git a/trunk/ProcessHacker.Native/Objects/LsaHandle.cs b/trunk/ProcessHacker.Native/Objects/LsaHandle.cs
index 67928e1ef..698662ffe 100644
--- a/trunk/ProcessHacker.Native/Objects/LsaHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/LsaHandle.cs
@@ -2,7 +2,7 @@
* Process Hacker -
* local security authority handle
*
- * Copyright (C) 2008 wj32
+ * Copyright (C) 2008-2009 wj32
*
* This file is part of Process Hacker.
*
diff --git a/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs b/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs
index 24f874501..598ebef4d 100644
--- a/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/LsaPolicyHandle.cs
@@ -2,7 +2,7 @@
* Process Hacker -
* local security policy handle
*
- * Copyright (C) 2008 wj32
+ * Copyright (C) 2008-2009 wj32
*
* This file is part of Process Hacker.
*
diff --git a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
index cbbbf8c9f..057d93279 100644
--- a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
@@ -234,6 +234,19 @@ namespace ProcessHacker.Native.Objects
return new ThreadHandle(this.CreateThread(startAddress, parameter), access);
}
+ ///
+ /// Debugs the process with the specified debug object. This requires the
+ /// PROCESS_SUSPEND_RESUME permission.
+ ///
+ /// A handle to a debug object.
+ public void Debug(DebugObjectHandle debugObjectHandle)
+ {
+ int status;
+
+ if ((status = Win32.NtDebugActiveProcess(this, debugObjectHandle)) < 0)
+ Win32.ThrowLastError(status);
+ }
+
///
/// Removes as many pages as possible from the process' working set. This requires the
/// PROCESS_QUERY_INFORMATION and PROCESS_SET_INFORMATION permissions.
@@ -744,6 +757,52 @@ namespace ProcessHacker.Native.Objects
}
}
+ ///
+ /// Opens the next linked process.
+ ///
+ /// The desired access to the next process.
+ /// A process handle.
+ public ProcessHandle GetNextProcess(ProcessAccess access)
+ {
+ int status;
+ IntPtr handle;
+
+ if ((status = Win32.NtGetNextProcess(
+ this,
+ access,
+ 0,
+ 0,
+ out handle
+ )) < 0)
+ Win32.ThrowLastError(status);
+
+ return new ProcessHandle(handle, true);
+ }
+
+ ///
+ /// Opens the next linked thread belonging to the process.
+ ///
+ /// A thread handle. You may specify null.
+ /// The desired access to the next thread.
+ /// A thread handle.
+ public ThreadHandle GetNextThread(ThreadHandle threadHandle, ThreadAccess access)
+ {
+ int status;
+ IntPtr handle;
+
+ if ((status = Win32.NtGetNextThread(
+ this,
+ threadHandle != null ? threadHandle : IntPtr.Zero,
+ access,
+ 0,
+ 0,
+ out handle
+ )) < 0)
+ Win32.ThrowLastError(status);
+
+ return new ThreadHandle(handle, true);
+ }
+
///
/// Gets the process' page priority, ranging from 0-7.
///
@@ -909,9 +968,6 @@ namespace ProcessHacker.Native.Objects
/// Determines whether the process is running in a job.
///
/// A boolean.
- /// According to this function, almost every single
- /// process is in a job! This function does not tell us
- /// the name of the job though.
public bool IsInJob()
{
bool result;
@@ -921,6 +977,22 @@ namespace ProcessHacker.Native.Objects
return result;
}
+
+ ///
+ /// Determines whether the process is running in the specified job.
+ ///
+ /// The job object to check.
+ /// A boolean.
+ public bool IsInJob(JobObjectHandle jobObjectHandle)
+ {
+ bool result;
+
+ if (!Win32.IsProcessInJob(this, jobObjectHandle, out result))
+ Win32.ThrowLastError();
+
+ return result;
+ }
+
///
/// Gets whether the process is a NTVDM process.
///
@@ -1007,6 +1079,18 @@ namespace ProcessHacker.Native.Objects
return readLen;
}
+ ///
+ /// Stops debugging the process attached to the specified debug object.
+ ///
+ /// The debug object which was used to debug the process.
+ public void RemoveDebug(DebugObjectHandle debugObjectHandle)
+ {
+ int status;
+
+ if ((status = Win32.NtRemoveProcessDebug(this, debugObjectHandle)) < 0)
+ Win32.ThrowLastError(status);
+ }
+
///
/// Resumes the process. This requires the PROCESS_SUSPEND_RESUME permission.
///
diff --git a/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs b/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs
index e39bd43a1..ac962c544 100644
--- a/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/WindowStationHandle.cs
@@ -1,4 +1,26 @@
-using System;
+/*
+ * Process Hacker -
+ * window station handle
+ *
+ * Copyright (C) 2009 wj32
+ *
+ * This file is part of Process Hacker.
+ *
+ * Process Hacker is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Process Hacker is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Process Hacker. If not, see .
+ */
+
+using System;
using System.Collections.Generic;
using System.Text;
using ProcessHacker.Native.Api;
diff --git a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
index 301e20ec5..dcf42d639 100644
--- a/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
+++ b/trunk/ProcessHacker.Native/ProcessHacker.Native.csproj
@@ -49,6 +49,7 @@
+
@@ -77,6 +78,7 @@
+
diff --git a/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs b/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs
new file mode 100644
index 000000000..4cef678bc
--- /dev/null
+++ b/trunk/ProcessHacker.Native/Security/DebugObjectAccess.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace ProcessHacker.Native.Security
+{
+ [Flags]
+ public enum DebugObjectAccess : uint
+ {
+ ReadEvent = 0x1,
+ ProcessAssign = 0x2,
+ SetInformation = 0x4,
+ QueryInformation = 0x8,
+ All = StandardRights.Required | StandardRights.Synchronize |
+ ReadEvent | ProcessAssign | SetInformation | QueryInformation
+ }
+}
diff --git a/trunk/ProcessHacker/Forms/TerminatorWindow.cs b/trunk/ProcessHacker/Forms/TerminatorWindow.cs
index a7fb02d59..3f0aa7e88 100644
--- a/trunk/ProcessHacker/Forms/TerminatorWindow.cs
+++ b/trunk/ProcessHacker/Forms/TerminatorWindow.cs
@@ -23,6 +23,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
+using System.Threading;
using System.Windows.Forms;
using ProcessHacker.Native;
using ProcessHacker.Native.Api;
@@ -47,10 +48,11 @@ namespace ProcessHacker
this.AddTest("TP1", "Terminates the process using TerminateProcess");
this.AddTest("TP2", "Creates a remote thread in the process which terminates the process");
- this.AddTest("TJ1", "Assigns the process to a job object and terminates the job");
this.AddTest("TT1", "Terminates the process' threads");
this.AddTest("TT2", "Modifies the process' threads with contexts which terminate the process");
this.AddTest("CH1", "Closes the process' handles");
+ this.AddTest("TJ1", "Assigns the process to a job object and terminates the job");
+ this.AddTest("TD1", "Debugs the process and closes the debug object");
this.AddTest("TP3", "Terminates the process in kernel-mode (if possible)");
this.AddTest("TT3", "Terminates the process' threads in kernel-mode (if possible)");
this.AddTest("M1", "Writes garbage to the process' memory regions");
@@ -122,6 +124,97 @@ namespace ProcessHacker
return false;
}
+ private void CH1()
+ {
+ using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.DupHandle))
+ {
+ int i = 0;
+
+ while (true)
+ {
+ if (i >= 0x1000)
+ break;
+
+ try
+ {
+ Win32.DuplicateObject(phandle, new IntPtr(i), 0, 0, 0x1);
+ }
+ catch
+ { }
+
+ i++;
+ }
+ }
+ }
+
+ private void M1()
+ {
+ this.M1Internal();
+ }
+
+ private unsafe void M1Internal()
+ {
+ using (MemoryAlloc alloc = new MemoryAlloc(0x1000))
+ {
+ using (ProcessHandle phandle = new ProcessHandle(_pid,
+ ProcessAccess.QueryInformation |
+ Program.MinProcessWriteMemoryRights))
+ {
+ phandle.EnumMemory((info) =>
+ {
+ for (int i = 0; i < info.RegionSize; i += 0x1000)
+ {
+ try
+ {
+ phandle.WriteMemory(info.BaseAddress.Increment(i), alloc, 0x1000);
+ }
+ catch
+ { }
+ }
+
+ return true;
+ });
+ }
+ }
+ }
+
+ private void M2()
+ {
+ using (ProcessHandle phandle = new ProcessHandle(_pid,
+ ProcessAccess.QueryInformation | ProcessAccess.VmOperation))
+ {
+ phandle.EnumMemory((info) =>
+ {
+ phandle.ProtectMemory(info.BaseAddress, info.RegionSize, MemoryProtection.NoAccess);
+ return true;
+ });
+ }
+ }
+
+ private void TD1()
+ {
+ using (var dhandle =
+ DebugObjectHandle.Create(DebugObjectAccess.ProcessAssign, DebugObjectFlags.KillOnClose))
+ {
+ using (var phandle = new ProcessHandle(_pid, ProcessAccess.SuspendResume))
+ phandle.Debug(dhandle);
+ }
+ }
+
+ private void TJ1()
+ {
+ using (var jhandle = JobObjectHandle.Create(null))
+ {
+ using (ProcessHandle phandle =
+ new ProcessHandle(_pid, ProcessAccess.SetQuota | ProcessAccess.Terminate))
+ {
+ phandle.AssignToJobObject(jhandle);
+ }
+
+ jhandle.Terminate();
+ }
+ }
+
private void TP1()
{
using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.Terminate))
@@ -143,17 +236,11 @@ namespace ProcessHacker
Win32.ThrowLastError();
}
- private void TJ1()
+ private void TP3()
{
- using (var jhandle = JobObjectHandle.Create(null))
+ using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights))
{
- using (ProcessHandle phandle =
- new ProcessHandle(_pid, ProcessAccess.SetQuota | ProcessAccess.Terminate))
- {
- phandle.AssignToJobObject(jhandle);
- }
-
- jhandle.Terminate();
+ phandle.Terminate();
}
}
@@ -195,81 +282,6 @@ namespace ProcessHacker
}
}
- private void M1()
- {
- this.M1Internal();
- }
-
- private unsafe void M1Internal()
- {
- using (MemoryAlloc alloc = new MemoryAlloc(0x1000))
- {
- using (ProcessHandle phandle = new ProcessHandle(_pid,
- ProcessAccess.QueryInformation |
- Program.MinProcessWriteMemoryRights))
- {
- phandle.EnumMemory((info) =>
- {
- for (int i = 0; i < info.RegionSize; i += 0x1000)
- {
- try
- {
- phandle.WriteMemory(info.BaseAddress.Increment(i), alloc, 0x1000);
- }
- catch
- { }
- }
-
- return true;
- });
- }
- }
- }
-
- private void M2()
- {
- using (ProcessHandle phandle = new ProcessHandle(_pid,
- ProcessAccess.QueryInformation | ProcessAccess.VmOperation))
- {
- phandle.EnumMemory((info) =>
- {
- phandle.ProtectMemory(info.BaseAddress, info.RegionSize, MemoryProtection.NoAccess);
- return true;
- });
- }
- }
-
- private void CH1()
- {
- using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.DupHandle))
- {
- int i = 0;
-
- while (true)
- {
- if (i >= 0x1000)
- break;
-
- try
- {
- Win32.DuplicateObject(phandle, new IntPtr(i), 0, 0, 0x1);
- }
- catch
- { }
-
- i++;
- }
- }
- }
-
- private void TP3()
- {
- using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights))
- {
- phandle.Terminate();
- }
- }
-
private void TT3()
{
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(_pid);