The following C++ code causes a bluescreen.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <Windows.h>
#pragma comment(lib, "ntdll.lib")
using namespace std;
EXTERN_C NTSTATUS NTAPI RtlAdjustPrivilege(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
EXTERN_C NTSTATUS NTAPI NtRaiseHardError(NTSTATUS, ULONG, ULONG, PULONG_PTR, ULONG, PULONG);
int main(int argc, char **argv)
{
BOOLEAN bl;
RtlAdjustPrivilege(19, TRUE, FALSE, &bl);
unsigned long response;
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, 0, 6, &response);
return 0;
}
I want to use C# for this so I tried to use P/Invoke. But it doesn't work. The problem is properly at the NtRaiseHardError signature. I haven't found anything about it online (pinvoke.net for example doesn't show NtRaiseHardError because it is undocumented.)
This is what I tried:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
namespace BSCS
{
class Program
{
private static ulong STATUS_ASSERTION_FAILURE = 0xC0000420;
static void Main(string[] args)
{
Console.WriteLine("Adjusting privileges");
RtlAdjustPrivilege(19, true, false, out bool previousValue);
Console.WriteLine("Triggering BSOD");
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, 0, 6, out ulong oul);
Console.WriteLine("Done");
}
[DllImport("ntdll.dll")]
private static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege,
out bool PreviousValue);
[DllImport("ntdll.dll")]
private static extern IntPtr NtRaiseHardError(ulong status, ulong ul, ulong ul2, ulong ul3, ulong ul4, out ulong oul);
}
}
Both of your pinvoke declarations are wrong. Principally your use of C# ulong
which is a 64 bit type. The C++ long
type is 32 bits in Windows.
I'd declare them like this
[DllImport("ntdll.dll")]
private static extern uint RtlAdjustPrivilege(
int Privilege,
bool bEnablePrivilege,
bool IsThreadPrivilege,
out bool PreviousValue
);
[DllImport("ntdll.dll")]
private static extern uint NtRaiseHardError(
uint ErrorStatus,
uint NumberOfParameters,
uint UnicodeStringParameterMask,
IntPtr Parameters,
uint ValidResponseOption,
out uint Response
);
I've taken a short cut with the PULONG_PTR
. Because you are passing the null pointer it's easier to declare it as IntPtr
and pass IntPtr.Zero
.