应用层与内核通讯是通过通讯端口来进行的,下面的这个API就是内核用来创建一个内核端口的。
NTSTATUS FltCreateCommunicationPort( _In_ PFLT_FILTER Filter, _Out_ PFLT_PORT *ServerPort, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _In_opt_ PVOID ServerPortCookie, _In_ PFLT_CONNECT_NOTIFY ConnectNotifyCallback, _In_ PFLT_DISCONNECT_NOTIFY DisconnectNotifyCallback, _In_opt_ PFLT_MESSAGE_NOTIFY MessageNotifyCallback, _In_ LONG MaxConnections );
这里面有重要的三个回调函数,ConnectNotifyCallback,DisconnectNotifyCallback,MessageNotifyCallback。
ConnectNotifyCallback:当应用层调用FilterConnectCommunicationPort 来与minifilter driver建立连接的时候,Filter Manager 会调用这个回调函数。
Pointer to a caller-supplied callback routine to be called whenever the user-mode handle count for the client port reaches zero or when the minifilter driver is about to be unloaded。
The Filter Manager calls this routine, at IRQL = PASSIVE_LEVEL, whenever a user-mode application callsFilterSendMessage to send a message to the minifilter driver through the client port.
学习最有效,最快的方式不是看书和看文档,而是实战,来看看示例代码:
NTSTATUS
SSMFInitializeCommPort()
{
NTSTATUS status = STATUS_SUCCESS;
PSECURITY_DESCRIPTOR sd;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING uniString;
status = FltBuildDefaultSecurityDescriptor(&sd,
FLT_PORT_ALL_ACCESS);
if (!NT_SUCCESS(status))
{
return status;
}
RtlInitUnicodeString(&uniString, SSMF_PORT_NAME);
InitializeObjectAttributes(&oa,
&uniString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
sd);
status = FltCreateCommunicationPort(gFilterHandle,
&gServerPort,
&oa,
NULL,
SSMFConnect,
SSMFDisconnect,
SSMFMessage,
1);
FltFreeSecurityDescriptor(sd);
return status;
}
这个SSMFInitializeCommPort函数就是创建了一个内核端口供应用层连接,当然还有那三个重要的函数要实现,在这里我们只是简单的输出一下log信息和返回一些简单的数据。
NTSTATUS
SSMFConnect(
_In_ PFLT_PORT ClientPort,
_In_ PVOID ServerPortCookie,
_In_reads_bytes_(SizeOfContext) PVOID ConnectionContext,
_In_ ULONG SizeOfContext,
_Flt_ConnectionCookie_Outptr_ PVOID *ConnectionCookie
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(ServerPortCookie);
UNREFERENCED_PARAMETER(ConnectionContext);
UNREFERENCED_PARAMETER(SizeOfContext);
UNREFERENCED_PARAMETER(ConnectionCookie);
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("SSMF!SSMFConnect entered"));
gClientPort = ClientPort;
return STATUS_SUCCESS;
}
VOID
SSMFDisconnect(
_In_opt_ PVOID ConnectionCookie
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(ConnectionCookie);
//
// Close our handle
//
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("SSMF!SSMFDisconnect entered"));
FltCloseClientPort(gFilterHandle, &gClientPort);
}
NTSTATUS
SSMFMessage(
_In_ PVOID ConnectionCookie,
_In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer,
_In_ ULONG InputBufferSize,
_Out_writes_bytes_to_opt_(OutputBufferSize, *ReturnOutputBufferLength) PVOID OutputBuffer,
_In_ ULONG OutputBufferSize,
_Out_ PULONG ReturnOutputBufferLength
)
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
UNREFERENCED_PARAMETER(ConnectionCookie);
UNREFERENCED_PARAMETER(InputBuffer);
UNREFERENCED_PARAMETER(OutputBuffer);
UNREFERENCED_PARAMETER(OutputBufferSize);
UNREFERENCED_PARAMETER(ReturnOutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferSize);
if (InputBuffer)
{
char* data = (char*)InputBuffer;
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("The message data is %s",data));
}
if (OutputBuffer != NULL && OutputBufferSize > 4)
{
RtlCopyMemory(OutputBuffer, "1234", 4);
*ReturnOutputBufferLength = 4;
}
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("SSMF!SSMFMessage entered"));
return status;
}
下面我们来看看应用层怎么来与内核通讯并且传递数据:
HANDLE port = INVALID_HANDLE_VALUE;
printf("Connecting to filter's port...\n");
HRESULT hResult = FilterConnectCommunicationPort(SSMF_PORT_NAME,
0,
NULL,
0,
NULL,
&port);
if (hResult != S_OK)
{
return false;
}
printf("connected to the filter's port\n");
//send message
char buffer[100] = { 0 };
strcpy_s(buffer, "abcdefg");
char out_buf[100] = { 0 };
DWORD ret_size = 0;
hResult = FilterSendMessage(port, buffer, strlen(buffer), out_buf, 100, &ret_size);
if (hResult == S_OK)
{
printf("The data is %s,len is %d\n", out_buf,ret_size);
}
CloseHandle(port);