win驱动下过滤器原理:
简单说就是电脑一般真实设备只有一个,像键盘,但有的说一个电脑有多个键盘。多个键盘分别是多个不同的真实物体。
而真实设备对应多个设备对象。多个设备共同组成一个设备栈。不能的设备对应不同的设备对象。如键盘与鼠标是不同的设备对象。设备对象上层是驱动对象。每个设备对象只有唯一的驱动对象。驱动对象有多个设备对象。如一个驱动对象有键盘,鼠标设备对象。一般通信是用户层调用api去访问相应的设备。而调用api底层是调用驱动。也就是发请求给驱动。这个请求一般叫做irp包,然后这个包给设备对象。因为一个真实设备有多个设备对象。因此这个包从设备对象栈第一个开始一直发。直到发给真实设备。在设备栈中的设备对象可以不是同一个驱动对象。比如过滤器驱动创建的设备对象。如果这个设备对象把这个包不往下发也就是不给真实设备。就达到了过滤的作用。
那这些设备对象怎么与真实设备对象关联的呢,就是通过api把一个驱动对象创建的设备对象附加到真实设备对象上。
结构图
回顾过滤器原理
简单代码引用独钓寒江书的源码串口过滤
///
/// @file comcap.c
/// @author crazy_chu
/// @date 2008-6-18
///
#include
#define NTSTRSAFE_LIB
#include
#ifndef SetFlag
#define SetFlag(_F,_SF) ((_F) |= (_SF))
#endif
#ifndef ClearFlag
#define ClearFlag(_F,_SF) ((_F) &= ~(_SF))
#endif
#define CCP_MAX_COM_ID 32
// 过滤设备和真实设备
static PDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID] = { 0 };
static PDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID] = { 0 };
// 打开一个端口设备
PDEVICE_OBJECT ccpOpenCom(ULONG id,NTSTATUS *status)
{
UNICODE_STRING name_str;
static WCHAR name[32] = { 0 };
PFILE_OBJECT fileobj = NULL;
PDEVICE_OBJECT devobj = NULL;
// 输入字符串。
memset(name,0,sizeof(WCHAR)*32);
RtlStringCchPrintfW(
name,32,
L"\Device\Serial%d",id);
RtlInitUnicodeString(&name_str,name);
// 打开设备对象
*status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);
if (*status == STATUS_SUCCESS)
ObDereferenceObject(fileobj);
return devobj;
}
NTSTATUS
ccpAttachDevice(
PDRIVER_OBJECT driver,
PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT *fltobj,
PDEVICE_OBJECT *next)
{
NTSTATUS status;
PDEVICE_OBJECT topdev = NULL;
// 生成设备,然后绑定之。
status = IoCreateDevice(driver,
0,
NULL,
oldobj->DeviceType,
0,
FALSE,
fltobj);
if (status != STATUS_SUCCESS)
return status;
// 拷贝重要标志位。
if(oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if(oldobj->Flags & DO_DIRECT_IO)
(*fltobj)->Flags |= DO_DIRECT_IO;
if(oldobj->Flags & DO_BUFFERED_IO)
(*fltobj)->Flags |= DO_BUFFERED_IO;
if(oldobj->Characteristics & FILE_DEVICE_SECURE_OPEN)
(*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
(*fltobj)->Flags |= DO_POWER_PAGABLE;
// 绑定一个设备到另一个设备上
topdev = IoAttachDeviceToDeviceStack(*fltobj,oldobj);
if (topdev == NULL)
{
// 如果绑定失败了,销毁设备,重新来过。
IoDeleteDevice(*fltobj);
*fltobj = NULL;
status = STATUS_UNSUCCESSFUL;
return status;
}
*next = topdev;
// 设置这个设备已经启动。
(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
// 这个函数绑定所有的串口。
void ccpAttachAllComs(PDRIVER_OBJECT driver)
{
ULONG i;
PDEVICE_OBJECT com_ob;
NTSTATUS status;
for(i = 0;i { // 获得object引用。 com_ob = ccpOpenCom(i,&status); if(com_ob == NULL) continue; // 在这里绑定。并不管绑定是否成功。 ccpAttachDevice(driver,com_ob,&s_fltobj[i],&s_nextobj[i]); // 取消object引用。 } } #define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000) #define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000) void ccpUnload(PDRIVER_OBJECT drv) { ULONG i; LARGE_INTEGER interval; // 首先解除绑定 for(i=0;i { if(s_nextobj[i] != NULL) IoDetachDevice(s_nextobj[i]); } // 睡眠5秒。等待所有irp处理结束 interval.QuadPart = (5*1000 * DELAY_ONE_MILLISECOND); KeDelayExecutionThread(KernelMode,FALSE,&interval); // 删除这些设备 for(i=0;i { if(s_fltobj[i] != NULL) IoDeleteDevice(s_fltobj[i]); } } NTSTATUS ccpDispatch(PDEVICE_OBJECT device,PIRP irp) { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp); NTSTATUS status; ULONG i,j; // 首先得知道发送给了哪个设备。设备一共最多CCP_MAX_COM_ID // 个,是前面的代码保存好的,都在s_fltobj中。 for(i=0;i { if(s_fltobj[i] == device) { // 所有电源操作,全部直接放过。 if(irpsp->MajorFunction == IRP_MJ_POWER) { // 直接发送,然后返回说已经被处理了。 PoStartNextPowerIrp(irp); IoSkipCurrentIrpStackLocation(irp); return PoCallDriver(s_nextobj[i],irp); } // 此外我们只过滤写请求。写请求的话,获得缓冲区以及其长度。 // 然后打印一下。 if(irpsp->MajorFunction == IRP_MJ_WRITE) { // 如果是写,先获得长度 ULONG len = irpsp->Parameters.Write.Length; // 然后获得缓冲区 PUCHAR buf = NULL; if(irp->MdlAddress != NULL) buf = (PUCHAR) MmGetSystemAddressForMdlSafe(irp->MdlAddress,NormalPagePriority); else buf = (PUCHAR)irp->UserBuffer; if(buf == NULL) buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer; // 打印内容 for(j=0;j { DbgPrint("comcap: Send data: %2xrn", buf[j]); } } // 这些请求直接下发执行即可。我们并不禁止或者改变它。 IoSkipCurrentIrpStackLocation(irp); return IoCallDriver(s_nextobj[i],irp); } } // 如果根本就不在被绑定的设备中,那是有问题的,直接返回参数错误。 irp->IoStatus.Information = 0; irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(irp,IO_NO_INCREMENT); return STATUS_SUCCESS; } NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) { size_t i; // 所有的分发函数都设置成一样的。 for(i=0;i { driver->MajorFunction[i] = ccpDispatch; } // 支持动态卸载。 driver->DriverUnload = ccpUnload; // 绑定所有的串口。 ccpAttachAllComs(driver); // 直接返回成功即可。 return STATUS_SUCCESS; } ©著作权归作者所有:来自51CTO博客作者土匪猿的原创作品,如需转载,请注明出处,否则将追究法律责任 每一份赞赏源于懂得



