寒江独钓NDIS驱动学习总结

第一部分: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协议和小端口联系起来

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
  对于在“蓝网之家”影响下蠢蠢而动搞 Windows 95 远程启动的朋友可能不少,那么大家一定对 NDIS 这几个字母不会感到陌生。其实不只是在远程启动这一层,只要是网卡的驱动盘,大家都会在里面发现有类似 NDISNDIS2、NDIS3、NDIS4一样的目录,只是大家在 Windows 9x 或 NT 中安装、设置网卡时没有注意到它罢了。但即使大搞特搞 RPL 的朋友对其大概也是只知其然而不其所以然。    NDIS 是什么?有什么作用?       NDIS 的全称是 Network Device Interface Specification,中文意思就是网络设备接口规范。    根据 OSI 七层模型,物理层定义了对网卡、线缆以及其它物理硬件设备进行配置的标准。节点间建立通信时是由物理层在传输介质上传送二进制信息实现的,因此,在发送端和接收端都还必须有一个程序来格式化这种信息流并将其传送给上一层。NDIS 的作用就是避免在访问网卡每次进行传输时都编写相应的代码。由此说来,NDIS 本质上是一种软件接口,有了 NDIS ,所有的传输就可以采用一种通用的方式来访问由不同厂商制造的网卡了,即它是用来连接协议堆栈和网卡的。   与此相关的软件还有重定向器(Redirector)和服务器(Server)。前者的目的是截获来自 OSI 会话层的网络调用,并通过将其传送到相应的协议驱动程序接口而格式化成 NDIS 能够识别和使用的命令。后者则负责接收从重向器传过来的来自于远程计算机的请求,再将这一请求传送给相应的本地文件系统驱动程序,最后再由该“服务器”将数据沿协议堆栈向下传递给客户机。    TCP协议也是通过调用 NDIS 接口服务来完成传输操作的。
### 回答1: 《寒江独Windows内核编程源码》是一本非常经典的内核编程书籍。该书主要介绍了Windows内核的结构和工作原理,以及如何进行内核编程。作者通过自己的实践经验,深入浅出地解释了内核编程的基本原理和技巧。 该书的主要内容包括:Windows内核架构、内核模式和用户模式编程、驱动程序开发、处理器管理、内存管理、进程和线程管理、设备驱动程序、文件系统等。通过学习这些内容,读者可以全面了解Windows内核的各个方面,并具备进行内核编程的基础知识和技能。 内核编程是一项非常高级和复杂的技术,需要读者具备扎实的操作系统和编程基础。《寒江独Windows内核编程源码》提供了丰富的源码示例和实践案例,帮助读者加深对内核编程的理解,并能够在实践中掌握内核编程的各种技巧和方法。 通过学习该书,读者可以深入了解Windows内核的工作原理和开发方法,提升自己的技术水平,并有可能在内核开发领域取得突破。同时,该书也适合作为操作系统课程的参考书籍,帮助读者更好地理解操作系统的底层原理和设计思想。 总之,《寒江独Windows内核编程源码》是一本值得学习的经典书籍,通过学习该书,读者可以从理论和实践两个方面全面提升自己的内核编程能力。 ### 回答2: 寒江独Windows内核编程源码,这是指在Windows操作系统内核级别的编程过程中,个人独自执的情景。在传统的Windows内核编程中,需要深入理解Windows操作系统的内部机制、数据结构和调度算法,并通过编写驱动程序或者修改系统核心源码来实现特定的功能或解决某些问题。这是一项相当具有挑战性和专业性的技术领域。 寒江者,指的是独自一人默默鱼的情景。在这个比喻中,内核编程者是在深入学习和专研Windows内核编程的过程中,独自探索和解决问题,就像在江边的一个人默默地捕捞。 Windows内核编程源码指的是Windows操作系统的核心代码。对这些源码的学习和理解,是了解Windows操作系统内部工作原理的关键。通过研究内核编程源码,我们可以了解系统如何管理进程、内存分配、文件系统等功能,以及与硬件的交互过程。 进行寒江独Windows内核编程源码可以带来许多好处。首先,它可以深入了解Windows操作系统的底层工作原理,从而更好地进行系统调试和性能优化。其次,它可以为用户定制和开发高性能的驱动程序,提升系统的稳定性和响应能力。此外,通过研究内核编程源码,可以了解Windows操作系统的安全性和漏洞,从而更好地防范和解决安全问题。 然而,寒江独Windows内核编程源码并不是一项简单的事情,它需要对操作系统原理、编程语言和底层架构有深入的理解。同时,需要拥有扎实的计算机科学基础和编程技巧,以及耐心和毅力来解决各种挑战和问题。 总之,寒江独Windows内核编程源码是一项有挑战性的技术活动,通过对Windows操作系统内核代码的深入研究和理解,可以提高对系统的控制和优化能力,从而为用户提供更好的系统性能和功能。 ### 回答3: 《寒江独Windows内核编程源码》是一本关于Windows内核编程的书籍,作者以“寒江独”来形容自己在Windows内核编程领域的独孤求败之意。这本书主要介绍了Windows操作系统的内核编程细节和原理。 在这本书中,作者首先介绍了Windows内核的基本概念和架构,包括进程和线程管理、内存管理、驱动程序开发等。接着,作者深入讲解了Windows内核的各个模块和重要组件的实现原理,如调度器、文件系统、网络协议栈等。读者可以通过学习这些源码,深入理解Windows内核的工作原理和设计思想。 《寒江独Windows内核编程源码》不仅仅是一本理论性的书籍,更重要的是它提供了丰富的源代码示例和实践案例,读者可以通过实际的代码实现和调试来加深对内核编程的理解。同时,本书还特别注重实用性,提供了大量的编程技巧和调试技巧,帮助读者快速掌握Windows内核编程的方法和技巧。 总之,《寒江独Windows内核编程源码》是一本全面而深入的Windows内核编程技术书籍,适合那些对Windows系统内核感兴趣的程序员和操作系统开发者阅读。通过学习这本书,读者可以系统地学习Windows内核编程的原理和实践,提升自己的技术水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值