mirror of https://github.com/dahall/Vanara.git
Add two undocumented API in ntdll (#386)
API1: DbgUiSetThreadDebugObject API2: NtRemoveProcessDebugpull/387/head
parent
38e611f1e3
commit
a9ff5e3c8f
|
@ -300,142 +300,169 @@ namespace Vanara.PInvoke
|
||||||
[In] HPROCESS ParentProcess, [In] PROCESS_CREATE_FLAGS Flags, [In, Optional] IntPtr SectionHandle,
|
[In] HPROCESS ParentProcess, [In] PROCESS_CREATE_FLAGS Flags, [In, Optional] IntPtr SectionHandle,
|
||||||
[In, Optional] IntPtr DebugPort, [In, Optional] IntPtr ExceptionPort, uint JobMemberLevel);
|
[In, Optional] IntPtr DebugPort, [In, Optional] IntPtr ExceptionPort, uint JobMemberLevel);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>Set the debug object handle in the TEB. This function is UNDOCUMENTED.</summary>
|
||||||
/// <para>
|
/// <param name="DebugObjectHandle">Debug object handle. Retrieve from NtQueryInformationProcess</param>
|
||||||
/// [ <c>NtQueryInformationProcess</c> may be altered or unavailable in future versions of Windows. Applications should use the
|
/// <returns>
|
||||||
/// alternate functions listed in this topic.]
|
/// <para>The function returns an NTSTATUS success or error code.</para>
|
||||||
/// </para>
|
/// <para>
|
||||||
/// <para>Retrieves information about the specified process.</para>
|
/// The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the DDK, and are
|
||||||
/// </summary>
|
/// described in the DDK documentation under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques /
|
||||||
/// <param name="ProcessHandle">A handle to the process for which information is to be retrieved.</param>
|
/// Logging Errors.
|
||||||
/// <param name="ProcessInformationClass">
|
/// </para>
|
||||||
/// <para>
|
/// </returns>
|
||||||
/// The type of process information to be retrieved. This parameter can be one of the following values from the
|
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
|
||||||
/// <c>PROCESSINFOCLASS</c> enumeration.
|
public static extern NTStatus DbgUiSetThreadDebugObject(IntPtr DebugObjectHandle);
|
||||||
/// </para>
|
|
||||||
/// <list type="table">
|
/// <summary>Call the kernel to remove the debug object. This function is UNDOCUMENTED.</summary>
|
||||||
/// <listheader>
|
/// <param name="ProcessHandle">The process handle.</param>
|
||||||
/// <term>Value</term>
|
/// <param name="DebugObjectHandle">Debug object handle. Retrieve from NtQueryInformationProcess</param>
|
||||||
/// <term>Meaning</term>
|
/// <returns>
|
||||||
/// </listheader>
|
/// <para>The function returns an NTSTATUS success or error code.</para>
|
||||||
/// <item>
|
/// <para>
|
||||||
/// <term>ProcessBasicInformation<br/>0</term>
|
/// The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the DDK, and are
|
||||||
/// <term>
|
/// described in the DDK documentation under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques /
|
||||||
/// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a
|
/// Logging Errors.
|
||||||
/// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions
|
/// </para>
|
||||||
/// to obtain this information.
|
/// </returns>
|
||||||
/// </term>
|
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
|
||||||
/// </item>
|
public static extern NTStatus NtRemoveProcessDebug(HPROCESS ProcessHandle, IntPtr DebugObjectHandle);
|
||||||
/// <item>
|
|
||||||
/// <term>ProcessDebugPort<br/>7</term>
|
/// <summary>
|
||||||
/// <term>
|
/// <para>
|
||||||
/// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process
|
/// [ <c>NtQueryInformationProcess</c> may be altered or unavailable in future versions of Windows. Applications should use the
|
||||||
/// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.
|
/// alternate functions listed in this topic.]
|
||||||
/// </term>
|
/// </para>
|
||||||
/// </item>
|
/// <para>Retrieves information about the specified process.</para>
|
||||||
/// <item>
|
/// </summary>
|
||||||
/// <term>ProcessWow64Information<br/>26</term>
|
/// <param name="ProcessHandle">A handle to the process for which information is to be retrieved.</param>
|
||||||
/// <term>
|
/// <param name="ProcessInformationClass">
|
||||||
/// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based
|
/// <para>
|
||||||
/// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information.
|
/// The type of process information to be retrieved. This parameter can be one of the following values from the
|
||||||
/// </term>
|
/// <c>PROCESSINFOCLASS</c> enumeration.
|
||||||
/// </item>
|
/// </para>
|
||||||
/// <item>
|
/// <list type="table">
|
||||||
/// <term>ProcessImageFileName<br/>27</term>
|
/// <listheader>
|
||||||
/// <term>
|
/// <term>Value</term>
|
||||||
/// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or
|
/// <term>Meaning</term>
|
||||||
/// GetProcessImageFileName function to obtain this information.
|
/// </listheader>
|
||||||
/// </term>
|
/// <item>
|
||||||
/// </item>
|
/// <term>ProcessBasicInformation<br/>0</term>
|
||||||
/// <item>
|
/// <term>
|
||||||
/// <term>ProcessBreakOnTermination<br/>29</term>
|
/// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a
|
||||||
/// <term>Retrieves a ULONG value indicating whether the process is considered critical.</term>
|
/// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions
|
||||||
/// </item>
|
/// to obtain this information.
|
||||||
/// <item>
|
/// </term>
|
||||||
/// <term>ProcessSubsystemInformation<br/>75</term>
|
/// </item>
|
||||||
/// <term>
|
/// <item>
|
||||||
/// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the
|
/// <term>ProcessDebugPort<br/>7</term>
|
||||||
/// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration.
|
/// <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
|
||||||
/// </item>
|
/// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.
|
||||||
/// </list>
|
/// </term>
|
||||||
/// </param>
|
/// </item>
|
||||||
/// <param name="ProcessInformation">
|
/// <item>
|
||||||
/// <para>
|
/// <term>ProcessWow64Information<br/>26</term>
|
||||||
/// A pointer to a buffer supplied by the calling application into which the function writes the requested information. The size of
|
/// <term>
|
||||||
/// the information written varies depending on the data type of the ProcessInformationClass parameter:
|
/// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based
|
||||||
/// </para>
|
/// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information.
|
||||||
/// <para>PROCESS_BASIC_INFORMATION</para>
|
/// </term>
|
||||||
/// <para>
|
/// </item>
|
||||||
/// When the ProcessInformationClass parameter is <c>ProcessBasicInformation</c>, the buffer pointed to by the ProcessInformation
|
/// <item>
|
||||||
/// parameter should be large enough to hold a single <c>PROCESS_BASIC_INFORMATION</c> structure having the following layout:
|
/// <term>ProcessImageFileName<br/>27</term>
|
||||||
/// </para>
|
/// <term>
|
||||||
/// <code><![CDATA[
|
/// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or
|
||||||
///typedef struct _PROCESS_BASIC_INFORMATION {
|
/// GetProcessImageFileName function to obtain this information.
|
||||||
/// PVOID Reserved1;
|
/// </term>
|
||||||
/// PPEB PebBaseAddress;
|
/// </item>
|
||||||
/// PVOID Reserved2[2];
|
/// <item>
|
||||||
/// ULONG_PTR UniqueProcessId;
|
/// <term>ProcessBreakOnTermination<br/>29</term>
|
||||||
/// PVOID Reserved3;
|
/// <term>Retrieves a ULONG value indicating whether the process is considered critical.</term>
|
||||||
///} PROCESS_BASIC_INFORMATION;
|
/// </item>
|
||||||
/// ]]></code>
|
/// <item>
|
||||||
/// <para>
|
/// <term>ProcessSubsystemInformation<br/>75</term>
|
||||||
/// The <c>UniqueProcessId</c> member points to the system's unique identifier for this process. Use the GetProcessId function to
|
/// <term>
|
||||||
/// retrieve this information.
|
/// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the
|
||||||
/// </para>
|
/// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration.
|
||||||
/// <para>The <c>PebBaseAddress</c> member points to a PEB structure.</para>
|
/// </term>
|
||||||
/// <para>The other members of this structure are reserved for internal use by the operating system.</para>
|
/// </item>
|
||||||
/// <para>ULONG_PTR</para>
|
/// </list>
|
||||||
/// <para>
|
/// </param>
|
||||||
/// When the ProcessInformationClass parameter is <c>ProcessWow64Information</c>, the buffer pointed to by the ProcessInformation
|
/// <param name="ProcessInformation">
|
||||||
/// parameter should be large enough to hold a <c>ULONG_PTR</c>. If this value is nonzero, the process is running in a WOW64
|
/// <para>
|
||||||
/// environment; otherwise, if the value is equal to zero, the process is not running in a WOW64 environment.
|
/// A pointer to a buffer supplied by the calling application into which the function writes the requested information. The size of
|
||||||
/// </para>
|
/// the information written varies depending on the data type of the ProcessInformationClass parameter:
|
||||||
/// <para>Use the IsWow64Process2 function to determine whether a process is running in the WOW64 environment.</para>
|
/// </para>
|
||||||
/// <para>UNICODE_STRING</para>
|
/// <para>PROCESS_BASIC_INFORMATION</para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// When the ProcessInformationClass parameter is <c>ProcessImageFileName</c>, the buffer pointed to by the ProcessInformation
|
/// When the ProcessInformationClass parameter is <c>ProcessBasicInformation</c>, the buffer pointed to by the ProcessInformation
|
||||||
/// parameter should be large enough to hold a <c>UNICODE_STRING</c> structure as well as the string itself. The string stored in
|
/// parameter should be large enough to hold a single <c>PROCESS_BASIC_INFORMATION</c> structure having the following layout:
|
||||||
/// the <c>Buffer</c> member is the name of the image file.
|
/// </para>
|
||||||
/// </para>
|
/// <code><![CDATA[
|
||||||
/// <para>
|
///typedef struct _PROCESS_BASIC_INFORMATION {
|
||||||
/// If the buffer is too small, the function fails with the STATUS_INFO_LENGTH_MISMATCH error code and the ReturnLength parameter is
|
/// PVOID Reserved1;
|
||||||
/// set to the required buffer size.
|
/// PPEB PebBaseAddress;
|
||||||
/// </para>
|
/// PVOID Reserved2[2];
|
||||||
/// </param>
|
/// ULONG_PTR UniqueProcessId;
|
||||||
/// <param name="ProcessInformationLength">The size of the buffer pointed to by the ProcessInformation parameter, in bytes.</param>
|
/// PVOID Reserved3;
|
||||||
/// <param name="ReturnLength">
|
///} PROCESS_BASIC_INFORMATION;
|
||||||
/// A pointer to a variable in which the function returns the size of the requested information. If the function was successful,
|
/// ]]></code>
|
||||||
/// this is the size of the information written to the buffer pointed to by the ProcessInformation parameter, but if the buffer was
|
/// <para>
|
||||||
/// too small, this is the minimum size of buffer needed to receive the information successfully.
|
/// The <c>UniqueProcessId</c> member points to the system's unique identifier for this process. Use the GetProcessId function to
|
||||||
/// </param>
|
/// retrieve this information.
|
||||||
/// <returns>
|
/// </para>
|
||||||
/// <para>The function returns an NTSTATUS success or error code.</para>
|
/// <para>The <c>PebBaseAddress</c> member points to a PEB structure.</para>
|
||||||
/// <para>
|
/// <para>The other members of this structure are reserved for internal use by the operating system.</para>
|
||||||
/// The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the DDK, and are
|
/// <para>ULONG_PTR</para>
|
||||||
/// described in the DDK documentation under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques /
|
/// <para>
|
||||||
/// Logging Errors.
|
/// When the ProcessInformationClass parameter is <c>ProcessWow64Information</c>, the buffer pointed to by the ProcessInformation
|
||||||
/// </para>
|
/// parameter should be large enough to hold a <c>ULONG_PTR</c>. If this value is nonzero, the process is running in a WOW64
|
||||||
/// </returns>
|
/// environment; otherwise, if the value is equal to zero, the process is not running in a WOW64 environment.
|
||||||
/// <remarks>
|
/// </para>
|
||||||
/// <para>
|
/// <para>Use the IsWow64Process2 function to determine whether a process is running in the WOW64 environment.</para>
|
||||||
/// The <c>NtQueryInformationProcess</c> function and the structures that it returns are internal to the operating system and
|
/// <para>UNICODE_STRING</para>
|
||||||
/// subject to change from one release of Windows to another. To maintain the compatibility of your application, it is better to use
|
/// <para>
|
||||||
/// public functions mentioned in the description of the ProcessInformationClass parameter instead.
|
/// When the ProcessInformationClass parameter is <c>ProcessImageFileName</c>, the buffer pointed to by the ProcessInformation
|
||||||
/// </para>
|
/// parameter should be large enough to hold a <c>UNICODE_STRING</c> structure as well as the string itself. The string stored in
|
||||||
/// <para>
|
/// the <c>Buffer</c> member is the name of the image file.
|
||||||
/// If you do use <c>NtQueryInformationProcess</c>, access the function through run-time dynamic linking. This gives your code an
|
/// </para>
|
||||||
/// opportunity to respond gracefully if the function has been changed or removed from the operating system. Signature changes,
|
/// <para>
|
||||||
/// however, may not be detectable.
|
/// If the buffer is too small, the function fails with the STATUS_INFO_LENGTH_MISMATCH error code and the ReturnLength parameter is
|
||||||
/// </para>
|
/// set to the required buffer size.
|
||||||
/// <para>
|
/// </para>
|
||||||
/// This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Ntdll.dll.
|
/// </param>
|
||||||
/// </para>
|
/// <param name="ProcessInformationLength">The size of the buffer pointed to by the ProcessInformation parameter, in bytes.</param>
|
||||||
/// </remarks>
|
/// <param name="ReturnLength">
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess __kernel_entry NTSTATUS
|
/// A pointer to a variable in which the function returns the size of the requested information. If the function was successful,
|
||||||
// NtQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN
|
/// this is the size of the information written to the buffer pointed to by the ProcessInformation parameter, but if the buffer was
|
||||||
// ULONG ProcessInformationLength, OUT PULONG ReturnLength );
|
/// too small, this is the minimum size of buffer needed to receive the information successfully.
|
||||||
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// <para>The function returns an NTSTATUS success or error code.</para>
|
||||||
|
/// <para>
|
||||||
|
/// The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the DDK, and are
|
||||||
|
/// described in the DDK documentation under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques /
|
||||||
|
/// Logging Errors.
|
||||||
|
/// </para>
|
||||||
|
/// </returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The <c>NtQueryInformationProcess</c> function and the structures that it returns are internal to the operating system and
|
||||||
|
/// subject to change from one release of Windows to another. To maintain the compatibility of your application, it is better to use
|
||||||
|
/// public functions mentioned in the description of the ProcessInformationClass parameter instead.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// If you do use <c>NtQueryInformationProcess</c>, access the function through run-time dynamic linking. This gives your code an
|
||||||
|
/// opportunity to respond gracefully if the function has been changed or removed from the operating system. Signature changes,
|
||||||
|
/// however, may not be detectable.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Ntdll.dll.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess __kernel_entry NTSTATUS
|
||||||
|
// NtQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN
|
||||||
|
// ULONG ProcessInformationLength, OUT PULONG ReturnLength );
|
||||||
|
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
|
||||||
[PInvokeData("winternl.h", MSDNShortId = "0eae7899-c40b-4a5f-9e9c-adae021885e7")]
|
[PInvokeData("winternl.h", MSDNShortId = "0eae7899-c40b-4a5f-9e9c-adae021885e7")]
|
||||||
public static extern NTStatus NtQueryInformationProcess([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, [Out] IntPtr ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);
|
public static extern NTStatus NtQueryInformationProcess([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, [Out] IntPtr ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);
|
||||||
|
|
||||||
|
|
|
@ -1,72 +1,128 @@
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NUnit.Framework.Constraints;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using Vanara.Extensions;
|
using Vanara.Extensions;
|
||||||
using Vanara.InteropServices;
|
|
||||||
using static Vanara.PInvoke.NtDll;
|
using static Vanara.PInvoke.NtDll;
|
||||||
|
|
||||||
namespace Vanara.PInvoke.Tests
|
namespace Vanara.PInvoke.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public partial class WinternlTests
|
public partial class WinternlTests
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void NtQueryInformationProcessTest()
|
public void NtQueryInformationProcessTest()
|
||||||
{
|
{
|
||||||
HPROCESS hProc = Kernel32.GetCurrentProcess();
|
HPROCESS hProc = Kernel32.GetCurrentProcess();
|
||||||
var procIsWow64 = hProc.IsWow64();
|
var procIsWow64 = hProc.IsWow64();
|
||||||
var procIs64 = Environment.Is64BitProcess;
|
var procIs64 = Environment.Is64BitProcess;
|
||||||
var osIs64 = Environment.Is64BitOperatingSystem;
|
var osIs64 = Environment.Is64BitOperatingSystem;
|
||||||
|
|
||||||
using var pbi = NtQueryInformationProcess<PROCESS_BASIC_INFORMATION>(hProc, PROCESSINFOCLASS.ProcessBasicInformation);
|
using var pbi = NtQueryInformationProcess<PROCESS_BASIC_INFORMATION>(hProc, PROCESSINFOCLASS.ProcessBasicInformation);
|
||||||
Assert.That(pbi, ResultIs.ValidHandle);
|
Assert.That(pbi, ResultIs.ValidHandle);
|
||||||
// Can get pointer here since PROCESS_BASIC_INFORMATION has no managed types
|
// Can get pointer here since PROCESS_BASIC_INFORMATION has no managed types
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
var rpbi = (PROCESS_BASIC_INFORMATION*)pbi;
|
var rpbi = (PROCESS_BASIC_INFORMATION*)pbi;
|
||||||
Assert.That(rpbi->UniqueProcessId.ToInt32(), Is.EqualTo(Kernel32.GetCurrentProcessId()));
|
Assert.That(rpbi->UniqueProcessId.ToInt32(), Is.EqualTo(Kernel32.GetCurrentProcessId()));
|
||||||
Assert.That(rpbi->PebBaseAddress, Is.Not.EqualTo(IntPtr.Zero));
|
Assert.That(rpbi->PebBaseAddress, Is.Not.EqualTo(IntPtr.Zero));
|
||||||
// Have to use ToStructure here since PEB has managed types
|
// Have to use ToStructure here since PEB has managed types
|
||||||
var peb = rpbi->PebBaseAddress.ToStructure<PEB>();
|
var peb = rpbi->PebBaseAddress.ToStructure<PEB>();
|
||||||
// Have to use ToStructure here since RTL_USER_PROCESS_PARAMETERS has managed types
|
// Have to use ToStructure here since RTL_USER_PROCESS_PARAMETERS has managed types
|
||||||
var upp = peb.ProcessParameters.ToStructure<RTL_USER_PROCESS_PARAMETERS>();
|
var upp = peb.ProcessParameters.ToStructure<RTL_USER_PROCESS_PARAMETERS>();
|
||||||
Assert.That(upp.CommandLine.ToString(hProc), Is.Not.Empty);
|
Assert.That(upp.CommandLine.ToString(hProc), Is.Not.Empty);
|
||||||
TestContext.WriteLine($"Img: {upp.ImagePathName.ToString(hProc)}; CmdLine: {upp.CommandLine.ToString(hProc)}");
|
TestContext.WriteLine($"Img: {upp.ImagePathName.ToString(hProc)}; CmdLine: {upp.CommandLine.ToString(hProc)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
NtQueryResult<IntPtr> pdp = null;
|
NtQueryResult<IntPtr> pdp = null;
|
||||||
Assert.That(() => pdp = NtQueryInformationProcess<IntPtr>(hProc, PROCESSINFOCLASS.ProcessDebugPort), Throws.Nothing);
|
Assert.That(() => pdp = NtQueryInformationProcess<IntPtr>(hProc, PROCESSINFOCLASS.ProcessDebugPort), Throws.Nothing);
|
||||||
Assert.That(pdp, ResultIs.ValidHandle);
|
Assert.That(pdp, ResultIs.ValidHandle);
|
||||||
TestContext.WriteLine($"DbgPort: {pdp.Value.ToInt64()}");
|
TestContext.WriteLine($"DbgPort: {pdp.Value.ToInt64()}");
|
||||||
|
|
||||||
NtQueryResult<BOOL> pwi = null;
|
NtQueryResult<BOOL> pwi = null;
|
||||||
Assert.That(() => pwi = NtQueryInformationProcess<BOOL>(hProc, PROCESSINFOCLASS.ProcessWow64Information), Throws.Nothing);
|
Assert.That(() => pwi = NtQueryInformationProcess<BOOL>(hProc, PROCESSINFOCLASS.ProcessWow64Information), Throws.Nothing);
|
||||||
Assert.That(pwi, ResultIs.ValidHandle);
|
Assert.That(pwi, ResultIs.ValidHandle);
|
||||||
Assert.That(pwi.Value.Value, Is.True);
|
Assert.That(pwi.Value.Value, Is.True);
|
||||||
|
|
||||||
NtQueryResult<UNICODE_STRING> pfn = null;
|
NtQueryResult<UNICODE_STRING> pfn = null;
|
||||||
Assert.That(() => pfn = NtQueryInformationProcess<UNICODE_STRING>(hProc, PROCESSINFOCLASS.ProcessImageFileName), Throws.Nothing);
|
Assert.That(() => pfn = NtQueryInformationProcess<UNICODE_STRING>(hProc, PROCESSINFOCLASS.ProcessImageFileName), Throws.Nothing);
|
||||||
Assert.That(pfn, ResultIs.ValidHandle);
|
Assert.That(pfn, ResultIs.ValidHandle);
|
||||||
TestContext.WriteLine($"Fn: {pfn.Value.ToString(hProc)}");
|
TestContext.WriteLine($"Fn: {pfn.Value.ToString(hProc)}");
|
||||||
|
|
||||||
NtQueryResult<BOOL> pbt = null;
|
NtQueryResult<BOOL> pbt = null;
|
||||||
Assert.That(() => pbt = NtQueryInformationProcess<BOOL>(hProc, PROCESSINFOCLASS.ProcessBreakOnTermination), Throws.Nothing);
|
Assert.That(() => pbt = NtQueryInformationProcess<BOOL>(hProc, PROCESSINFOCLASS.ProcessBreakOnTermination), Throws.Nothing);
|
||||||
Assert.That(pbt, ResultIs.ValidHandle);
|
Assert.That(pbt, ResultIs.ValidHandle);
|
||||||
Assert.That(pbt.Value.Value, Is.False);
|
Assert.That(pbt.Value.Value, Is.False);
|
||||||
|
|
||||||
NtQueryResult<SUBSYSTEM_INFORMATION_TYPE> psi = null;
|
NtQueryResult<SUBSYSTEM_INFORMATION_TYPE> psi = null;
|
||||||
// This is documented, but fails on Win10
|
// This is documented, but fails on Win10
|
||||||
Assert.That(() => psi = NtQueryInformationProcess<SUBSYSTEM_INFORMATION_TYPE>(hProc, PROCESSINFOCLASS.ProcessSubsystemInformation), Throws.ArgumentException);
|
Assert.That(() => psi = NtQueryInformationProcess<SUBSYSTEM_INFORMATION_TYPE>(hProc, PROCESSINFOCLASS.ProcessSubsystemInformation), Throws.ArgumentException);
|
||||||
//Assert.That(psi, ResultIs.ValidHandle);
|
//Assert.That(psi, ResultIs.ValidHandle);
|
||||||
//Assert.That(Enum.IsDefined(typeof(SUBSYSTEM_INFORMATION_TYPE), psi.Value), Is.True);
|
//Assert.That(Enum.IsDefined(typeof(SUBSYSTEM_INFORMATION_TYPE), psi.Value), Is.True);
|
||||||
//TestContext.WriteLine($"SubSys: {psi.Value}");
|
//TestContext.WriteLine($"SubSys: {psi.Value}");
|
||||||
|
|
||||||
// Try undocumented fetch
|
// Try undocumented fetch
|
||||||
NtQueryResult<uint> ppb = null;
|
NtQueryResult<uint> ppb = null;
|
||||||
Assert.That(() => ppb = NtQueryInformationProcess<uint>(hProc, PROCESSINFOCLASS.ProcessPriorityBoost), Throws.Nothing);
|
Assert.That(() => ppb = NtQueryInformationProcess<uint>(hProc, PROCESSINFOCLASS.ProcessPriorityBoost), Throws.Nothing);
|
||||||
TestContext.WriteLine($"Priority boost: {ppb.Value}");
|
TestContext.WriteLine($"Priority boost: {ppb.Value}");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[Test]
|
||||||
|
public void DbgUiSetThreadDebugObjectAndNtRemoveProcessDebugTest()
|
||||||
|
{
|
||||||
|
Kernel32.STARTUPINFO StartInfo = new Kernel32.STARTUPINFO
|
||||||
|
{
|
||||||
|
dwFlags = Kernel32.STARTF.STARTF_USESHOWWINDOW,
|
||||||
|
wShowWindow = (ushort)ShowWindowCommand.SW_HIDE
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.IsTrue(Kernel32.CreateProcess("notepad.exe", dwCreationFlags: Kernel32.CREATE_PROCESS.DEBUG_PROCESS | Kernel32.CREATE_PROCESS.CREATE_UNICODE_ENVIRONMENT, lpStartupInfo: StartInfo, lpProcessInformation: out Kernel32.SafePROCESS_INFORMATION Information));
|
||||||
|
|
||||||
|
using (Information)
|
||||||
|
using (NtQueryResult<IntPtr> DebugObjectHandleQueryResult = NtQueryInformationProcess<IntPtr>(Information.hProcess, PROCESSINFOCLASS.ProcessDebugObjectHandle))
|
||||||
|
{
|
||||||
|
Assert.That(DebugObjectHandleQueryResult, ResultIs.ValidHandle);
|
||||||
|
Assert.That(DebugObjectHandleQueryResult.Value, ResultIs.ValidHandle);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assert.DoesNotThrow(() => DbgUiSetThreadDebugObject(DebugObjectHandleQueryResult.Value).ThrowIfFailed());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Kernel32.SafeHPROCESS DebugProcessHandle = Kernel32.SafeHPROCESS.Null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Kernel32.WaitForDebugEvent(out Kernel32.DEBUG_EVENT Event, Kernel32.INFINITE));
|
||||||
|
|
||||||
|
if (Event.dwDebugEventCode == Kernel32.DEBUG_EVENT_CODE.CREATE_PROCESS_DEBUG_EVENT)
|
||||||
|
{
|
||||||
|
DebugProcessHandle = new Kernel32.SafeHPROCESS(Event.u.CreateProcessInfo.hProcess);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(Kernel32.ContinueDebugEvent(Event.dwProcessId, Event.dwThreadId, Kernel32.DEBUG_CONTINUE.DBG_CONTINUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.AreNotEqual(Kernel32.SafeHPROCESS.Null, DebugProcessHandle);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DebugProcessHandle.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Assert.DoesNotThrow(() => DbgUiSetThreadDebugObject(IntPtr.Zero).ThrowIfFailed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Assert.IsTrue(Kernel32.TerminateProcess(Information.hProcess, 0));
|
||||||
|
Assert.DoesNotThrow(() => NtRemoveProcessDebug(Information.hProcess, DebugObjectHandleQueryResult.Value).ThrowIfFailed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue