
Kernel-Mode-Prozessschutz-Treiber mit Benutzer-GUI
Kernel-Mode-Prozessschutz-Treiber, der ObRegisterCallbacks verwendet, um Speicherzugriffsberechtigungen von Handles zu entfernen. Einfache Implementierung, die Handle-Erstellung abfängt und PROCESS_VM_READ/WRITE/OPERATION bei unbefugten Zugriffsversuchen entfernt.


Hinweis: Falls das GIF nicht animiert, direkt auf Imgur ansehen
Der Treiber registriert OB-Callbacks auf der Höhe 321123 und fängt die Vorgänge OB_OPERATION_HANDLE_CREATE und OB_OPERATION_HANDLE_DUPLICATE ab. Wenn ein Prozess versucht, ein Handle auf ein geschütztes Ziel zu öffnen, überprüfen wir den Quellprozessnamen anhand einer Whitelist (explorer.exe, csrss.exe, svchost.exe, MsMpEng.exe, RuntimeBroker.exe) und entfernen die Zugriffsrechte, wenn dieser nicht erlaubt ist.
Die aktuelle Implementierung verwendet namensbasierte Übereinstimmung mittels PsGetProcessImageFileName (undokumentierte API). Die Schutzliste wird über eine verkettete Liste mit Spinlock-Synchronisation verwaltet. Ein Worker-Thread existiert, aber die Aktualisierungslogik ist noch nicht implementiert.
Die Benutzermodus-Komponente bietet eine ImGui-GUI zum Hinzufügen von Prozessen zur Schutzliste. Die Kommunikation erfolgt über IOCTL-Codes über den Symlink \\Device\\Aegis mittels METHOD_BUFFERED-Transfer. Der Treiber erstellt einen Symlink von \\DosDevices\\Aegis nach \\Device\\Aegis, sodass der Benutzermodus über \\\\.\\Aegis darauf zugreifen kann.
Kernel (km/):
driver.c - DriverEntry, OB-Registrierung, IOCTL-Dispatcher, Geräte-/Symlink-Erstellungprotect_manager/ - Prozesslistenverwaltung, Worker-Thread (Aktualisierungslogik steht noch aus)Benutzermodus (um/):
client.cpp - Hauptschleife, ImGui-Rendering, Fensterverwaltunggui/ - DirectX 11 + ImGui-Setup, benutzerdefinierte Schriftarten (Gilroy)service_manager/ - SCM-Integration zum Laden/Entladen des Treibersioctl_manager/ - DeviceIoControl-Wrapper für die Treiberkommunikation321123 (Standard für Drittanbieter ist 321000+, höher gesetzt, um Kollisionen zu vermeiden)PsGetProcessImageFileName – undokumentierte API, die nur den .exe-Dateinamen zurückgibt (max. 15 Zeichen)KSPIN_LOCK-Operationen auf DISPATCH_LEVEL (IRQL 2), um Race Conditions zu verhindernNonPagedPool für protect_manager (immer im RAM, schnellerer Zugriff, begrenzter Pool)PagedPool für einzelne Prozessstrukturen (können ausgelagert werden)KEVENT für asynchrone Verarbeitung (derzeit nur Stub)METHOD_BUFFERED für sichere Pufferbehandlung, Gerätetyp 0x8000 (Drittanbieterbereich)SERVICE_DEMAND_STARTDeviceIoControl mit IOCTL-Codes, die in der gemeinsamen ioctl.h definiert sindOB-Callback-Registrierung:
// Register OB callbacks for handle creation/duplication
OB_CALLBACK_REGISTRATION ob_registration = { 0 };
OB_OPERATION_REGISTRATION op_registration = { 0 };
RtlSecureZeroMemory(&ob_registration, sizeof(ob_registration));
RtlSecureZeroMemory(&op_registration, sizeof(op_registration));
op_registration.ObjectType = PsProcessType;
op_registration.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
// we care about duplication because smart hackers or malware, often do not create handles
// but duplicate current ones to not arouse suspicion
op_registration.PreOperation = pre_open_process;
RtlInitUnicodeString(&ob_registration.Altitude, L"321123");
// 321000 is standard for 3rd party drivers, we set it a bit higher to not have collision
status = ObRegisterCallbacks(&ob_registration, ®_handle);
Handle-Zugriffsentfernung:
OB_PREOP_CALLBACK_STATUS pre_open_process(PVOID reg_context, POB_PRE_OPERATION_INFORMATION info)
{
if (info->ObjectType == *PsProcessType) {
PEPROCESS proc = (PEPROCESS)info->Object;
char* process_name = (char*)PsGetProcessImageFileName(proc);
// Lock list at DISPATCH_LEVEL to prevent BSOD
KIRQL irql;
KeAcquireSpinLock(&g_protect_manager->list_lock, &irql);
// Check if process is in protection list
for (entry = g_protect_manager->process_list.Flink;
entry != &g_protect_manager->process_list;
entry = entry->Flink) {
pprocess proces = CONTAINING_RECORD(entry, process, entry);
if (strcmp(proces->path, process_name) == 0) {
// Check source process - allow system processes
PEPROCESS source_process = IoGetCurrentProcess();
char* source_name = (char*)PsGetProcessImageFileName(source_process);
if (strcmp(source_name, "explorer.exe") == 0 ||
strcmp(source_name, "csrss.exe") == 0 || ...) {
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
return OB_PREOP_SUCCESS;
}
// Strip VM_READ, VM_WRITE, VM_OPERATION (0x1, 0x10, 0x20)
// We don't set to 0 because it can cause bugs
info->Parameters->CreateHandleInformation.DesiredAccess &= ~(0x1 | 0x10 | 0x20);
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
return OB_PREOP_SUCCESS;
}
}
KeReleaseSpinLock(&g_protect_manager->list_lock, irql);
}
return OB_PREOP_SUCCESS;
}
Prozesslistenverwaltung:
NTSTATUS protect_manager_protect_process(pprotect_manager self, pprocess process)
{
// KIRQL (Kernel Interrupt Request Level) 0-31 tells CPU to not disturb
// 0 = PASSIVE_LEVEL, 2 = DISPATCH_LEVEL, 31 = HIGH_LEVEL
KIRQL irql;
// Acquire spinlock, raises IRQL to DISPATCH_LEVEL (2)
// Locks the list so it doesn't change while we edit
KeAcquireSpinLock(&self->list_lock, &irql);
InsertTailList(&self->process_list, &process->entry);
KeReleaseSpinLock(&self->list_lock, &irql);
// Signal worker thread to refresh
self->refresh_needed = TRUE;
KeSetEvent(&self->worker_event, 0, FALSE); // FALSE = auto revert IRQL
return STATUS_SUCCESS;
}
Benutzermodus-IOCTL-Kommunikation:
bool ioctl_manager::check(std::string name)
{
// Open driver device via symlink \\\\.\\Aegis -> \\Device\\Aegis
this->driver_object = CreateFile(this->path, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
// Send process name to driver via IOCTL
result = DeviceIoControl(this->driver_object, IOCTL_PROTECT_PID,
(LPVOID)data.c_str(), data.size() + 1,
NULL, 0, &bytes_returned, NULL);
CloseHandle(this->driver_object); // don't forget to close handles
return result;
}
Der gesamte Code ist ausführlich mit Erklärungen zu Kernel-Konzepten, IRQL-Ebenen, Speicherverwaltung und potenziellen Fallstricken kommentiert. Sehen Sie sich gerne die Quelle an – sie ist lehrreich und gut dokumentiert.
bcdedit /set testsigning on)Build-Ergebnisse: km.sys (Treiber) und um.exe (Benutzermodus-App).
OB_OPERATION_HANDLE_CREATE, Duplikationsangriffe möglichprotect_manager.c ist leerExAllocatePool statt ExAllocatePool2PsActiveProcessHead, Treiberverstecken aus PsLoadedModuleListNur zu Bildungszwecken. Verwendet undokumentierte APIs, die mit Windows-Updates kaputtgehen können. Erfordert Testsigungsmodus oder ordnungsgemäße Codesignierung, um ausgeführt zu werden.