2013年11月13日星期三

minifilter通讯之简单示例

应用层的代码如下:

/*
名字:minifilter通讯之简单示例.之所以说简单是因为没有列举异步,多线程等全面和安全的用法.

个人感觉FilterSendMessage就像DeviceIoControl,可以发送和接受信息.
        但是要自定义格式结构,驱动收到了再解析.

FilterGetMessage和FilterReplyMessage可能需要多线程或者异步等措施,这里不列举了,只是简单列举一下调用:

//FILTER_MESSAGE_HEADER  MessageBuffer;
//hResult = FilterGetMessage(port, &MessageBuffer, sizeof (FILTER_MESSAGE_HEADER), 0);
//if (IS_ERROR( hResult )) {
//    OutputDebugString(L"FilterGetMessage fail!\n");
//} else {
//    OutputDebugString(L"FilterGetMessage ok!\n");
//}

//FILTER_REPLY_HEADER  ReplyBuffer;
//hResult = FilterReplyMessage(port, &ReplyBuffer,sizeof(FILTER_REPLY_HEADER));
//if (IS_ERROR( hResult )) {
//    OutputDebugString(L"FilterReplyMessage fail!\n");
//} else {
//    OutputDebugString(L"FilterReplyMessage ok!\n");
//}

不足之处,敬请指出.
made by correy
made at 2013.11.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com

效果如下(包括驱动打印的消息):
用户发来的信息是:test
[1124] FilterSendMessage ok!
[1124] 从内核发来的信息是:
[1124] to user client
[1124]

*/

#include <windows.h>

//这两个文件在VS中没有,在WDK中有.
//如果要用VS编译要拷贝相应的文件到相应的目录或者改变目录的设置等.
#include <fltuser.h>
#pragma comment(lib, "fltLib.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    MessageBox(0,L"请附加调试器",L"调试专用",0);//如果是远程调试的话,这行特别有用.

    HANDLE port = INVALID_HANDLE_VALUE;
    HRESULT hResult = S_OK;

    hResult = FilterConnectCommunicationPort( L"\\CommunicationPort", 0, NULL, 0, NULL, &port );
    if (IS_ERROR( hResult )) {
        OutputDebugString(L"FilterConnectCommunicationPort fail!\n");
        return hResult;
    }

    wchar_t InBuffer[] = L"test";
    wchar_t OutBuffer[MAX_PATH] = {0};
    DWORD bytesReturned = 0;
    hResult = FilterSendMessage(port, InBuffer, lstrlen(InBuffer), OutBuffer, sizeof(OutBuffer), &bytesReturned);
    if (IS_ERROR( hResult )) {
        OutputDebugString(L"FilterSendMessage fail!\n");
        CloseHandle( port );
        return hResult;
    } else {
        OutputDebugString(L"FilterSendMessage ok!\n");
    }

    OutputDebugString(L"从内核发来的信息是:");
    OutputDebugString(OutBuffer);
    OutputDebugString(L"\n");

    CloseHandle( port );

 return 0;
}

驱动的代码如下:

/*
内核中没有:FltGetMessage,FltReplyMessage函数.
个人认为:MessageNotifyCallback有FltGetMessage,FltReplyMessage,FltSendMessage这三个函数的功能.
所以在MessageNotifyCallback里面调用这些函数是不对的,得到一些意想不到的效果.建议不要这样做.

FltGetMessage除了在MessageNotifyCallback里面,大多的地方都可以调用,但是用户层最好开启线程处理函数.

FltGetMessage函数调用示例代码如下:
//{
//    wchar_t SenderBuffer[] = L"SenderBuffer";
//    wchar_t ReplyBuffer[] = L"ReplyBuffer";
//    ULONG replyLength = sizeof(ReplyBuffer);
//
//    status = FltSendMessage( gFilterHandle, &g_ClientPort, SenderBuffer, sizeof(SenderBuffer), ReplyBuffer, &replyLength, NULL);
//    if (STATUS_SUCCESS == status) {
//        DbgPrint( "send message to user-mode\n");       
//    } else {
//        DbgPrint( "couldn't send message to user-mode to scan file, status 0x%X\n", status );
//    }
//}
*/

#include <fltKernel.h>

PFLT_FILTER gFilterHandle;
PFLT_PORT g_ServerPort;
PFLT_PORT g_ClientPort;

NTSTATUS MessageNotifyCallback (
    IN PVOID PortCookie,
    IN PVOID InputBuffer OPTIONAL,
    IN ULONG InputBufferLength,
    OUT PVOID OutputBuffer OPTIONAL,
    IN ULONG OutputBufferLength,//用户可以接受的数据的最大长度.
    OUT PULONG ReturnOutputBufferLength)
    /*
    这里要注意:1.数据地址的对齐.
               2.文档建议使用:try/except处理.
               3.如果是64位的驱动要考虑32位的EXE发来的请求.
    */
{
    NTSTATUS status = 0;
    wchar_t buffer[] = L"to user client";//
    
    PAGED_CODE();

    UNREFERENCED_PARAMETER(PortCookie);

    //打印用户发来的信息
    KdPrint(("用户发来的信息是:%ls\n",InputBuffer));

    //返回用户一些信息.
    *ReturnOutputBufferLength = sizeof(buffer);
    RtlCopyMemory(OutputBuffer,buffer,* ReturnOutputBufferLength);

    /*
    minispy在这里用FilterSendMessage获取信息的,对就是FilterSendMessage.
    这里某个类型里面获取信息,这些信息是在各种操作时(IRP的MJ_)加入链表的.
    注意链表的操作一定要同步,支持多线程.
    然后用户的一个线程在不停的获取这些信息.
    */

    return status;
}

VOID DisconnectNotifyCallback (_In_opt_ PVOID ConnectionCookie)
{
    PAGED_CODE();

    UNREFERENCED_PARAMETER(ConnectionCookie);

    FltCloseClientPort(gFilterHandle, &g_ClientPort);//应该加判断,如果ConnectionCookie == 我们的值就执行这行.
}

NTSTATUS ConnectNotifyCallback (IN PFLT_PORT ClientPort, IN PVOID ServerPortCookie, IN PVOID ConnectionContext, IN ULONG SizeOfContext, OUT PVOID * ConnectionPortCookie)
{
    PAGED_CODE();

    UNREFERENCED_PARAMETER( ServerPortCookie );
    UNREFERENCED_PARAMETER( ConnectionContext );
    UNREFERENCED_PARAMETER( SizeOfContext);
    UNREFERENCED_PARAMETER( ConnectionPortCookie);

    //可以加以判断,禁止非法的连接,从而给予保护.
    g_ClientPort = ClientPort;//保存以供以后使用.

    return STATUS_SUCCESS;
}

#pragma PAGEDCODE
NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
    return STATUS_SUCCESS;
}

#pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)
NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)
{
    FltCloseCommunicationPort(g_ServerPort);//没有这一行是停止不了驱动的,查询也是永远等待中.
    FltUnregisterFilter( gFilterHandle );
    return STATUS_SUCCESS;
}

CONST FLT_REGISTRATION FilterRegistration = {
    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    NULL,                               //  Operation callbacks
    PtUnload,                           //  MiniFilterUnload
    NULL,                               //  InstanceSetup
    PtInstanceQueryTeardown,            //  InstanceQueryTeardown
    NULL,                               //  InstanceTeardownStart
    NULL,                               //  InstanceTeardownComplete
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};

DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;
    PSECURITY_DESCRIPTOR sd;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING uniString;

    UNREFERENCED_PARAMETER(RegistryPath);

    KdBreakPoint();

    __try
    {
        status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle); 
        if (!NT_SUCCESS(status)) //;
        {       
            __leave;
        }

        status  = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);
        if (!NT_SUCCESS( status )) {
            __leave;
        }

        RtlInitUnicodeString(&uniString, L"\\CommunicationPort");
        InitializeObjectAttributes( &oa, &uniString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd);
        status = FltCreateCommunicationPort(gFilterHandle, &g_ServerPort, &oa, NULL, ConnectNotifyCallback, DisconnectNotifyCallback, MessageNotifyCallback, 1);
        FltFreeSecurityDescriptor( sd );
        if (!NT_SUCCESS( status )) {
            __leave;
        }

        status = FltStartFiltering(gFilterHandle);//这个结果在下面判断.
    } __finally {
        if (!NT_SUCCESS( status ) )
        {
            if (NULL != g_ServerPort) {
                FltCloseCommunicationPort(g_ServerPort);
            }

            if (NULL != gFilterHandle) {
                FltUnregisterFilter(gFilterHandle);
            }
        }       
    }

    return status;
}

没有评论:

发表评论