
커널 모드 프로세스 보호 드라이버 (사용자 GUI 포함)
커널 모드 프로세스 보호 드라이버로, ObRegisterCallbacks를 사용하여 핸들에서 메모리 접근 권한을 제거합니다. 핸들 생성에 후킹하여 PROCESS_VM_READ/WRITE/OPERATION을 무단 접근 시도에서 제거하는 기본적인 구현입니다.


참고: GIF가 애니메이션되지 않으면 Imgur에서 직접 보기
드라이버는 고도 321123에서 OB 콜백을 등록하고 OB_OPERATION_HANDLE_CREATE 및 OB_OPERATION_HANDLE_DUPLICATE 작업을 가로챕니다. 프로세스가 보호 대상에 대한 핸들을 열려고 할 때, 소스 프로세스 이름을 허용 목록(explorer.exe, csrss.exe, svchost.exe, MsMpEng.exe, RuntimeBroker.exe)과 비교하여 허용되지 않으면 접근 권한을 제거합니다.
현재 구현은 PsGetProcessImageFileName(비공식 API)을 사용한 이름 기반 매칭입니다. 보호 목록은 스핀락 동기화를 사용한 연결 리스트로 관리됩니다. 워커 스레드가 존재하지만 갱신 로직은 아직 구현되지 않았습니다.
사용자 모드 구성 요소는 보호 목록에 프로세스를 추가하기 위한 ImGui GUI를 제공합니다. 통신은 METHOD_BUFFERED 전송을 사용하여 \\Device\\Aegis 심볼릭 링크를 통해 IOCTL 코드로 이루어집니다. 드라이버는 \\DosDevices\\Aegis에서 \\Device\\Aegis로의 심볼릭 링크를 생성하여 사용자 모드가 \\\\.\\Aegis를 통해 접근할 수 있도록 합니다.
커널 (km/):
driver.c - DriverEntry, OB 등록, IOCTL 디스패처, 디바이스/심볼릭 링크 생성protect_manager/ - 프로세스 목록 관리, 워커 스레드 (갱신 로직 보류)사용자 모드 (um/):
client.cpp - 메인 루프, ImGui 렌더링, 창 관리gui/ - DirectX 11 + ImGui 설정, 사용자 정의 폰트 (Gilroy)service_manager/ - 드라이버 로딩/언로딩을 위한 SCM 통합ioctl_manager/ - 드라이버 통신을 위한 DeviceIoControl 래퍼321123으로 등록 (3rd party 표준은 321000 이상이며, 충돌을 피하기 위해 더 높게 설정)PsGetProcessImageFileName 사용 - .exe 파일명만 반환하는 비공식 API (최대 15자)KSPIN_LOCK 작업을 DISPATCH_LEVEL (IRQL 2)에서 수행하여 경쟁 조건 방지NonPagedPool은 protect_manager용 (항상 RAM에 있음, 빠른 접근, 제한된 풀)PagedPool은 개별 프로세스 구조용 (페이지 아웃 가능)KEVENT가 있는 시스템 스레드 (현재 스텁)METHOD_BUFFERED, 디바이스 타입 0x8000 (3rd party 범위)SERVICE_DEMAND_START로 "AegisDriver" 서비스 생성ioctl.h에 정의된 IOCTL 코드로 DeviceIoControl 사용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);
핸들 접근 제거:
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;
}
프로세스 목록 관리:
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;
}
사용자 모드 IOCTL 통신:
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;
}
모든 코드는 커널 개념, IRQL 레벨, 메모리 관리 및 잠재적 함정에 대한 자세한 설명이 포함되어 있습니다. 소스 코드를 확인해보세요 - 교육적이며 잘 문서화되어 있습니다.
bcdedit /set testsigning on)빌드 출력: km.sys (드라이버) 및 um.exe (사용자 모드 앱).
OB_OPERATION_HANDLE_CREATE만 처리, 복제 공격 가능protect_manager.c의 갱신 로직이 비어 있음ExAllocatePool2 대신 ExAllocatePool 사용PsActiveProcessHead에서 연결 해제로 프로세스 숨기기, PsLoadedModuleList에서 드라이버 숨기기교육 목적으로만 사용하십시오. Windows 업데이트에서 중단될 수 있는 비공식 API를 사용합니다. 실행하려면 테스트 서명 또는 적절한 코드 서명이 필요합니다.