Filter-Hook Driver入门(1) ☆ Filter-Hook Driver
☆ PacketFilterExtensionPtr
☆ 设置/清除回调函数
1) 调用IoGetDeviceObjectPointer()获取IpFilterDriver相应的设备对象
2) 调用IoBuildDeviceIoControlRequest()构造IRP
3) 调用IoCallDriver()向IpFilterDriver提交IRP
☆ 一个完整的Filter-Hook Driver框架(丢弃所有ICMP报文以及接收到的RST报文)
1) ipflthookdrv.c
2) dirs
3) sources
4) makefile
5) installdriver.c
6) ipflthookdrvtest.c
7) 验证效果
☆ 参考资源
--------------------------------------------------------------------------
☆ Filter-Hook Driver
从Windows 2000开始IpFilterDriver是系统自带的一个驱动,顾名思义,就是IP过滤
驱动,对应ipfltdrv.sys文件。缺省情况下,这个驱动并未加载,但可以手工加载。
> sc queryex IpFilterDriver
SERVICE_NAME: IpFilterDriver
TYPE : 1 KERNEL_DRIVER
STATE : 1 STOPPED
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 0
FLAGS :
> enumservice.exe findstr /I ipfilter
设备驱动程序 停止 IpFilterDriver IP Traffic Filter Driver
> net start IpFilterDriver
The IP Traffic Filter Driver service was started sUCcessfully.
> enumservice.exe findstr /I ipfilter
设备驱动程序 运行 IpFilterDriver IP Traffic Filter Driver
> net stop IpFilterDriver
The IP Traffic Filter Driver service was stopped successfully.
Filter-Hook Driver是一种KMD,与IpFilterDriver相配合。显然这只能用于TCP/IP
协议,而对IPX/SPX、NetBEUI等其它协议无能为力。
最多只能安装一个Filter-Hook Driver。仅当filter-hook callback function为空
时,Filter-Hook Driver才能向IpFilterDriver注册自己所提供的回调函数,后者调
用filter-hook callback function以决定如何处理接收到的或者即将发送的IP报文。
注册回调函数结束之后,IpFilterDriver将Filter-Hook Driver相应的文件对象与回
调函数关联起来,以此确保只有一个Filter-Hook Driver可用。
从Windows XP开始,微软不推荐采用Filter-Hook Driver实现防火墙。从网络层次结
构上看,Filter-Hook Driver太高了。此外,Filter-Hook Driver还将干挠到ICS或
其它个人防火墙。ICS即Internet Connection Sharing,可以简单理解成XP/2003自
带的个人防火墙,当然事实上并非这么简单,ICS可以实现端口转发、NAT等类似功能。
如果你愿意,可以试着利用ICS将一台XP/2003配成NAT网关,我未实际测试,tk做过
一些实验。对于XP/2003,推荐采用NDIS Intermediate Driver实现防火墙。尽管如
此,我还是学习一下Filter-Hook Driver,因为它实现起来相对简单些。
用户态有一套Packet Filtering API,直接与IpFilterDriver打交道,做了适度优化,
可以根据srcIp、dstIp、srcPort、dstPort等等进行过滤,但与Filter-Hook Driver
无关!如果只关注IP地址和端口,可以考虑该套API,但试图过滤ICMP报文时就应考
虑Filter-Hook Driver。
☆ PacketFilterExtensionPtr
前面提到的回调函数的原型如下:
typedef PF_FORWARD_ACTION ( *PacketFilterExtensionPtr )
(
IN unsigned char *PacketHeader,
IN unsigned char *Packet,
IN unsigned int PacketLength,
IN unsigned int RecvInterfaceIndex,
IN unsigned int SendInterfaceIndex,
IN IPAddr RecvLinkNextHop,
IN IPAddr SendLinkNextHop
);
由于是回调函数,函数名是什么都无所谓,DDK文档建议起一个有意义的名字。该函
数有三种返回值:
PF_FORWARD
直接交给IP协议栈处理。如果IP报文是发给本机的,延IP协议栈向上传输。如果
IP报文是发给另一台主机的,并且本机使能了"IP转发(路由功能)",则根据路由
表进行相应转发。
PF_DROP
IP协议栈将丢弃该IP报文。
PF_PASS
如果用户态Packet Filtering API定义了过滤规则,在此得到机会进行过滤。如
果Filter-Hook Driver觉得应该给用户态Packet Filtering API一个机会,必须
返回PF_PASS,此时由IpFilterDriver亲自过滤。返回PF_FORWARD意味着Packet
Filtering API所定义的过滤规则失效,嘿嘿。
☆ 设置/清除回调函数
1) 调用IoGetDeviceObjectPointer()获取IpFilterDriver相应的设备对象
NTSTATUS IoGetDeviceObjectPointer
(
IN PUNICODE_STRING ObjectName,
IN Access_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject
);
ObjectName
要对应DD_IPFLTRDRVR_DEVICE_NAME,这是pfhook.h中定义的宏,即
L"\\Device\\IPFILTERDRIVER"。注意ObjectName的类型,需要调用
RtlInitUnicodeString()。
DesiredAccess
DDK文档中指出应指定"SYNCHRONIZE GENERIC_READ GENERIC_WRITE"。如果
图省事,可以指定STANDARD_RIGHTS_ALL。
参看Platform SDK DOC中ACCESS_MASK Reference。
FileObject
卸载Filter-Hook Driver时,应调用ObDereferenceObject()减小这个文件对象
的引用计数,此时将间接减小相应设备对象的引用计数,否则IpFilterDriver无
法正确卸载。
VOID ObDereferenceObject
(
IN PVOID Object
);
DeviceObject
后面将用到这个返回数据
2) 调用IoBuildDeviceIoControlRequest()构造IRP
PIRP IoBuildDeviceIoControlRequest
(
IN ULONG IoControlCode,
IN PDEVICE_OBJECT DeviceObject,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN BOOLEAN InternalDeviceIoControl,
IN PKEVENT Event,
OUT PIO_STATUS_BLOCK IoStatusBlock
);
IoControlCode
必须指定IOCTL_PF_SET_EXTENSION_POINTER
DeviceObject
IpFilterDriver相应的设备对象
InputBuffer
应该强制类型转换成PPF_SET_EXTENSION_HOOK_INFO,其ExtensionPointer成员
等于回调函数地址。如果ExtensionPointer成员为NULL,意味着清除操作。
typedef struct _PF_SET_EXTENSION_HOOK_INFO
{
PacketFilterExtensionPtr ExtensionPointer;
} PF_SET_EXTENSION_HOOK_INFO, *PPF_SET_EXTENSION_HOOK_INFO;
卸载Filter-Hook Driver时,必须清除回调函数。
InputBufferLength
sizeof( PF_SET_EXTENSION_HOOK_INFO )
OutputBuffer
NULL
OutputBufferLength
0
InternalDeviceIoControl
必须指定成FALSE,使得IpFilterDriver处理IRP_MJ_DEVICE_CONTROL的Dispatch
例程被调用。
Event
NULL
IoStatusBlock
应该指定一个有效值
3) 调用IoCallDriver()向IpFilterDriver提交IRP
NTSTATUS IoCallDriver
(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
);
DeviceObject
IpFilterDriver相应的设备对象
Irp
第2步构造的IRP
☆ 一个完整的Filter-Hook Driver框架(丢弃所有ICMP报文以及接收到的RST报文)
1) ipflthookdrv.c
本例可以丢弃所有ICMP报文以及接收到的RST报文。一般丢弃所有ICMP报文并不会造
成大的问题。显然,ping、tracert这类依赖ICMP报文的工具将无法正常使用,别人
也不能ping你,呵。根据th_flags丢弃所有发送到本机的RST报文,但允许本机发送
RST报文给别人。至于TCP/IP协议相关的更复杂的演示就不搞了,毕竟不是正经写防
火墙。
--------------------------------------------------------------------------
/*
* For x86/EWindows XP SP1 & VC 7 & Windows DDK 2600.1106
* build -cZ -x86
*/
/************************************************************************
* *
* Head File *
* *
************************************************************************/
#include <ntddk.h>
/*
* typedef ULONG IPAddr, IPMask;
*/
#include <ntddndis.h>
#include <pfhook.h>
/*
* 用到了CTL_CODE宏
*/
#include <devioctl.h>