> For the complete documentation index, see [llms.txt](https://0xsec.gitbook.io/0xsec/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://0xsec.gitbook.io/0xsec/malware-analysis/sakdriver-reversing-a-kernel-driver-rootkit.md).

# SakDriver: Reversing a Kernel Driver Rootkit

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

Cobalt Strike is a paid penetration testing product that allows an attacker to deploy an agent named 'Beacon' on the victim machine. Beacon includes a lot of functionality to the attacker, including, but not limited to command execution, key logging, file transfer, SOCKS proxying, privilege escalation, mimikatz, port scanning and lateral movement. Beacon is in-memory/file-less, in that it consists of stageless or multi-stage shellcode that once loaded by exploiting a vulnerability or executing a shellcode loader, will reflectively load itself into the memory of a process without touching the disk. It supports C2 and staging over HTTP, HTTPS, DNS, SMB named pipes as well as forward and reverse TCP.

The Beacon implant has become popular amongst targeted attackers and criminal users as it is well written, stable, and highly customizable.

### Technical Analysis

Upon having the cobalt strike beacon sample I ran basic checks and tools to gather initial information about the agent. It uncovered that what i am looking at is not a user land beacon but a [kernel rootkit](https://www.securview.com/ai-security-essentials/kernel-rootkit) loading as a driver.

<figure><img src="/files/3QjF9w6eyOSPq6J9nanA" alt=""><figcaption></figcaption></figure>

It actively hooks and patches the **ETW**(Event Tracing for Windows) structure in kernel which blinds the defense system before it even logs an event. It also hides and unhides process via [DKOM](https://en.wikipedia.org/wiki/Direct_kernel_object_manipulation)(**Direct Kernel Object Manipulation**), hides the C2 communication port `NSI_HIDE_PORT` and unblocks IP `WFP_UNBLOCK_IP` using the [WFP](https://learn.microsoft.com/en-us/windows/win32/fwp/windows-filtering-platform-start-page)(**Windows Filtering Platform**) which is the core architecture behind the windows firewall.

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

It also has to do something with the time stamp counter in hypervisor likely when the rootkit is in a sandbox environment. The driver is named as `SakDriver` with a PDB path pointing to `E:\tools\oldfilelaoda\x64\Release\CrackerDrv.pdb` .

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

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

After loading it in IDA, in `DriverEntry` function which is the main entry function for a driver, it uses the [`DriverObject`](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_driver_object), created by I/O manager for each driver that has been installed and loaded which contains storage for entry points of driver routines such as `DriverEntry`, `Unload`, `MajorFunction` etc. and also information like `DriverName` .

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

<figure><img src="/files/2mpeGKSAgncXGt8FdioZ" alt=""><figcaption></figcaption></figure>

Now further in function, it use the member `DriverSection` (pointer to [`_KLDR_DATA_TABLE_ENTRY`](https://www.tssc.de/winint/Win11_22621_ntoskrnl/_KLDR_DATA_TABLE_ENTRY.htm) in kernel mode containing information about the loaded module) and sets the [unload routine](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nc-wdm-driver_unload) to `DriverUnload` after which it loads the DLL name from offset `0x48` .

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

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

Now if the driver is already present in system it then iterates through the `FullDllName->Buffer` to find string `\SystemRoot\System32\Drivers` using custom loop rather than using kernel API’s and search for driver’s name.

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

Then it calls a function which takes the driver name and opens a handle to the `\\Registry\\Machine\\System\\CurrentControlSet\\Services` (*store information about each service*), allocating a [Non-Paged memory](https://learn.microsoft.com/en-us/windows/win32/memory/memory-pools) region with **NX**(*No-Execute*) of `0x218` bytes with tag `CvrD` and then iterates over each subkey under `Services` and fills the `PoolWithTag` region with [`KEY_BASIC_INFORMATION`](https://ntdoc.m417z.com/key_basic_information) .

<figure><img src="/files/2WqniMGucAuD744zlSVX" alt=""><figcaption></figcaption></figure>

It then opens handle for the intended driver and query its `ImagePath` (*points to location of file*) and stores path into a global state then it registers the driver as a [minifilter driver](https://hackyboiz.github.io/2025/08/15/banda/Minifilter-Driver/en/) (*type of driver used to monitor, intercept and modify file system I/O requests*) and sets [`IRP_MJ_DIRECTORY_CONTROL`](https://github.com/tpn/winsdk-10/blob/master/Include/10.0.14393.0/km/wdm.h#L26589) as [MajorFunction](https://ntdoc.m417z.com/flt_operation_registration#majorfunction) to have control over directory I/O request to evade scans by AV softwares.

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

<figure><img src="/files/9tLduzqF2975aPanRa7O" alt=""><figcaption></figcaption></figure>

It then fingerprints OS information of the victimized user and prepares a POST request to send this info to a C2 server(`43.160.247.24`) at `/api/event.php` endpoint with a custom user-agent `SakDriver 1.0`.

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

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

In case, if it’s a fresh installation then it installs the driver into system at one of the paths`\\Device\\HarddiskVolume%lu\\Windows\\System32\\drivers\\DRIVER_NAME` , `\\??\\C:\\Windows\\System32\\drivers\\DRIVER_NAME` with naming `sak_XXX.sys` and the **XXX** is a random seed containing XOR’s of a memory region, frequency performance counter, PID and TID. Also it registers the service as `msXXXX` in registry at `\\Registry\\Machine\\System\\CurrentControlSet\\Services\\SERVICE_NAME` as `Microsoft Player Service` display name and `Provides support for %04X operations` as description to camouflage itself as a legitimate windows service and in case of error registers itself as `SakDriver` ( *Not OPSec friendly :)* ) and if everything goes right it sends `install_success` mark to C2 and deletes the dropper.

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

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

Now it queries system to get the memory address of `ntoskrnl.exe` , and then build its own Import Address Table(**IAT**) in memory to use kernel API’s by deobfuscating API names and resolving their address during runtime using `sub_14000E34C` which will take address of `ntoskrnl` and decrypted API name to manually parse PE header to find the Export Directory which will be used to get address of those API’s , it will also help to bypass EDR’s static scanning.

<figure><img src="/files/1xK0t9qpgsM0DlbDWZO1" alt=""><figcaption></figcaption></figure>

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

It then call `CmRegisterCallbackEx` to register a [RegistryCallback](https://learn.microsoft.com/windows-hardware/drivers/ddi/wdm/nc-wdm-ex_callback_function) routine, which is called every time a thread performs an operation on the registry. The registry callback function named `Function` performs function like If an AV software tries to modify the registry keys of rootkit, it catches that modification and throws `STATUS_ACCESS_DENIED` which will abort registry modification.

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

Here’s the interesting part, now what author did is, it is using its own registry callback to receive C2 commands from a user-mode agent. So if a user-mode agent writes the command in benign registry using user-land API’s it completely evades EDR scans, although for every write driver checks for a specific magic bytes `0x2625B7146B` and extracts commands from it.

<table><thead><tr><th width="140">Command ID</th><th>What It Does</th></tr></thead><tbody><tr><td>22661</td><td>Arbitrary Read/Write Process memory (attaches kernel thread to address space of target process, locks and map the memory to kernel then reads or writes into process memory)</td></tr><tr><td>13592</td><td>Performs <a href="https://wumb0.in/windows-10-kvas-and-software-smep.html">KVA Shadowing</a> bypass to inject and steal information from user-land process.</td></tr><tr><td>13129</td><td>Allocates memory in the victim process to perform <a href="https://redcanary.com/threat-detection-report/techniques/process-injection/">Process Injection</a></td></tr><tr><td>13128</td><td>Free the allocated memory after thread finish execution</td></tr><tr><td>12937</td><td>Copies data between 2 different process i.e. rootkit and user-land</td></tr><tr><td>10246</td><td>Attach to user-land process and parse the dll to locate the API names address ex. VirtualAlloc.</td></tr><tr><td>9072</td><td>Forcefully deletes the protected or executing files</td></tr><tr><td>8784</td><td>Kernel to User-mode DLL injection via Kernel APC queuing (parses PEB to locate kernel32.dll and finds address of LoadLibrary by parsing dll)</td></tr><tr><td>8306</td><td>Defensive measure by setting a callback whenever system does <strong>OpenProcess</strong> or <strong>OpenThread</strong> and intercept handle, threads opened for rootkit and strips out permissions like <strong>PROCESS_TERMINATE, PROCESS_QUERY_INFORMATION</strong> and also it bypass access rights for low privilege process to higher ones(setting access to <strong>PROCESS_ALL_ACCESS</strong>) specifically for <strong>v8(</strong><em><strong>still need to find out</strong></em><strong>).</strong></td></tr><tr><td>16964</td><td>Query memory for basic information about the region</td></tr><tr><td>22323</td><td>Read/Write to any physical memory address by read/writing to its virtual pointer which is obtained by building a custom page table with RW permissions and injecting that into empty space in <a href="https://connormcgarr.github.io/paging/">PML4</a>. Also copies data directly from physical address</td></tr><tr><td>13831</td><td>Resolves PID by process name</td></tr><tr><td>13664</td><td>Spoofs hardware to send packets in form of mouse or PS2 keyboard/mouse data and execute the callback with forged input.<br><code>\\Driver\\mouhid</code> and <code>\\Driver\\i8042prt</code></td></tr><tr><td>37720</td><td>Reads the memory of a process by querying <a href="https://rayanfam.com/topics/inside-windows-page-frame-number-part1/">PFN</a> database and mapping addresses</td></tr><tr><td>39029</td><td>Changes the protection of page</td></tr><tr><td>38536</td><td>Returns process section base address from EPROCESS structure</td></tr><tr><td>38435</td><td>Walks PEB of a process to loop through loaded DLLs and match it with attacker supplied name eg. kernel32.dll and returns base address of DLL</td></tr><tr><td>37973</td><td>Extracts driver name</td></tr><tr><td>29557</td><td>Deobfuscate APIs and gets their address also applies system wide hooks on <a href="https://windowsscriptingdotorg.wordpress.com/tag/circular-kernel-context-logger/">CKCL</a>, <a href="https://benjitrapp.github.io/defenses/2024-02-11-etw/">ETWP</a>, Syscall Table, <strong>HvlGetQpcBias</strong>, <strong>GetCpuClock.</strong> Else it scans <strong>win32kfull.sys</strong> for a specific pattern in text section to get address of undocumented function</td></tr><tr><td>29556</td><td>Spoofs hardware to send packets in form of keyboard or PS2 keyboard/mouse data and execute the callback. <code>\\Driver\\kbdhid</code> and <code>\\Driver\\i8042prt</code></td></tr><tr><td>25736</td><td>Perform Hardware spoofing for <a href="https://deepwiki.com/FiYHer/EASY-HWID-SPOOFER/4.1-disk-spoofing">Disk</a>, <a href="https://github.com/roomyoni/Nvidia-GPU-Spoof/blob/main/SpoofGPU.h">Nvidia GPU</a>, <a href="https://www.unknowncheats.me/forum/anti-cheat-bypass/395788-spoofing-smbios-help.html">SMBIOS</a></td></tr><tr><td>25897</td><td>Executes a user thread with attackers DLL/ malicious function</td></tr><tr><td>29462</td><td><a href="https://web.archive.org/web/20250318163756/https://captain-woof.medium.com/ghostly-reflective-pe-loader-how-to-make-a-remote-process-inject-a-pe-in-itself-3b65f2083de0">Reflective PE loading</a></td></tr></tbody></table>

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

It then applies a stealth layer on the registry to avoid any read or write query on the drivers service by AV and EDRs.

These are the things it perform as a callback function, and now coming back to Main entry it now perform Network filtering by blocking the requests made by security solutions to C2 IP and port. It also hides some ports like **6891, 12341, 12342, 12343, 6543, 7543, 9199** by hooking **NSI** driver.

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

Then it tries to create a [WFP device object](https://medium.com/@s12deff/building-a-windows-network-filter-driver-intercepting-outbound-connections-b604c366008c) so that it can observe the network stack and adds `just-do-it.icu` and `91.99.165.207` to the blocking table.

### IOCs

* Domain and IP: `just-do-it.icu, 91.99.165.207, 43.160.247.24` and these domain and IPs haven’t been flagged by VirusTotal yet and infra is still working.
* Ports: **6891, 12341, 12342, 12343, 6543, 7543, 9199**

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

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

<figure><img src="/files/5nc5jCikikYEa3icee03" alt=""><figcaption></figcaption></figure>

* Endpoint: `/api/event.php`&#x20;
* Hash: `4e95aba17c1a423cda5cc9f9f04f7cf8db17e294eb31ed1aa85063601b82fe8d`
* Driver name: **SakDriver, sak\_xxx.sys, ms\_xxxx**

### Yara Rule

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

```c
rule SakDriver_Rootkit {
    meta:
        description = "Detects an advanced Windows kernel rootkit featuring ETW/CKCL hooking, NSI manipulation, HWID spoofing, and WFP."
        author = "0xSec"
        date = "2026-07-26"

    strings:
        /*
            Use of ntoskrnl.exe / ntkrnlpa.exe
        */
        $ntoskrnl_str = "ntoskrnl.exe" ascii
        $ntkrnlpa_str = "ntkrnlpa.exe" ascii

        $ascii_str1 = "AWAVAUATASARAQAPPQSRUTVW" ascii
        $ascii_str2 = "_^\\]Z[YXAXAYAZA[" ascii

        /*
            Encrypted API Strings
        */
        $enc_api_alloc   = "iCtZ[WZ[OYkWM44#/\t +(:0J" ascii // ZwAllocateVirtualMemory
        $enc_api_win32k  = "lkB_Y\x0b\x0bQHHH\\`@" ascii       // __win32kstub_
        $enc_api_ntuser  = "}@`ERJhO^NDiV.%-4D" ascii       // NtUserQueryWindow

        /*
           WFP Targets
        */
        $domain       = "just-do-it.icu" ascii wide
        $ip           = "91.99.165.207" ascii wide
        $dev_sakdriver   = "\\Device\\SakDriverWFP" ascii wide

        /*
           Debug Strings
        */
        $dbg_etw_hook    = "[%s] ssdt call back ptr is 0x%p" ascii
        $dbg_khook_init  = "k_hook::Initialize" ascii
        $dbg_nsi_hide    = "[NSI] Adding default hidden ports..." ascii
        $dbg_wfp_fail    = "Failed to start auto-unblock thread" ascii
        $dbg_wfp_ip_block = "Failed to add IP to block list." ascii

        /*
            HWID spoof strings
        */
        $hwid_mouse = "\\Driver\\mouhid" ascii
        $hwid_keyboard = "\\Driver\\kbdhid" ascii
        $hwid_gpu = "\\Driver\\nvlddmkm" ascii
        $hwid_ps2 = "\\Driver\\i8042prt" ascii

    condition:
        uint16(0) == 0x5A4D // PE magic
        and filesize < 5MB
        and (
            ($ascii_str1 and $ascii_str2)
            and all of ($hwid_*)
            or ($ntoskrnl_str and $ntkrnlpa_str)
            or 2 of ($enc_api_*)
            or ($dev_sakdriver and $domain and $ip)
            or all of ($dbg_*)
        )
}

```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://0xsec.gitbook.io/0xsec/malware-analysis/sakdriver-reversing-a-kernel-driver-rootkit.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
