
Driver di protezione dei processi in modalità kernel con interfaccia utente GUI
Driver di protezione dei processi in modalità kernel che utilizza ObRegisterCallbacks per rimuovere i permessi di accesso alla memoria dagli handle. Implementazione di base che intercetta la creazione degli handle e rimuove PROCESS_VM_READ/WRITE/OPERATION dai tentativi di accesso non autorizzati.


Nota: Se la GIF non si anima, visualizzala direttamente su Imgur
Il driver registra callback OB all'altitudine 321123 e intercetta le operazioni OB_OPERATION_HANDLE_CREATE e OB_OPERATION_HANDLE_DUPLICATE. Quando un processo tenta di aprire un handle verso un target protetto, controlliamo il nome del processo sorgente rispetto a una whitelist (explorer.exe, csrss.exe, svchost.exe, MsMpEng.exe, RuntimeBroker.exe) e rimuoviamo i diritti di accesso se non è consentito.
L'implementazione attuale utilizza un matching basato sul nome tramite PsGetProcessImageFileName (API non documentata). La lista di protezione è gestita tramite una lista concatenata con sincronizzazione spinlock. Esiste un thread worker, ma la logica di aggiornamento non è ancora implementata.
Il componente in modalità utente fornisce un'interfaccia ImGui per aggiungere processi alla lista di protezione. La comunicazione avviene tramite codici IOCTL sul symlink \\Device\\Aegis usando il trasferimento METHOD_BUFFERED. Il driver crea un symlink da \\DosDevices\\Aegis a \\Device\\Aegis in modo che la modalità utente possa accedervi tramite \\\\.\\Aegis.
Kernel (km/):
driver.c - DriverEntry, registrazione OB, dispatcher IOCTL, creazione device/symlinkprotect_manager/ - Gestione lista processi, thread worker (logica di aggiornamento in sospeso)Modalità utente (um/):
client.cpp - Loop principale, rendering ImGui, gestione finestregui/ - Configurazione DirectX 11 + ImGui, font personalizzati (Gilroy)service_manager/ - Integrazione SCM per caricamento/scaricamento driverioctl_manager/ - Wrapper DeviceIoControl per comunicazione con driver321123 (lo standard di terze parti è 321000+, impostato più alto per evitare collisioni)PsGetProcessImageFileName - API non documentata che restituisce solo il nome del file .exe (massimo 15 caratteri)KSPIN_LOCK a DISPATCH_LEVEL (IRQL 2) per prevenire condizioni di competizioneNonPagedPool per protect_manager (sempre in RAM, accesso più veloce, pool limitato)PagedPool per le strutture dei singoli processi (possono essere messe in pagina)KEVENT per elaborazione asincrona (attualmente stub)METHOD_BUFFERED per la gestione sicura del buffer, tipo dispositivo 0x8000 (range terze parti)SERVICE_DEMAND_STARTDeviceIoControl con codici IOCTL definiti in ioctl.h condivisoRegistrazione callback OB:
// 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);
Rimozione accesso handle:
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;
}
Gestione lista processi:
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;
}
Comunicazione IOCTL in modalità utente:
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;
}
Tutto il codice è accuratamente commentato con spiegazioni sui concetti del kernel, i livelli IRQL, la gestione della memoria e le potenziali insidie. Sentiti libero di consultare il sorgente: è educativo e ben documentato.
bcdedit /set testsigning on)Output di build: km.sys (driver) e um.exe (app modalità utente).
OB_OPERATION_HANDLE_CREATE, attacchi di duplicazione possibiliprotect_manager.c è vuotaExAllocatePool invece di ExAllocatePool2PsActiveProcessHead, nascondere driver da PsLoadedModuleListSolo a scopo educativo. Utilizza API non documentate che potrebbero rompersi con gli aggiornamenti di Windows. Richiede il test signing o una firma del codice appropriata per essere eseguito.