noble_shi
驱动牛犊
驱动牛犊
  • 注册日期2003-07-15
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分73分
  • 威望9点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
阅读:6813回复:25

圣诞礼物-中间层驱动的工作原理

楼主#
更多 发布于:2004-12-24 16:56
  
  在我刚接触NDIS的时候,在本论坛受益匪浅,现在将中间层驱动的一些看法写出来,给新学习NDIS的一点点方向,希望大家多提批评意见。

由于有些图,所以只能用附件了
附件名称/大小 下载次数 最后更新
2004-12-24_中间层驱动工作原理.doc (39KB)  1657

最新喜欢:

wingmanwingma... wuhpowuhpo
gqtang
驱动牛犊
驱动牛犊
  • 注册日期2001-08-28
  • 最后登录2012-02-25
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望77点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-12-27 15:30
咋不能下载呢?
noble_shi
驱动牛犊
驱动牛犊
  • 注册日期2003-07-15
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分73分
  • 威望9点
  • 贡献值0点
  • 好评度6点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2004-12-27 18:33
上传了DOC老是不能下载,只能把图该为文本了,真的对不起,如果谁需要给我发MAIL把。


中间层驱动工作原理

作者:noble
联系方式:noble _shi @21cn.com
本文如有错误,请联系作者,谢谢。


(1)注册表常识:
1)、设备数据库所在的注册表健值为:
HKLMSYSTEMCurrentControlSetEnum
ENUM子项中是一个设备数据库,在数据库存放计算机中所有安装的,并且被系统认识到的设备。
所有的用户(包括管理员)都不能更改ENUM项的内容。这是为了保护操作系统和安装的设备的完整性。为了更改设备的设置,应该使用“设备管理器”。
为了在设备管理器中现实隐藏的,非即插即用的,以及没有连接到计算机上的所有设备,你应该首先在命令解释器中敲入命令set DEVMGR_SHOW_NONPRESENT_DEVICES=1,然后启动设备管理器,就可以在设备管理器中删除和重新配置这些设备了。

2)、硬件设备类所在的注册表健值为:
HKLMSYSTEMCurrentControlSetControlClass
Class项下存放硬件设备类的配置信息。在Class项下的每个子项都代表一个设备类,子项的名称使用“唯一全局标识符(GUIS)”,这些标识符存放该设备类的配置信息。在每个类标识符下,还会有以4位数命名的子项,他们代表该设备类里的具体设备,其他的配置数据只应用于该具体设备。
如网卡的设备类是{4D36E972-E325-11CE-BFC1-08002BE10318},并假定我们网卡对应的4为数命名子项名为0005。
其中
HKLMSYSTEMCurrentControlSetClass{4D36E972-E325-11CE-BFC1-08002BE10318}\
05Linkage 中:
Export:代表该设备在设备名字空间输出的设备名字。
RootDevice:代表当前设备的GUID。中间层驱动这里有两个GUID,第一个是自己的GUID,第二个是该中间层驱动绑定的下层MINIPORT的GUID。
UpperBind:代表上层绑定它的NDIS协议驱动或NDIS中间层驱动。当某个协议驱动绑定该MINIPORT设备时,则这个协议驱动的名字必须出现在UpperBind健值的字符串中,否则不能进行绑定。也就是说,UpperBind健值的字符串决定了那个协议驱动(当然也包括中间层驱动注册的协议)和当前的MINIPORT设备绑定,即,它决定了NDIS的上下层绑定关系。

注:一般添加中间层驱动后,中间层驱动只插入到真是网卡和相应协议中间,不会插入到虚拟网卡(如安装虚拟机后虚拟出来的网卡设备)和相应协议中间。

3)、驱动程序所在的注册表健值为:
HKLMSYSTEMCurrentControlSetServices
ENUM子项
通常如果某个服务下存在ENUM子项,表明该服务是用来控制某个设备或者设备交互的,它的下面存放该设备的实例。用户不要去试图修改该子项的内容,因为每次系统启动时,都会重写该子项的内容。
LINKAGE子项
值项Bind
存放该协议所在绑定栈的最低层小端口设备实例(即MINIPORT)。
值项Export
存放该服务必须访问的对象,该对象必须已经安装在系统中,并且该服务能够使用。
值项Route
指定子项Linkage从那里获取绑定数据。
Parameters Adapters子项
这里,我们只解释中间层驱动中该子项的意义。为此,我们假设当前我们讨论的HKLMSYSTEMCurrentControlSetServicesXXXX中的XXXX为中间层驱动。
对于中间层驱动,该子项下含有一个子项,是以我们当前中间层驱动绑定的下层MINIPORT设备的GUID命名的,在我的系统中,健值如下:
{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}
在{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}子项有个健,名称为UpperBindings,该健的健值是当前中间层驱动的MINIPORT设备名称,在我的系统中为如下健值:
Device {5BF5A311-13E4-4746-8865-339DDD6C73AF}

(2)中间层驱动
在我们的函数NDIS_PROTOCOL_CHARACTERISTICS-> BindAdapterHandler()中,会调用一系列函数(如NdisOpenProtocolConfiguration、NdisReadConfiguration)来访问注册表,其实都是访问ParametersAdapters{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}子项。
注意,函数NDIS_PROTOCOL_CHARACTERISTICS-> BindAdapterHandler()的倒数第二个参数是SystemSpecific1,如果我们安装的是XPASSTHRU,则其具体指的是如下字符串:
xfilterParametersAdapters{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}
其中xfilter 是XPASSTHRU的,而{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}在不同的系统中不同。
函数NdisOpenProtocolConfiguration()其实只是构造一个查询注册表的RTL_QUERY
_REGISTRY_TABLE结构(该结构在利用函数RtlQueryRegistryValues()查询注册表是使用)。并将这个结构封装到NDIS_WRAPPER_CONFIGURATION_HANDLE结构中,然后作为NdisOpenProtocolConfiguration()的第二个参数返回。
其实NdisOpenProtocolConfiguration()构造的RTL_QUERY_REGISTRY_TABLE结构的含义也就是查询HKLMSYSTEMCurrentControlSetServices xfilterParametersAdapters{
102454C2-9DB3-42A1-B4CF-6A8B67A516C0}下的健值(xfilter 会随着安装不同的中间层驱动而不同,{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}在不同的系统中不同,下面均省略这些注释)。
函数NdisReadConfiguration()有两个作用,它首先修改在函数NdisOpenProtocolConf
iguration()构造的RTL_QUERY_REGISTRY_TABLE结构。也就是在查询HKLMSYSTEM
CurrentControlSetServices xfilterParametersAdapters{102454C2-9DB3-42A1-B4CF-6A8B6
7A516C0}的基础上加上了一个健,将其变成HKLMSYSTEMCurrentControlSetServices xfilterParametersAdapters{102454C2-9DB3-42A1-B4CF-6A8B67A516C0}UpperBindings。然后函数NdisReadConfiguration()会调用函数RtlQueryRegistryValues()查询新构造的这个注册表,并将结果存储在调用函数NdisReadConfiguration()时的第二个参数中。在我的系统中,RtlQueryRegistryValues()读出的这个新构造的这个注册表的健值是:Device {5BF5A311-13E4-4746-8865-339DDD6C73AF}(后面我们称为RESULT1),它其实是我们注册的中间层驱动(XPASSTHRU)的设备输出(其构造是Device+GUID)。
其实我们读出的这个中间层驱动(XPASSTHRU)的设备(即我们刚才读出的那个健值RESULT1)只在后面的函数NdisIMInitializeDeviceInstanceEx()中才用得着,并且RESULT1是作为函数NdisIMInitializeDeviceInstanceEx()的第二个参数的。
这里有个地方让人感到迷惑,即在函数BindAdapterHandler()我们一旦调用了函数NdisOpenAdapter()绑定了一个下层的MINIPORT,为什么还要调用函数NdisIMInitializeDeviceInstanceEx()初始化我们中间层驱动自己的MINIPORT(因为函数NdisIMInitializeDeviceInstanceEx()的参数是RESULT1,而RESULT1代表我们中间层驱动的MINIPORT)。为了解释这个原因,我们先做如下假设。


------------------------------------------ ------------------------------------------
| PROT-IM | | PROT-TCPIP |
------------------------------------------ ------------------------------------------
| |
------------------------------------------ ------------------------------------------
| NDIS_OPEN_BLOCK1 | | NDIS_OPEN_BLOCK2 |
------------------------------------------ ------------------------------------------
| |
------------------------------------------ ------------------------------------------
| MINIPORT-NIC | | MINIPORT-IM |
------------------------------------------ ------------------------------------------

我们假设我们系统安装了一个中间层驱动(假设为XPASSTRHU),在上图中,PROT-IM和MINIPORT-IM分别代表我们中间层驱动的协议驱动程序和小端口驱动程序,PROT-TCPIP代表真正的协议驱动程序,MINIPORT-NIC代表真是网卡的小端口驱动程序。
当PROT-TCPIP需要发送数据时,会调用函数NdisSend(),其实它会调用MINIPORT-IM中的发送数据函数,但是MINIPORT-IM和MINIPORT-NIC没联系,按照常规是不能发送数据到MINIPORT-NIC的。但是我们可以看到PROT-IM是可以和MINIPORT-NIC互相发送数据的,所以我们必须将MINIPORT-IM和PROT-IM联系起来。
另外当MINIPORT-NIC需要将数据提交给PROT-TCPIP时,只能首先将数据提交给PROT-IM,PROT-IM也只能通过MINIPORT-IM才能和PROT-TCPIP联系起来。
所以必须将PROT-IM和MINIPORT-IM联系起来。有人说这两个东西都是我们中间层驱动注册得,难道还联系不起来吗?不错,但是不管怎样你都得通过你得代码才能将他们联系起来呀!下面我们就介绍联系得方法。
我们以XPASSTHRU为例,在其函数ProtocolBindAdapter()中,先分配了一个ADAPT结构(这个结构是自己定义的,可根据用户的需要定义)。当调用函数ProtocolBindAdapter()调用函数NdisOpenAdapter()进行绑定时,是以&Adapt->BindingHandle作为函数NdisOpenAdapter()的第三个参数的,这样Adapt->BindingHandle就指向了NDIS_OPEN_BLOCK1(注意,调用函数NdisOpenAdapter()时的第三个参数会返回指向绑定以后的NDIS_OPEN_BLOCK指针)。然后函数ProtocolBindAdapter()会调用函数NdisIMInitializeDeviceInstanceEx(),该函数会进一步调用XPASSTHRU的NDIS_MINIPORT_CHARACTERISTICS->InitializeHandler()函数。上面我们讨论过,NdisIMInitializeDeviceInstanceEx()中的第二个参数就是XPASSTHRU注册的小端口驱动的设备实例(即上面的RESULT1)。在函数NdisIMInitializeDeviceInstanceEx()中会根据设备名称(RESULT1),找到对应的MINIPORT结构,并将其指针作为参数传递给NDIS_MINIPORT_CHARACTERISTICS->InitializeHandler()函数(以后简称InitializeHandler()函数)。在InitializeHandler()函数中,会进一步将MINIPORT结构指针赋值给ADAPT->MiniportHandle(ADAPT就是上面在函数ProtocolBindAdapter()中分配的那个结构)。
这样数据结构ADAPT中就含有了两个指针,一个指向NDIS_OPEN_BLOCK1,另一个指向MINIPORT-IM,而NDIS_OPEN_BLOCK1和PROT-IM是密切联系的,所以ADAPT就将PROT-IM和MINIPORT-IM紧密的联系起来了。
另外注意,NDIS_MINIPORT_BLOCK->DeviceContext是指向我们的ADAPT结构的,这个赋值在函数NdisIMInitializeDeviceInstanceEx()中完成。上面谈到了也是在函数NdisIMInitializeDeviceInstanceEx()中完成了从ADAPT-> MiniportHandle到MINIPORT的绑定,所以在函数NdisIMInitializeDeviceInstanceEx()中完成了ADAPT和MINIPORT的互相连接(即指针互相指向)。
函数InitializeHandler()中可以利用句柄MINIPORT的句柄得到我们的ADAPT结构,具体实现这个功能的函数是NdisIMGetDeviceContext(),这个函数的参数是个NDIS_HANDLE类型,但是在该函数内部,会将这个参数转换成NDIS_MINIPORT_BLOCK结构,并返回NDIS_MINIPORT_BLOCK->DeviceContext。
在函数NdisOpenAdapter()中,除了上面提到的完成了由Adapt->BindingHandle到NDIS_OPEN_BLOCK1的指向外,还完成了我们没有提到的由NDIS_OPEN_BLOCK1-> ProtocolBindingContext到ADAPT的指向,所以函数NdisOpenAdapter()完成了ADAPT和NDIS_OPEN_BLOCK1的互相连接(即指针互相指向)。
讲到这里,我们上图完善为下图:

------------------------------------ -----------------------------------
| PROT-IM | | PROT-TCPIP |
------------------------------------ ------------------------------------
| ------------------------------ |
------------------------------------   | ADAPT   | ------------------------------------
| NDIS_OPEN_BLOCK1 | ---- |---BindingHandle | |NDIS_OPEN_BLOCK2 |
| ProtocolBindingContext-|---- | | | |
------------------------------------ | MiniportHandle | -------------------------------------
| -----------------|------------- |
------------------------------------ | | ------------------------------------
| MINIPORT-NIC | | |----------------- |MINIPORT-IM |
| | |----------------------- |DeviceContext |
------------------------------------ -------------------------------------



下面大家也许就可以做一些HOOK了,例如对OPEN_BLOCK结构的HOOK,对ADAPT的HOOK等,这里就不作介绍了,呵呵。


[编辑 -  12/27/04 by  noble_shi]

[编辑 -  12/27/04 by  noble_shi]

[编辑 -  12/27/04 by  noble_shi]
ririri
驱动牛犊
驱动牛犊
  • 注册日期2004-06-02
  • 最后登录2005-07-15
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2004-12-30 16:03
请给我发一份
谢谢!
micmil@tom.com
zzgzzzx
驱动牛犊
驱动牛犊
  • 注册日期2003-05-13
  • 最后登录2009-02-22
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望15点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2004-12-31 09:56
能不能把这篇文档发一份给我呀,我也是刚入门开始的,急需!!
zhangzx@vtion.com.cn
ooio_karl
驱动牛犊
驱动牛犊
  • 注册日期2003-01-22
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分6分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2005-01-02 11:45
你好,
希望也能给我一份,
ooio_karl@126.com
多谢了!
highw
驱动牛犊
驱动牛犊
  • 注册日期2002-01-10
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分372分
  • 威望38点
  • 贡献值0点
  • 好评度36点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2005-01-02 21:18
其实是可以下载的,用FlashGet或其他下载工具就可以。
msn : armlinux2000@hotmail.com
suerdj2k
驱动牛犊
驱动牛犊
  • 注册日期2004-12-28
  • 最后登录2006-02-08
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2005-01-11 08:55
对,可以下,感谢共享!
============================== 苏州工业园区 NDIS驱动 软件研发
lipluto
驱动牛犊
驱动牛犊
  • 注册日期2002-12-08
  • 最后登录2010-03-15
  • 粉丝0
  • 关注0
  • 积分74分
  • 威望47点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2005-01-19 11:56
好文章,感谢中。。。
sfqj82
驱动小牛
驱动小牛
  • 注册日期2004-12-30
  • 最后登录2011-09-03
  • 粉丝0
  • 关注0
  • 积分80分
  • 威望15点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2005-01-31 14:50
顶~~
互相交流~共同进步!
dengyh
驱动牛犊
驱动牛犊
  • 注册日期2002-11-22
  • 最后登录2005-02-03
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2005-02-02 17:23
给我一份呀,多谢!
magicfound@163.com
songty44
驱动牛犊
驱动牛犊
  • 注册日期2004-11-13
  • 最后登录2008-10-24
  • 粉丝0
  • 关注0
  • 积分157分
  • 威望20点
  • 贡献值0点
  • 好评度14点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2005-03-10 20:58
感谢大哥,小弟要一份。
songty44@126.com
jhaoq
驱动牛犊
驱动牛犊
  • 注册日期2005-03-15
  • 最后登录2005-05-24
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2005-03-15 19:26
我想要一份jhaoq@hotmail.com
jhaoq
harry_chen
驱动牛犊
驱动牛犊
  • 注册日期2002-07-08
  • 最后登录2007-05-25
  • 粉丝0
  • 关注0
  • 积分31分
  • 威望4点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2005-03-19 21:44
也可给我一份谢谢!
harryccf@163.com
学而不思则罔,思而不学则殆 学而思之,思而学之,岂非圣人乎?
wwww2
驱动牛犊
驱动牛犊
  • 注册日期2002-04-29
  • 最后登录2016-09-08
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望10点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
14楼#
发布于:2005-03-30 18:55
感谢搂主分享!!
ljmmary
驱动牛犊
驱动牛犊
  • 注册日期2004-07-06
  • 最后登录2007-04-10
  • 粉丝0
  • 关注0
  • 积分44分
  • 威望6点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2005-04-04 23:31
正好需要资料,真是一场及时雨,谢谢了!
xiaoming
qiyidi
驱动牛犊
驱动牛犊
  • 注册日期2005-03-22
  • 最后登录2011-08-19
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望15点
  • 贡献值0点
  • 好评度15点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2005-06-15 09:50
佩服!
写得很好,可给我一份祥细的资料吗?

邮箱:qiyidi@163.com

谢谢!

[编辑 -  6/15/05 by  qiyidi]
lovesch
驱动牛犊
驱动牛犊
  • 注册日期2004-08-10
  • 最后登录2007-08-29
  • 粉丝0
  • 关注0
  • 积分80分
  • 威望8点
  • 贡献值0点
  • 好评度8点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2007-07-20 10:08
能给我发一份吗?
j_qq@163.com。。谢谢
XO威士忌
驱动牛犊
驱动牛犊
  • 注册日期2007-07-19
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望153点
  • 贡献值1点
  • 好评度40点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2007-07-20 10:58
我是新手中的新手,论坛里的兄弟都像LZ这样就好了。
真是感谢啊!
temptemp
驱动牛犊
驱动牛犊
  • 注册日期2004-02-26
  • 最后登录2008-03-11
  • 粉丝0
  • 关注0
  • 积分111分
  • 威望12点
  • 贡献值0点
  • 好评度11点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2007-07-21 21:24
学习中!!!
上一页
游客

返回顶部