Blue Screen of Death

Analyzing Malware: BSOD

My Logo

Malware Name: BSOD (Blue Screen of Death)

The infamous blue screen of death — I’m sure many of you have come across this at least once in your lifetime, and it probably did so at the exact moment you were working on a paper due at midnight… which you forgot to save.

Let’s dive into the workings of this malware:

How the malware works:

-The script first hides the console; by doing so, the victim user is unaware of anything happening on their machine.


            ShowWindow(console_window, SW_HIDE);
            

-The script then sets itself as a high priority process, which means this process is given more CPU time and scheduling preference, this process becomes the CPU’s main focus of attention.


            SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
            

-The next piece of code calls the function RtlAdjustPrivilege, which is a low-level Windows API used to enable or disable privileges for the current process or thread. This is run to enable shutdown privileges


            let mut enabled: BOOLEAN = 0;
            let privilege = RtlAdjustPrivilege(19, 1 as BOOLEAN, 0 as BOOLEAN, &mut enabled);
                
            

Function:


            RtlAdjustPrivilege (ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled)
                
            

Privilege Escalation Details

19 → Privilege
The privilege ID, 19 enables the Shutdown privilege.
1 → Enable
Enables the privilege.
0 → CurrentThread
Specifies that the process token should be adjusted (applies shutdown privilege to the whole process instead of a singular thread).
&mut enabled → Enabled
Reports back whether the privilege was previously enabled.

After this function runs, a check is performed to determine whether it executed successfully. If successful, the program will continue. If not, it will run a cleanup function and exit (explained later).

Code that checks whether call to RtlAdjustPrivilege was successful:


                if privilege != STATUS_SUCCESS {
                    error_ret = privilege;
                    cleanup(error_ret);
                    return;
                }
            

------------------------------------------------------------------------------------------------------------------------------------------------------

-Next, the code for triggering the BSOD is executed.

Random Function

System Time Breakdown

SystemTime::now()
Gets the current system time.
.duration_since(SystemTime::UNIX_EPOCH)
Calculates time since Jan 1, 1970 (Unix epoch).
.unwrap()
Panics if the time is earlier than the epoch (might occur if the system clock is broken).
.as_secs() as u32
Gets the number of whole seconds in the duration (returns a 64-bit number) and casts it to a 32-bit unsigned integer.
& 0xF_FFFF
Applies a bitmask to keep only the lowest 20 bits.

*A bitmask is a binary number used to select, test, or clear specific bits in another number using bitwise operations. Can be used to isolate or manipulate specific bits in a value.

Using the resulting value, a random BSOD error code is generated:


            let bsod_code = 0xC000_0000 | ((random & 0xF00) << 8) | ((random & 0xF0) << 4) | (random & 0xF);

            

NTSTATUS Error Code Construction

0xC000_0000
NTSTATUS code structure prefix.
random & 0xF00
Gets bits 8–11 from random, then << 8 moves them to bits 16–19.
random & 0xF0
Gets bits 4–7 from random, then << 4 moves them to bits 8–11.
random & 0xF
Gets bits 0–3 from random and keeps them in place.

The result of this bit manipulation creates a random error code, such as 0xC0000026.

------------------------------------------------------------------------------------------------------------------------------------------------------

After the random error code is generated, it is used as a parameter in the function “NtRaiseHardError” which is an undocumented Windows Native API function used in lower-level code. It is what triggers the BSOD


            let bsod = NtRaiseHardError(bsod_code as NTSTATUS, 0, 0, null_mut(), 6, &mut u_resp);

            

Function:


        NtRaiseHardError (ErrorStatus, NumberOfParameters, UnicodeStringParameterMask, Parameters, ResponseOption, Response)

            

Function Parameters

bsod_code as NTSTATUS
32-bit error code generated previously.
0 → NumberOfParameters
No parameters passed to the error message.
0 → UnicodeStringParameterMask
Optional parameter used to specify which parameters (in the upcoming parameters array) are strings — none in this case.
null_mut() → Parameters
Array of pointers to parameters that will be used to format the error message string — none in this case.
ResponseOption → 6
Defines whether the user can choose to ignore the error, continue, or take other actions. Value 6 represents OptionShutDownSystem.
Response → &mut u_resp
A pointer to the variable that will store the user’s response to the error dialog (but it is ignored here).

------------------------------------------------------------------------------------------------------------------------------------------------------

The next piece of code checks to see whether the call to NtRaiseHardError failed, and if so, performs a cleanup and returns early


            if bsod != STATUS_SUCCESS {
                error_ret = bsod;
                cleanup(error_ret);
                return;
            }
            

Checks to see if bsod succeeded (Usually represented by the value 0x00000000)

If the call to NtRaiseHardError fails, this indicates that the function was run with insufficient privileges, was blocked or there were invalid parameters.

If the function call does fail, the value is stored in the variable error_ret which is then passed into the cleanup function.