Added in PR #386 to branch

nullableenabled
David Hall 2023-04-10 15:45:00 -06:00
parent b2a78e184b
commit c5605d51b8
2 changed files with 76 additions and 2 deletions

View File

@ -210,6 +210,12 @@ public static partial class NtDll
/// <summary>Reserved.</summary>
MaxSubsystemInformationType,
}
/// <summary>Set the debug object handle in the TEB. This function is UNDOCUMENTED.</summary>
/// <param name="DebugObjectHandle">Debug object handle. Retrieve from NtQueryInformationProcess</param>
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
public static extern void DbgUiSetThreadDebugObject(IntPtr DebugObjectHandle);
/// <summary>Creates a process. This function is UNDOCUMENTED.</summary>
/// <param name="ProcessHandle">The process handle.</param>
/// <param name="DesiredAccess">The desired access.</param>
@ -524,7 +530,7 @@ public static partial class NtDll
if (ret.Succeeded)
return res;
if (ret != NTStatus.STATUS_INFO_LENGTH_MISMATCH || qsz == 0)
throw ret.GetException();
throw ret.GetException()!;
res.Size = qsz;
NtWow64QueryInformationProcess64(ProcessHandle, ProcessInformationClass, ((IntPtr)res).ToInt32(), res.Size, out _).ThrowIfFailed();
return res;
@ -538,7 +544,7 @@ public static partial class NtDll
if (status.Succeeded)
return mem;
if (status != NTStatus.STATUS_INFO_LENGTH_MISMATCH || sz == 0)
throw status.GetException();
throw status.GetException()!;
mem.Size = sz;
NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out _).ThrowIfFailed();
return mem;
@ -551,6 +557,20 @@ public static partial class NtDll
/// <returns><see langword="true"/> if structures returned from <c>NtQueryInformationProcess</c> must be configured exclusively for 64-bit use.</returns>
public static bool NtQueryInformationProcessRequiresWow64Structs(HPROCESS ProcessHandle) => IsWow64(Kernel32.GetCurrentProcess()) && !IsWow64(ProcessHandle);
/// <summary>Call the kernel to remove the debug object. This function is UNDOCUMENTED.</summary>
/// <param name="ProcessHandle">The process handle.</param>
/// <param name="DebugObjectHandle">Debug object handle. Retrieve from NtQueryInformationProcess</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>
[DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
public static extern NTStatus NtRemoveProcessDebug(HPROCESS ProcessHandle, IntPtr DebugObjectHandle);
/// <summary>
/// <para>
/// [ <c>NtQueryInformationProcess</c> may be altered or unavailable in future versions of Windows. Applications should use the

View File

@ -68,4 +68,58 @@ public partial class WinternlTests
Assert.That(() => ppb = NtQueryInformationProcess<uint>(hProc, PROCESSINFOCLASS.ProcessPriorityBoost), Throws.Nothing);
TestContext.WriteLine($"Priority boost: {ppb.Value}");
}
[Test]
public void DbgUiSetThreadDebugObjectAndNtRemoveProcessDebugTest()
{
Kernel32.STARTUPINFO StartInfo = new()
{
dwFlags = Kernel32.STARTF.STARTF_USESHOWWINDOW,
wShowWindow = (ushort)ShowWindowCommand.SW_HIDE
};
Assert.That(Kernel32.CreateProcess(@"C:\Program Files\Notepad++\notepad++.exe", dwCreationFlags: Kernel32.CREATE_PROCESS.DEBUG_PROCESS | Kernel32.CREATE_PROCESS.CREATE_UNICODE_ENVIRONMENT, lpStartupInfo: StartInfo, lpProcessInformation: out Kernel32.SafePROCESS_INFORMATION Information), ResultIs.Successful);
using (Information)
using (NtQueryResult<IntPtr> DebugObjectHandleQueryResult = NtQueryInformationProcess<IntPtr>(Information.hProcess, PROCESSINFOCLASS.ProcessDebugObjectHandle))
{
Assert.That(DebugObjectHandleQueryResult, ResultIs.ValidHandle);
Assert.That(DebugObjectHandleQueryResult.Value, ResultIs.ValidHandle);
try
{
DbgUiSetThreadDebugObject(DebugObjectHandleQueryResult.Value);
try
{
Kernel32.SafeHPROCESS DebugProcessHandle = Kernel32.SafeHPROCESS.Null;
try
{
while (true)
{
Assert.That(Kernel32.WaitForDebugEvent(out Kernel32.DEBUG_EVENT Event, Kernel32.INFINITE), ResultIs.Successful);
if (Event.dwDebugEventCode == Kernel32.DEBUG_EVENT_CODE.CREATE_PROCESS_DEBUG_EVENT)
{
DebugProcessHandle = new Kernel32.SafeHPROCESS(Event.u.CreateProcessInfo.hProcess);
break;
}
Assert.That(Kernel32.ContinueDebugEvent(Event.dwProcessId, Event.dwThreadId, Kernel32.DEBUG_CONTINUE.DBG_CONTINUE), ResultIs.Successful);
}
Assert.False(DebugProcessHandle.IsNull);
}
finally
{
DebugProcessHandle.Dispose();
}
}
finally
{
DbgUiSetThreadDebugObject(IntPtr.Zero);
}
}
finally
{
Assert.That(Kernel32.TerminateProcess(Information.hProcess, 0), ResultIs.Successful);
Assert.That(NtRemoveProcessDebug(Information.hProcess, DebugObjectHandleQueryResult.Value), ResultIs.Successful);
}
}
}
}