[转载]关于驱动中的ObReferenceObjectByName 和 IoGetDeviceObjectPointer

今天huhu0013问我为什么ObReferenceObjectByName不能得到Device类型的对象,讨论一番,最终得到如下解释,记录一下:

=================================================================================
原文:http://www.boxcounter.org/?action=show&id=13

 

前些阵子学写过滤驱动,遇到个问题,在网上找到了相应的资料,Blog下来。

 

我写的程序需要挂在文件系统上,我看《Programming the Windows Driver Model 》中用IoGetDeviceObjectPointer

 

 

 

NTSTATUS 
  IoGetDeviceObjectPointer(
    IN PUNICODE_STRING   ObjectName ,
    IN ACCESS_MASK   DesiredAccess ,
    OUT PFILE_OBJECT   * FileObject ,
    OUT PDEVICE_OBJECT   * DeviceObject
    );

 

 

来获取要挂载的驱动对象,于是我也采用了相同的方法,但是却发现始终无法获取到"//FileSystem//Ntfs" 和//FileSystem//FastFat " , 参考了sinister的WssHookFS驱动程序,发现是用ObReferenceObjectByName 来获取的,试了下,果然成功了。于是很想 知道这两个函数的区别,自己琢磨了下win2K的源码,无奈功力不够,看来半天,也没发现什么蹊跷,上网搜现成的,得到下面的资料,感谢原作者 flyingkisser

 


 

    有时,我们需要得到像"/Device/XXX"或"/Driver/XXX"这种对象的地址,一般想到的最方便的方法是就是用 ObReferenceObjectByName .

 

 

NTKERNELAPI
NTSTATUS
ObReferenceObjectByName(
    IN PUNICODE_STRING ObjectName,
    IN ULONG Attributes,
    IN PACCESS_STATE PassedAccessState OPTIONAL,
    IN ACCESS_MASK DesiredAccess OPTIONAL,
    IN POBJECT_TYPE ObjectType,
    IN KPROCESSOR_MODE AccessMode,
    IN OUT PVOID ParseContext OPTIONAL,
    OUT PVOID *Object
    );

 

这个函数没有公开,但是被导出了。其参数也比较简单,没什么多说的。比如我们想得到"/Driver /KbdClass"对象的地址,调用这个函数可以轻易获得。然而,当我们用这个API去获/Device/KeyboardClass0"对象的地址 时,总是返回0xC0000024,即STATUS_OBJECT_TYPE_MIMATCH对象的类型不匹配,这是哪门子错误,虽然,此路不通时,还有 别的方法可以获得这个对象的地址,但是,我总想把这个问题搞清楚,于是在xp下面逆向了一个这个函数,并结合win2k源代码,最后终于找到了问题所在。


    ObReferenceObjectByName是ObpLookupObjectName 的包裹函数,对于给定的"/X1/X2"这样的名称,
ObpLookupObjectName会通过ObpLookupDirectoryEntry得到"/X1"对象的地址,再定位到对象头,由对象头再找 到对象类型的对象的地址,然后再判断一下类型对象->TypeInfo->ParseProcedure有没有值,如果不为空,则调 用。    如果为空,则不调用(嗯,的确是费话...).对于"/Device"或是"/Driver",他们的类型对象的ParseProcdedure都是空, 所以代码继续往下走,再通过ObpLookupDirectoryEntry得到"/X1/X2"对象的地址,然后,和上面是同样的过程,先定位到对象 头,再找到对象类型对象的地址,再判断类型对象->TypeInfo->ParseProcedure是不是为空.如果是Driver类型的 对象,它的Type对象,名称为Driver,其ParseProcedure为空,没有被调用,成功返回如果是Device类型的对象,它的Type对 象,名称为Device,其ParseProcedure不为空,指向IopParseDevice,而在IopParseDevice内部,会对传入的 一个参数进行检测,这个参数就是我们调用ObReferenceObjectByName()时给定的第7个参数:ParseContext.先把这个指 针转换成指向OPEN_PACKET类型的指针如果这个指针为空,或是这个结构体的Type成员不等于O_TYPE_OPEN_PACKET或者Size 成员不等于sizeof(OPEN_PACKET)就返回0xC0000024错误,即STATUS_OBJECT_TYPE_MIMATCH.而这个参 数一般我们给定的都是空。所以,ObReferenceObjectByName最终返回了STATUS_OBJECT_TYPE_MIMATCH。

    其实这里win2k源代码中是有一段注释的,意思是保证这个Routine的调用是从NtCreateFile()发起的,而不是其实任意的对象打开或创 建操作发起的,尽是这个参数被标记为"可选的".所以,看到这里大家应该清楚了吧,说到底,还是我们被M$玩弄了。


那么,如何解决这个问题呢?
我本想搞清楚这个ParseContext指向的OPEN_PACKET类型的结构体如何初始化的,不过在IopParseDevice里面会看到大量使 用了这个结构体的成员,所以,我觉得分析下去挺没意思了,体力活,实在不想干。其实解决这个问题也很简单,调用 IoGetDeviceObjectPointer()就是了,当然,从它的名称也能看出,它只能得到Device类型的对象的地址 。其实 比较稳妥的方法是调用ZwCreateFile()得到给定名称的对象的句柄,再用ObReferenceObjectByHandle就能得到对象的地 址了,然后句柄就可以ZwClose掉了,最后对象用完以后可别忘了ObDereferenceObject一下。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值