diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys index 77f7e46f3..c9ca9c6c3 100644 Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ diff --git a/trunk/KProcessHacker/include/kprocesshacker.h b/trunk/KProcessHacker/include/kprocesshacker.h index 6cb96eba0..c3ac00dc4 100644 --- a/trunk/KProcessHacker/include/kprocesshacker.h +++ b/trunk/KProcessHacker/include/kprocesshacker.h @@ -81,10 +81,16 @@ #define KPH_TIMEOUT_TO_SEC ((LONGLONG) 1 * 10 * 1000 * 1000) #define KPH_REL_TIMEOUT_IN_SEC(Time) (Time * -1 * KPH_TIMEOUT_TO_SEC) +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); +VOID DriverUnload(PDRIVER_OBJECT DriverObject); NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp); +BOOLEAN AddClientEntry(HANDLE ProcessId); +BOOLEAN IsProcessClient(HANDLE ProcessId); +BOOLEAN RemoveClientEntry(HANDLE ProcessId); + #endif \ No newline at end of file diff --git a/trunk/KProcessHacker/include/protect.h b/trunk/KProcessHacker/include/protect.h index ea111d18e..e250a3004 100644 --- a/trunk/KProcessHacker/include/protect.h +++ b/trunk/KProcessHacker/include/protect.h @@ -38,6 +38,7 @@ typedef struct _KPH_PROCESS_ENTRY { LIST_ENTRY ListEntry; PEPROCESS Process; + PEPROCESS CreatorProcess; HANDLE Tag; LOGICAL AllowKernelMode; ACCESS_MASK ProcessAllowMask; diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c index 654daf83e..38c28ec5d 100644 --- a/trunk/KProcessHacker/kprocesshacker.c +++ b/trunk/KProcessHacker/kprocesshacker.c @@ -28,6 +28,17 @@ #include "include/ps.h" #include "include/version.h" +typedef struct _KPH_CLIENT_ENTRY +{ + LIST_ENTRY ListEntry; + HANDLE ProcessId; +} KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY; + +LIST_ENTRY ClientListHead; +KSPIN_LOCK ClientListLock; +NPAGED_LOOKASIDE_LIST ClientLookasideList; +static BOOLEAN ProtectionInitialized = FALSE; + #pragma alloc_text(PAGE, KphDispatchCreate) #pragma alloc_text(PAGE, KphDispatchClose) #pragma alloc_text(PAGE, KphDispatchDeviceControl) @@ -35,25 +46,6 @@ #pragma alloc_text(PAGE, KphUnsupported) #pragma pack(1) -static BOOLEAN ProtectionInitialized = FALSE; - -VOID DriverUnload(PDRIVER_OBJECT DriverObject) -{ - UNICODE_STRING dosDeviceName; - - RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME); - IoDeleteSymbolicLink(&dosDeviceName); - IoDeleteDevice(DriverObject->DeviceObject); - - if (ProtectionInitialized) - { - KphProtectDeinit(); - ProtectionInitialized = FALSE; - } - - dprintf("Driver unloaded\n"); -} - NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { NTSTATUS status = STATUS_SUCCESS; @@ -78,6 +70,19 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) if (!NT_SUCCESS(status)) return status; + /* Initialize client list structures */ + InitializeListHead(&ClientListHead); + KeInitializeSpinLock(&ClientListLock); + ExInitializeNPagedLookasideList( + &ClientLookasideList, + NULL, + NULL, + 0, + sizeof(KPH_CLIENT_ENTRY), + KPH_TAG, + 0 + ); + RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME); RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME); @@ -105,6 +110,26 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) return STATUS_SUCCESS; } +VOID DriverUnload(PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING dosDeviceName; + + RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME); + IoDeleteSymbolicLink(&dosDeviceName); + IoDeleteDevice(DriverObject->DeviceObject); + + /* Destroy client list structures */ + ExDeleteNPagedLookasideList(&ClientLookasideList); + + if (ProtectionInitialized) + { + KphProtectDeinit(); + ProtectionInitialized = FALSE; + } + + dprintf("Driver unloaded\n"); +} + NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) { NTSTATUS status = STATUS_SUCCESS; @@ -119,6 +144,13 @@ NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) } #endif + /* Add a client entry. */ + if (!AddClientEntry(PsGetCurrentProcessId())) + { + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_INSUFFICIENT_RESOURCES; + } + dprintf("Client (PID %d) connected\n", PsGetCurrentProcessId()); dprintf("Base IOCTL is 0x%08x\n", KPH_CTL_CODE(0)); @@ -135,6 +167,9 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) dprintf("Removed %d protection entries\n", count); } + /* Remove the client entry. */ + RemoveClientEntry(PsGetCurrentProcessId()); + dprintf("Client (PID %d) disconnected\n", PsGetCurrentProcessId()); return status; @@ -149,6 +184,80 @@ VOID InitProtection() } } +BOOLEAN AddClientEntry(HANDLE ProcessId) +{ + KIRQL oldIrql; + PKPH_CLIENT_ENTRY entry = ExAllocateFromNPagedLookasideList(&ClientLookasideList); + + if (!entry) + return FALSE; + + KeAcquireSpinLock(&ClientListLock, &oldIrql); + InsertHeadList(&ClientListHead, &entry->ListEntry); + KeReleaseSpinLock(&ClientListLock, oldIrql); + + return TRUE; +} + +BOOLEAN IsProcessClient(HANDLE ProcessId) +{ + KIRQL oldIrql; + PLIST_ENTRY entry = ClientListHead.Flink; + + KeAcquireSpinLock(&ClientListLock, &oldIrql); + + while (entry != &ClientListHead) + { + PKPH_CLIENT_ENTRY clientEntry = + CONTAINING_RECORD(entry, KPH_CLIENT_ENTRY, ListEntry); + + if (clientEntry->ProcessId == ProcessId) + { + KeReleaseSpinLock(&ClientListLock, oldIrql); + + return TRUE; + } + + entry = entry->Flink; + } + + KeReleaseSpinLock(&ClientListLock, oldIrql); + + return FALSE; +} + +BOOLEAN RemoveClientEntry(HANDLE ProcessId) +{ + KIRQL oldIrql; + PLIST_ENTRY entry = ClientListHead.Flink; + + KeAcquireSpinLock(&ClientListLock, &oldIrql); + + while (entry != &ClientListHead) + { + PKPH_CLIENT_ENTRY clientEntry = + CONTAINING_RECORD(entry, KPH_CLIENT_ENTRY, ListEntry); + + if (clientEntry->ProcessId == ProcessId) + { + RemoveEntryList(&clientEntry->ListEntry); + ExFreeToNPagedLookasideList( + &ClientLookasideList, + clientEntry + ); + KeReleaseSpinLock(&ClientListLock, oldIrql); + + return TRUE; + } + + entry = entry->Flink; + } + + KeReleaseSpinLock(&ClientListLock, oldIrql); + + return FALSE; +} + /* from YAPM */ NTSTATUS GetObjectName(PFILE_OBJECT FileObject, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength) { diff --git a/trunk/KProcessHacker/protect.c b/trunk/KProcessHacker/protect.c index b6e5b7007..a9d5a394e 100644 --- a/trunk/KProcessHacker/protect.c +++ b/trunk/KProcessHacker/protect.c @@ -161,7 +161,7 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer( access = DesiredAccess; /* If we have an access state, get the desired access from it. */ - if (PassedAccessState != NULL) + if (PassedAccessState) access = PassedAccessState->OriginalDesiredAccess; /* Search for and copy the corresponding process protection entry. */ @@ -174,6 +174,8 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer( if ( /* check if kernel-mode is exempt from protection */ !(processEntry.AllowKernelMode && AccessMode == KernelMode) && + /* allow the creator of the rule to bypass protection */ + processEntry.CreatorProcess != PsGetCurrentProcess() && (access & mask) != access ) { @@ -228,10 +230,11 @@ PKPH_PROCESS_ENTRY KphProtectAddEntry( /* Lookaside list no longer needed. */ ExReleaseRundownProtection(&ProtectedProcessRundownProtect); - if (entry == NULL) + if (!entry) return NULL; entry->Process = Process; + entry->CreatorProcess = PsGetCurrentProcess(); entry->Tag = Tag; entry->AllowKernelMode = AllowKernelMode; entry->ProcessAllowMask = ProcessAllowMask; @@ -326,7 +329,7 @@ BOOLEAN KphProtectRemoveByProcess( { PKPH_PROCESS_ENTRY entry = KphProtectFindEntry(Process, NULL); - if (entry == NULL) + if (!entry) return FALSE; KphpProtectRemoveEntry(entry);