NDIS中间层驱动包截获技术
摘要:简要概括了NDIS的概念,阐述了NDIS的工作流程,详细说明了如何编写NDIS中间层驱动程序以获得网络封包的详细信息。并且给出了一些代表性的示例代码,供读者参考。
一.NDIS驱动模型简介
NDIS(Network Driver InterfaceSpecification)是网络驱动程序接口规范的简称。它横跨传输层、网络层和数据链路层,定义了网卡或网卡驱动程序与上层协议驱动程序之间的通信接口规范,屏蔽了底层物理硬件的不同,使上层的协议驱动程序可以和底层任何型号的网卡通信。NDIS为网络驱动程序创建了一个完整的开发环境,只需调用NDIS 函数,而不用考虑操作系统的内核以及与其他驱动程序的接口问题,从而使得网络驱动程序可以从与操作系统的复杂通讯中分离,极大地方便了网络驱动程序的编写。另外,利用NDIS的封装特性,可以专注于一层驱动的设计,减少了设计的复杂性,同时易于扩展驱动程序栈。
防火墙的开发一般采用的是中间驱动程序。通过NDIS中间层驱动,我们可以截获来自网卡的所有原始数据包。图1则是NDIS中间层驱动的工作过程图
图1
NDIS中间层驱动程序是工作在MINIPROT和PROTOCOL接口之间的,驱动程序必须向下导出一个PROTOCOL接口,向上导出一个MINIPORT接口。将自己创建的驱动程序插入到网卡驱动程序与传输驱动程序之间。如此一来,当下层的网卡驱动程序接收到数据后会通过MINIPORT接口发送到我们导出的PROTOCOL接口上,NDIS中间层驱动程序便接收到了来自网卡的数据并调用我们准备好的回调函数处理数据包信息。接着NDIS中间层驱动在处理数据包完毕后再继续把数据通过导出的MINIPROT接口向PROTOCOL接口发送。这样就完成了一个截获数据包的过程。
二.NDIS中间层驱动的工作流程
在开始学习NDIS中间层驱动之前,我们有必要了解下NDIS是怎样工作的。当然这就包括了它的接收数据包的流程了。那么我们来看看NDIS接收数据包流程到底是怎样的:
1.低层的网卡驱动调用NdisMIndicateReceive或者NdisMEthIndicateReceive函数通知上一层它们已经收到数据。
2.接着系统调用我们自定义的PtReceive或者PtReceivePacket函数,到底系统会调用哪个函数跟机器的网卡有关。接着在函数中调用NdisGetReceivedPacket函数接受低层传上来的数据,如果我们得到了一个完整的packet包,我们就申请一个缓冲区存放下层传上来的数据,接着调用NdisMIndicateReceivePacket通知上层设备。如果此时MyPacket 的status是NDIS_STATUS_RESOUR
CES,我们就在本函数中释放我们分配的缓冲区;否则我们在上层发送4的时候,在MPReturnPacket中释放该缓冲区。
3.如果在PtReceive或者PtReceivePacket函数中无法得到一个完整的packet,那么就调用NdisMEthIndicateReceive等函数通知系统。recv函数
4.当上层设备得到了一个完整的数据并且处理完毕以后,它会调用NdisReturnPacket,然后NDIS会调用我们的MPReturnPacket。如果申请的缓冲区没释放,则在MPReturnPacket函数中释放该缓冲区。然后同样的向下层调用NdisReturnPacket。下层会释放他们自己申请的缓冲区。
5.如果3发生,那么系统会调用我们的PtReceiveComplete函数。在PtReceiveComplete 函数中我们应该调用NdisMEthIndicateReceiveComplete,通知系统我们收到了完整的数据。
6.当上层协议驱动得知底层已经收到了完整的数据报文以后,可能会调用NdisTransferData,要求下层把剩余的数据传上来。然后系统调用我们的MPTransferData 例程。在MPTransferData中,调用NdisTransferData。必须注意的是该函数的返回值:如果返回success,说明剩余的数据立刻就传上来了。此时会立即返回。7步骤就不会调用;如果返回pending,表明底层在此阻塞,底层会在稍后的时候调用7。
7.当底层miniport驱动做好了一个完整的packet,它会调用NdisTransferDataComplete。同样的,系统会调用我们的PtTransferDataComplete函数。这样,整个接收数据的流程就结束了。
图2
通过流程图我们可以知道在PtReceive或者PtReceivePacket中可以得到我们所
希望的数据,然后在以上2个函数中加入我们自己的处理代码,就可以达到截获数据并进
行相应处理的目的了。
三.在驱动程序中导出接口
我们首先必须在我们的驱动程序中向系统注册导出我们的虚拟接口。这些工作将在DriverEntry函数中完成,代码如下:
复制代码
1NDIS_STATUS Status;
2NDIS_PROTOCOL_CHARACTERISTICS PChars;//保存有关导出PROTOCOL接口的回调函数地址的结构
3NDIS_MINIPORT_CHARACTERISTICS MChars;//保存有关导出MINIPORT接口的回调函数地址的结构
4PNDIS_CONFIGURATION_PARAMETER Param;
5NDIS_STRING Name;
6NdisMInitializeWrapper(&NdisWrapperHandle,DriverObject,RegistryPath,NULL);
//初始化NdisWrapperHandle
7…………//设置其他的回调函数
8MChars.SendPacketsHandler=MPSendPackets;//设置发送数据包的回调函数
9//向NDIS注册我们的MINIPORT接口
10Status=NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
11&MChars,
12sizeof(MChars),
13&DriverHandle);
14…………//设置其他的回调函数
15PChars.ReceivePacketHandler=PtReceivePacket;//设置接收数据包的回调函数16//向NDIS注册我们的MINIPORT接口
17NdisRegisterProtocol(&Status,
18&ProtHandle,
19&PChars,
20sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
21//通知NDIS生成我们所注册的2个接口
22NdisIMAssociateMiniport(DriverHandle,ProtHandle);
23…………
24//theend
如此一来,我们的驱动程序可以看成是工作在网卡层与协议层之间了,当底层网卡有数据到来时会先经过我们的驱动程序处理后再往上层设备发送的。那么我们就可以在自己的回调函数中处理来自网络的数据了。
四.回调函数的工作
在我们向系统注册的回调函数中,比较重要的就是PtReceive和PtReceivePacket 函数了。为了程序的通用性,2个回调函数的大致处理流程是一样的。我们仅拿PtReceive 函数来做例子。PtReceive函数的原型如下:
复制代码
25NDIS_STATUS
26PtReceive(
27IN NDIS_HANDLE ProtocolBindingContext,
28IN NDIS_HANDLE MacReceiveContext,
29IN PVOID HeaderBuffer,//以太头数据
30IN UINT HeaderBufferSize,//以太头数据大小
31IN PVOID LookAheadBuffer,//数据体部分
32IN UINT LookAheadBufferSize,//LookAheadBuffer数
据大小
33IN UINT PacketSize//数据包大小
34);
在该函数中,第三个参数的指向帧头的起始缓冲区,第五个参数指向数据体的起始缓冲区,第七个参数的值为缓冲区大小。如果PacketSize大于LookAheadBufferSize,表明数据还未全部拷贝上来。如果这2个参数相等,那么说明数据全部在LookAheadBuffer变量指向的缓冲区内。让我们来看看下面的代码:
复制代码
35PADAPT pAdapt=(PADAPT)ProtocolBindingContext;
36PNDIS_PACKET MyPacket,Packet;
37NDIS_STATUS Status=NDIS_STATUS_SUCCESS,DataStatus;
38if(!pAdapt->MiniportHandle)
39{
40Status=NDIS_STATUS_FAILURE;
41}
42else do
43{
44if(pAdapt->isSecondary)
45ASSERT(0);
46//从下层驱动获取数据包
47Packet=NdisGetReceivedPacket(pAdapt->BindingHandle,
MacReceiveContext);
48if(Packet!=NULL)
49{
50//如果数据包不为空那么就为下层即将
51//发送上来的数据包分配空间
52NdisDprAllocatePacket(&Status
53,&MyPacket,pAdapt->RecvPacketPoolHandle);
54if(Status==NDIS_STATUS_SUCCESS)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。