本方法的实现基础包括内核模式的回调机制和共享内存对象的互斥引用,涉及两个不同的驱动程序和一个共享内存对象,为方便起见,我们分别以发送源和接受端表示这两个不同的驱动程序,发送源将待传输数据存入共享内存对象并通过ExNotifyCallback函数通知系统,系统收到通知后即调用接受端已注册的回调例程,在该回调例程中可以访问共享内存对象中所存储的数据。
具体实现步骤如下:
一、共享内存对象管理
1.自定义内存对象数据结构
typedef struct _DATA_OBJECT
{
ULONG ReferenceCount; //对象的引用计数
ULONG ObjSize; //对象的大小
ULONG BufSize; //对象中带传输数据的大小
PVOID pBuffer; //存放待传输数据的地址
}DATA_OBJECT, *PDATA_OBJECT;
2.生成内存对象
NTSTATUS keCreateDataObject(PDATA_OBJECT *ppDataObj, ULONG Size)
{
ULONG dwLength;
PDATA_OBJECT pDataObj;
if (Size == 0)
return STATUS_INVALID_VARIANT;
dwLength = sizeof(DATA_OBJECT)+Size;
pDataObj = (PDATA_OBJECT)ExAllocatePoolWithTag(NonPagedPool, dwLength, 'SHTR'); //分配共享内存对象
if (pDataObj == NULL)
return STATUS_NO_MEMORY;
pDataObj->ObjSize = dwLength;
pDataObj->BufSize = Size;
pDataObj->ReferenceCount = 1; //初始引用计数为1
pDataObj->pBuffer = (PVOID)(pDataObj + 1); //用于存储待传输数据的内存地址
*ppDataObj = pDataObj;
return STATUS_SUCCESS;
}
3.引用内存对象
NTSTATUS keAddReferDataObject(PDATA_OBJECT pDataObj)
{
if (pDataObj)
{
InterlockedIncrement(&pDataObj->ReferenceCount); //引用计数增加1
return STATUS_SUCCESS;
}
return STATUS_INVALID_VARIANT;
}
4.获取内存对象数据
PVOID KeGetDataObjectBuffer(PDATA_OBJECT pDataObj)
{
if (pDataObj)
return pDataObj->pBuffer;
else
return NULL;
}
5.释放内存对象
NTSTATUS keReleaseDataObject(PDATA_OBJECT pDataObj)
{
ULONG uRef;
if (pDataObj)
{
uRef = InterlockedDecrement(&pDataObj->ReferenceCount);//引用计数减少1
if (uRef == 0) //引用计数为0时释放分配的内存
{
ExFreePoolWithTag(pDataObj, 'SHTR');
pDataObj = NULL;
}
return STATUS_SUCCESS;
}
return STATUS_INVALID_VARIANT;
}
二、发送源回调对象管理
typedef struct _CallbackContext
{
PCALLBACK_OBJECT pCallbackObject;
PVOID pCallbackRegisterHandle;
}CallbackContext, *PCallbackContext;
1.生成回调对象
NTSTATUS CreateCallbackObject(PCallbackContext pCallbackContext)
{
OBJECT_ATTRIBUTES ObjectAttr;
UNICODE_STRING CallBackObjectName;
NTSTATUS ntStatus;
PCALLBACK_OBJECT pCallbackObject = NULL;
PVOID pCallbackRegisterHandle = NULL;
RtlInitUnicodeString(&CallBackObjectName, L”\\Callback\\VenderDefinedCallbackObject”); //回调对象的名称
InitializeObjectAttributes(&ObjectAttr, &CallBackObjectName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
ntStatus = ExCreateCallback(&pCallbackObject, &ObjectAttr, TRUE, FALSE);
if (!NT_SUCCESS(ntStatus))
return ntStatus;
pCallbackContext->pCallbackObject = pCallbackObject; //保存生成的回调对象
return ntStatus;
}
2.关闭回调对象
VOID CloseCallbackObject(PCallbackContext pCallbackContext)
{
if (pCallbackContext->pCallbackObject)
{
ObDereferenceObject(pCallbackContext->pCallbackObject);
pCallbackContext->pCallbackObject = NULL;
}
}
3.准备待传输数据并通知系统待传输数据已准备好
VOID PrepareDataAndNotify(PCallbackContext pCallbackContext)
{
PVOID pData;
keAddReferDataObject(pDataObject);
pData = KeGetDataObjectBuffer(pDataObject)
{
copy data waiting to be transferred to pData;
}
keReleaseDataObject(pDataObject);
ExNotifyCallback(pCallbackContext->pCallbackObject, //生成的回调对象
(PVOID)pDataObj; //共享内存对象
Argument2); //其他参数
}
三、接收端回调对象管理
1.注册回调对象
NTSTATUS RegisterCallback(PCallbackContext pCallbackContext)
{
OBJECT_ATTRIBUTES ObjectAttr;
UNICODE_STRING CallBackObjectName;
NTSTATUS ntStatus;
PCALLBACK_OBJECT pCallbackObject = NULL;
PVOID pCallbackRegisterHandle = NULL;
RtlInitUnicodeString(&CallBackObjectName, L”\\Callback\\VenderDefinedCallbackObject”);
InitializeObjectAttributes(&ObjectAttr, &CallBackObjectName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL);
ntStatus = ExCreateCallback(&pCallbackObject, &ObjectAttr, FALSE, FALSE); //打开指定的回调对象
if (!NT_SUCCESS(ntStatus))
retrn ntStatus;
pCallbackRegisterHandle = ExRegisterCallback(pCallbackObject, CallbackRoutine, pCallbackContext); //注册回调例程
if (pCallbackRegisterHandle == NULL)
{
ObDereferenceObject(pCallbackObject);
return STATUS_UNSUCCESSFUL;
}
else
{
pCallbkContext->pCallbackObject = pCallbackObject;
pCallbkContext->pCallbackRegisterHandle = pCallbackRegisterHandle;
}
return STATUS_SUCCESS;
}
2.注销回调对象
VOID UnregisterCallback(PCallbackContext pCallbackContext)
{
if (pCallbackContext->pCallbackRegisterHandle)
{
ExUnregisterCallback(pCallbkContext->pCallbackRegisterHandle); //注销已注册的回调例程
pCallbkContext->pCamCallbackRegisterHandle = NULL;
}
if (pCallbackRegisterHandle == NULL)
{
ObDereferenceObject(pCallbackContext->pCallbackObject);
pCallbackContext->pCallbackObject = NULL;
}
}
3.回调例程
VOID CallbackRoutine(PVOID CallBackContext, PVOID Data, PVOID Argument2)
{
NTSTATUS ntStatus;
PDATA_OBJECT pDataObject = NULL;
PVOID pReceivedData = NULL;
PCallbackContext pCallbackContext = (PCallbackContext)CallBackContext;
pDataObject = (PDATA_OBJECT)Data;
if (pDataObject)
{
keAddReferDataObject(pDataObject);
pReceivedData = KeGetDataObjectBuffer(pDataObject)
{
Process received data;
}
keReleaseDataObject(pDataObject);
}
}
当然,通过在接收端生成新的回调对象、发送端注册该回调对象和扩充共享内存对象的数据结构,同样可以实现将接收端对所传输数据的处理结果反馈至发送端,从而实现发送端和接收端之间双向通讯。