-
Notifications
You must be signed in to change notification settings - Fork 1
/
blister.c
192 lines (157 loc) · 9.35 KB
/
blister.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <ntddk.h>
#include "customTypes.h"
#include "macros.h"
#include "core.h"
// function and globals definitions
DRIVER_UNLOAD UnloadDriver;
BlisterState driverState = { 0 };
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UNREFERENCED_PARAMETER(RegistryPath);
UNREFERENCED_PARAMETER(DriverObject);
NTSTATUS returnValue;
HANDLE hThread = NULL;
OB_CALLBACK_REGISTRATION obOpenProcPre = { 0 };
INFO("blister has started\n");
// initialize a mutex and protected process lists
// since driverState is a global variable and multiple functions / threads
// can access, read and modify the members of the structure concurrently
// we need to initialize the Lock guarded mutex (KGUARDED_MUTEX)
KeInitializeGuardedMutex(&driverState.Lock);
InitializeListHead(&driverState.SelfProtectedProcesses);
InitializeListHead(&driverState.ActiveSelfProtectedProcesses);
// set the driver unload function to UnloadDriver
DriverObject->DriverUnload = UnloadDriver;
INFO("Mutex and list initialized properly\n");
// set the callbacks required to turn user-land processes into PPLs
// set the ImageLoadCallbackPtr pointer in the driver callbacks to the
// pointer of the ImageLoadNotifyCallback function and set it with
// PsSetLoadImageNotifyRoutine
// @referece https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutine
driverState.Callbacks.ImageLoadNotify.ImageLoadCallbackPtr = ImageLoadNotifyCallback;
returnValue = PsSetLoadImageNotifyRoutine(driverState.Callbacks.ImageLoadNotify.ImageLoadCallbackPtr);
if (!NT_SUCCESS(returnValue)) {
ERROR("PsSetLoadImageNotifyRoutine failed to set ImageLoadNotifyCallback callback\n");
goto PostInitialization;
}
// mark the callback as registered in the driver status structure
driverState.Callbacks.ImageLoadNotify.IsRegistered = TRUE;
SUCCESS("PsSetLoadImageNotifyRoutine successfully set ImageLoadNotifyCallback callback\n");
// set the CreateProcessNotify pointer in the driver callbacks to the
// pointer of the PCreateProcessNotifyRoutineEx function and set it with
// PsSetCreateProcessNotifyRoutineEx
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutineex
driverState.Callbacks.ProcessNotify.CreateProcessNotifyPtr = PcreateProcessNotifyRoutineEx;
returnValue = PsSetCreateProcessNotifyRoutineEx(driverState.Callbacks.ProcessNotify.CreateProcessNotifyPtr, FALSE);
if (!NT_SUCCESS(returnValue)) {
ERROR("PsSetCreateProcessNotifyRoutineEx failed to set PCreateProcessNotifyRoutineEx callback\n");
goto PostInitialization;
}
// mark the callback as registered in the other driver status structure
driverState.Callbacks.ProcessNotify.IsRegistered = TRUE;
SUCCESS("PsSetCreateProcessNotifyRoutineEx successfully set PCreateProcessNotifyRoutineEx callback\n");
// set the OpenProcessNotify callback
// using the ObRegisterCallbacks function
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-obregistercallbacks
obOpenProcPre.Version = OB_FLT_REGISTRATION_VERSION; // default version
obOpenProcPre.OperationRegistrationCount = 1; // only one entry
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers#types-of-load-order-groups-and-their-altitude-ranges
UNICODE_STRING altitudeString;
RtlInitUnicodeString(&altitudeString, L"423851"); // initialize the altitude string to the Filter Load order group
obOpenProcPre.Altitude = altitudeString;
obOpenProcPre.RegistrationContext = NULL;
// allocate the OperationRegistration field with the blCb (blisterCallback) tag
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exallocatepool2
obOpenProcPre.OperationRegistration = (POB_OPERATION_REGISTRATION)ExAllocatePool2(POOL_FLAG_PAGED, sizeof(OB_OPERATION_REGISTRATION), 'blCb');
if (obOpenProcPre.OperationRegistration == NULL) {
returnValue = STATUS_UNSUCCESSFUL;
goto PostInitialization;
}
obOpenProcPre.OperationRegistration->ObjectType = PsProcessType;
// handle process creation and duplication so other processes can't
// get a privileged handle to the PPL through process duplication
obOpenProcPre.OperationRegistration->Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
// finally register the PobPreOperationCallback callback using ObRegisterCallbacks
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-obregistercallbacks
obOpenProcPre.OperationRegistration->PreOperation = PobPreOperationCallback;
returnValue = ObRegisterCallbacks(&obOpenProcPre, &driverState.Callbacks.OpenProcessNotify.RegistrationHandle);
if (!NT_SUCCESS(returnValue)) {
ERROR("ObRegisterCallbacks failed to set OpenProcessNotify callback\n");
goto PostInitialization;
}
// mark the callback as registered in the driver status structure
driverState.Callbacks.OpenProcessNotify.IsRegistered = TRUE;
PostInitialization:
// check if the rest of the DriverEntry function was successful
if (NT_SUCCESS(returnValue)) {
// create a thread to report the registered callbacks
OBJECT_ATTRIBUTES objectAttributes;
InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
returnValue = PsCreateSystemThread(&hThread, SYNCHRONIZE, &objectAttributes, NULL, NULL, ReportCallbacks, NULL);
if NT_SUCCESS(returnValue) {
INFO("Creating a PPL entry for the \"notepad.exe\" process\n");
// set a ProtectedProcessEntry with the process name "mimikatz.exe"
// we could also use a PID but that is obviously harder to hardcode
// allocate the entry with a tag of blEn (blisterEntry)
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exallocatepool2
UNICODE_STRING entryName = RTL_CONSTANT_STRING(L"notepad.exe");
ProtectedProcessEntry* entry = (ProtectedProcessEntry*)ExAllocatePool2(POOL_FLAG_PAGED, sizeof(ProtectedProcessEntry), 'blCb');
if (entry != NULL) {
// allocate a buffer for the process name with a tag of blPn (blisterProcessName)
entry->Name = (PUNICODE_STRING)ExAllocatePool2(POOL_FLAG_PAGED, sizeof(UNICODE_STRING), 'blCb');
// allocate a buffer for the string buffer with a tag of blBf (blisterBuffer)
entry->Name->Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, entryName.Length, 'blCb');
entry->Name->MaximumLength = entryName.Length;
// copy the name into the Name attribute of the entry
RtlCopyUnicodeString(entry->Name, &entryName);
// add the entry to the list of the processes to protect
InsertTailList(&driverState.SelfProtectedProcesses, &entry->CurEntry);
}
else {
ERROR("Failed to allocate entry for the protected process\n");
returnValue = STATUS_UNSUCCESSFUL;
}
}
}
// like after the PostInitialization label, check if the returnValue is negative
// meaning that the process of allocating, setting and adding the entry for mimikatz.exe
// into the list of processes to protect failed
// and we need to de-allocate all the buffers and un-register the callbacks
if (!NT_SUCCESS(returnValue)) {
// check if any notify routines were successfully registered
// if there are any, unregister them
// @reference https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-psremoveloadimagenotifyroutine
PCallbackState callbacks = &driverState.Callbacks;
// un-register ImageLoadNotify
if (callbacks->ImageLoadNotify.IsRegistered && callbacks->ImageLoadNotify.ImageLoadCallbackPtr != NULL) {
PsRemoveLoadImageNotifyRoutine(callbacks->ImageLoadNotify.ImageLoadCallbackPtr);
}
// un-register ProcessNotify
if (callbacks->ProcessNotify.IsRegistered && callbacks->ProcessNotify.CreateProcessNotifyPtr != NULL) {
PsSetCreateProcessNotifyRoutineEx(callbacks->ProcessNotify.CreateProcessNotifyPtr, TRUE);
}
// un-register OpenProcessNotify
if (callbacks->OpenProcessNotify.IsRegistered && callbacks->OpenProcessNotify.OpenProcessNotifyPtr != NULL) {
ObUnRegisterCallbacks(callbacks->OpenProcessNotify.RegistrationHandle);
}
// free the buffer with the tag blCb (blisterCallback) allocated
// to register the OpenProcess callback
if (obOpenProcPre.OperationRegistration != NULL) {
ExFreePoolWithTag(obOpenProcPre.OperationRegistration, 'blCb');
}
}
// close the thread handle if we have created it
if (hThread != NULL) {
ZwClose(hThread);
hThread = NULL;
}
INFO("blister is exiting\n");
return returnValue;
}
VOID UnloadDriver(IN PDRIVER_OBJECT DriverObject) {
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
PAGED_CODE();
if (deviceObject != NULL) {
IoDeleteDevice(deviceObject);
}
}