转载:http://blog.csdn.net/heyabo/article/details/8721611

转载:http://www.cnblogs.com/ljinshuan/archive/2012/03/15/2397743.html

一、建立通信端口

在DriverEntry函数里创建一个安全性叙述子。

函数FltBuildDefaultSecurityDescriptor是用来申请一个安全叙述子(简单点就是给使用通信端口的用户申请个权限,这里可以看到申请的权限是FLT_PORT_ALL_ACCESS,意思就是:用户层的程序连接到设置了这个权限级别的通信端口后,可以获得所有操作权限)。函数InitializeObejectAttributes就是用来给我们要创建的对象(名称是:MINISPY_PORT_NAME)设置一些属性值。

FltCreateCommunicationPort就是给这个端口定义所需要的三个函数,同时注册这个端口(注册了才能用)。这里注册的三个函数分别是:

MiniConnect用户层和内核层建立连接的时候会调用该函数

MiniDisconnect用户层和内核层断开连接的时候会调用该函数

MiniMessage用户层和内核层进行通讯的时候会调用

当然,既然称他们为回调函数,那他们就不是我们用户层的程序去调用的,工作原理是这样的,我们在用户层通过两个api:FilterConnectCommunicationPort和FilterSendMessage来发出请求,然后通讯端口会根据我们的请求自己去调用这三个函数完成具体的工作。其中前者对应NPMiniConnect,后者对应NPMiniMessage。

完成上面三个回调函数后,内核中的通讯代码已经准备好了。

#define MINISPY_PORT_NAME                                L"\\MiniPort"  //通信端口名字

PFLT_PORT     gServerPort;//服务端口
PFLT_PORT gClientPort;//客户端口 // Defines the commands between the utility and the filter
typedef enum _MINI_COMMAND {
ENUM_PASS = ,
ENUM_BLOCK
} MINI_COMMAND; // Defines the command structure between the utility and the filter.
typedef struct _COMMAND_MESSAGE {
MINI_COMMAND Command;
} COMMAND_MESSAGE, *PCOMMAND_MESSAGE;
NTSTATUS
DriverEntry (
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
PSECURITY_DESCRIPTOR sd;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING uniString; UNREFERENCED_PARAMETER( RegistryPath ); PT_DBG_PRINT( PTDBG_TRACE_ROUTINES,
("MiniFilter!DriverEntry: Entered\n") ); //
// Register with FltMgr to tell it our callback routines
// status = FltRegisterFilter( DriverObject,
&FilterRegistration,
&gFilterHandle ); FLT_ASSERT( NT_SUCCESS( status ) ); if (NT_SUCCESS( status )) { //
// Start filtering i/o
// status = FltStartFiltering( gFilterHandle ); if (!NT_SUCCESS( status )) { FltUnregisterFilter( gFilterHandle );
}
} //产生一个安全性叙述子
status=FltBuildDefaultSecurityDescriptor(&sd,FLT_PORT_ALL_ACCESS);
RtlInitUnicodeString( &uniString, MINISPY_PORT_NAME ); //初始化对象属性
InitializeObjectAttributes( &oa,
&uniString,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
NULL,
sd ); //内核建立通信端口
status = FltCreateCommunicationPort(gFilterHandle,&gServerPort,&oa,NULL,MiniConnect,MiniDisconnect,MiniMessage,);
FltFreeSecurityDescriptor( sd ); return status;
}
//用户态和内核态建立连接
NTSTATUS
MiniConnect(
__in PFLT_PORT ClientPort,
__in PVOID ServerPortCookie,
__in_bcount(SizeOfContext) PVOID ConnectionContext,
__in ULONG SizeOfContext,
__deref_out_opt PVOID *ConnectionCookie
)
{
DbgPrint("[mini-filter] NPMiniConnect");
PAGED_CODE(); UNREFERENCED_PARAMETER( ServerPortCookie );
UNREFERENCED_PARAMETER( ConnectionContext );
UNREFERENCED_PARAMETER( SizeOfContext);
UNREFERENCED_PARAMETER( ConnectionCookie ); ASSERT( gClientPort == NULL );
gClientPort = ClientPort;
return STATUS_SUCCESS;
} //用户态和内核断开连接
VOID
MiniDisconnect(
__in_opt PVOID ConnectionCookie
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER( ConnectionCookie );
DbgPrint("[mini-filter] NPMiniDisconnect"); // Close our handle
FltCloseClientPort( gFilterHandle, &gClientPort );
} //用户态和内核态传送数据
NTSTATUS
MiniMessage (
__in PVOID ConnectionCookie,
__in_bcount_opt(InputBufferSize) PVOID InputBuffer,
__in ULONG InputBufferSize,
__out_bcount_part_opt(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer,
__in ULONG OutputBufferSize,
__out PULONG ReturnOutputBufferLength
)
{
MINI_COMMAND command;
NTSTATUS status; PAGED_CODE(); UNREFERENCED_PARAMETER( ConnectionCookie );
UNREFERENCED_PARAMETER( OutputBufferSize );
UNREFERENCED_PARAMETER( OutputBuffer ); DbgPrint("[mini-filter] NPMiniMessage"); if ((InputBuffer != NULL) &&
(InputBufferSize >= (FIELD_OFFSET(COMMAND_MESSAGE,Command) +
sizeof(MINI_COMMAND)))) { try {
// Probe and capture input message: the message is raw user mode
// buffer, so need to protect with exception handler
command = ((PCOMMAND_MESSAGE) InputBuffer)->Command; } except( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode();
} switch (command) {
//释放规则
case ENUM_PASS:
{
DbgPrint("[mini-filter] ENUM_PASS");
gCommand = ENUM_PASS;
status = STATUS_SUCCESS;
break;
}
//阻擋規則
case ENUM_BLOCK:
{
DbgPrint("[mini-filter] ENUM_BLOCK");
gCommand = ENUM_BLOCK;
status = STATUS_SUCCESS;
break;
} default:
DbgPrint("[mini-filter] default");
status = STATUS_INVALID_PARAMETER;
break;
}
} else { status = STATUS_INVALID_PARAMETER;
} return status;
}

二、应用层通过DLL使用通信端口

在用户态编写应用程序时,开发者可以编写一个简单的动态链接库(DLL)来提供与内核中的MiniFilter内核驱动程序通信的功能。

动态库

.h

#ifndef _MINIFILTER_H_
#define _MINIFILTER_H_ #include <windows.h>
#include <stdio.h>
#include <FltUser.h>
#pragma comment(lib, "fltLib.lib") extern HANDLE g_hPort;
#define MIN_PORT_NAME L"\\MiniPort" #ifdef MINI_EXPORTS
#define MINI_API _declspec(dllexport)
#else
#define MINI_API _declspec(dllexport)
#endif // NPMINI_EXPORTS extern "C" MINI_API int InitialCommuicationPort(void);
extern "C" MINI_API int NPSendMessage(PVOID InputBuffer); typedef enum _MINI_COMMAND {
ENUM_PASS = ,
ENUM_BLOCK
}MIN_COMMAND; typedef struct _COMAND_MESSAGE
{
MIN_COMMAND Command;
} COMMAND_MESSAGE,*PCOMMAND_MESSAGE; #endif

.cpp

#include "stdafx.h"
#include "MiniFilter_dll.h" //初始化句柄
HANDLE g_hPort = INVALID_HANDLE_VALUE; int InitialCommuicationPort(void)
{
DWORD hResult = FilterConnectCommunicationPort(MIN_PORT_NAME,,NULL,,NULL,&g_hPort);
printf("进入了通信端口初始化\n");
if (hResult != S_OK)
{
return hResult;
printf("通信端口初始化不成功\n");
}
printf("通信端口初始化成功\n");
return ;
} int NPSendMessage(PVOID InputBuffer)
{
DWORD bytesReturned = ;
DWORD hResult = ;
PCOMMAND_MESSAGE command_message = (PCOMMAND_MESSAGE)InputBuffer; printf("进入发送消息\n");
hResult = FilterSendMessage(g_hPort,command_message,sizeof(command_message),NULL,NULL,&bytesReturned); if (hResult != S_OK)
{
return hResult;
}
return ;
}

为了在任意目标机器上使用,此动态库以静态链接C/C++运行时库

三、用户程序调用

在此是显示调用动态库

.h

#include <windows.h>
#include <vector>
#include <string> using namespace std; HANDLE g_hPort = INVALID_HANDLE_VALUE; typedef enum _MINI_COMMAND {
ENUM_PASS = ,
ENUM_BLOCK
}MIN_COMMAND; typedef struct _COMAND_MESSAGE
{
MIN_COMMAND Command;
}COMMAND_MESSAGE,*PCOMMAND_MESSAGE; class CApp
{
public:
CApp();
virtual ~CApp(); int Init(); void Message(COMMAND_MESSAGE data); private: HINSTANCE m_hModule; bool LoadminifilterDll();
};

.cpp

#include "App.h"
#include <iostream>
using namespace std; typedef int (*pSendMessage)(PVOID pInBufffer);
typedef int (*pInitiaCommunicationPort)(); CApp::CApp()
{
m_hModule = NULL; LoadminifilterDll();
} CApp::~CApp()
{
if (m_hModule)
{
FreeLibrary(m_hModule);
}
} bool CApp::LoadminifilterDll()
{
printf("进入了LoadminifilterDll,此函数是为了Minifilter_dll.dll中的NPSendMessage\n");
m_hModule = LoadLibrary(L"MiniFilter_dll.dll"); if (m_hModule != NULL)
{
pInitiaCommunicationPort pInit = (pInitiaCommunicationPort)GetProcAddress(m_hModule,"InitialCommuicationPort"); if (!pInit) {
printf("调用了pInit ,但是失败了\n");
return false;
}
pInit();
printf("调用了pInit ,并链接成功了\n");
return true;
} printf("获得MiniFilter_dll.dll的句柄失败\n");
return false;
} void CApp::Message(COMMAND_MESSAGE data)
{
if (m_hModule == NULL)
{
if (LoadminifilterDll() == false)
{
return ;
}
} printf("发送数据\n"); //根据符号名得到函数地址
pSendMessage send = (pSendMessage)GetProcAddress(m_hModule,"NPSendMessage"); send(&data);
} void main()
{
CApp app;
char input;
while (true)
{
cout << "Enter 'a' for PASS MODE, 'b' for BLOCKMODE or 'q' to EXIT" << endl;
cin >> input;
if (input=='a' || input=='A')
{
COMMAND_MESSAGE data;
data.Command =ENUM_PASS;
printf("上一句是 data.Command = ENUM_PASS;\n");
app.Message(data);
printf("==>NOTEPAD.EXE PASS MODE\n");
}
else if (input=='b' || input=='B')
{
COMMAND_MESSAGE data;
data.Command = ENUM_BLOCK;
app.Message(data);
printf("==>NOTEPAD.EXE BLOCK MODE\n");
}
else if (input== 'q' || input=='Q')
{
printf("EXIT\n");
break;
}
else
{
printf("Wrong Parameter!!!\n");
}
}
system("pause");
}

DLL是以静态链接运行时库的,所以用户程序也要以静态链接运行时库。

四、

驱动装好后,以管理员权限在cmd下net start MiniFilter开启服务

UseMiniFilter.exe 和 MiniFilter_dll.dll放在同一目录下

以管理员权限打开UseMiniFilter.exe

输入字符 b (阻止打开)

打开一个txt

通信成功了!!!!

[内核驱动] miniFilter 内核层与应用程序通信的更多相关文章

  1. 向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知

    完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249 用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEV ...

  2. Linux驱动之内核自带的S3C2440的LCD驱动分析

    先来看一下应用程序是怎么操作屏幕的:Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户 ...

  3. linux内核驱动模型

    linux内核驱动模型,以2.6.32内核为例.(一边写一边看的,有点乱.) 1.以内核对象为基础.用kobject表示,相当于其它对象的基类,是构建linux驱动模型的关键.具有相同类型的内核对象构 ...

  4. Unix/Linux环境C编程新手教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建

    1. openSUSE是一款优秀的linux. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRjYXN0Y3Bw/font/5a6L5L2T/font ...

  5. Unix/Linux环境C编程入门教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建

    1. openSUSE是一款优秀的linux. 2.选择默认虚拟机 3.选择稍后安装操作系统 4.选择linux  opensuse 5. 选择默认虚拟机名称 6.设置处理器为双核. 7.内存设置为2 ...

  6. 【引用】Linux 内核驱动--多点触摸接口

    本文转载自James<Linux 内核驱动--多点触摸接口>   译自:linux-2.6.31.14\Documentation\input\multi-touch-protocol.t ...

  7. Linux内核驱动开发之KGDB原理介绍及kgdboe方式配置

    接博文<Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)>.上篇博文中,仅简单介绍使用串口的Kgbd的流程(kgdboc方式),本文将重点介绍KGDB调试Linux内核的原 ...

  8. linux内核驱动——从helloworld开始

    学习编程第一个都是学习hello world程序,学习内核驱动自然也不例外,我也是!本文整理了网上的一些资料以及加上自己的一些心得体会,希望对初学者有帮助,可别小看这个简单的hello world,本 ...

  9. 内核开发知识第二讲,编写Kerner 程序中注意的问题.

    一丶函数多线程的安全问题 什么是函数多线程安全. 简单来说就是 ,一个函数在调用过程中.还没有返回的时候.再次被其他线程调用了.但是函数执行的结果是可靠的.就可以了说这个函数是安全的. 比如我们在用户 ...

随机推荐

  1. 开源unittest测试报告源码BSTestRunner.py

    开源BSTestRunner 生成HTML测试报告源码: 保存代码到BSTestRunner.py 配合Unittest使用,很完美. python2: """ A Te ...

  2. [转]kafka介绍

    转自 https://www.cnblogs.com/hei12138/p/7805475.html kafka介绍 1.1. 主要功能 根据官网的介绍,ApacheKafka®是一个分布式流媒体平台 ...

  3. MFC 显示图片

    //定义成员变量 CStatic m_picture; m_picture.Create(L"XXX",WS_VISIBLE|WS_CHILD|SS_BITMAP ,CRect(, ...

  4. 五 js对象简介

    对象简介 js中没有"类"的概念,只有对象. A:对象声明方式有三种 ------------1.调用Object函数创建对象: var person = new Object; ...

  5. djago 定义后台地址

    在app 中urls.py 可替换原始后台登陆地址  /admin   为自定义地址

  6. Python基础知识摘要

    python字典 增,删,改,查 1.增:XXX[新的key] = value 2.删:DEL XXX[key] 3.改:XXX[已经存在的key] = NewValue 4.查:aList.exte ...

  7. 利用QPainter绘制散点图

    [1]实例代码 (1)代码目录结构(备注:QtCreator默认步骤新建工程) (2)工程pro文件 QT += core gui greaterThan(QT_MAJOR_VERSION, ): Q ...

  8. BIOS 搭配 MBR/GPT 的开机流程

    鸟哥私房菜书上内容: BIOS 搭配 MBR/GPT 的开机流程 在计算机概论里面我们有谈到那个可爱的BIOS与CMOS两个东西, CMOS是记录各项硬件参数且嵌入在主板上面的储存器,BIOS则是一个 ...

  9. Linux下实现免密登录

    过程如下: 1.Linux下生成密钥 通过命令”ssh-keygen -t rsa“ 2.1 通过ssh-copy-id的方式 命令: ssh-copy-id -i ~/.ssh/id_rsa.put ...

  10. Bluetooth_FTP_SPEC: 蓝牙FTP介绍

    FTP(Bluetooth File Transfer Profile) defines howfolders and files on a server device can be browsed ...