基于NDIS(网络驱动接口标准)包拦截技术

看了很多提供数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进行拦截。但编写该过滤程序拦截程序非常的复杂,这里介绍一种更有效的基于NDIS包拦截技术……

  通常用户都知道,NDIS协议驱动程序是通过填写一张NDIS_PROTOCOL_CHARACTERISTICS的表,并调用NDIS API函数NdisRegisterProtocol进行注册。现在我们来关注一下NDIS_PROTOCOL_CHARACTERISTICS这张表,这张表中存有所有协议驱动程序与底层的派发函数的入口。如SendHandler,ReceiveHandler,BindAdapterHandler等,

  当网卡有数据包进入时,会通过表中ReceiveHandle 或ReceivePacketHandler通知协议驱动程序有一个该协议的数据包进入,反之协议驱动程序是通过SendHandler或SendPacketsHandler函数向网卡驱动发送数据包到网络上去的,有人会奇怪程序中明明不是调用NdisSend或NdisSendPackets函数发送的吗?没错,是这样的,但是你可以看一下NDIS。H的头文件里对这两个函数的定义就知道了,他们都是一个宏定义实际并通过这表中SendHandler或SendPacketsHandler发送的。

  现在我们所要做的事情应该很清楚了,只要我们能够将每一个协议程序所填写的NDIS_PROTOCOL_CHARACTERISTICS表里的派发函数指向自己的函数,我们就能成功的对数据包进行拦截。那么每个协议驱动程序的这张表到底存放在那里呢?看下面的对NdisRegisterProtocol重新给出的原型就很明白了。

struct_NDIS_PROTOCOL_BLOCK
  {
  PNDIS_OPEN_BLOCKOpenQueue;//queueofopensforthisprotocol
  REFERENCERef;//containsspinlockforOpenQueue
  UINTLength;//ofthisNDIS_PROTOCOL_BLOCKstruct
  NDIS50_PROTOCOL_CHARACTERISTICSProtocolCharacteristics;//handleraddresses
  struct_NDIS_PROTOCOL_BLOCK*NextProtocol;//Linktonext
  ULONGMaxPatternSize;
  #ifdefined(NDIS_WRAPPER)
  //
  //Protocolfilters
  //
  struct_NDIS_PROTOCOL_FILTER*ProtocolFilter[NdisMediumMax+1];
  WORK_QUEUE_ITEMWorkItem;//UsedduringNdisRegisterProtocolto
  //notifyprotocolsofexistingdrivers.
  KMUTEXMutex;//ForserializationofBind/Unbindrequests
  PKEVENTDeregEvent;//UsedbyNdisDeregisterProtocol
  #endif
  };
  typedefstruct_NDIS_PROTOCOL_BLOCKNDIS_PROTOCOL_BLOCK,*PNDIS_PROTOCOL_BLOCK;
  EXPORT
  VOID
  NdisRegisterProtocol(
  OUTPNDIS_STATUSStatus,
  OUTPNDIS_PROTOCOL_BLOCKNdisProtocolHandle,/*注意NDIS_HANDLE所指向的就是PNDIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。*/
  INPNDIS_PROTOCOL_CHARACTERISTICSProtocolCharacteristics,
  INUINTCharacteristicsLength
  );

  NDIS_PROTOCOL_BLOCK(协议表) 是NDIS维护所有系统中已注册协义的单向链接表。字段NextProtocol指向下一个协议表。

  庆幸的是,当我们注册一新的协议时,NDIS总是会把新注册的协义放在链表的头并返回这张表,所以只要我们注册一个新的协议通过新协议注册返回的链表头就可以轻而易举的遍历系统中所有协议表.现在我们所希望得到的每个协议的NDIS_PROTOCOL_CHARACTERISTICS表就放在我们面前了,如何勾挂表中的派发函数,我想不必多说了吧。顺便说一句NDISREGISTERPROTOCOL为NDIS_PROTOCOL_BLOCK所分配的内存是NonPagedPool类型的。对于核心DRIVER来说,核心区内存是一个线性的内存区,所有核心DRIVER是可以随便访问核心内存区的任意地址。所要注意的是不同IRQL级别下对分页和非分页内存。

  有人会问这样就行了吗?真的拦截下来了吗?如果有那位仁兄心急现在就写程序的话,准会失望的,因为他会发现结果什么东西都没拦截到或偶而会拦截到一些数据包。为什么?

  因为NDIS网卡驱动和协议驱动在发送和接收到数居时并不是调用PNDIS_OPEN_BLOCK->ProtocolCharacteristics里的派发函数。怎么办?

  有必要先介绍一下NDIS网卡驱动和协议驱动之间是如何BINDING 的吧,NdisRegisterProtocol在注册完一个协议后,不久NDIS会通过调用表中BindAdapterHandler派发函数,通知协议对每一个网卡进行BINDING。或者当系统通PNP找到一块新的网卡,也会调用BindAdapterHandler对协议进行BINDING。协议在BINDING 调用里,会根据自己的需要使用NdisOpenAdapter将自身绑定到适合的网卡。并返回NdisBindingHandle.NdisBindingHandle是什么?NdisBindingHandl其实是指向NDIS_OPEN_BLOCK表的一根指针,那么NDIS_OPEN_BLOCK表有什么用呢?当协议顺利的绑定后,每个绑定的网卡和每一个协议之间建立了数据传输的通道,而NDIS_OPEN_BLOCK就是用来维护这一数据通道的表。

struct_NDIS_OPEN_BLOCK
  {
  PNDIS_MAC_BLOCKMacHandle;//pointertoourMAC
  NDIS_HANDLEMacBindingHandle;//contextwhencallingMacXXfuncs
  PNDIS_ADAPTER_BLOCKAdapterHandle;//pointertoouradapter
  PNDIS_PROTOCOL_BLOCKProtocolHandle;//pointertoourprotocol
  NDIS_HANDLEProtocolBindingContext;//contextwhencallingProtXXfuncs
  PNDIS_OPEN_BLOCKAdapterNextOpen;//usedbyadapter\''''sOpenQueue
  PNDIS_OPEN_BLOCKProtocolNextOpen;//usedbyprotocol\''''sOpenQueue
  PFILE_OBJECTFileObject;//createdbyoperatingsystem
  BOOLEANClosing;//TRUEwhenremovingthisstruct
  BOOLEANUnloading;//TRUEwhenprocessingunload
  BOOLEANNoProtRsvdOnRcvPkt;//Reflecttheprotocol_options
  NDIS_HANDLECloseRequestHandle;//0indicatesaninternalclose
  KSPIN_LOCKSpinLock;//guardsClosing
  PNDIS_OPEN_BLOCKNextGlobalOpen;
  //
  //TheseareoptimizationsforgettingtoMACroutines.Theyarenot
  //necessary,butareheretosaveadereferencethroughtheMACblock.
  //
  SEND_HANDLERSendHandler;
  TRANSFER_DATA_HANDLERTransferDataHandler;
  //
  //TheseareoptimizationsforgettingtoPROTOCOLroutines.Theyarenot
  //necessary,butareheretosaveadereferencethroughthePROTOCOLblock.
  //
  SEND_COMPLETE_HANDLERSendCompleteHandler;
  TRANSFER_DATA_COMPLETE_HANDLERTransferDataCompleteHandler;
  RECEIVE_HANDLERReceiveHandler;
  RECEIVE_COMPLETE_HANDLERReceiveCompleteHandler;
  //
  //ExtentionstotheOPEN_BLOCKsinceProduct1.
  //
  RECEIVE_HANDLERPostNt31ReceiveHandler;
  RECEIVE_COMPLETE_HANDLERPostNt31ReceiveCompleteHandler;
  //
  //NDIS4.0extensions
  //
  RECEIVE_PACKET_HANDLERReceivePacketHandler;
  SEND_PACKETS_HANDLERSendPacketsHandler;
  //
  //MoreNDIS3.0CachedHandlers
  //
  RESET_HANDLERResetHandler;
  REQUEST_HANDLERRequestHandler;
  //
  //NeededforPnP
  //
  UNICODE_STRINGAdapterName;//Upcasednameoftheadapterweareboundto
  };

  上面的表结构可以很清楚的看到这张表是一个单向链接表,并且存放了和PNDIS_OPEN_BLOCK->ProtocolCharacteristics一样的数据收发派发函数,当第N块网卡发送数据包到第N个协议时,就会调用第N个协议与第N个网卡之间建立的NDIS_OPEN_BLOCK表里的SendHandler或SendPacketHandler。所以我们还需要对这张表里的派发函数进行处理(勾挂)。

你可能感兴趣的:(数据结构,网络协议)