第一部分:NDIS协议驱动

协议驱动框架上层与应用层交互,下层与小端口驱动绑定(可能有中间层),主要功能是处理应用层请求发包和接收以太网包的作用。

1.协议驱动DriverEntry编写步骤:

(1)定义需要用到的变量

(2)生成控制设备:针对不同操作系统调用IoCreateDeviceSecure或IoCreateDevice函数;

生成该设备的符号链接:为了应用层调用该设备对象备用,通过IoCreateSymbolicLink这个API调用;

设置控制设备对象的Flags:主要是设置其为直接IO通信方式,应该是为了方便快速;

初始化锁和链表:初始化锁是为了保护全局变量、同步;链表是为了保存多个打开上下文OpenContext以便日后检索。

(3)在DriverEntry中填写协议特征(实际上就是协议的回调函数列表)

协议特征是一个结构体NDIS_PROTOCOL_CHARACTERISTICS,包含了协议驱动的一系列特征(其实就是回调函数),对应绑定的网卡不同的信息,Windows会采用不同的回调函数处理。

系统会对每个实际存在的网卡实例,调用本协议驱动在协议特征集合中提供的一个回调函数。

发生各种事件时(比如网卡接收到一个新的数据包),特征中的某个函数也会被调用,协议的开发者实现这些函数,就可以在其中决定如何处理接收到的数据包了。

当应用层试图发出一个以太网包时,可以打开这个协议并发出请求(socket或者其他设备接口)

(4)在DriverEntry中使用内核API函数NdisRegisterProtocolDriver,把自己注册成协议驱动

(5)DriverEntry收尾工作,收尾无非就是如果status状态不为success就释放掉上文创建的资源;如果成功则返回status结束DriverEntry。

2.协议与网卡的绑定

一般来说协议和网卡的绑定不是一对一的,通常来说,同一个协议是会在同一台主机的所有网卡生效。绑定主要是对应的下面这个回调函数。

protocolChar.BindAdapterHandler = NdisProtBindAdapter;

NdisProtBindAdapter的实现主要工作有

1.打开上下文的分配和初始化(通俗易懂的理解就是将打开上下文理解为与绑定相关的一些信息,没有这些信息程序会出错)

(1)首先是为打开上下文分配内存空间以及清零,代码自己设置了宏NPROT_ALLOC_MEM、NPROT_ZERO_MEM,其实就是AllocatePoolWithTag和NdisZeroMemory这两个个API;

(2)初始化打开上下文结构,包括几个用到的数据成员。锁、读队列、写对队列、包队列等

(3)给打开上下文增加一个引用计数,在释放回调函数的时候对应减去这个引用计数

(4)读取配置(寒江将这部分阉割了)

(5)正式的绑定过程是调用的ndisprotCreateBinding这个函数,并将这个打开上下文保存到全局链表。

(6)绑定网卡的主要是在ndisprotCreateBinding这个函数中实现的,而完成一个绑定只需要调用一个NdisOpenAdapter API,这个API就将一个协议绑定到一个网卡上。

2. ndisprotCreateBinding主要工作

(1.设法防止多线程竞争

使用自旋锁,主要是在内核中一次操作很快,所以自旋锁用的比较多,其中NPROT_ACQUIRE_LOCK和NPROT_RELEASE_LOCK分别对应NdisAcquireSpinLock(_pLock)、 NdisReleaseSpinLock(_pLock)这两个API

(2.分配和初始化这次绑定的相关资源

包池是一组预先已经分配好的“包描述符”,缓冲池是一组已经分配好的“包缓冲区描述符”

为什么要有包池和缓冲池的概念呢?这是因为在NDIS中每一个以太网包是用一个包描述符来描述,并且包内容用包缓冲区描述符来描述的

在发送和接收包的时候,包不是立即接收和发送的,它们存放在缓冲区中排队等待接收和发送,那么这个时候我们可以自己创建两个包池来容纳发送和接收的包,这样就没有必要多次分配包描述符和包缓冲区描述符。

(3.获得网卡的一些参数

OIDs是NDIS Object Identifiers的简称,使用这个东东的主要目的是我们需要获得显卡的MAC地址以及最大帧长等MAC层、物理层相关的信息,这些信息对于发送包至关重要。

获取参数是调用ndisprotDoRequest这个函数。ndisprotDoRequest这个函数是协议驱动中作者自己封装的一个函数,底层架构其实是调用的NdisRequest这个函数,所有的OID请求都通过它来发送,返回的NTSTATUS如果是未决,则请求完成时会调用xxxComplete函数处理,然后等待xxxComplete函数处理完得到结果。

3.协议与网卡的解绑

当网卡拔出时,协议驱动会解除与这块网卡的绑定,解除绑定调用的内核API是NdisCloseAdatper。关键点是解决在解绑的同时防止再向网卡发送请求,避免冲突

4.用户态发包收包

主要用到的是R3程序APIReadFile、WriteFile、DeviceIoControl

主要步骤是:

1 使用CreateFile打开协议驱动对象的CDO控制设备对象,得到一个句柄。

2 使用DeviceIoControl来进行R0和R3程序的通信

3 使用WriteFile来发送数据包、使用ReadFile来接收包

4 使用CloseFile来关闭句柄,操作结束

5.内核态完成功能实现

内核相应的创建、发包收包请求是IRP_MJ_CREATE、 IRP_MJ_READ、IRP_MJ_WRITE,驱动通过调用对应的分发函数处理对应的请求。

第二点就是接收队列的设置,一个数据包传输完成会先将其保存到“包池”(缓冲区中)。

第二部分:NDIS小端口驱动

1. 小端口驱动DriverEntry编写步骤:

和协议驱动如出一辙。但是源代码是用的WDF框架编写的

1 首先进入DriverEntry检查版本号(可选),调用NdisGetVersion()API

2. WDF_NO_EVENT_CALLBACK初始化驱动标志

WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);

3. 设置WdfDriverInitNoDispatchOverride表示框架不能拦截IO直接发给驱动的Irps

config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;

4. 创建WDFDriver对象

调用WdfDriverCreate这个API

5. 初始化一个包装句柄(Wrapper Handler)

初始化包装句柄。这个句柄是注册小端口必须的。但是对小端口驱动的开发者而言,除了调用一些NDIS函数需要提供这个句柄之外,并没有什么实质的意义

6 填写小端口特征、注册小端口 其中因为要保护全局变量 所以需要有一个锁 另外需要有一个链表储存需要的信息 所以要初始化它们

注册小端口使用NdisMRegisterMiniport,这个API需要包装句柄与小端口特征。

初始化全局变量。这些全局变量是在整个驱动中使用的

NdisAllocateSpinLock(&GlobalData.Lock)和

NdisInitializeListHead(&GlobalData.AdapterList);

到这里小端口DriverEntry就结束了,逻辑很简单和协议驱动完全一致

2. 打开ndisprot设备

(1)打开协议驱动设备对象

一般的IO目标只能打开本驱动生成的设备,这种IO目标被称为本地IO目标,如果要打开其他驱动生成的设备,必须使用远程IO目标

远程IO目标使用WDF的内核API函数WdfIoTargetCreate来生成,用WdfIoTargetOpen来绑定

(2)给IO目标发送DeviceIoControl请求

IO目标和设备对象不同,不能使用Zw系列函数来发送请求

所以要给IO目标发送同步的控制请求需要用WdfIoTargetSendIoCtlSynchronously这个API函数

(3)打开ndisprot接口并完成配置设备

ndisprot是一个协议驱动,这个协议驱动绑定了所有的网卡,本质上来说协议驱动绑定了所有的小端口驱动的每个实例,所以ndisprot也会和ndisedge绑定

现在ndisedge要操纵ndisprot进行收发数据包

步骤

1打开ndisprot的控制设备,这使用生成IO目标,打开IO目标来完成;

2给ndisprot的控制设备发送功能码为IOCTL_NDISPROT_BIND_WAIT的控制请求来等待绑定完成;

3不断发送IOCTL_NDISPROT_QUERY_BINDING来查询它的每个绑定,直到找到第一个名字与ndisedge生成的实例不同的绑定,或者遍历完都没有找到返回错误;

4找到一个就发送IOCTL_NDISPROT_OPEN_DEVICE来指定使用这个绑定发送\接收数据包;

这一系列的操作在NICOpenNdisProtocolInterface中完成,这个函数最终是被MPInitialize调用。

3. 使用ndisprot发送/接收包

(1)使用ndisprot发送包

主要是编写小端口驱动的发包接口,发送控制块TCB,遍历包组找到不是自己的另外的驱动对象填写TCB

(2)使用ndisprot接收包

提交数据包的内核API,从接收控制块(RCB)提交包,对ndisprot读请求的完成函数,读请求的发送,用于读包的WDF工作任务,ndisedge读工作任务的生成与入列。

第三部分:NDIS中间层驱动

中间层驱动的DriverEntry和前面两种没有什么区别,并且其中的套路API基本一样,所以就不赘述了

DriverEntry入口函数步骤如下

1 初始化包装句柄

2 注册小端口特征

3 注册协议特征

4 关联两个接口

通过调用NdisIMAssociateMiniport将协议驱动包装句柄和小端口驱动包装句柄传入这个函数将NDIS协议和小端口联系起来

寒江独钓NDIS驱动学习总结相关推荐

  1. 《寒江独钓》内核学习笔记

    <寒江独钓>内核学习笔记(1)-- IRP - .Little Hann 时间 2013-11-30 15:40:00  博客园_.Little Hann原文  http://www.cn ...

  2. 《寒江独钓》内核学习笔记(1)-- IRP - .Little Hann

     原文  http://www.cnblogs.com/LittleHann/p/3450436.html 在学习内核过滤驱动的过程中,遇到了大量的涉及IRP操作的代码,这里有必要对IRP的数据结 ...

  3. ETHREAD APC 《寒江独钓》内核学习笔记(4)

    继续学习windows 中和线程有关系的数据结构: ETHREAD.KTHREAD.TEB 1. 相关阅读材料 <windows 内核原理与实现> --- 潘爱民 2. 数据结构分析 我们 ...

  4. THREAD APC 《寒江独钓》内核学习笔记(4)

    继续学习windows 中和线程有关系的数据结构: ETHREAD.KTHREAD.TEB 1. 相关阅读材料 <windows 内核原理与实现> --- 潘爱民 2. 数据结构分析 我们 ...

  5. windows7 《寒江独钓》传统键盘过滤驱动学习

    本人驱动方面小白一枚,如果有什么不足之处与不正确之处还请各位大佬多多指正. 另外,本篇博客参考了以下博客,非常感谢原作者的分享!我在学习的时候真的受到了很大的帮助! IRP相关: http://blo ...

  6. 寒江独钓windows 内核安全编程学习笔记

    寒江独钓windows 内核安全编程学习笔记 本博客记录自己的学习过程,如有侵犯或者打扰请告知. 由于项目的需求,第一次接触到驱动程序.开始学习了寒江大神的的内核安全编程.小白一个,第一章就遇到了问题 ...

  7. 驱动开发专家解读 寒江独钓 Windows内核安全编程

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 驱动开发 ...

  8. 寒江独钓-Windows内核安全编程(完整版).pdf

    寒江独钓-Windows内核安全编程(完整版).pdf   编写Windows内核程序,就意味着这个程序可以执行任意指令,可以访问计算机所有的软件.硬件资源.因此,稍有不慎就有可能将系统变得不稳定.W ...

  9. 寒江独钓:Windows内核安全编程(china-pub到货首发)

    寒江独钓:Windows内核安全编程(china-pub到货首发) [作 者]谭文;杨潇;邵坚磊等 [丛 书 名] 驱网核心技术丛书  [出 版 社] 电子工业出版社     [书 号] 978712 ...

最新文章

  1. gitk、Git GUI 图形化工具中文显示乱码的解决方案
  2. SharePoint 沙盒解决方案 VS 场解决方案
  3. lightingJS
  4. 10.MYSQL:什么是事务?事务的性质?事务的应用?
  5. 一般计算机系统中的文件系统采用,南昌大学2001年考研专业课试卷操作系统A
  6. 9 月 19 日,腾讯云安全中心监测到  Apache Tomcat 修复了2个严重级别的漏洞, 分别为: 信息泄露漏洞(CVE-2017-12616)、远程代码执行漏洞(CVE-2017-12615
  7. java什么时候需要同步_JAVA中线程在什么时候需要同步和互斥
  8. python字符串的表示形式_python - 如何为类对象创建自定义字符串表示形式?_class_酷徒编程知识库...
  9. 计算机编程课程顺序_九月份可以开始提供650多种免费的在线编程和计算机科学课程
  10. 『51cto十周年庆典』社区活动大汇总
  11. 给老板汇报技术规划的一些要点(转)
  12. 数据流分析之WorkList Algorithm
  13. mongodb 日期分组聚合_MongoDB基于时间段的聚合查询
  14. 个人计算机软件著作权,个人可以申请软件专利权吗?软件著作权申请的注意事项有哪些?...
  15. 反引号在linux中的作用
  16. Mysql8.0下载(网盘云盘)
  17. 微信可以改彩色昵称了
  18. 路由器自动ip服务器无响应,路由器无法自动分配IP地址原因及解决方法
  19. 腾讯文档导出Excel文档显示‘文件已损坏,无法打开‘解决方法
  20. 如何正确的看待人工智能?只有编程基础的人可以学吗?

热门文章

  1. 广图登陆知网下载资源教程
  2. Android 设置来电铃声、通知铃声、闹钟铃声中的坑
  3. 鹰迪电商|抖音发布作品定位可以随便设置吗?
  4. PyCharm 创建纯Python项目
  5. 电源硬件设计----升降压变换器(负压输出)基础
  6. dns服务器未响应网速卡,DNS服务器未响应且网速突然变的不好是什么原因 怎样解决...
  7. 线性系统粗浅认识——第七次作业
  8. #500-7 [编程作业]3_4 念整数
  9. 基于matlab的锁相环频率合成器,基于MATLAB锁相环.ppt
  10. 欢迎大家关注公众号【音视频开发训练营】