# Kernel Shield

<figure><img src="/files/V3Q43q7D8RYZzn96la80" alt=""><figcaption></figcaption></figure>

*Your organization's incident response team has been called in after a devastating ransomware attack encrypted critical servers across the network. During forensic analysis, the team discovered that the ransomware didn't just encrypt files — it first deployed a malicious kernel driver named 'NSecKrnl' to neutralize all endpoint detection and response (EDR) solutions running on the target machines.*&#x20;

*By operating at the kernel level, the driver was able to intercept process handle operations, strip security tool access rights, and forcefully terminate any protective processes before the ransomware payload executed. Without EDR visibility, the ransomware operated completely undetected.*&#x20;

*Your task as a malware analyst is to load this kernel driver into IDA Pro and fully reverse engineer its capabilities. Uncover how it initializes, how it evades kernel integrity checks, how it communicates with its usermode ransomware component via IOCTL codes, and how it systematically kills EDR processes. Your findings will be critical to understanding the full attack chain and building detections to prevent future incidents.*

***

Hi all,\
welcome to my writeup for the real world challenge **Kernel Shield** from [malops.io](https://malops.io/).

Malops.io is an advanced Malware Analysis Training Platform, providing a guided path to dissect and analyze real world malware, created and maintained by Nextron Threat Researcher Gameel Ali. The goal is to practice reversing real malware samples, to understand the behavior and used techniques used by the provided sample.

During my analysis I renamed most of the generic names created by the Disassembler and Debugger, to better understand the malware and the purpose of the variables, functions etc.

As far it is possible, I will try not to make the answer too obvious (e.g. omitting technical terms) so you can follow along in your own analysis environment.

After answering the provided question, which focused solely on analysing the kernel component, I took a quick look at the user-mode application because I was interested in understanding [BYOVD attack paths](https://attack.mitre.org/techniques/T1068/) in more depth and how they work.

> **Important:**\
> This writeup focuses on answering the provided questions in an explanatory/educational manner. Therefore, the analysis was conducted superficially and does not claim to be exhaustive. To answer the questions, some quick and dirty approaches have been used to catch the solutions. This article is not a substitute for a thorough analysis in case of infection via a BYOVD attack!

***

## Questions

### 1) The driver exposes itself to usermode applications under a specific name. What is this name?

In order to be able to communicate with user-space applications via <kbd><mark style="color:$primary;">IOCTLs<mark style="color:$primary;"></kbd>, the kernel driver must create a <kbd><mark style="color:$primary;">DEVICE\_OBJECT<mark style="color:$primary;"></kbd> by calling the API <kbd><mark style="color:orange;">IoCreateDevice<mark style="color:orange;"></kbd> and make it accessible for user-mode processes via <kbd><mark style="color:orange;">IoCreateSymbolicLink<mark style="color:orange;"></kbd>. These operations are performed inside the <kbd><mark style="color:$success;">DriverEntry<mark style="color:$success;"></kbd> function.&#x20;

<figure><img src="/files/WNGxc5LQfR4oLwRlAehB" alt=""><figcaption><p>creation of the Device Object</p></figcaption></figure>

### 2) During initialization, the driver tampers with its own loader entry to bypass a kernel security check. What hex value is OR'd into that field?

The kernel driver accesses the <kbd><mark style="color:$primary;">DriverSection<mark style="color:$primary;"></kbd> member of the <kbd><mark style="color:$primary;">DRIVER\_OBJECT<mark style="color:$primary;"></kbd> struct and from here the <kbd><mark style="color:$primary;">LDR\_DATA\_TABLE\_ENTRY<mark style="color:$primary;"></kbd> struct to manipulate a specific flag. The <kbd><mark style="color:$primary;">DriverSection<mark style="color:$primary;"></kbd> member points to the <kbd><mark style="color:$primary;">LDR\_DATA\_TABLE\_ENTRY<mark style="color:$primary;"></kbd> struct. \
At offset 0x68, the <kbd><mark style="color:$primary;">Flags<mark style="color:$primary;"></kbd> member is located. The original value is ORed with 0x20.

> [Kernel data structures](https://www.codemachine.com/articles/kernel_structures.htmlhttps://www.codemachine.com/articles/kernel_structures.html)\
> [LDR\_DATA\_TABLE\_ENTRY](https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntldr/ldr_data_table_entry.htm)

<figure><img src="/files/ZC2cYbDPETifen5xDDXJ" alt=""><figcaption><p>flag manipulation</p></figcaption></figure>

### 3) At what byte offset from the base of the loader data table entry does this tampering occur?

The tampering occurs at offset 0x68 of the <kbd><mark style="color:$primary;">LDR\_DATA\_TABLE\_ENTRY<mark style="color:$primary;"></kbd> struct.

### 4) One of the IOCTL codes handled by the dispatch function leads to forced process termination. What is this code in hex?

{% hint style="info" %}
IOCTL:\
Stands for input and output control and is an interface through which applications communicate with device drivers. To accomplish this, the user-mode application uses the API <kbd>DeviceIoControl</kbd> to send specific control codes to the requested device object. An IOCTL code is a 32 bit value with several fields, to access specific device types or the type of access requested.

[IOCTL](https://learn.microsoft.com/en-us/windows/win32/devio/device-input-and-output-control-ioctl-)

[DeviceIoControl](https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol)

[IOCTL code structure](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes?source=recommendations)
{% endhint %}

To solve this question, I worked backwards starting from the API call to <kbd><mark style="color:orange;">ZwTerminateProcess<mark style="color:orange;"></kbd>.

This API is called only one time, namely inside a function, that has been registered with the <kbd><mark style="color:$primary;">DriverObject->MajorFunction<mark style="color:$primary;"></kbd> member previously. It is moved into an array located at the end of the <kbd><mark style="color:$primary;">DRIVER\_OBJECT<mark style="color:$primary;"></kbd> struct and contains pointers to various entry points for dispatch routines. Each index represents an IRP function code. In this case, the entry point at index 0xE represents the <kbd><mark style="color:$primary;">IRP\_MJ\_DEVICE\_CONTROL<mark style="color:$primary;"></kbd> [function](https://github.com/ayoubfaouzi/windows-internals/blob/master/IRP%20Major%20Functions%20List.md).

<figure><img src="/files/0FKxVBMS5YaK2HBSFZFk" alt=""><figcaption><p>setting up dispatch routines</p></figcaption></figure>

<figure><img src="/files/tC7YHi87H6Eu1PNaDX3A" alt=""><figcaption><p>call to ZwTerminateProcess</p></figcaption></figure>

<figure><img src="/files/YZf52kV4hT3QAQbrdnfO" alt=""><figcaption><p>IOCTL code checks</p></figcaption></figure>

### 5) When the dispatch function receives an unrecognized IOCTL or a NULL input buffer, it returns a specific NTSTATUS code. What is it in hex?

In the above picture we can see a hardcoded status code, set up at the beginning of the function. If every IOCTL check fails, this code is returned. Otherwise the returned status code is <kbd><mark style="color:$primary;">STATUS\_SUCCESS<mark style="color:$primary;"></kbd>.

### 6) The driver maintains internal tracking arrays with a fixed capacity. How many entries can each array hold?

For this question I checked the contents of the <kbd><mark style="color:$primary;">.data<mark style="color:$primary;"></kbd> section because it is the only writable section of the PE file and is used to track various stuff. Inside this section we can see huge arrays, filled with NULL bytes. The size of these arrays is 8192 bytes. Dividing it with 8 bytes (size of a QWORD) returns 1024 entries that can be stored.

<figure><img src="/files/34TWllJZ6orMtXypLmoR" alt=""><figcaption><p>array in .data section</p></figcaption></figure>

<figure><img src="/files/7CJuAWX0gQpwsSeP0DPq" alt=""><figcaption><p>references to this array</p></figcaption></figure>

### 7) The driver registers a kernel callback to intercept handle operations at a specific altitude. What is this altitude number?

{% hint style="info" %}
To register object notifications. a kernel driver can register object-callback routines via calls to <kbd>nt!ObRegisterCallbacks</kbd>. Basically, when calling this API, a new callback operation is registered for a specific object type (<kbd>PsProcessType</kbd>, <kbd>PsThreadType</kbd> or <kbd>ExDesktopObjectType</kbd>). When setting up object-callback routines, multiple structs and members are involved. \
For example, the <kbd>Altitude</kbd> member of the <kbd>OB\_CALLBACK\_REGISTRATION</kbd> struct, defines the order in which the callback routines should be invoked.

Matt Hand - Evading EDR, p. 62ff

[ObRegisterCallbacks](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-obregistercallbacks)

[OB\_CALLBACK\_REGISTRATION structure](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_ob_callback_registration)

[OB\_OPERATION\_REGISTRATION structure](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_ob_operation_registration)
{% endhint %}

To answer this question, I searched for calls to the API <kbd><mark style="color:orange;">ObRegisterCallbacks<mark style="color:orange;"></kbd> and analyzed, how the different struct members of the <kbd><mark style="color:$primary;">OB\_CALLBACK\_REGISTRATION<mark style="color:$primary;"></kbd> struct are filled.

```c
typedef struct _OB_CALLBACK_REGISTRATION {
  USHORT                    Version;
  USHORT                    OperationRegistrationCount;
  UNICODE_STRING            Altitude;
  PVOID                     RegistrationContext;
  OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
```

In the pickture below, we can see how a unicode string is moved into the <kbd><mark style="color:$primary;">Altitude<mark style="color:$primary;"></kbd> member. This unicode string is treated as a decimal number in the struct.

<figure><img src="/files/aporJxiwTv1Ebqt3L4Qq" alt=""><figcaption><p>filling the OB_CALLBACK_REGISTRATION struct</p></figcaption></figure>

In case of this driver, the <kbd><mark style="color:$primary;">ObjectType<mark style="color:$primary;"></kbd> specified in the <kbd><mark style="color:$primary;">OB\_OPERATION\_REGISTRATION<mark style="color:$primary;"></kbd> struct is the <kbd><mark style="color:$primary;">PsProcessType<mark style="color:$primary;"></kbd>. This defines, that the callback routine is executed, everytime a handle to a process (in our case) is obtained.

```c
typedef struct _OB_OPERATION_REGISTRATION {
  POBJECT_TYPE                *ObjectType;
  OB_OPERATION                Operations;
  POB_PRE_OPERATION_CALLBACK  PreOperation;
  POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
```

In the picture below, we can see the <kbd><mark style="color:$primary;">PsProcessType<mark style="color:$primary;"></kbd> is moved into RAX and later moved into the <kbd><mark style="color:$primary;">OB\_OPERATION\_REGISTRATION<mark style="color:$primary;"></kbd> struct.

<figure><img src="/files/YWVpWXipnQBedfN4uk3g" alt=""><figcaption><p>ObjectType</p></figcaption></figure>

### 8) When the driver opens a handle to a process it is about to forcefully terminate, what handleattribute value (hex) does it request?

Before a process can be terminated via a call to <kbd><mark style="color:orange;">ZwTerminateProcess<mark style="color:orange;"></kbd>, a valid handle to this process must be obtained. To accomplish this, the malware uses the API <kbd><mark style="color:orange;">ObOpenObjectByPointer<mark style="color:orange;"></kbd>, which returns a handle to the desired object.

```c
NTSTATUS ObOpenObjectByPointer(
  [in]           PVOID           Object,
  [in]           ULONG           HandleAttributes,
  [in, optional] PACCESS_STATE   PassedAccessState,
  [in]           ACCESS_MASK     DesiredAccess,
  [in, optional] POBJECT_TYPE    ObjectType,
  [in]           KPROCESSOR_MODE AccessMode,
  [out]          PHANDLE         Handle
);
```

The handle is stored in a variable, pointed to by the last parameter of this API call. Additionally, we also find the answer for this question in this function.

<figure><img src="/files/m5HPTVKrGi4bAADK6P4R" alt=""><figcaption><p>function to terminate a specific process</p></figcaption></figure>

The <kbd><mark style="color:$primary;">HandleAttributes<mark style="color:$primary;"></kbd> value is an ORed combination of multiple values, defining the desired attributes for the object handle. In case of this kernel driver, this value is set to <kbd><mark style="color:$primary;">OBJ\_KERNEL\_HANDLE<mark style="color:$primary;"></kbd>. The values are defined in the <kbd><mark style="color:$primary;">ntdef.h<mark style="color:$primary;"></kbd> header file.

> [ntdef.h header file](https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/shared/ntdef.h)

### 9) What is the PDB filename embedded in the binary?

The answer can be found by statically examining the driver.

<figure><img src="/files/swxrjmK5T7cUWdVdoRtg" alt=""><figcaption><p>Malcat showing the Debug path</p></figcaption></figure>

### 10) The driver creates its device object with a specific device type constant. What is this value in hex?

A device object is created via a call to <kbd><mark style="color:orange;">IoCreateDevice<mark style="color:orange;"></kbd>. The <kbd><mark style="color:$primary;">DeviceType<mark style="color:$primary;"></kbd> parameter specifies the underlying hardware for the driver. [This type is later stored in the <kbd><mark style="color:$primary;">DEVICE\_OBJECT<mark style="color:$primary;"></kbd> structure.](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/specifying-device-types)

```c
NTSTATUS IoCreateDevice(
  [in]           PDRIVER_OBJECT  DriverObject,
  [in]           ULONG           DeviceExtensionSize,
  [in, optional] PUNICODE_STRING DeviceName,
  [in]           DEVICE_TYPE     DeviceType,
  [in]           ULONG           DeviceCharacteristics,
  [in]           BOOLEAN         Exclusive,
  [out]          PDEVICE_OBJECT  *DeviceObject
);
```

<figure><img src="/files/G1WgPxbLMbsGtms9NDFh" alt=""><figcaption></figcaption></figure>

In case of this driver, the <kbd><mark style="color:$primary;">DeviceType<mark style="color:$primary;"></kbd> <kbd><mark style="color:$primary;">FILE\_DEVICE\_UNKNOWN<mark style="color:$primary;"></kbd> will be created, represented by a specific hex value.

### 11) All four IOCTL codes are evenly spaced. What is the stride (difference) between consecutive codes?

Examining the function responsible for calling a specific function based on the <kbd><mark style="color:$primary;">IOCTL<mark style="color:$primary;"></kbd>, reveals that various calculations are performed alongside <kbd><mark style="color:$primary;">if-statements<mark style="color:$primary;"></kbd>.

<figure><img src="/files/qvgOEDwumOWBXdectBef" alt=""><figcaption><p>IOCTL code calculation</p></figcaption></figure>

### 12) Before the handle interception callback checks its internal tables, it performs a self-check to avoid interfering when a process operates on itself. What kernel API provides the current process pointer for this comparison?

In the above questions we understood, that the kernel driver uses callbacks to monitor handle operations in regards to processes.

The function used as a callback routine is moved onto the stack too, similar to the <kbd><mark style="color:$primary;">PsProcessType<mark style="color:$primary;"></kbd> described above.

<figure><img src="/files/YjdptrFNP8XrkV3FnUmo" alt=""><figcaption><p>setting up a callback routine</p></figcaption></figure>

This function performs several checks, also if the current process is the same like the process it is operating on.

<figure><img src="/files/CjldOJH9321eaXQ202sE" alt=""><figcaption></figcaption></figure>

### 13) After unregistering the handle interception callback during driver teardown, the registration handle global is set to a specific value. What is it?

Every <kbd><mark style="color:$primary;">DRIVER\_OBJECT<mark style="color:$primary;"></kbd> struct also contains a member (<kbd><mark style="color:$primary;">DriverUnload<mark style="color:$primary;"></kbd>) that points to a function, that is called when the driver is unloaded. In the first questions we were able to see, how this member is filled with a pointer to an unloading function.&#x20;

<figure><img src="/files/8dXcWei9M3iOiOPF1ZbX" alt=""><figcaption><p>DriverUnload function</p></figcaption></figure>

This function is responsible for removing various callback routines and device objects, but also for removing the registered object callback routine (highlighted line).

<figure><img src="/files/vHL4hojopf2uEX3bZ1Ab" alt=""><figcaption><p>unregistering the object callback routine</p></figcaption></figure>

A NULL-pointer is assigned to the global registration handle variable.

### 14) The handle interception monitors two types of operations simultaneously. What is the combined flag value (decimal) in the operation registration structure?

The <kbd><mark style="color:$primary;">OperationRegistration<mark style="color:$primary;"></kbd> member is filled via stack operations. Then the stack address is moved into this member (at 0x140001581).&#x20;

<figure><img src="/files/PRiaGP3fzgF8AA21JTwQ" alt=""><figcaption></figcaption></figure>

The <kbd><mark style="color:$primary;">Operations<mark style="color:$primary;"></kbd> member specifies, if the callback routines should be executed if new handles are created or if they will be duplicated (<kbd><mark style="color:$primary;">OB\_OPERATION\_HANDLE\_CREATE<mark style="color:$primary;"></kbd> and <kbd><mark style="color:$primary;">OB\_OPERATION\_HANDLE\_DUPLICATE<mark style="color:$primary;"></kbd>).

### 15) The termination function must release a reference on the process object before returning. What kernel API performs this dereferencing?

During the function responsible for terminating the desired process, a specific API is called to release references on process objects. This happens before returning.

<figure><img src="/files/x7nQ5eLLyQBVDcnDOqXa" alt=""><figcaption><p>process termination function</p></figcaption></figure>

### 16) During initialization, the driver registers a notification callback for image loading events. The function registered for this purpose is unusually small. What is its size in bytes (hex)?

A callback routine for image loading events is set up via a call to the <kbd><mark style="color:orange;">PsSetLoadImageNotifyRoutine<mark style="color:orange;"></kbd> API. Like other notifications, a function will be executed on image loading (e.g. DLL, EXE) events. The function set as <kbd><mark style="color:$primary;">NotifyRoutine<mark style="color:$primary;"></kbd> is small and visible in the picture below.

<figure><img src="/files/CTz1ZZchp5dv0JSNAr9L" alt=""><figcaption><p>setting up an image notify routine</p></figcaption></figure>

### 17) The address of the function that the driver assigns as its DriverUnload handler is what?

<figure><img src="/files/wShrTdD1Pwsxr5kL4VNy" alt=""><figcaption><p>function prologue of the driver unload function</p></figcaption></figure>

***

## Continuation of work

Since I am interested in how BYOVD attacks are used to interfere negatively with processes of security tools, I decided to take a deeper look into the whole situation here.\
The blog post of the Malops team provided information regarding the [CVE-2025-68947](https://nvd.nist.gov/vuln/detail/CVE-2025-68947) abused here.

> Sources:
>
> <https://nvd.nist.gov/vuln/detail/CVE-2025-68947>
>
> <https://www.sentinelone.com/vulnerability-database/cve-2025-68947/>
>
> <https://undercodetesting.com/kernel-panic-how-a-single-ioctl-bug-cve-2025-68947-lets-hackers-kill-any-process-on-your-machine/>
>
> <https://hexastrike.com/resources/blog/threat-intelligence/valleyrat-exploiting-byovd-to-kill-endpoint-security/>
>
> <https://vx-underground.org/Malware%20Analysis/2025/2025-09-07%20-%20ValleyRAT%20Exploiting%20BYOVD%20to%20Kill%20Endpoint%20Security>

### CVE-2025-68947

The NSecKrnl driver for Windows allows local and authenticated attackers to terminate processes owned by other users, but also SYSTEM or Protected Processes. To achieve this goal, the attacker used crafted IOCTL requests to the driver.

Regarding this CVE, SentinelOne mentions that the driver does not validate the authorization to request process termination. This means that, with specific IOCTL requests, target processes can be terminated even if the caller is not authorized to request it. A proper authorization check isn't implemented, as we were able to see while answering the questions for this challenge.

### Attack vector

In order to exploit the vulnerability in the NSecKrnl driver, the attacker must meet the following prerequisites (as per SentinelOne):

1. The attacker obtains or deploys the vulnerable NSecKrnl driver on the target system
2. The attacker opens a handle to the driver's device object
3. The attacker crafts IOCTL requests specifying target process identifiers
4. The driver executes the process termination with kernel-level privileges
5. Target processes, including security software, are forcibly terminated

### Own analysis

In order to understand BYOVD techniques better, I decided to take my own look into the user-mode application, responsible for controlling the driver, although there already exist some excellent and deep-technical writeups like the ones on the blog on [Hexastrike](https://hexastrike.com/resources/blog/threat-intelligence/valleyrat-exploiting-byovd-to-kill-endpoint-security/#elementor-toc__heading-anchor-4) and on [VXUG](https://vx-underground.org/Malware%20Analysis/2025/2025-09-07%20-%20ValleyRAT%20Exploiting%20BYOVD%20to%20Kill%20Endpoint%20Security). From their reports, I found the user-application with the SHA256 hash:

> b4ac2e473c5d6c5e1b8430a87ef4f33b53b9ba0f585d3173365e437de4c816b2

Instead of just reading the writeups, I decided to use my knowledge of the challenge and the answered questions, to find crucial aspects in the user-mode application, responsible for the communication with the device object and the deployment of the kernel driver itself.

#### Communication with the driver

From the analysis performed above, we know that the user-space application communicates via <kbd><mark style="color:$primary;">IOCTL<mark style="color:$primary;"></kbd> codes with the kernel driver. This happens via the API <kbd><mark style="color:orange;">DeviceIoControl<mark style="color:orange;"></kbd>.

<figure><img src="/files/cgvt9N3UFiqy0mNaHnW3" alt=""><figcaption><p>targeted processes</p></figcaption></figure>

<figure><img src="/files/1X6ZVWOOavlrfH5Ah5Qt" alt=""><figcaption><p>enumerating processes with calls to DeviceIoControl</p></figcaption></figure>

The malware fills multiple variables with hardcoded process names. Then, it creates a snapshot of all running processes via <kbd><mark style="color:orange;">CreateToolhelp32Snapshot<mark style="color:orange;"></kbd> and uses the gathered processes for a check with each process of the hardcoded list. For every targeted process (20 in total), a new snapshot is created and looped through until it finds a match. At address 0x140006D7F in the above picture we see, that the <kbd><mark style="color:$primary;">do-while loop<mark style="color:$primary;"></kbd> runs 20 times, checking each hardcoded process name individually with a snapshot taken before.

<figure><img src="/files/lCOJw4YqTzS3n42zErXl" alt=""><figcaption><p>matched process</p></figcaption></figure>

When a match is found, the malware proceeds with a call to <kbd><mark style="color:orange;">DeviceIoControl<mark style="color:orange;"></kbd> with the <kbd><mark style="color:$primary;">IOCTL<mark style="color:$primary;"></kbd> code, we discovered when analyzing the kernel driver. The third parameter (<kbd><mark style="color:$primary;">lpInBuffer<mark style="color:$primary;"></kbd>) is a pointer to a buffer, that contains information for the driver to perform the operation (in this case the PID of the targeted process).

#### Dropping the driver

The <kbd><mark style="color:$primary;">.rsrc section<mark style="color:$primary;"></kbd> of the user-mode application contains our driver in plaintext.

<figure><img src="/files/zawWp6ndQMyOpEqfseBW" alt=""><figcaption><p>begin of driver in .rsrc section</p></figcaption></figure>

The triage information, especially the file hashes of this PE file, are identical to the binary we analyzed during this challenge.

<figure><img src="/files/EL9Ay76iUXdFP0Hr5Nxw" alt=""><figcaption><p>Triage information about the driver</p></figcaption></figure>

This PE file is dropped into the <kbd><mark style="color:$primary;">Temp<mark style="color:$primary;"></kbd> directory during execution with a file name generated randomly.

<figure><img src="/files/xWLMiErNlgcpH6yFAtLB" alt=""><figcaption><p>dropped driver file with a random name</p></figcaption></figure>

#### Loading the driver

The dropped driver file is used to create a Registry key responsible for setting up a service (SYSTEM\CurrentControlSet\Services\\). Notable here is the service type 1, indicating a <kbd><mark style="color:$primary;">SERVICE\_KERNEL\_DRIVER<mark style="color:$primary;"></kbd>. The assignment happens through setting the value for the <kbd><mark style="color:$primary;">Type<mark style="color:$primary;"></kbd> key via a call to <kbd><mark style="color:orange;">RegSetKeyValueW<mark style="color:orange;"></kbd> with the value to be written as fifth parameter.

<figure><img src="/files/xXzPMs7Hdyx3kQ5NfWh1" alt=""><figcaption><p>modification of the ImagePath and Type keys during service setup</p></figcaption></figure>

After the Registry key has been created, the user-mode application loads the APIs <kbd><mark style="color:orange;">RtlAdjustPrivilege<mark style="color:orange;"></kbd> and <kbd><mark style="color:orange;">NtLoadDriver<mark style="color:orange;"></kbd> dynamically from <kbd><mark style="color:$primary;">ntdll.dll<mark style="color:$primary;"></kbd> and uses them, to escalate the privileges and load the driver, based on the set Registry key as the only parameter needed for a call to <kbd><mark style="color:orange;">NtLoadDriver<mark style="color:orange;"></kbd>.

<figure><img src="/files/VI3qWxNEDw5fowLI3nlG" alt=""><figcaption><p>instructions to load the driver manually</p></figcaption></figure>

<figure><img src="/files/jWAQrFXnznDu7q73FB1h" alt=""><figcaption><p>loaded NSecKrnl driver</p></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://txc.gitbook.io/documentation/writeups/malops.io/kernel-shield.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
