
Driver de proteção de processos em modo kernel com GUI de usuário
Driver de proteção de processos em modo kernel usando ObRegisterCallbacks para remover permissões de acesso à memória de handles. Implementação básica que intercepta a criação de handles e remove PROCESS_VM_READ/WRITE/OPERATION de tentativas de acesso não autorizadas.


Nota: Se o GIF não animar, veja-o diretamente no Imgur
O driver registra callbacks OB na altitude 321123 e intercepta as operações OB_OPERATION_HANDLE_CREATE e OB_OPERATION_HANDLE_DUPLICATE. Quando um processo tenta abrir um handle para um alvo protegido, verificamos o nome do processo de origem contra uma lista de permissão (explorer.exe, csrss.exe, svchost.exe, MsMpEng.exe, RuntimeBroker.exe) e removemos os direitos de acesso se não for permitido.
A implementação atual usa correspondência baseada em nome com PsGetProcessImageFileName (API não documentada). A lista de proteção é gerenciada por meio de uma lista encadeada com sincronização por spinlock. Existe uma thread de trabalho, mas a lógica de atualização ainda não foi implementada.
O componente em modo de usuário fornece uma GUI ImGui para adicionar processos à lista de proteção. A comunicação ocorre por meio de códigos IOCTL sobre o link simbólico \\Device\\Aegis usando transferência METHOD_BUFFERED. O driver cria um link simbólico de \\DosDevices\\Aegis para \\Device\\Aegis para que o modo de usuário possa acessá-lo via \\\\.\\Aegis.
Kernel (km/):
driver.c - DriverEntry, registro OB, dispatcher IOCTL, criação de dispositivo/link simbólicoprotect_manager/ - Gerenciamento da lista de processos, thread de trabalho (lógica de atualização pendente)Modo de usuário (um/):
client.cpp - Loop principal, renderização ImGui, gerenciamento de janelasgui/ - Configuração DirectX 11 + ImGui, fontes personalizadas (Gilroy)service_manager/ - Integração com SCM para carregar/descarregar o driverioctl_manager/ - Wrapper DeviceIoControl para comunicação com o driver321123 (o padrão de terceiros é 321000+, definido mais alto para evitar colisões)PsGetProcessImageFileName – API não documentada que retorna apenas o nome do arquivo .exe (máx. 15 caracteres)KSPIN_LOCK em DISPATCH_LEVEL (IRQL 2) para evitar condições de corridaNonPagedPool para protect_manager (sempre na RAM, acesso mais rápido, pool limitado)PagedPool para estruturas de processo individuais (podem ser paginadas)KEVENT para processamento assíncrono (atualmente um esboço)METHOD_BUFFERED para manipulação segura de buffers, tipo de dispositivo 0x8000 (faixa de terceiros)SERVICE_DEMAND_STARTDeviceIoControl com códigos IOCTL definidos no ioctl.h compartilhadoRegistro de callback OB:
// Registrar callbacks OB para criação/duplicação de handles
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;
// nos importamos com duplicação porque hackers inteligentes ou malwares muitas vezes não criam handles
// mas duplicam os existentes para não levantar suspeitas
op_registration.PreOperation = pre_open_process;
RtlInitUnicodeString(&ob_registration.Altitude, L"321123");
// 321000 é o padrão para drivers de terceiros, definimos um pouco mais alto para não ter colisão
status = ObRegisterCallbacks(&ob_registration, ®_handle);
Remoção de acesso ao 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);
// Bloquear lista em DISPATCH_LEVEL para evitar BSOD
KIRQL irql;
KeAcquireSpinLock(&g_protect_manager->list_lock, &irql);
// Verificar se o processo está na lista de proteção
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) {
// Verificar processo de origem – permitir processos do sistema
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;
}
// Remover VM_READ, VM_WRITE, VM_OPERATION (0x1, 0x10, 0x20)
// Não definimos como 0 porque pode causar 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;
}
Gerenciamento da lista de processos:
NTSTATUS protect_manager_protect_process(pprotect_manager self, pprocess process)
{
// KIRQL (Kernel Interrupt Request Level) 0-31 diz à CPU para não incomodar
// 0 = PASSIVE_LEVEL, 2 = DISPATCH_LEVEL, 31 = HIGH_LEVEL
KIRQL irql;
// Adquirir spinlock, eleva IRQL para DISPATCH_LEVEL (2)
// Bloqueia a lista para que não mude enquanto editamos
KeAcquireSpinLock(&self->list_lock, &irql);
InsertTailList(&self->process_list, &process->entry);
KeReleaseSpinLock(&self->list_lock, irql);
// Sinalizar thread de trabalho para atualizar
self->refresh_needed = TRUE;
KeSetEvent(&self->worker_event, 0, FALSE); // FALSE = reverter IRQL automaticamente
return STATUS_SUCCESS;
}
Comunicação IOCTL do modo de usuário:
bool ioctl_manager::check(std::string name)
{
// Abrir dispositivo do driver via link simbólico \\\\.\\Aegis -> \\Device\\Aegis
this->driver_object = CreateFile(this->path, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
// Enviar nome do processo ao 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); // não esquecer de fechar handles
return result;
}