通常用户都知道,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_BLOCK OpenQueue; // queue of opens for this protocol
  REFERENCE Ref; // contains spinlock for OpenQueue
  UINT Length; // of this NDIS_PROTOCOL_BLOCK struct
  NDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;// handler addresses
  struct _NDIS_PROTOCOL_BLOCK * NextProtocol; // Link to next
  ULONG MaxPatternSize;
  #if defined(NDIS_WRAPPER)
  //
  // Protocol filters
  //
  struct _NDIS_PROTOCOL_FILTER * ProtocolFilter[NdisMediumMax+1];
  WORK_QUEUE_ITEM WorkItem; // Used during NdisRegisterProtocol to
  // notify protocols of existing drivers.
  KMUTEX Mutex; // For serialization of Bind/Unbind requests
  PKEVENT DeregEvent; // Used by NdisDeregisterProtocol
  #endif
  };
  typedef struct _NDIS_PROTOCOL_BLOCK NDIS_PROTOCOL_BLOCK, *PNDIS_PROTOCOL_BLOCK;
  EXPORT
  VOID
  NdisRegisterProtocol(
  OUT PNDIS_STATUS Status,
  OUT PNDIS_PROTOCOL_BLOCK NdisProtocolHandle, /*注意NDIS_HANDLE所指向的就是PNDIS_PROTOCOL_BLOCK的结构,不要有什么怀疑。*/
  IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
  IN UINT CharacteristicsLength
  );

  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_BLOCK MacHandle; // pointer to our MAC
  NDIS_HANDLE MacBindingHandle; // context when calling MacXX funcs
  PNDIS_ADAPTER_BLOCK AdapterHandle; // pointer to our adapter
  PNDIS_PROTOCOL_BLOCK ProtocolHandle; // pointer to our protocol
  NDIS_HANDLE ProtocolBindingContext;// context when calling ProtXX funcs
  PNDIS_OPEN_BLOCK AdapterNextOpen; // used by adapter/''''s OpenQueue
  PNDIS_OPEN_BLOCK ProtocolNextOpen; // used by protocol/''''s OpenQueue
  PFILE_OBJECT FileObject; // created by operating system
  BOOLEAN Closing; // TRUE when removing this struct
  BOOLEAN Unloading; // TRUE when processing unload
  BOOLEAN NoProtRsvdOnRcvPkt; // Reflect the protocol_options
  NDIS_HANDLE CloseRequestHandle; // 0 indicates an internal close
  KSPIN_LOCK SpinLock; // guards Closing
  PNDIS_OPEN_BLOCK NextGlobalOpen;
  //
  // These are optimizations for getting to MAC routines. They are not
  // necessary, but are here to save a dereference through the MAC block.
  //
  SEND_HANDLER SendHandler;
  TRANSFER_DATA_HANDLER TransferDataHandler;
  //
  // These are optimizations for getting to PROTOCOL routines. They are not
  // necessary, but are here to save a dereference through the PROTOCOL block.
  //
  SEND_COMPLETE_HANDLER SendCompleteHandler;
  TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
  RECEIVE_HANDLER ReceiveHandler;
  RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
  //
  // Extentions to the OPEN_BLOCK since Product 1.
  //
  RECEIVE_HANDLER PostNt31ReceiveHandler;
  RECEIVE_COMPLETE_HANDLER PostNt31ReceiveCompleteHandler;
  //
  // NDIS 4.0 extensions
  //
  RECEIVE_PACKET_HANDLER ReceivePacketHandler;
  SEND_PACKETS_HANDLER SendPacketsHandler;
  //
  // More NDIS 3.0 Cached Handlers
  //
  RESET_HANDLER ResetHandler;
  REQUEST_HANDLER RequestHandler;
  //
  // Needed for PnP
  //
  UNICODE_STRING AdapterName; // Upcased name of the adapter we are bound to
  };

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

  http://www.gjpsoft.com/ndishook1.c此部分为NT部分的源代码。要使用在9X下需要修改,因为没有整体分开,一些函数和头文件未给出,但不影响框架请阅读者自己修改。

【转帖】基于NDIS(网络驱动接口标准)包拦截技术相关推荐

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

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

  2. 网络数据包拦截通用技术(协议驱动hook)

    网络数据包拦截通用技术 作者:甘嘉平 (gjp) 看到很多仁兄提供的数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层 对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进 ...

  3. 网络数据包拦截通用技术

    网络数据包拦截通用技术 作者:甘嘉平 (gjp) 看到很多仁兄提供的数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层 对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据包进 ...

  4. COPY FROM 文章标题 网络数据包拦截通用技术

    COPY FROM 文章标题 网络数据包拦截通用技术 看到很多仁兄提供的数据包的拦截技术,其中最多的是编写IM DRIVER在NDIS中间层 对MINIPORT(网卡驱动程序)和协议驱动程序之间的数据 ...

  5. 网络流量监测与调度技术研究

    网络流量监测与调度技术研究 网络流量监测与调度技术研究 学习目标:流量监测 学习内容: 流量监测 流量监测的设计框架 框架一 框架二 框架三 申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接 ...

  6. Windows网络驱动、NDIS驱动(微端口驱动、中间层驱动、协议驱动)、TDI驱动(网络传输层过滤)、WFP(Windows Filtering Platfrom))

    catalog 0.引言 1.Windows 2000网络结构和OSI模型 2.NDIS驱动 3.NDIS微端口驱动编程实例 4.NDIS中间层驱动编程实例 5.TDI驱动 6.TDI驱动 7.TDI ...

  7. NDIS开发[网络驱动开发] NDIS开发1

    转自:http://wuli5164233.blog.163.com/blog/static/46019544200912555843646/ NDIS开发[网络驱动开发] NDIS开发(1) 200 ...

  8. 【转帖】NAT在NDIS中间层驱动中的实现

    1.概要     相信在IPv6的时代到来之前,NAT仍然是解决大多数人上网的主要途径,而且它在企业内网Intranet中也扮演着十分重要的角色.     NAT的全称是Network Address ...

  9. NDIS中间层的驱动包截获技术教程

    NDIS(Network Driver Interface Specification)是网络驱动程序接口规范的简称.它横跨传输层.网络层和数据链路层,定义了网卡或网卡驱动程序与上层协议驱动程序之间的 ...

最新文章

  1. 数梦工场联手阿里云 推出大数据一体机
  2. spark on yarn提交后vcore数不对
  3. zookeeper-一个关于paxos的故事
  4. numpy.cov()和numpy.var()的用法
  5. 或许每条喵咪上辈子都是陨落的码农
  6. js--window关闭事件
  7. MS sql server 基础知识回顾(二)-表连接和子查询
  8. php快速就业教程,PHP就业快学教程004,基本语法“条件控制语句”!
  9. 6-3 jmu-python-函数-找钱 (10分)
  10. Python中Round函数:怎么解释?怎么用?
  11. x86 单线并发多拨_【转帖】适用所有CC版的 openwrt 单线并发多拨教程!!!
  12. 前端同学需要知道的产品原型绘制技巧
  13. Arduino中Serial.print()与Serial.write()函数的区别,以及串口通信中十六进制与字符串的收发格式问题和转换过程详解
  14. Boomer压测环境搭建(Windows)
  15. mysql导入dum_MySql 利用mysqlmysqldum导入导出数据
  16. 计算机本地用户删除后怎么恢复,大神面对win7系统计算机管理本地用户和组不见了的还原步骤...
  17. Mr.Alright---安兔兔、cpu-Z等三方检测apk的主频和屏幕尺寸如何修改
  18. c语言招生信息查询系统,《C语言程序设计》课程设计报-招生信息查询系统.docx...
  19. 说好一个创业故事的5个步骤
  20. 2020年 前端面试问题总结:附答案

热门文章

  1. css 文字重叠_同时文字字体重叠显示不全解决方法
  2. wps自动识别目录错误_使用net 5自动识别代码中的错误
  3. OSChina 周四乱弹 —— 举杯邀明月 对眼成三人
  4. 学习笔记-nodejs之fs模块
  5. 9507龙尚模块调试
  6. 角蜂鸟上手之路(一)——初玩FaceNet
  7. U盘做成系统盘后从64G变成32G,怎么办
  8. 安全阀为什么要校验? 多久校验一次合适?
  9. 多网站批量蜘蛛日志分析工具
  10. 计算机网络第六章学习通题目及答案