Prologue
Kernel Drivers In 2022
Being an efficient backdoor with extremely evasive persistency.
Do highly privileged operations without the dependency of LPE exploit or privileged users.
Easily evade AV / EDR hooks.
Be able to hide your agent without suspicious user-mode hooks.
Create a driver to monitor and log specific events (like specially crafted Sysmon to meet your organization's needs.
Create kernel mode hooks to find advanced rootkits and malware.
Provide kernel mode protection to your blue agents (such as OSQuery, Wazuh, etc.).
Basic driver structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <ntddk.h>
extern "C"
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject->DriverUnload = MyUnload;
KdPrint(("Hello World!\n"));
return STATUS_SUCCESS;
}
void MyUnload(PDRIVER_OBJECT DriverObject) {
UNREFERENCED_PARAMETER(DriverObject);
KdPrint(("Goodbye World!\n"));
}
RegistryPath
is not used, we can use UNREFERENCED_PARAMETER
to optimize the variable.DriverEntry
is the first function that is called when the driver is loaded and it is very much like the main function for user-mode programs, except it gets two parameters:DriverObject: A pointer to the driver object.
RegistryPath: A pointer to a UNICODE_STRING structure that contains the path to the driver's registry key.
DriverObject
is an important object that will serve us a lot in the future, its definition is:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT, *PDRIVER_OBJECT;
MajorFunction
: This is an array of important functions that the driver can implement for IO management in different ways (direct or with IOCTLs), handling IRPs and more.MajorFunction
array). DriverUnload
function. This function will be responsible to stop callbacks and free any memory that was allocated.NTSTATUS
code, this code will be used to determine if the driver will be loaded or not.Testing a driver
bcdedit /set testsigning on
KdPrint
's output). To load the driver, you can use the following command:1
2
sc create DriverName type= kernel binPath= C:\Path\To\Driver.sys
sc start DriverName
sc stop DriverName
The attacker has found/generated a certificate (the expiration date doesn't matter).
The attacker has allowed test signing (just like we did now).
The attacker has a vulnerable driver with 1-day that allows loading drivers.
The attacker has a zero-day that allows load drivers.
Resources
Windows Kernel Programming.
Windows Internals Part 7.
MSDN (I know I said amazing, I lied here).