转载自: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发送的。

[cpp] view plaincopy
  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. #define NdisSendPackets(NdisBindingHandle, PacketArray, NumberOfPackets)                \
  9. {                                                                                       \
  10. (((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->NdisCommonOpenBlock.SendPacketsHandler)(  \
  11. (PNDIS_OPEN_BLOCK)(NdisBindingHandle),                                          \
  12. (PacketArray),                                                                  \
  13. (NumberOfPackets));                                                             \
  14. }

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

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

[cpp] view plaincopy
  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. struct _NDIS_PROTOCOL_BLOCK * NextProtocol; // Link to next
  8. ULONG MaxPatternSize;
  9. #if defined(NDIS_WRAPPER)
  10. //
  11. // Protocol filters
  12. //
  13. struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1];
  14. WORK_QUEUE_ITEM WorkItem;   // Used during NdisRegisterProtocol to
  15. // notify protocols of existing drivers.
  16. KMUTEX Mutex;               // For serialization of Bind/Unbind requests
  17. PKEVENT DeregEvent;         // Used by NdisDeregisterProtocol
  18. #endif
  19. };

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

[cpp] view plaincopy
  1. typedef struct _NDIS_PROTOCOL_BLOCK     NDIS_PROTOCOL_BLOCK, *PNDIS_PROTOCOL_BLOCK;
[cpp] view plaincopy
  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

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

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

[cpp] view plaincopy
  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. RESET_COMPLETE_HANDLER          ResetCompleteHandler;
  24. REQUEST_COMPLETE_HANDLER        RequestCompleteHandler;
  25. union
  26. {
  27. RECEIVE_HANDLER             ReceiveHandler;
  28. WAN_RECEIVE_HANDLER         WanReceiveHandler;
  29. };
  30. RECEIVE_COMPLETE_HANDLER        ReceiveCompleteHandler;
  31. STATUS_HANDLER                  StatusHandler;
  32. STATUS_COMPLETE_HANDLER         StatusCompleteHandler;
  33. NDIS_STRING                     Name;
  34. //
  35. // Start of NDIS 4.0 extensions.
  36. //
  37. RECEIVE_PACKET_HANDLER          ReceivePacketHandler;
  38. //
  39. // PnP protocol entry-points
  40. //
  41. BIND_HANDLER                    BindAdapterHandler;
  42. UNBIND_HANDLER                  UnbindAdapterHandler;
  43. PNP_EVENT_HANDLER               PnPEventHandler;
  44. UNLOAD_PROTOCOL_HANDLER         UnloadHandler;
  45. } NDIS40_PROTOCOL_CHARACTERISTICS;

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

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

[cpp] view plaincopy
  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. RESET_COMPLETE_HANDLER          ResetCompleteHandler;
  24. REQUEST_COMPLETE_HANDLER        RequestCompleteHandler;
  25. union
  26. {
  27. RECEIVE_HANDLER             ReceiveHandler;
  28. WAN_RECEIVE_HANDLER         WanReceiveHandler;
  29. };
  30. RECEIVE_COMPLETE_HANDLER        ReceiveCompleteHandler;
  31. STATUS_HANDLER                  StatusHandler;
  32. STATUS_COMPLETE_HANDLER         StatusCompleteHandler;
  33. NDIS_STRING                     Name;
  34. } 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就是用来维护这一数据通道的表。

[cpp] view plaincopy
  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. // These are optimizations for getting to MAC routines. They are not
  20. // necessary, but are here to save a dereference through the MAC block.
  21. //
  22. union
  23. {
  24. SEND_HANDLER            SendHandler;
  25. WAN_SEND_HANDLER        WanSendHandler;
  26. };
  27. TRANSFER_DATA_HANDLER       TransferDataHandler;
  28. //
  29. // These are optimizations for getting to PROTOCOL routines.  They are not
  30. // necessary, but are here to save a dereference through the PROTOCOL block.
  31. //
  32. SEND_COMPLETE_HANDLER       SendCompleteHandler;
  33. TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
  34. RECEIVE_HANDLER             ReceiveHandler;
  35. RECEIVE_COMPLETE_HANDLER    ReceiveCompleteHandler;
  36. //
  37. // Extentions to the OPEN_BLOCK since Product 1.
  38. //
  39. union
  40. {
  41. RECEIVE_HANDLER         PostNt31ReceiveHandler;
  42. WAN_RECEIVE_HANDLER     WanReceiveHandler;
  43. };
  44. RECEIVE_COMPLETE_HANDLER    PostNt31ReceiveCompleteHandler;
  45. //
  46. // NDIS 4.0 extensions
  47. //
  48. RECEIVE_PACKET_HANDLER      ReceivePacketHandler;
  49. SEND_PACKETS_HANDLER        SendPacketsHandler;
  50. //
  51. // More NDIS 3.0 Cached Handlers
  52. //
  53. RESET_HANDLER               ResetHandler;
  54. REQUEST_HANDLER             RequestHandler;
  55. RESET_COMPLETE_HANDLER      ResetCompleteHandler;
  56. STATUS_HANDLER              StatusHandler;
  57. STATUS_COMPLETE_HANDLER     StatusCompleteHandler;
  58. REQUEST_COMPLETE_HANDLER    RequestCompleteHandler;
  59. };

上面的表结构可以很清楚的看到这张表是一个单向链接表,并且存放了和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、不要重复勾挂同一个函数。

NDIS的NDIS_PROTOCOL_BLOCK和NDIS_OPEN_BLOCK的介绍相关推荐

  1. NDIS Filter Drivers指南

    NDIS Filter Drivers 译者序  本文是根据DDK中相关章节翻译,本人英语水有限文中难免有翻译及写的不当之处,如 果有任何问题可以通LZIOG@163.com邮件联系和交流. 1 介绍 ...

  2. 关于个人防火墙的真相

    原文作者:MaD  原文标题:The truth aboutpersonal firewalls 电子邮件:mad-factor@mail.ru作者国籍:俄罗斯 声明:1.本人翻译水平有限,有不当之请 ...

  3. 完整适配LUCI界面的Openwrt中EC20的QMI拨号

    目前4G模块应用已经非常普及,跟之前的3G不同,3G基本使用ppp拨号,usbserial驱动,Linux内核自带支持,此应用非常简单. 4G模块由于速率较高,usbserial驱动性能满足不了,因此 ...

  4. 拨号PPP NDIS RNDIS CDC ECM NCM QMI_WWAN GOBINET RMNET MBIM概念介绍

    PPP   PPP 用于建立点对点链路.最初是用于慢速设备的,比如早期通过串行线上网.通过一套协议,维护硬件链路上的数据连接,并具备安全和认证特性,可建立计费模式.   我们在PPP拨号脚本中也常常可 ...

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

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

  6. 【转帖】基于NDIS(网络驱动接口标准)包拦截技术

    通常用户都知道,NDIS协议驱动程序是通过填写一张NDIS_PROTOCOL_CHARACTERISTICS的表,并调用NDIS API函数NdisRegisterProtocol进行注册.现在我们来 ...

  7. Network 之四 常用 Linux 网络命令及网络调试工具介绍

    网络互连模型 主要就是值得 OSI 参考模型与 TCP/IP 五层模型: 下面再来一张详细点的(来源于科来网络): 网络命令   目前,我们常用的网络相关的命令有两大类:net-tools 和 ipr ...

  8. NDIS与WinSock关系之自我扫盲

           起来真是雷人,最近几天纠结与一个最基本的概念,就是NDIS与WinSock关系,想来想去都没有想明白,真实汗Ing,赶紧找了篇精美的文章来扫盲一下. 原文如下: 文章转自http://w ...

  9. 基于Passthru的NDIS开发的个人理解

    基于Passthru的NDIS开发的个人理解 这几天对NDIS的学习,基本思路是:首先熟悉理论知识→然后下载一个例子进行研究→最后例子自己模仿扩展→最最后尝试自己写一个新的. Passthru是微软N ...

最新文章

  1. 实施文档_Word 2010文档处理案例教程
  2. 【正一专栏】登贝莱,该不该来!
  3. 2014-06-27nbsp;20:47
  4. 无边框对话框改变大小
  5. BCOS系统合约介绍
  6. java输出二进制数_Java打印整数的二进制表示(代码与解析)
  7. Oracle MD5加密
  8. 性能测试—接口压测指标分析
  9. covid 19如何重塑美国科技公司的工作文化
  10. 【转】用MYSQL都可能会遇到的问题:MYSQL字符数字转换
  11. 太原理工微型计算机控制试卷,太原理工大学微机原理考试(13届葬仪落整理).docx...
  12. 云原生时代的 YAML 教程
  13. [LUOGU] P2886 [USACO07NOV]牛继电器Cow Relays
  14. Process Node.js 进程
  15. python100例详解-Python 经典算法100及解析(小结)
  16. LeetCode 分数加减运算
  17. JavaWeb学习-动态代理-2-invoke()方法和动态代理Waiter类练习
  18. SDU信息门户(8)组队和文件系统分析
  19. 【毕业设计】机器学习的员工离职模型研究-python
  20. html中出现弹窗偏右,打印机打印某些网页时,右边总是打印不全,怎么办

热门文章

  1. c# winform vlcControl 播放视频列表
  2. N个专项搜索引擎(zz)
  3. 汽车二自由度模型公式推导及simulink模型——传递函数、状态空间
  4. http://39.98.219.132 题库标准答案(题库序号:1966)之最多的金币
  5. 机构推荐的2011年十大金股
  6. mysql获取当前的月_MYSQL中获取当前的年和月
  7. 使用Arduino开发板和颜色传感器TCS230实现颜色感应
  8. 配置jdk16时没有jre目录
  9. 恒业微晶冲刺创业板上市:计划募资8亿元,戴联平为实控人
  10. 一句话脚本系列之获取eth0网卡的IP地址(或MAC地址)