转载自: http://www.cnblogs.com/welfear/archive/2011/02/14/1954454.html
1、介绍
1、1 TDI驱动作用
TDI协议驱动主要应用于版本号在nt4至nt5之间的操作系统,本文档对TDI驱动的分析主要参考nt4所提供 的TDI驱动。TDI是Transport Driver Interface首字母缩写,主要提供网络层协议和传输层协议的实现。
1、2 Windows NT网络总体结构
(1)网络应用程序一般通过MSDN提供的ws2_32.dll的文档使用winsock网络接口。如果在注册表里设置了其它 的SPI服务,Windows NT会加载相映的动态连接库实现应用层的winsock API过滤。ws2_32.dll通过查找 注册表里的服务提供者信息,调用不同服务提供者的实现接口。
(2)相对于TCP/IP,程序会进入msafd.dll和 wshtcpip.dll中。在wshtcpip.dll中,通过调用ntdll.dll中的Native API把请求发送到afd.sys中。AFD 是一个文件系统驱动,所以Windows NT的网络驱动和文件密切相关。然后请求到达TDI驱动,对于TCP/IP 对应的驱动是tcpip.sys。
(3)最后请求会传递到NDIS中通过miniport驱动发送或接收网卡数据。
以上是网络数据包的大致流程。值得说明的是AFD(Ancillary Function Driver)的设计,通过设计统一的接口和注册表中的信息达到实现不同协议栈的目的。不过这部分设计也有intel公司功劳,因为代码中有很多intel 公司工程师的署名:-)。
2、过滤设备
2、1 绑定目标
TDI会创建四个网络设备而不是三个。它们是\Device\Tcp、\Device\Udp、\Device\RawIp、\Device\Ip, 其中的 \Device\Ip 我们不必关心。真正的传送IP数据的是\Device\RawIp。
就我们的过滤目的而言,IP设 备都不用关心。这样,我们使用IoCreateDevice创建两个我们自己的设备,并通过IoAttachDevice放到 \Device\Tcp和\Device\Udp之上。对IoAttachDevice的使用要小心,IoAttachDevice会用IoCreateFile 打开目的设备,绑定设备之后在关闭,但那时我们的设备已经在设备栈之上,所以也会收到close IRP。
同时为了以后使用方便我们保存了TDI设备的地址。创建的设备要设置Flags为DO_DIRECT_IO,因为TDI设 备都使用这个方式。
2、2 分发函数
除了IRP_MJ_INTERNAL_DEVICE_CONTROL之外,其它的IRP都被发送到TCPDispatch之中。在TCPDispatch里有如下几种情况:
(1)\Device\Ip 的IRP被送到IPDispatch之中。这些IRP可能是从ipconfig、ping、route中发出的。
(1、1) IPCleanup负责清理未处理IRP。
(1、2)IPDispatchDeviceControl 中先处理 IOCTL_ICMP_ECHO_REQUEST 调用关系如下:
DispatchEchoRequest->ICMPEchoRequest->ICMPEcho->SendEcho->IPTransmit->SendIPPacket。
IOCTL_ICMP_ECHO_REQUEST支持了SDK中提供的icmp.dll的接口实现。
ICMPEchoRequest可以被内核协议栈直接使用也可以接受用户请求。IOCTL_IP_GET_NTE_INFO、IOCTL_IP_ADD_NTE、 IOCTL_IP_DELETE_NTE提供路由表设置功能;IOCTL_IP_SET_DHCP_INTERFACE提供DHCP设置功能;
IOCTL_IP_SET_ADDRESS提供地址设置功能。用户可以通过interface系列API使用以上功能;
IOCTL_IP_SET_FILTER_POINTER提供对IP过滤驱动的支持。
(2)其它三个设备统一在TCPDispatch中得到分配。
(2、1)处理IRP_MJ_DEVICE_CONTROL时。
先使用TdiMapUserRequest把用户I/O Control code 转化成内部 成MinorFunction。比如IOCTL_TDI_CONNECT变成TDI_CONNECT。
调用TCPDispatchDeviceControl 和TCPDispatchInternalDeviceControl。前者是用来实现IOCTL_TCP_QUERY_INFORMATION_EX和IOCTL_TCP_SET_INFORMATION_EX的。不过在windows 2000之后IRP_MJ_DEVICE_CONTROL并不再需 要转换了。
(2、2)为IRP_MJ_QUERY_SECURITY保留接口。看来微软早意识到RawIP的安全问题,不过这个接口在XP的 SP2补丁之后才起作用。
(2、3)TCPCreate、TCPClose、TCPCleanup几个分派函数处理TDI_CONTROL_CHANNEL_FILE、 TDI_CONNECTION_FILE和TDI_TRANSPORT_ADDRESS_FILE。TDI_CONTROL_CHANNEL_FILE对应EA为空的情况。
TCPCreate实现如下:
得到从NtCreateFile中的Ea(extra缩写)参数,如果为空,则要创建的是TDI_CONTROL_CHANNEL_FILE。如果不为空,用FindEA查找TdiTransportAddress,如果找到用TdiOpenAddress建立地址对象。传输地址对象是三个设备都可以有的。
再用FindEA查找 TdiConnectionContext,如果找到则用TdiOpenConnection建立连接对象,并且只有Tcp设备可以建立。
(2、4)TCPDispatchInternalDeviceControl 实现了TDI的大多数功能。
和常见的文件系统驱动类似,TDI 驱动使用由AFD文件系统驱动建立的FsContext文件控制块,而FsContext2保存了地址对象类型。
A、如果FsContext2为 TDI_CONNECTION_FILE,也就是连接对象,有这几种IRP处理:
TDI_RECEIVE、 TDI_DISASSOCIATE_ADDRESS、TDI_CONNECTTDI_DISCONNECT、TDI_LISTENTDI_ACCEPT、TDI_SEND、 TDI_ASSOCIATE_ADDRESS。
B、如果FsContext2为TDI_TRANSPORT_ADDRESS_FILE,要处理:TDI_SET_EVENT_HANDLER、 TDI_SEND_DATAGRAM、TDI_RECEIVE_DATAGRAM。
C、最后两种TDI_QUERY_INFORMATION和TDI_SET_INFORMATION三个设备都可以处理。
TdiMapUserRequest用于把IRP_MJ_DEVICE_CONTROL映射为IRP_MJ_INTERNAL_DEVICE_CONTROL。 通过AFD.sys发送的网络请求被转化成IRP_MJ_INTERNAL_DEVICE_CONTROL,所以可以先不考虑 IRP_MJ_DEVICE_CONTROL。另外,WinNT组件内部使用IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER 和IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER来直接发送数据包,这个未公开的机制可以绕过我们的过滤。在必要时也要考虑在内。
2、3 过滤地址
2、3、1 本地地址
本地地址放在EAName之后,TRANSPORT_ADDRESS结构里的TDI_ADDRESS_IP中的 sin_port 和 in_addr。
2、3、1 远程地址
TCP协议的远程地址在(PTDI_REQUEST_KERNEL_CONNECT)&(IrpSp->Parameters)之中;
而RawIp和UDP协议的远程地址在(PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters)之中。
2、4 过滤内容
过滤TDI_SEND、TDI_RECEIVE、TDI_SEND_DATAGRAM、TDI_RECEIVE_DATAGRAM时查看irp->MdlAddress。
2、4、1 过滤HTTP