Created
June 20, 2021 21:48
-
-
Save michel-pi/6faf624ae843c6d3f381d4f913f79fd4 to your computer and use it in GitHub Desktop.
Using NtRaiseHardError to display a MessageBox
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
namespace Undocumented.Windows | |
{ | |
public static unsafe class MessageBox | |
{ | |
// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FError%2FNtRaiseHardError.html | |
private static readonly delegate* unmanaged[Stdcall]<uint, uint, uint, uint*, uint, uint*, uint> _ntRaiseHardError; | |
static MessageBox() | |
{ | |
var ntdll = NativeLibrary.Load("ntdll.dll"); | |
_ntRaiseHardError = | |
(delegate* unmanaged[Stdcall]<uint, uint, uint, uint*, uint, uint*, uint>) | |
NativeLibrary.GetExport(ntdll, "NtRaiseHardError"); | |
} | |
public static int Show(string text, string caption, uint type) | |
{ | |
// used when: MessageBoxW(null, text, caption, MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION) | |
// more advanced message boxes can be created with NtUserCreateWindow | |
if (caption == null) | |
{ | |
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox | |
// The dialog box title. If this parameter is NULL, the default title is Error. | |
caption = "Error"; | |
} | |
if (text == null) | |
{ | |
// no text | |
// handle gracefully | |
text = string.Empty; | |
} | |
fixed (char* textPointer = text) | |
{ | |
fixed (char* captionPointer = caption) | |
{ | |
var textBuffer = new UnicodeString | |
{ | |
Buffer = textPointer, | |
Length = (ushort)(text.Length * sizeof(char)), | |
MaximumLength = (ushort)(text.Length * sizeof(char)) | |
}; | |
var captionBuffer = new UnicodeString | |
{ | |
Buffer = captionPointer, | |
Length = (ushort)(caption.Length * sizeof(char)), | |
MaximumLength = (ushort)(caption.Length * sizeof(char)) | |
}; | |
// the 4th (index 3) parameter can optionally be message box timeout value | |
var parameters = stackalloc nint[] | |
{ | |
(nint)(&textBuffer), | |
(nint)(&captionBuffer), | |
(nint)type | |
}; | |
Unsafe.SkipInit(out uint response); | |
var status = _ntRaiseHardError( | |
0x50000018u, // NtStatus -> STATUS_SERVICE_NOTIFICATION (0x40000018u) | HARDERROR_OVERRIDE_ERRORMODE (0x10000000u) | |
3u, // length of parameters array | |
3u, // always 3 | |
(uint*)parameters, | |
default, // turns out to be OptionOk for default which is 0 i believe. | |
&response); | |
if (status != 0) | |
{ | |
// error | |
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox | |
// msdn: If the function fails, the return value is zero. To get extended error information, call GetLastError. | |
// SetLastError with RtlNtStatusToDosError | |
return 0; | |
} | |
return (int)response; | |
} | |
} | |
} | |
internal struct UnicodeString | |
{ | |
public ushort Length; | |
public ushort MaximumLength; | |
public char* Buffer; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment