前言:
熟悉驅動開發的人們都知道,在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));
}
結果如下:

從結果分析可知是正確的,當沒有回調注冊時,即使發送通知其它驅動也收不到任何通知,當注冊回調以后,每當發送通知都可以接收到的消息。
