NDIS的NDIS_PROTOCOL_BLOCK和NDIS_OPEN_BLOCK的介绍

转载自:http://blog.sina.com.cn/s/blog_4de78d5901000bfd.html

 

本人简单的介绍一种更有效的基于NDIS包拦截技术

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

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

  1. #define NdisSend(Status, NdisBindingHandle, Packet)                                     \  
  2. {                                                                                       \  
  3.     *(Status) =                                                                         \  
  4.         (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->NdisCommonOpenBlock.SendHandler)(     \  
  5.             ((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->NdisCommonOpenBlock.BindingHandle, \  
  6.         (Packet));                                                                      \  
  7. }  
  8.   
  9. #define NdisSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets)                \  
  10. {                                                                                       \  
  11.     (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->NdisCommonOpenBlock.SendPacketsHandler)(  \  
  12.         (PNDIS_OPEN_BLOCK)(NdisBindingHandle),                                          \  
  13.         (PacketArray),                                                                  \  
  14.         (NumberOfPackets));                                                             \  
  15. }  



现在我们所要做的事情应该很清楚了,只要我们能够将每一个协议程序所填写的NDIS_PROTOCOL_CHARACTERISTICS表里的派发函数指向自己的函数,

我们就能成功的对数据包进行拦截。那么每个协议驱动程序的这张表到底存放在那里呢?太简单了,看一下下面的我对NdisRegisterProtocol重新给出的原型就很明白了。

  1. struct _NDIS_PROTOCOL_BLOCK  
  2. {  
  3.     PNDIS_OPEN_BLOCK OpenQueue; // queue of opens for this protocol  
  4.     REFERENCE Ref;              // contains spinlock for OpenQueue  
  5.     UINT Length;                // of this NDIS_PROTOCOL_BLOCK struct  
  6.     NDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;// handler addresses  
  7.   
  8.     struct _NDIS_PROTOCOL_BLOCK * NextProtocol; // Link to next  
  9.     ULONG MaxPatternSize;  
  10.     #if defined(NDIS_WRAPPER)  
  11.     //  
  12.     // Protocol filters  
  13.     //  
  14.     struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1];  
  15.     WORK_QUEUE_ITEM WorkItem;   // Used during NdisRegisterProtocol to  
  16.     // notify protocols of existing drivers.  
  17.     KMUTEX Mutex;               // For serialization of Bind/Unbind requests  
  18.     PKEVENT DeregEvent;         // Used by NdisDeregisterProtocol  
  19.     #endif  
  20. };  


以上struct _NDIS_PROTOCOL_BLOCK的定义为网友提供,在DDK的安装包里并没有搜索到,只是搜索到了以下:(它存在于nids.h中)

  1. typedef struct _NDIS_PROTOCOL_BLOCK     NDIS_PROTOCOL_BLOCK, *PNDIS_PROTOCOL_BLOCK;  


 

  1. EXPORT  
  2. VOID  
  3. NdisRegisterProtocol(  
  4.     __out   PNDIS_STATUS                      Status,  
  5.     __out   PNDIS_HANDLE                      NdisProtocolHandle,  
  6.     __in    PNDIS_PROTOCOL_CHARACTERISTICS    ProtocolCharacteristics,  
  7.     __in    UINT                              CharacteristicsLength  
  8.     );  

/*注意NDIS_HANDLE所指向的就是PNDIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。*/


NDIS_PROTOCOL_BLOCK(协议表) 是NDIS维护所有系统中已注册协义的单向链接表字段NextProtocol指向下一个协议表
庆幸的是,当我们注册一新的协议时,NDIS总是会把新注册的协义放在链表的头并返回这张表,所以只要我们注册一个新的协议,通过新协议注册返回的链表头就可以轻而易举的遍历系统中所有协议表。

eg: 以下是一个注册自己的协议的函数

NDIS把新注册的协义放在链表的头并返回这张表,新表指针为phProtocolHandle

  1. NTSTATUS RegisterFakeProtocol( OUT PNDIS_HANDLE phProtocolHandle, IN PUCHAR pszProtocolName )  
  2. {  
  3.     NDIS40_PROTOCOL_CHARACTERISTICS     ndis40pcFakeProtCharacts;  
  4.     NDIS_STATUS                         nsRegStatus;  
  5.   
  6.     // Prepare the Protocol Characteristics structure.  
  7.   
  8.     memset( & ndis40pcFakeProtCharacts, 0, sizeof( ndis40pcFakeProtCharacts ) );  
  9.   
  10.     ndis40pcFakeProtCharacts.MajorNdisVersion = 0x4;  
  11.     ndis40pcFakeProtCharacts.MinorNdisVersion = 0;  
  12.     ndis40pcFakeProtCharacts.Reserved = 0;  
  13.   
  14.     ndis40pcFakeProtCharacts.OpenAdapterCompleteHandler = & FakeProtocol_OpenAdapterComplete;  
  15.     ndis40pcFakeProtCharacts.CloseAdapterCompleteHandler = & FakeProtocol_CloseAdapterComplete;  
  16.     ndis40pcFakeProtCharacts.SendCompleteHandler = & FakeProtocol_SendComplete;  
  17.     ndis40pcFakeProtCharacts.TransferDataCompleteHandler = & FakeProtocol_TransferDataComplete;  
  18.     ndis40pcFakeProtCharacts.ResetCompleteHandler = & FakeProtocol_ResetComplete;  
  19.     ndis40pcFakeProtCharacts.RequestCompleteHandler = & FakeProtocol_RequestComplete;  
  20.     ndis40pcFakeProtCharacts.ReceiveHandler = & FakeProtocol_Receive;  
  21.     ndis40pcFakeProtCharacts.ReceiveCompleteHandler = & FakeProtocol_ReceiveComplete;  
  22.     ndis40pcFakeProtCharacts.StatusHandler = & FakeProtocol_Status;  
  23.     ndis40pcFakeProtCharacts.StatusCompleteHandler = & FakeProtocol_StatusComplete;  
  24.   
  25.     NdisInitializeString( & ndis40pcFakeProtCharacts.Name, pszProtocolName );  
  26.   
  27.     ndis40pcFakeProtCharacts.ReceivePacketHandler = & FakeProtocol_ReceivePacket;  
  28.     ndis40pcFakeProtCharacts.BindAdapterHandler = & FakeProtocol_BindAdapter;  
  29.     ndis40pcFakeProtCharacts.UnbindAdapterHandler = & FakeProtocol_UnbindAdapter;  
  30.     ndis40pcFakeProtCharacts.PnPEventHandler = & FakeProtocol_PnpEvent;  
  31.     ndis40pcFakeProtCharacts.UnloadHandler = & FakeProtocol_UnloadProtocol;  
  32.   
  33.     // Register the Fake Protocol with the Fake Handlers.  
  34.   
  35.     NdisRegisterProtocol( & nsRegStatus, phProtocolHandle, & ndis40pcFakeProtCharacts, sizeof( ndis40pcFakeProtCharacts ) );  
  36.   
  37.     if ( nsRegStatus != NDIS_STATUS_SUCCESS )  
  38.     {  
  39.         * phProtocolHandle = NULL;  
  40.         return STATUS_UNSUCCESSFUL;  
  41.     }  
  42.   
  43.     // Return to the caller.  
  44.   
  45.     return STATUS_SUCCESS;  
  46. }  

以上注册的是NDIO 4.0的协议,从D:\WINDDK\7600.16385.1\inc\ddk\ndis.h(6164)有如下定义:

  1. typedef struct _NDIS40_PROTOCOL_CHARACTERISTICS  
  2. {  
  3.     UCHAR                           MajorNdisVersion;  
  4.     UCHAR                           MinorNdisVersion;  
  5.     USHORT                          Filler;  
  6.     union  
  7.     {  
  8.         UINT                        Reserved;  
  9.         UINT                        Flags;  
  10.     };  
  11.     OPEN_ADAPTER_COMPLETE_HANDLER   OpenAdapterCompleteHandler;  
  12.     CLOSE_ADAPTER_COMPLETE_HANDLER  CloseAdapterCompleteHandler;  
  13.     union  
  14.     {  
  15.         SEND_COMPLETE_HANDLER       SendCompleteHandler;  
  16.         WAN_SEND_COMPLETE_HANDLER   WanSendCompleteHandler;  
  17.     };  
  18.     union  
  19.     {  
  20.      TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;  
  21.      WAN_TRANSFER_DATA_COMPLETE_HANDLER WanTransferDataCompleteHandler;  
  22.     };  
  23.   
  24.     RESET_COMPLETE_HANDLER          ResetCompleteHandler;  
  25.     REQUEST_COMPLETE_HANDLER        RequestCompleteHandler;  
  26.     union  
  27.     {  
  28.         RECEIVE_HANDLER             ReceiveHandler;  
  29.         WAN_RECEIVE_HANDLER         WanReceiveHandler;  
  30.     };  
  31.     RECEIVE_COMPLETE_HANDLER        ReceiveCompleteHandler;  
  32.     STATUS_HANDLER                  StatusHandler;  
  33.     STATUS_COMPLETE_HANDLER         StatusCompleteHandler;  
  34.     NDIS_STRING                     Name;  
  35.   
  36.     //  
  37.     // Start of NDIS 4.0 extensions.  
  38.     //  
  39.     RECEIVE_PACKET_HANDLER          ReceivePacketHandler;  
  40.   
  41.     //  
  42.     // PnP protocol entry-points  
  43.     //  
  44.     BIND_HANDLER                    BindAdapterHandler;  
  45.     UNBIND_HANDLER                  UnbindAdapterHandler;  
  46.     PNP_EVENT_HANDLER               PnPEventHandler;  
  47.     UNLOAD_PROTOCOL_HANDLER         UnloadHandler;  
  48.   
  49. } NDIS40_PROTOCOL_CHARACTERISTICS;  

需要说明的在其实nids.h中都只是定义NDIS 3.0  协议:

如D:\WINDDK\3790.1830\inc\ddk\wxp\ndis.h(9370):

  1. typedef struct _NDIS30_PROTOCOL_CHARACTERISTICS  
  2. {  
  3.     UCHAR                           MajorNdisVersion;  
  4.     UCHAR                           MinorNdisVersion;  
  5.     USHORT                          Filler;  
  6.     union  
  7.     {  
  8.         UINT                        Reserved;  
  9.         UINT                        Flags;  
  10.     };  
  11.     OPEN_ADAPTER_COMPLETE_HANDLER   OpenAdapterCompleteHandler;  
  12.     CLOSE_ADAPTER_COMPLETE_HANDLER  CloseAdapterCompleteHandler;  
  13.     union  
  14.     {  
  15.         SEND_COMPLETE_HANDLER       SendCompleteHandler;  
  16.         WAN_SEND_COMPLETE_HANDLER   WanSendCompleteHandler;  
  17.     };  
  18.     union  
  19.     {  
  20.      TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;  
  21.      WAN_TRANSFER_DATA_COMPLETE_HANDLER WanTransferDataCompleteHandler;  
  22.     };  
  23.   
  24.     RESET_COMPLETE_HANDLER          ResetCompleteHandler;  
  25.     REQUEST_COMPLETE_HANDLER        RequestCompleteHandler;  
  26.     union  
  27.     {  
  28.         RECEIVE_HANDLER             ReceiveHandler;  
  29.         WAN_RECEIVE_HANDLER         WanReceiveHandler;  
  30.     };  
  31.     RECEIVE_COMPLETE_HANDLER        ReceiveCompleteHandler;  
  32.     STATUS_HANDLER                  StatusHandler;  
  33.     STATUS_COMPLETE_HANDLER         StatusCompleteHandler;  
  34.     NDIS_STRING                     Name;  
  35. } NDIS30_PROTOCOL_CHARACTERISTICS;  

 

 

顺便说一句NDISREGISTERPROTOCOL为NDIS_PROTOCOL_BLOCK所分配的内存是NonPagedPool类型的。对于核心DRIVER来说,核心区内存是一个线性的内存区,所有核心DRIVER是可以随便访问核心内存区的任意地址。所要注意的是不同IRQL级别下对分页和非分页内存。
有人会问这样就行了吗?真的拦截下来了吗?如果有那位仁兄心急现在就写程序的话,准会失望的,因为他会发现结果什么东西都没拦截到或偶而会拦截到一些数据包。为什么?
因为NDIS网卡驱动和协议驱动在发送和接收到数居时并不是调用PNDIS_OPEN_BLOCK->ProtocolCharacteristics里的派发函数。怎么办?
有必要先介绍一下NDIS网卡驱动和协议驱动之间是如何BINDING 的吧:
(1)NdisRegisterProtocol在注册完一个协议后,不久NDIS会通过调用表中BindAdapterHandler派发函数,通知协议对每一个网卡进行BINDING。或者当系统通PNP找到一块新的网卡时也会调用BindAdapterHandler对协议进行BINDING;

(2)协议在BINDING 调用里,会根据自己的需要使用NdisOpenAdapter将自身绑定到适合的网卡。并返回NdisBindingHandle.NdisBindingHandle。

(2、1)NdisBindingHandle.NdisBindingHandle是什么?NdisBindingHandl其实是指向NDIS_OPEN_BLOCK表的一根指针,那么NDIS_OPEN_BLOCK表有什么用呢?当协议顺利的绑定后,每个绑定的网卡和每一个协议之间建立了数据传输的通道,而NDIS_OPEN_BLOCK就是用来维护这一数据通道的表

  1. struct _NDIS_OPEN_BLOCK  
  2. {  
  3.     PNDIS_MAC_BLOCK             MacHandle;          // pointer to our MAC  
  4.     NDIS_HANDLE                 MacBindingHandle;   // context when calling MacXX funcs  
  5.     PNDIS_ADAPTER_BLOCK         AdapterHandle;      // pointer to our adapter  
  6.     PNDIS_PROTOCOL_BLOCK        ProtocolHandle;     // pointer to our protocol  
  7.     NDIS_HANDLE                 ProtocolBindingContext;// context when calling ProtXX funcs  
  8.     PNDIS_OPEN_BLOCK            AdapterNextOpen;    // used by adapter's OpenQueue  
  9.     PNDIS_OPEN_BLOCK            ProtocolNextOpen;   // used by protocol's OpenQueue  
  10.     PNDIS_OPEN_BLOCK            NextGlobalOpen;  
  11.     BOOLEAN                     Closing;            // TRUE when removing this struct  
  12.     BOOLEAN                     Unbinding;          // TRUE when starting to unbind the adapter  
  13.     BOOLEAN                     NoProtRsvdOnRcvPkt; // Reflect the protocol_options  
  14.     BOOLEAN                     ProcessingOpens;  
  15.     PNDIS_STRING                BindDeviceName;  
  16.     KSPIN_LOCK                  SpinLock;           // guards Closing  
  17.     PNDIS_STRING                RootDeviceName;  
  18.   
  19.     //  
  20.     // These are optimizations for getting to MAC routines. They are not  
  21.     // necessary, but are here to save a dereference through the MAC block.  
  22.     //  
  23.     union  
  24.     {  
  25.         SEND_HANDLER            SendHandler;  
  26.         WAN_SEND_HANDLER        WanSendHandler;  
  27.     };  
  28.     TRANSFER_DATA_HANDLER       TransferDataHandler;  
  29.   
  30.     //  
  31.     // These are optimizations for getting to PROTOCOL routines.  They are not  
  32.     // necessary, but are here to save a dereference through the PROTOCOL block.  
  33.     //  
  34.     SEND_COMPLETE_HANDLER       SendCompleteHandler;  
  35.     TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;  
  36.     RECEIVE_HANDLER             ReceiveHandler;  
  37.     RECEIVE_COMPLETE_HANDLER    ReceiveCompleteHandler;  
  38.   
  39.     //  
  40.     // Extentions to the OPEN_BLOCK since Product 1.  
  41.     //  
  42.     union  
  43.     {  
  44.         RECEIVE_HANDLER         PostNt31ReceiveHandler;  
  45.         WAN_RECEIVE_HANDLER     WanReceiveHandler;  
  46.     };  
  47.     RECEIVE_COMPLETE_HANDLER    PostNt31ReceiveCompleteHandler;  
  48.   
  49.     //  
  50.     // NDIS 4.0 extensions  
  51.     //  
  52.     RECEIVE_PACKET_HANDLER      ReceivePacketHandler;  
  53.     SEND_PACKETS_HANDLER        SendPacketsHandler;  
  54.   
  55.     //  
  56.     // More NDIS 3.0 Cached Handlers  
  57.     //  
  58.     RESET_HANDLER               ResetHandler;  
  59.     REQUEST_HANDLER             RequestHandler;  
  60.     RESET_COMPLETE_HANDLER      ResetCompleteHandler;  
  61.     STATUS_HANDLER              StatusHandler;  
  62.     STATUS_COMPLETE_HANDLER     StatusCompleteHandler;  
  63.     REQUEST_COMPLETE_HANDLER    RequestCompleteHandler;  
  64. };  


上面的表结构可以很清楚的看到这张表是一个单向链接表,并且存放了和PNDIS_OPEN_BLOCK->ProtocolCharacteristics一样的数据收发派发函数。当第N块网卡发送数据包到第N个协议时,就会调用第N个协议与第N个网卡之间建立的NDIS_OPEN_BLOCK表里的SendHandler或SendPacketHandler。所以我们还需要对这张表里的派发函数进行处理(勾挂)。
那么又如何勾挂协议与网卡之间的NDIS_OPEN_BLOCK表呢。我们再回到NDIS_PROTOCOL_BLOCK这张表中,在NDIS_PROTOCOL_BLOCK表中字段PNDIS_OPEN_BLOCK OpenQueue;就是所有该协议所有NDIS_OPEN_BLOCK的表头。通过AdapterNextOpen遍历一下,再勾挂一把。就可以顺利拦截了。

值得注意的是。
1、NDIS_OPEN_BLOCK、NDIS_PROTOCOL_BLOCK这些结构不同NDIS版本是不同的


解决方法是在windows 98和windows95下(ndis 3.1)使用windows98ddk 带的NDIS.H 里的定义;
在windows me下(ndis 5.0或4。0)请使用WINDOWS 98ddk里NDIS.H里的定义nt(ndis4.0)用NTDDK里的定议,以此类推,2000(ndis5.0)。


2、不要重复勾挂同一个函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值