public void NtQueryInformationProcessTest() { var curProc = Process.GetCurrentProcess(); HPROCESS hProc = curProc.Handle; NtQueryResult <PROCESS_BASIC_INFORMATION> pbi = null; Assert.That(() => pbi = NtQueryInformationProcess <PROCESS_BASIC_INFORMATION>(hProc, PROCESSINFOCLASS.ProcessBasicInformation), Throws.Nothing); Assert.That(pbi, Is.Not.Null); // Can do AsRef here since PROCESS_BASIC_INFORMATION has no managed types ref var rpbi = ref pbi.AsRef();
/// <summary> /// <para>Retrieves information about the specified process.</para> /// </summary> /// <typeparam name="T">The type of the structure to retrieve.</typeparam> /// <param name="ProcessHandle">A handle to the process for which information is to be retrieved.</param> /// <param name="ProcessInformationClass"> /// <para> /// The type of process information to be retrieved. This parameter can be one of the following values from the /// <c>PROCESSINFOCLASS</c> enumeration. /// </para> /// <list type="table"> /// <listheader> /// <term>Value</term> /// <term>Meaning</term> /// </listheader> /// <item> /// <term>ProcessBasicInformation <br/> 0</term> /// <term> /// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a /// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions /// to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessDebugPort <br/> 7</term> /// <term> /// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process /// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function. /// </term> /// </item> /// <item> /// <term>ProcessWow64Information <br/> 26</term> /// <term> /// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based /// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessImageFileName <br/> 27</term> /// <term> /// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or /// GetProcessImageFileName function to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessBreakOnTermination <br/> 29</term> /// <term>Retrieves a ULONG value indicating whether the process is considered critical.</term> /// </item> /// <item> /// <term>ProcessSubsystemInformation <br/> 75</term> /// <term> /// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the /// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration. /// </term> /// </item> /// </list> /// </param> /// <returns>The structure and associated memory for any allocated sub-types.</returns> /// <exception cref="System.ArgumentException">Mismatch between requested type and class.</exception> public static NtQueryResult <T> NtQueryInformationProcess <T>([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass) where T : struct { if (!CorrespondingTypeAttribute.CanGet(ProcessInformationClass, typeof(T))) { throw new ArgumentException("Mismatch between requested type and class."); } var mem = new NtQueryResult <T>(); var status = NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out var sz); if (status.Succeeded) { return(mem); } if (status != NTStatus.STATUS_INFO_LENGTH_MISMATCH || sz == 0) { throw status.GetException(); } mem.Size = sz; NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out _).ThrowIfFailed(); return(mem); }
/// <summary> /// <para>Retrieves information about the specified process.</para> /// </summary> /// <typeparam name="T">The type of the structure to retrieve.</typeparam> /// <param name="ProcessHandle">A handle to the process for which information is to be retrieved.</param> /// <param name="ProcessInformationClass"> /// <para> /// The type of process information to be retrieved. This parameter can be one of the following values from the /// <c>PROCESSINFOCLASS</c> enumeration. /// </para> /// <list type="table"> /// <listheader> /// <term>Value</term> /// <term>Meaning</term> /// </listheader> /// <item> /// <term>ProcessBasicInformation <br/> 0</term> /// <term> /// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a /// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions /// to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessDebugPort <br/> 7</term> /// <term> /// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process /// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function. /// </term> /// </item> /// <item> /// <term>ProcessWow64Information <br/> 26</term> /// <term> /// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based /// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessImageFileName <br/> 27</term> /// <term> /// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or /// GetProcessImageFileName function to obtain this information. /// </term> /// </item> /// <item> /// <term>ProcessBreakOnTermination <br/> 29</term> /// <term>Retrieves a ULONG value indicating whether the process is considered critical.</term> /// </item> /// <item> /// <term>ProcessSubsystemInformation <br/> 75</term> /// <term> /// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the /// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration. /// </term> /// </item> /// </list> /// </param> /// <returns>The structure and associated memory for any allocated sub-types.</returns> /// <exception cref="System.ArgumentException">Mismatch between requested type and class.</exception> public static NtQueryResult <T> NtQueryInformationProcess <T>([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass) where T : struct { var validTypes = CorrespondingTypeAttribute.GetCorrespondingTypes(ProcessInformationClass, CorrespondingAction.Get).ToArray(); if (validTypes.Length > 0 && Array.IndexOf(validTypes, typeof(T)) == -1) { throw new ArgumentException("Mismatch between requested type and class."); } #if x64 // Check if the target is a 32 bit process running in WoW64 mode. if (IsWow64(ProcessHandle)) { // We are 64 bit. Target process is 32 bit running in WoW64 mode. throw new PlatformNotSupportedException("Unable to query a 32-bit process from a 64-bit process."); } #else if (NtQueryInformationProcessRequiresWow64Structs(ProcessHandle)) { if (validTypes.Length > 1 && !TypeIsWow()) { throw new ArgumentException("Type name must end in WOW64 to indicate it was configured exclusively for 64-bit use."); } var mem = new NtQueryResult <T>(); var status = NtWow64QueryInformationProcess64(ProcessHandle, ProcessInformationClass, ((IntPtr)mem).ToInt32(), mem.Size, out var sz); if (status.Succeeded) { return(mem); } if (status != NTStatus.STATUS_INFO_LENGTH_MISMATCH || sz == 0) { throw status.GetException(); } mem.Size = sz; NtWow64QueryInformationProcess64(ProcessHandle, ProcessInformationClass, ((IntPtr)mem).ToInt32(), mem.Size, out _).ThrowIfFailed(); return(mem); } #endif // Target process is of the same bitness as us. else { if (validTypes.Length > 1 && TypeIsWow()) { throw new ArgumentException("Type name must not end in WOW64 should be configured for 32 or 64-bit use."); } var mem = new NtQueryResult <T>(); var status = NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out var sz); if (status.Succeeded) { return(mem); } if (status != NTStatus.STATUS_INFO_LENGTH_MISMATCH || sz == 0) { throw status.GetException(); } mem.Size = sz; NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out _).ThrowIfFailed(); return(mem); } bool TypeIsWow() => typeof(T).Name.EndsWith("WOW64"); }
public void NtQueryInformationProcessTest() { HPROCESS hProc = Kernel32.GetCurrentProcess(); var procIsWow64 = hProc.IsWow64(); var procIs64 = Environment.Is64BitProcess; var osIs64 = Environment.Is64BitOperatingSystem; using var pbi = NtQueryInformationProcess <PROCESS_BASIC_INFORMATION>(hProc, PROCESSINFOCLASS.ProcessBasicInformation); Assert.That(pbi, ResultIs.ValidHandle); // Can get pointer here since PROCESS_BASIC_INFORMATION has no managed types unsafe { var rpbi = (PROCESS_BASIC_INFORMATION *)pbi; Assert.That(rpbi->UniqueProcessId.ToInt32(), Is.EqualTo(Kernel32.GetCurrentProcessId())); Assert.That(rpbi->PebBaseAddress, Is.Not.EqualTo(IntPtr.Zero)); // Have to use ToStructure here since PEB has managed types var peb = rpbi->PebBaseAddress.ToStructure <PEB>(); // Have to use ToStructure here since RTL_USER_PROCESS_PARAMETERS has managed types var upp = peb.ProcessParameters.ToStructure <RTL_USER_PROCESS_PARAMETERS>(); Assert.That(upp.CommandLine.ToString(hProc), Is.Not.Empty); TestContext.WriteLine($"Img: {upp.ImagePathName.ToString(hProc)}; CmdLine: {upp.CommandLine.ToString(hProc)}"); } NtQueryResult <IntPtr> pdp = null; Assert.That(() => pdp = NtQueryInformationProcess <IntPtr>(hProc, PROCESSINFOCLASS.ProcessDebugPort), Throws.Nothing); Assert.That(pdp, ResultIs.ValidHandle); TestContext.WriteLine($"DbgPort: {pdp.Value.ToInt64()}"); NtQueryResult <BOOL> pwi = null; Assert.That(() => pwi = NtQueryInformationProcess <BOOL>(hProc, PROCESSINFOCLASS.ProcessWow64Information), Throws.Nothing); Assert.That(pwi, ResultIs.ValidHandle); Assert.That(pwi.Value.Value, Is.True); NtQueryResult <UNICODE_STRING> pfn = null; Assert.That(() => pfn = NtQueryInformationProcess <UNICODE_STRING>(hProc, PROCESSINFOCLASS.ProcessImageFileName), Throws.Nothing); Assert.That(pfn, ResultIs.ValidHandle); TestContext.WriteLine($"Fn: {pfn.Value.ToString(hProc)}"); NtQueryResult <BOOL> pbt = null; Assert.That(() => pbt = NtQueryInformationProcess <BOOL>(hProc, PROCESSINFOCLASS.ProcessBreakOnTermination), Throws.Nothing); Assert.That(pbt, ResultIs.ValidHandle); Assert.That(pbt.Value.Value, Is.False); NtQueryResult <SUBSYSTEM_INFORMATION_TYPE> psi = null; // This is documented, but fails on Win10 Assert.That(() => psi = NtQueryInformationProcess <SUBSYSTEM_INFORMATION_TYPE>(hProc, PROCESSINFOCLASS.ProcessSubsystemInformation), Throws.ArgumentException); //Assert.That(psi, ResultIs.ValidHandle); //Assert.That(Enum.IsDefined(typeof(SUBSYSTEM_INFORMATION_TYPE), psi.Value), Is.True); //TestContext.WriteLine($"SubSys: {psi.Value}"); // Try undocumented fetch NtQueryResult <uint> ppb = null; Assert.That(() => ppb = NtQueryInformationProcess <uint>(hProc, PROCESSINFOCLASS.ProcessPriorityBoost), Throws.Nothing); TestContext.WriteLine($"Priority boost: {ppb.Value}"); }