/* * KProcessHacker * * Copyright (C) 2010-2016 wj32 * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ #include #include DRIVER_INITIALIZE DriverEntry; DRIVER_UNLOAD DriverUnload; __drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate; __drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose; ULONG KphpReadIntegerParameter( __in_opt HANDLE KeyHandle, __in PUNICODE_STRING ValueName, __in ULONG DefaultValue ); NTSTATUS KphpReadDriverParameters( __in PUNICODE_STRING RegistryPath ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, DriverEntry) #pragma alloc_text(PAGE, DriverUnload) #pragma alloc_text(PAGE, KphpReadIntegerParameter) #pragma alloc_text(PAGE, KphpReadDriverParameters) #pragma alloc_text(PAGE, KpiGetFeatures) #endif PDRIVER_OBJECT KphDriverObject; PDEVICE_OBJECT KphDeviceObject; ULONG KphFeatures; KPH_PARAMETERS KphParameters; NTSTATUS DriverEntry( __in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING RegistryPath ) { NTSTATUS status; UNICODE_STRING deviceName; PDEVICE_OBJECT deviceObject; PAGED_CODE(); KphDriverObject = DriverObject; if (!NT_SUCCESS(status = KphDynamicDataInitialization())) return status; KphDynamicImport(); if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath))) return status; // Create the device. RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME); status = IoCreateDevice( DriverObject, 0, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject ); if (!NT_SUCCESS(status)) return status; KphDeviceObject = deviceObject; // Set up I/O. DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl; DriverObject->DriverUnload = DriverUnload; deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; dprintf("Driver loaded\n"); return status; } VOID DriverUnload( __in PDRIVER_OBJECT DriverObject ) { PAGED_CODE(); IoDeleteDevice(KphDeviceObject); dprintf("Driver unloaded\n"); } NTSTATUS KphDispatchCreate( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION stackLocation; PFILE_OBJECT fileObject; PIO_SECURITY_CONTEXT securityContext; PKPH_CLIENT client; stackLocation = IoGetCurrentIrpStackLocation(Irp); fileObject = stackLocation->FileObject; securityContext = stackLocation->Parameters.Create.SecurityContext; dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId()); if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck || KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) { UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)]; PPRIVILEGE_SET requiredPrivileges; // Check for SeDebugPrivilege. requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer; requiredPrivileges->PrivilegeCount = 1; requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY; requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE; requiredPrivileges->Privilege[0].Luid.HighPart = 0; requiredPrivileges->Privilege[0].Attributes = 0; if (!SePrivilegeCheck( requiredPrivileges, &securityContext->AccessState->SubjectSecurityContext, Irp->RequestorMode )) { status = STATUS_PRIVILEGE_NOT_HELD; dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId()); } } if (NT_SUCCESS(status)) { client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK'); if (client) { memset(client, 0, sizeof(KPH_CLIENT)); ExInitializeFastMutex(&client->StateMutex); ExInitializeFastMutex(&client->KeyBackoffMutex); fileObject->FsContext = client; } else { dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId()); status = STATUS_INSUFFICIENT_RESOURCES; } } Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS KphDispatchClose( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION stackLocation; PFILE_OBJECT fileObject; PKPH_CLIENT client; stackLocation = IoGetCurrentIrpStackLocation(Irp); fileObject = stackLocation->FileObject; client = fileObject->FsContext; if (client) { ExFreePoolWithTag(client, 'ChpK'); } Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } /** * Reads an integer (REG_DWORD) parameter from the registry. * * \param KeyHandle A handle to the Parameters key. If NULL, the function * fails immediately and returns \a DefaultValue. * \param ValueName The name of the parameter. * \param DefaultValue The value that is returned if the function fails * to retrieve the parameter from the registry. * * \return The parameter value, or \a DefaultValue if the function failed. */ ULONG KphpReadIntegerParameter( __in_opt HANDLE KeyHandle, __in PUNICODE_STRING ValueName, __in ULONG DefaultValue ) { NTSTATUS status; UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)]; PKEY_VALUE_PARTIAL_INFORMATION info; ULONG resultLength; PAGED_CODE(); if (!KeyHandle) return DefaultValue; info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer; status = ZwQueryValueKey( KeyHandle, ValueName, KeyValuePartialInformation, info, sizeof(buffer), &resultLength ); if (info->Type != REG_DWORD) status = STATUS_OBJECT_TYPE_MISMATCH; if (!NT_SUCCESS(status)) { dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status); return DefaultValue; } return *(PULONG)info->Data; } /** * Reads the driver parameters. * * \param RegistryPath The registry path of the driver. */ NTSTATUS KphpReadDriverParameters( __in PUNICODE_STRING RegistryPath ) { NTSTATUS status; HANDLE parametersKeyHandle; UNICODE_STRING parametersString; UNICODE_STRING parametersKeyName; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING valueName; PAGED_CODE(); // Open the Parameters key. RtlInitUnicodeString(¶metersString, L"\\Parameters"); parametersKeyName.Length = RegistryPath->Length + parametersString.Length; parametersKeyName.MaximumLength = parametersKeyName.Length; parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK'); if (!parametersKeyName.Buffer) return STATUS_INSUFFICIENT_RESOURCES; memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length); memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length); InitializeObjectAttributes( &objectAttributes, ¶metersKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL ); status = ZwOpenKey( ¶metersKeyHandle, KEY_READ, &objectAttributes ); ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK'); if (!NT_SUCCESS(status)) { dprintf("Unable to open Parameters key: 0x%x\n", status); status = STATUS_SUCCESS; parametersKeyHandle = NULL; // Continue so we can set up defaults. } // Read in the parameters. RtlInitUnicodeString(&valueName, L"SecurityLevel"); KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck); KphReadDynamicDataParameters(parametersKeyHandle); if (parametersKeyHandle) ZwClose(parametersKeyHandle); return status; } NTSTATUS KpiGetFeatures( __out PULONG Features, __in KPROCESSOR_MODE AccessMode ) { PAGED_CODE(); if (AccessMode != KernelMode) { __try { ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG)); *Features = KphFeatures; } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } else { *Features = KphFeatures; } return STATUS_SUCCESS; }