Search code examples
c#c++-clipinvokeblue-screen-of-death

C# How to P/Invoke NtRaiseHardError


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);
        }
    }

Solution

  • 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.