├── README.md ├── .gitignore └── Source ├── ProcCallback.vcxproj.filters ├── ProcCallback.sln ├── ProcCallback.vcxproj └── Source.cpp /README.md: -------------------------------------------------------------------------------- 1 | # ProcCallback 2 | An example of how a driver can register a handle creation callback. 3 | 4 | ## Disclaimer 5 | This is a proof-of-concept and is not meant to run on production machines 6 | 7 | ## Installation 8 | * bcdedit /set TESTSIGNING on 9 | * sc.exe create ProcCallback binPath= type= kernel 10 | * sc.exe start ProcCallback 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /Source/ProcCallback.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | -------------------------------------------------------------------------------- /Source/ProcCallback.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33213.308 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcCallback", "ProcCallback.vcxproj", "{5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|x64 = Debug|x64 12 | Release|ARM64 = Release|ARM64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|ARM64.ActiveCfg = Debug|ARM64 17 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|ARM64.Build.0 = Debug|ARM64 18 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|ARM64.Deploy.0 = Debug|ARM64 19 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|x64.ActiveCfg = Debug|x64 20 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|x64.Build.0 = Debug|x64 21 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Debug|x64.Deploy.0 = Debug|x64 22 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|ARM64.ActiveCfg = Release|ARM64 23 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|ARM64.Build.0 = Release|ARM64 24 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|ARM64.Deploy.0 = Release|ARM64 25 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|x64.ActiveCfg = Release|x64 26 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|x64.Build.0 = Release|x64 27 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97}.Release|x64.Deploy.0 = Release|x64 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {2BF00AD5-A6D9-4374-A969-2C0D7AD9E60C} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /Source/ProcCallback.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {5FC7BF11-F8F3-4548-A600-9FEF8BD67D97} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | ProcCallback 29 | 30 | 31 | 32 | Windows10 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | WDM 37 | false 38 | 39 | 40 | Windows10 41 | false 42 | WindowsKernelModeDriver10.0 43 | Driver 44 | WDM 45 | false 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | WDM 53 | 54 | 55 | Windows10 56 | false 57 | WindowsKernelModeDriver10.0 58 | Driver 59 | WDM 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | DbgengKernelDebugger 71 | 72 | 73 | DbgengKernelDebugger 74 | 75 | 76 | DbgengKernelDebugger 77 | 78 | 79 | DbgengKernelDebugger 80 | 81 | 82 | 83 | sha256 84 | 85 | 86 | /INTEGRITYCHECK %(AdditionalOptions) 87 | 88 | 89 | 90 | 91 | sha256 92 | 93 | 94 | 95 | /INTEGRITYCHECK %(AdditionalOptions) 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Source/Source.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Author: Jonathan Johnson (@jsecurity101) 3 | // 4 | 5 | 6 | #include 7 | 8 | #define DRIVER_TAG 'klbc' 9 | PVOID ProcessRegistrationHandle; 10 | UNICODE_STRING g_RegPath; 11 | NTSTATUS ProcCreateCloseCallback(PDEVICE_OBJECT DeviceObject, PIRP Irp); 12 | 13 | _IRQL_requires_max_(DISPATCH_LEVEL) 14 | NTSTATUS CompleteRequest(PIRP Irp, NTSTATUS status = STATUS_SUCCESS, ULONG_PTR info = 0); 15 | 16 | void ProcUnloadCallback(PDRIVER_OBJECT DriverObject); 17 | 18 | _IRQL_requires_max_(APC_LEVEL) 19 | NTSTATUS RegisterCallbacks(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject); 20 | 21 | _IRQL_requires_max_(APC_LEVEL) 22 | void PostProcessHandleCallback(PVOID RegistrationContext, POB_POST_OPERATION_INFORMATION OperationInformation); 23 | 24 | _IRQL_requires_max_(APC_LEVEL) 25 | OB_PREOP_CALLBACK_STATUS PreProcessHandleCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation); 26 | 27 | 28 | extern "C" 29 | NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { 30 | PAGED_CODE(); 31 | 32 | g_RegPath.Buffer = (PWSTR)ExAllocatePool2(POOL_FLAG_PAGED, 33 | RegistryPath->Length, DRIVER_TAG); 34 | 35 | if (g_RegPath.Buffer == NULL) { 36 | DbgPrint("Failed allocation\n"); 37 | return STATUS_INSUFFICIENT_RESOURCES; 38 | } 39 | 40 | g_RegPath.Length = g_RegPath.MaximumLength = RegistryPath->Length; 41 | memcpy(g_RegPath.Buffer, RegistryPath->Buffer, g_RegPath.Length); 42 | 43 | DbgPrint("ProcCallback Driver Entry Called 0x%p\n", DriverObject); 44 | DbgPrint("Registry Path %wZ\n", g_RegPath); 45 | 46 | DriverObject->DriverUnload = ProcUnloadCallback; 47 | DriverObject->MajorFunction[IRP_MJ_CREATE] = ProcCreateCloseCallback; 48 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = ProcCreateCloseCallback; 49 | 50 | UNICODE_STRING name; 51 | RtlInitUnicodeString(&name, L"\\Device\\ProcCallback"); 52 | PDEVICE_OBJECT DeviceObject; 53 | NTSTATUS status = IoCreateDevice(DriverObject, 0, &name, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject); 54 | 55 | if (!NT_SUCCESS(status)) { 56 | DbgPrint("Error creating device: 0x%X\n", status); 57 | ExFreePool(g_RegPath.Buffer); 58 | return status; 59 | } 60 | DriverObject->DeviceObject = DeviceObject; 61 | DeviceObject->Flags |= DO_DIRECT_IO; 62 | 63 | UNICODE_STRING symlink; 64 | RtlInitUnicodeString(&symlink, L"\\??\\ProcCallback"); 65 | status = IoCreateSymbolicLink(&symlink, &name); 66 | if (!NT_SUCCESS(status)) { 67 | DbgPrint("Error creating device: 0x%X\n", status); 68 | ExFreePool(g_RegPath.Buffer); 69 | IoDeleteDevice(DeviceObject); 70 | return status; 71 | } 72 | 73 | status = RegisterCallbacks(DriverObject, DeviceObject); 74 | if (!NT_SUCCESS(status)) { 75 | DbgPrint("Error registering callbacks: 0x%X\n", status); 76 | ExFreePool(g_RegPath.Buffer); 77 | return status; 78 | } 79 | 80 | ExFreePool(g_RegPath.Buffer); 81 | return status; 82 | } 83 | 84 | void ProcUnloadCallback(PDRIVER_OBJECT DriverObject) { 85 | UNREFERENCED_PARAMETER(DriverObject); 86 | PAGED_CODE(); 87 | 88 | ObUnRegisterCallbacks(ProcessRegistrationHandle); 89 | DbgPrint((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Pre/PostProcessHandleCallback Unloaded\n")); 90 | 91 | UNICODE_STRING symlink; 92 | RtlInitUnicodeString(&symlink, L"\\??\\ProcCallback"); 93 | IoDeleteSymbolicLink(&symlink); 94 | IoDeleteDevice(DriverObject->DeviceObject); 95 | DbgPrint("ProcCallback Driver Unloaded\n"); 96 | } 97 | 98 | 99 | //Function completes the driver requests 100 | _IRQL_requires_max_(DISPATCH_LEVEL) 101 | NTSTATUS CompleteRequest(PIRP Irp, NTSTATUS status, ULONG_PTR info) { 102 | PAGED_CODE(); 103 | Irp->IoStatus.Status = status; 104 | Irp->IoStatus.Information = info; 105 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 106 | return status; 107 | } 108 | 109 | //Function handles the create and close requests. Function just points to CompleteRequest. 110 | NTSTATUS ProcCreateCloseCallback(PDEVICE_OBJECT, PIRP Irp) { 111 | PAGED_CODE(); 112 | return CompleteRequest(Irp); 113 | } 114 | 115 | _IRQL_requires_max_(APC_LEVEL) 116 | NTSTATUS RegisterCallbacks(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject) { 117 | UNREFERENCED_PARAMETER(DeviceObject); 118 | UNREFERENCED_PARAMETER(DriverObject); 119 | PAGED_CODE(); 120 | NTSTATUS status; 121 | 122 | // Register OB_CALLBACK_REGISTRATION 123 | // Setting up callback for PsProcessType 124 | OB_CALLBACK_REGISTRATION CallbackRegistration; 125 | OB_OPERATION_REGISTRATION OperationRegistration; 126 | OperationRegistration.ObjectType = PsProcessType; 127 | OperationRegistration.Operations = OB_OPERATION_HANDLE_CREATE; 128 | OperationRegistration.PreOperation = PreProcessHandleCallback; 129 | OperationRegistration.PostOperation = PostProcessHandleCallback; 130 | 131 | // Set members 132 | UNICODE_STRING Altitude; 133 | RtlInitUnicodeString(&Altitude, L"385300"); 134 | CallbackRegistration.Version = OB_FLT_REGISTRATION_VERSION; 135 | CallbackRegistration.OperationRegistrationCount = 1; 136 | CallbackRegistration.Altitude = Altitude; 137 | CallbackRegistration.RegistrationContext = NULL; 138 | CallbackRegistration.OperationRegistration = &OperationRegistration; 139 | 140 | status = ObRegisterCallbacks(&CallbackRegistration, &ProcessRegistrationHandle); 141 | if (!NT_SUCCESS(status)) 142 | { 143 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed to load ObRegisterCallbacks : 0x%X\n", status); 144 | return status; 145 | } 146 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "ObRegisterCallbacks Loaded\n"); 147 | 148 | return status; 149 | } 150 | 151 | _IRQL_requires_max_(APC_LEVEL) 152 | void PostProcessHandleCallback(PVOID RegistrationContext, POB_POST_OPERATION_INFORMATION OperationInformation) { 153 | PAGED_CODE(); 154 | UNREFERENCED_PARAMETER(RegistrationContext); 155 | UNREFERENCED_PARAMETER(OperationInformation); 156 | 157 | ACCESS_MASK AccessRights = OperationInformation->Parameters->CreateHandleInformation.GrantedAccess; 158 | 159 | if (AccessRights != 0x0) { 160 | if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) { 161 | 162 | PEPROCESS openedProcess = (PEPROCESS)OperationInformation->Object; 163 | HANDLE targetPID = PsGetProcessId(openedProcess); 164 | HANDLE sourcePID = PsGetCurrentProcessId(); 165 | 166 | if (targetPID == sourcePID) { 167 | DbgPrint("Process %d created a handle to itself with access rights %d\n", sourcePID, AccessRights); 168 | } 169 | else { 170 | DbgPrint("Process %d created a handle to process %d with access rights %d\n", sourcePID, targetPID, AccessRights); 171 | } 172 | 173 | } 174 | } 175 | } 176 | 177 | _IRQL_requires_max_(APC_LEVEL) 178 | OB_PREOP_CALLBACK_STATUS PreProcessHandleCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation) { 179 | PAGED_CODE(); 180 | UNREFERENCED_PARAMETER(RegistrationContext); 181 | UNREFERENCED_PARAMETER(OperationInformation); 182 | 183 | if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE) { 184 | PEPROCESS openedProcess = (PEPROCESS)OperationInformation->Object; 185 | HANDLE targetPID = PsGetProcessId(openedProcess); 186 | HANDLE sourcePID = PsGetCurrentProcessId(); 187 | 188 | if (targetPID == (HANDLE)2972 && sourcePID == (HANDLE)9084) { 189 | if (OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess == PROCESS_ALL_ACCESS) { 190 | OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = 0x1000; 191 | DbgPrint("Changed rights from PROCESS_ALL_ACCESS to PROCESS_QUERY_LIMITED_ACCESS\n"); 192 | } 193 | 194 | } 195 | } 196 | 197 | return OB_PREOP_SUCCESS; 198 | } --------------------------------------------------------------------------------