[内核驱动] miniFilter 内核层与应用程序通信
转载: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 内核层与应用程序通信的更多相关文章
- 向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知
完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249 用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEV ...
- Linux驱动之内核自带的S3C2440的LCD驱动分析
先来看一下应用程序是怎么操作屏幕的:Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户 ...
- linux内核驱动模型
linux内核驱动模型,以2.6.32内核为例.(一边写一边看的,有点乱.) 1.以内核对象为基础.用kobject表示,相当于其它对象的基类,是构建linux驱动模型的关键.具有相同类型的内核对象构 ...
- Unix/Linux环境C编程新手教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建
1. openSUSE是一款优秀的linux. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRjYXN0Y3Bw/font/5a6L5L2T/font ...
- Unix/Linux环境C编程入门教程(12) openSUSECCPP以及Linux内核驱动开发环境搭建
1. openSUSE是一款优秀的linux. 2.选择默认虚拟机 3.选择稍后安装操作系统 4.选择linux opensuse 5. 选择默认虚拟机名称 6.设置处理器为双核. 7.内存设置为2 ...
- 【引用】Linux 内核驱动--多点触摸接口
本文转载自James<Linux 内核驱动--多点触摸接口> 译自:linux-2.6.31.14\Documentation\input\multi-touch-protocol.t ...
- Linux内核驱动开发之KGDB原理介绍及kgdboe方式配置
接博文<Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)>.上篇博文中,仅简单介绍使用串口的Kgbd的流程(kgdboc方式),本文将重点介绍KGDB调试Linux内核的原 ...
- linux内核驱动——从helloworld开始
学习编程第一个都是学习hello world程序,学习内核驱动自然也不例外,我也是!本文整理了网上的一些资料以及加上自己的一些心得体会,希望对初学者有帮助,可别小看这个简单的hello world,本 ...
- 内核开发知识第二讲,编写Kerner 程序中注意的问题.
一丶函数多线程的安全问题 什么是函数多线程安全. 简单来说就是 ,一个函数在调用过程中.还没有返回的时候.再次被其他线程调用了.但是函数执行的结果是可靠的.就可以了说这个函数是安全的. 比如我们在用户 ...
随机推荐
- SQLite之C#连接SQLite
SQLite是一个开源.免费的小型的Embeddable RDBMS(关系型数据库),用C实现,内存占用较小,支持绝大数的SQL92标准,现在已变得越来越流行,它的体积很小,被广泛应用于各种不同类型的 ...
- Mysql date,datetime的区别以及相互转换
参考:https://blog.csdn.net/a3025056/article/details/62885104/ 在数据库中一直有这三个时间类型有点搞不太清楚. 今天就来说一下之间的区别,其实是 ...
- shell基础:数值运算与运算符
linux的shell中,变量的类型默认都是字符串型. export将aa声明为环境变量.也可用declare声明.其实就是改变了-x属性 $(()) 最常用.
- Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- laravel orm
###多对多关系 多对多关系和之前的关系完全不一样,因为多对多关系可能出现很多冗余数据,用之前自带的表存不下了. 我们定义两个模型:Article 和 Tag,分别表示文章和标签,他们是多对多的关系. ...
- python 数据较大 性能分析
前提:若有一个几百M的文件需要解析,某个函数需要运行很多次(几千次),需要考虑性能问题 性能分析模块:cProfile 使用方法:cProfile.run("func()"),其中 ...
- Glorious Brilliance (最短路 + 带权二分图匹配)
这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...
- 激活win10
网盘地址 http://pan.baidu.com/s/1nvc5I1V 里面是2个东西,一个是rar解压缩软件,一个是激活工具本体 一个解压缩软件,一个激活工具的压缩包 安装解压软件,就是WINRA ...
- nodejs typescript怎么发送get、post请求,如何获取网易云通信token
nodejs typescript怎么发送get.post请求,如何获取网易云通信token yarn add jshashesyarn add superagent检查语法yarn lint==== ...
- 专题8:javascript函数详解
函数是一段可以反复调用的代码块.函数还能接受输入的参数,不同的参数会返回不同的值. 函数的声明 JavaScript 有三种声明函数的方法. (1)function 命令 function命令声明的代 ...