前言:
熟悉驅動開發的人們都知道,在windows系統內,系統自動提供許多回調函數,比如,進程回調,模塊回調,注冊表回調,等等。但windows也提供了一些函數使得開發者也可以自定義回調。利用回調也可以實現驅動模塊間的通訊。相關函數如下:
//創建回調或者打開回調 NTSTATUS ExCreateCallback ( _Outptr_ PCALLBACK_OBJECT *CallbackObject, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ BOOLEAN Create, _In_ BOOLEAN AllowMultipleCallbacks ); //注冊回調 PVOID ExRegisterCallback ( _Inout_ PCALLBACK_OBJECT CallbackObject, _In_ PCALLBACK_FUNCTION CallbackFunction, _In_opt_ PVOID CallbackContext ); //回調通知 VOID ExNotifyCallback ( _In_ PVOID CallbackObject, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2 ); //回調例程 VOID CALLBACK_FUNC( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2);
相關函數用法,這里不做多介紹,自行查閱msdn學習。
這里寫一個測試例子,分為sender和receiver,sender注冊回調后創建一個線程,定時的通知receiver。
receiver打開回調,注冊回調,一旦接收到通知后,把數據打印出來。
//sender #include <ntifs.h> #define CALLBACKNAME L"\\Callback\\driverStart" VOID UnloadDriver(PDRIVER_OBJECT driver); VOID MyThread(PVOID context); BOOLEAN gbSuccess = 0; //線程句柄 HANDLE ghThread = NULL; //回調指針 PCALLBACK_OBJECT gpObjCallback = NULL; KEVENT gEvent; NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING registry) { UNREFERENCED_PARAMETER(registry); NTSTATUS status; OBJECT_ATTRIBUTES objAttri; driver->DriverUnload = UnloadDriver; //初始化通知事件 KeInitializeEvent(&gEvent, SynchronizationEvent, FALSE); UNICODE_STRING uniCallbackName = RTL_CONSTANT_STRING(CALLBACKNAME); //這里必須指定OBJ_PERMANENT屬性,否則會失敗 InitializeObjectAttributes(&objAttri, &uniCallbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL); //注冊回調對象 status = ExCreateCallback(&gpObjCallback, &objAttri, TRUE, TRUE); if (!NT_SUCCESS(status)) { KdPrint(("[sysTest] ExCreateCallback error code:(0x%x).\n", status)); return status; } //注冊成功 gbSuccess = 1; //創建線程,定期發送 ExNotifyCallback status = PsCreateSystemThread(&ghThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, MyThread, NULL); if (!NT_SUCCESS(status)) { KdPrint(("[sysTest] PsCreateSystemThread error code:(0x%x).\n", status)); return status; } status = STATUS_SUCCESS; return status; } VOID MyThread(PVOID context) { UNREFERENCED_PARAMETER(context); NTSTATUS status; ULONG type = 1; //ULONG ulData = 0; PCHAR ulData = "hello"; LARGE_INTEGER tick = { 0 }; //時間間隔是定位2秒 tick = RtlConvertLongToLargeInteger(-10 * 1000 * 1000 * 2); while (tick.QuadPart != 0) { //等待3秒 status = KeWaitForSingleObject(&gEvent, Executive, KernelMode, FALSE, &tick); if (STATUS_TIMEOUT != status) { break; } //通知 ExNotifyCallback(gpObjCallback, &type, ulData); KdPrint(("[sysTest] send.\n")); } KdPrint(("[sysTest] thread ended.\n")); PsTerminateSystemThread(STATUS_SUCCESS); } VOID UnloadDriver(PDRIVER_OBJECT driver) { UNREFERENCED_PARAMETER(driver); KeSetEvent(&gEvent, 0, TRUE); if (NULL != ghThread) { ZwWaitForSingleObject(ghThread, FALSE, NULL); ZwClose(ghThread); ghThread = NULL; } if (gbSuccess) { ObDereferenceObject(gpObjCallback); } KdPrint(("[sysTest] driver stoped.\n")); } //receiver #include <ntifs.h> #define CALLBACKNAME L"\\Callback\\driverStart" VOID UnloadDriver(_In_ PDRIVER_OBJECT driver); VOID CALLBACK_FUNC( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2); PCALLBACK_OBJECT gpObjCallback = NULL; BOOLEAN gbSuccess = 0; PVOID gpCookie = NULL; NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING registry) { UNREFERENCED_PARAMETER(registry); driver->DriverUnload = UnloadDriver; NTSTATUS status; UNICODE_STRING uniName = RTL_CONSTANT_STRING(CALLBACKNAME); OBJECT_ATTRIBUTES objAttri; InitializeObjectAttributes(&objAttri, &uniName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ExCreateCallback(&gpObjCallback, &objAttri, FALSE, TRUE); if (!NT_SUCCESS(status)) { KdPrint(("[sysRecv1] ExCreateCallback error code:(0x%x).\n", status)); return status; } gbSuccess = 1; gpCookie = ExRegisterCallback(gpObjCallback, CALLBACK_FUNC, NULL); if (NULL == gpCookie) { KdPrint(("[sysRecv1] ExRegisterCallback error.\n")); return STATUS_UNSUCCESSFUL; } status = STATUS_SUCCESS; return status; } VOID UnloadDriver(_In_ PDRIVER_OBJECT driver) { UNREFERENCED_PARAMETER(driver); if (NULL != gpCookie) { ExUnregisterCallback(gpCookie); } KdPrint(("[sysRecv1] Drvier unloaded.\n")); } VOID CALLBACK_FUNC( _In_ PVOID CallbackContext, _In_ PVOID Argument1, _In_ PVOID Argument2) { UNREFERENCED_PARAMETER(CallbackContext); ULONG ulType; PCHAR ulValue; ulType = *(ULONG*)Argument1; ulValue = (PCHAR)Argument2; KdPrint(("[sysRecv1]:get notify ulType:(%d)\tulValue:(%s)\n", ulType, ulValue)); }
結果如下:
從結果分析可知是正確的,當沒有回調注冊時,即使發送通知其它驅動也收不到任何通知,當注冊回調以后,每當發送通知都可以接收到的消息。