summaryrefslogtreecommitdiff
path: root/general/obcallback/driver/callback.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /general/obcallback/driver/callback.c
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/obcallback/driver/callback.c')
-rw-r--r--general/obcallback/driver/callback.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/general/obcallback/driver/callback.c b/general/obcallback/driver/callback.c
new file mode 100644
index 00000000..39ecd1b4
--- /dev/null
+++ b/general/obcallback/driver/callback.c
@@ -0,0 +1,479 @@
+
+// Callback functions for Ob sample code tests.
+//
+// Notice:
+//
+// Use this sample code at your own risk; there is no support from Microsoft for the sample code.
+// In addition, this sample code is licensed to you under the terms of the Microsoft Public License
+// (http://www.microsoft.com/opensource/licenses.mspx)
+//
+//
+
+
+#include "pch.h"
+#include "tdriver.h"
+
+//
+// Globals
+//
+
+KGUARDED_MUTEX TdCallbacksMutex;
+BOOLEAN bCallbacksInstalled = FALSE;
+
+
+#define CB_PROCESS_TERMINATE 0x0001
+#define CB_THREAD_TERMINATE 0x0001
+
+// The following are for setting up callbacks for Process and Thread filtering
+PVOID pCBRegistrationHandle = NULL;
+
+OB_CALLBACK_REGISTRATION CBObRegistration = { 0 };
+OB_OPERATION_REGISTRATION CBOperationRegistrations[2] = { { 0 }, { 0 } };
+UNICODE_STRING CBAltitude = {0};
+TD_CALLBACK_REGISTRATION CBCallbackRegistration = {0};
+
+// Here is the protected process
+WCHAR TdwProtectName[NAME_SIZE+1] = {0};
+PVOID TdProtectedTargetProcess = NULL;
+HANDLE TdProtectedTargetProcessId = {0};
+
+
+//
+// TdDeleteProtectNameCallback
+//
+NTSTATUS TdDeleteProtectNameCallback ()
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdDeleteProtectNameCallback entering\n");
+
+ KeAcquireGuardedMutex (&TdCallbacksMutex);
+
+ // if the callbacks are active - remove them
+ if (bCallbacksInstalled == TRUE) {
+ ObUnRegisterCallbacks(pCBRegistrationHandle);
+ pCBRegistrationHandle = NULL;
+ bCallbacksInstalled = FALSE;
+ }
+
+
+ KeReleaseGuardedMutex (&TdCallbacksMutex);
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdDeleteProtectNameCallback exiting - status 0x%x\n", Status
+ );
+
+ return Status;
+}
+
+
+//
+// TdProtectNameCallback
+//
+
+NTSTATUS TdProtectNameCallback (
+ _In_ PTD_PROTECTNAME_INPUT pProtectName
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!pProtectName) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
+ "ObCallbackTest: TdProtectNameCallback: name to protect/filter NULL pointer\n"
+ );
+ }
+ else {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdProtectNameCallback: entering name to protect/filter %ls\n", pProtectName->Name
+ );
+ }
+ KeAcquireGuardedMutex (&TdCallbacksMutex);
+
+ // Need to copy out the name and then set the flag to filter
+ // This will allow process creation to watch for the process to be created and get the PID
+ // and then prevent any other process from opening up that PID to terminate
+
+ memcpy(TdwProtectName, pProtectName->Name, sizeof(TdwProtectName));
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: name copied %ls\n", TdwProtectName
+ );
+
+ // Need to enable the OB callbacks
+ // once the process is matched to a newly created process, the callbacks will protect the process
+ if (bCallbacksInstalled == FALSE) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdProtectNameCallback: installing callbacks\n"
+ );
+
+ // Setup the Ob Registration calls
+
+ CBOperationRegistrations[0].ObjectType = PsProcessType;
+ CBOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_CREATE;
+ CBOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
+ CBOperationRegistrations[0].PreOperation = CBTdPreOperationCallback;
+ CBOperationRegistrations[0].PostOperation = CBTdPostOperationCallback;
+
+ CBOperationRegistrations[1].ObjectType = PsThreadType;
+ CBOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_CREATE;
+ CBOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE;
+ CBOperationRegistrations[1].PreOperation = CBTdPreOperationCallback;
+ CBOperationRegistrations[1].PostOperation = CBTdPostOperationCallback;
+
+
+ RtlInitUnicodeString (&CBAltitude, L"1000");
+
+ CBObRegistration.Version = OB_FLT_REGISTRATION_VERSION;
+ CBObRegistration.OperationRegistrationCount = 2;
+ CBObRegistration.Altitude = CBAltitude;
+ CBObRegistration.RegistrationContext = &CBCallbackRegistration;
+ CBObRegistration.OperationRegistration = CBOperationRegistrations;
+
+
+ Status = ObRegisterCallbacks (
+ &CBObRegistration,
+ &pCBRegistrationHandle // save the registration handle to remove callbacks later
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
+ "ObCallbackTest: installing OB callbacks failed status 0x%x\n", Status
+ );
+ KeReleaseGuardedMutex (&TdCallbacksMutex); // Release the lock before exit
+ goto Exit;
+ }
+ bCallbacksInstalled = TRUE;
+
+ }
+
+
+ KeReleaseGuardedMutex (&TdCallbacksMutex);
+
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdProtectNameCallback: name to protect/filter %ls\n", TdwProtectName
+ );
+
+Exit:
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdProtectNameCallback: exiting status 0x%x\n", Status
+ );
+ return Status;
+}
+
+
+//
+// TdCheckProcessMatch - function to test a command line to see if the process is to be protected
+//
+NTSTATUS TdCheckProcessMatch (
+ _In_ PCUNICODE_STRING pustrCommand,
+ _In_ PEPROCESS Process,
+ _In_ HANDLE ProcessId
+)
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ WCHAR CommandLineBuffer[NAME_SIZE + 1] = {0}; // force a NULL termination
+ USHORT CommandLineBytes = 0;
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: entering\n");
+
+ if (!pustrCommand || !pustrCommand->Buffer) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: no Command line provided\n"
+ );
+ Status = FALSE;
+ goto Exit;
+ }
+ else {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: checking for %ls\n", TdwProtectName
+ );
+ }
+
+ KeAcquireGuardedMutex (&TdCallbacksMutex);
+
+
+ // Make sure that the CommandLineBuffer is NULL terminated
+ if (pustrCommand->Length < (NAME_SIZE * sizeof(WCHAR)))
+ CommandLineBytes = pustrCommand->Length;
+ else
+ CommandLineBytes = NAME_SIZE * sizeof(WCHAR);
+
+ if (CommandLineBytes) {
+ memcpy(CommandLineBuffer, pustrCommand->Buffer, CommandLineBytes);
+
+ // now check if the process to protect is in the command line
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: command line %ls\n", CommandLineBuffer
+ );
+
+ if (NULL != wcsstr (CommandLineBuffer, TdwProtectName)) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: match FOUND\n"
+ );
+
+ // Set the process to watch
+ TdProtectedTargetProcess = Process;
+ TdProtectedTargetProcessId = ProcessId;
+
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else {
+ Status = FALSE; // no command line buffer provided
+ }
+
+ KeReleaseGuardedMutex (&TdCallbacksMutex);
+
+
+Exit:
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: TdCheckProcessMatch: leaving status 0x%x\n", Status
+ );
+ return Status;
+}
+
+
+//
+// CBTdPreOperationCallback
+//
+OB_PREOP_CALLBACK_STATUS
+CBTdPreOperationCallback (
+ _In_ PVOID RegistrationContext,
+ _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo
+)
+{
+ PTD_CALLBACK_REGISTRATION CallbackRegistration;
+
+ ACCESS_MASK AccessBitsToClear = 0;
+ ACCESS_MASK AccessBitsToSet = 0;
+ ACCESS_MASK InitialDesiredAccess = 0;
+ ACCESS_MASK OriginalDesiredAccess = 0;
+
+
+ PACCESS_MASK DesiredAccess = NULL;
+
+ LPCWSTR ObjectTypeName = NULL;
+ LPCWSTR OperationName = NULL;
+
+ // Not using driver specific values at this time
+ CallbackRegistration = (PTD_CALLBACK_REGISTRATION)RegistrationContext;
+
+
+ TD_ASSERT (PreInfo->CallContext == NULL);
+
+ // Only want to filter attempts to access protected process
+ // all other processes are left untouched
+
+ if (PreInfo->ObjectType == *PsProcessType) {
+ //
+ // Ignore requests for processes other than our target process.
+ //
+
+ // if (TdProtectedTargetProcess != NULL &&
+ // TdProtectedTargetProcess != PreInfo->Object)
+ if (TdProtectedTargetProcess != PreInfo->Object)
+ {
+ goto Exit;
+ }
+
+ //
+ // Also ignore requests that are trying to open/duplicate the current
+ // process.
+ //
+
+ if (PreInfo->Object == PsGetCurrentProcess()) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: CBTdPreOperationCallback: ignore process open/duplicate from the protected process itself\n");
+ goto Exit;
+ }
+
+ ObjectTypeName = L"PsProcessType";
+ AccessBitsToClear = CB_PROCESS_TERMINATE;
+ AccessBitsToSet = 0;
+ }
+ else if (PreInfo->ObjectType == *PsThreadType) {
+ HANDLE ProcessIdOfTargetThread = PsGetThreadProcessId ((PETHREAD)PreInfo->Object);
+
+ //
+ // Ignore requests for threads belonging to processes other than our
+ // target process.
+ //
+
+ // if (CallbackRegistration->TargetProcess != NULL &&
+ // CallbackRegistration->TargetProcessId != ProcessIdOfTargetThread)
+ if (TdProtectedTargetProcessId != ProcessIdOfTargetThread) {
+ goto Exit;
+ }
+
+ //
+ // Also ignore requests for threads belonging to the current processes.
+ //
+
+ if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: CBTdPreOperationCallback: ignore thread open/duplicate from the protected process itself\n");
+ goto Exit;
+ }
+
+ ObjectTypeName = L"PsThreadType";
+ AccessBitsToClear = CB_THREAD_TERMINATE;
+ AccessBitsToSet = 0;
+ }
+ else {
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
+ "ObCallbackTest: CBTdPreOperationCallback: unexpected object type\n");
+ goto Exit;
+ }
+
+ switch (PreInfo->Operation) {
+ case OB_OPERATION_HANDLE_CREATE:
+ DesiredAccess = &PreInfo->Parameters->CreateHandleInformation.DesiredAccess;
+ OriginalDesiredAccess = PreInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess;
+
+ OperationName = L"OB_OPERATION_HANDLE_CREATE";
+ break;
+
+ case OB_OPERATION_HANDLE_DUPLICATE:
+ DesiredAccess = &PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
+ OriginalDesiredAccess = PreInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess;
+
+ OperationName = L"OB_OPERATION_HANDLE_DUPLICATE";
+ break;
+
+ default:
+ TD_ASSERT (FALSE);
+ break;
+ }
+
+ InitialDesiredAccess = *DesiredAccess;
+
+ // Filter only if request made outside of the kernel
+ if (PreInfo->KernelHandle != 1) {
+ *DesiredAccess &= ~AccessBitsToClear;
+ *DesiredAccess |= AccessBitsToSet;
+ }
+
+ //
+ // Set call context.
+ //
+
+ TdSetCallContext (PreInfo, CallbackRegistration);
+
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: CBTdPreOperationCallback: PROTECTED process %p (ID 0x%p)\n",
+ TdProtectedTargetProcess,
+ (PVOID)TdProtectedTargetProcessId
+ );
+
+ DbgPrintEx (
+ DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL,
+ "ObCallbackTest: CBTdPreOperationCallback\n"
+ " Client Id: %p:%p\n"
+ " Object: %p\n"
+ " Type: %ls\n"
+ " Operation: %ls (KernelHandle=%d)\n"
+ " OriginalDesiredAccess: 0x%x\n"
+ " DesiredAccess (in): 0x%x\n"
+ " DesiredAccess (out): 0x%x\n",
+ PsGetCurrentProcessId(),
+ PsGetCurrentThreadId(),
+ PreInfo->Object,
+ ObjectTypeName,
+ OperationName,
+ PreInfo->KernelHandle,
+ OriginalDesiredAccess,
+ InitialDesiredAccess,
+ *DesiredAccess
+ );
+
+Exit:
+
+ return OB_PREOP_SUCCESS;
+}
+
+//
+// TdPostOperationCallback
+//
+
+VOID
+CBTdPostOperationCallback (
+ _In_ PVOID RegistrationContext,
+ _In_ POB_POST_OPERATION_INFORMATION PostInfo
+ )
+{
+ PTD_CALLBACK_REGISTRATION CallbackRegistration = (PTD_CALLBACK_REGISTRATION)RegistrationContext;
+
+ TdCheckAndFreeCallContext (PostInfo, CallbackRegistration);
+
+ if (PostInfo->ObjectType == *PsProcessType) {
+ //
+ // Ignore requests for processes other than our target process.
+ //
+
+ if (CallbackRegistration->TargetProcess != NULL &&
+ CallbackRegistration->TargetProcess != PostInfo->Object
+ ) {
+ return;
+ }
+
+ //
+ // Also ignore requests that are trying to open/duplicate the current
+ // process.
+ //
+
+ if (PostInfo->Object == PsGetCurrentProcess()) {
+ return;
+ }
+ }
+ else if (PostInfo->ObjectType == *PsThreadType) {
+ HANDLE ProcessIdOfTargetThread = PsGetThreadProcessId ((PETHREAD)PostInfo->Object);
+
+ //
+ // Ignore requests for threads belonging to processes other than our
+ // target process.
+ //
+
+ if (CallbackRegistration->TargetProcess != NULL &&
+ CallbackRegistration->TargetProcessId != ProcessIdOfTargetThread
+ ) {
+ return;
+ }
+
+ //
+ // Also ignore requests for threads belonging to the current processes.
+ //
+
+ if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) {
+ return;
+ }
+ }
+ else {
+ TD_ASSERT (FALSE);
+ }
+
+}
+