紫水晶编程技术论坛 - 努力打造成全国最好的编程论坛

 找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 9609|回复: 22

IRP操作文件填坑日记

  [复制链接]

1

主题

81

帖子

1

精华

铂金会员

Rank: 5

积分
1818
发表于 2017-1-17 12:34:37 | 显示全部楼层 |阅读模式
背景:
近段时间一个项目需要IRP操作文件.于是.搜索硬盘.把好几年前的代码找出来.说起这个代码,需要感谢黑月教主(achillis)和炉子.当时炉子开源了PsVoid.
里面就有Irp操作文件.但是抄了之后.win7蓝屏.当时水平太菜.只好在Q上麻烦教主帮忙.教主帮忙分析一番之后.于是网上就有了.那个经典的ULONG
UnKnow[41]. 然后各个博客转载..当然了.当时我自己也先存了一份.不过后来没啥用一直扔硬盘上..直到这次使用...

过程:
代码大致逻辑为:[和PsVoid类似].其实网上随便找一个IRP操作文件的帖子或者源码.都差不多.

  1. Status = IrpCreateFile(
  2.     FilePath,
  3.     FILE_READ_ATTRIBUTES,
  4.     FILE_ATTRIBUTE_NORMAL,
  5.     FILE_SHARE_READ|FILE_SHARE_WRITE,
  6.     FILE_OPEN,
  7.     FILE_NO_INTERMEDIATE_BUFFERING|FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT,
  8.     &FileObject
  9.     );
  10. Status = FsRtlGetFileSize(FileObject,XXX);
  11. Status = IrpReadFile(FileObject,X,X......);
复制代码

最后调用
IrpClose(FileObject);

简单实验了一下,没有出现什么明显错误.于是就准备windbg双机调试走一遍,然后交付测试,在调试走的时候,一时好奇.在IrpCreateFile之后 !object FileObject. 查看了一下引用计数,
图片1.png
然后等IrpClose(FileObject)完再次!object FileObject. 一查看..Name没有了.但引用计数依然是1.
图片2.png
这是典型的对象泄漏啊..顿时来了精神.是不是这个代码几年前就有BUG.当时没注意..想着既然是对象引用计数不平衡.那就手动减少一下吧.
ObDereferenceObject(FileObject);
悲惨的蓝屏生活就此拉开了序幕.[中间甚至怀疑自己代码写的有问题.直接拿PsVoid的源码加一句ObDereferenceObject(FileObject);也是蓝屏的.]
加了这一行之后.在windowsXP SP3上测试的过程中偶尔就会蓝屏.但是又不是必现(后来我找到了一种必现的方法.).下边是蓝屏时候的堆栈.这两个堆栈交替出现.但必然是之一.
图片3.png
或者
图片4.png

顿时一脸懵逼啊.我就加了这一行.怎么NtFs创建CCB就有问题了..反复测试几次.在确定必然蓝屏而且可重现之后..看来是创建CCB或者从FCB抓什么锁导致的蓝屏.那么是不是这个时候文件对象里面什么成员无效了.导致从FileObject取什么东西然后访问蓝屏的..于是想带源码调试一下..
本来找盟主开源的那份Ntfs源码.编译之后替换进去.不知道怎么搞的.开机的时候巨卡.而且用kmd工具加载我的驱动就会卡在加载驱动那一直不返回..无奈.重新装了一个虚拟机.虚拟机采用Fat32分区.然后从WDK7601中找到FastFat源码(WXP版本).编译然后替换到windowsXP SP3虚拟机内,然后重新开机.开始了调试过程.
这次一加载驱动.fastfat内直接被断言下来了.(实际上走到IrpClose的发送Clean Irp那里.下发下去后击中断言.)
图片5.png

大致意思是说.一个引用计数必须不等于0.然后查看FCB内我的引用计数.的确就是0... 输入忽略之后继续走.引用技术减1成了负数.(0xFFFFFFFFF).
然后.为什么会是0呢.查找引用看看在那初始化的.或者说增加的.按照句柄的套路.打开的时候增加引用计数1.关闭减1.应该配对.这里估计猜着也差不多..
于是打开FastFat源码找到.然后对这个变量查找引用.最后定位到
图片6.png
很明显.只有FileObject-->Flags有这个标志位.才会加1.而我这个FileObject是自己创建出来的.Flags内正好没有这个标志位..那么为什么没有呢.系统是怎么处理这个标志位的.或者说在那初始化呢.在WRK内搜索这个宏.
图片7.png
最后来到了.IopParseDevice内的如下片段.很明显.这个是创建完FileObject后,应该根据CreateOptions然后主动的置位的.原来的代码内没有.. 于是.这就是引出了.这个IRP操作文件的第一个BUG..
[应该根据不同情况设置不同的Flags.(实际上还是WRK考虑的周全.我这里只是简单的解决了我加的这个非缓存读的标志.实际上还有其他的要处理.)而不能简单的_FileObject->Flags = FO_SYNCHRONOUS_IO;]
图片8.png

解决之后,继续调试.最后发现FastFat上蓝屏出现在.[中间跟踪Clean过程以及Close过程就不说了.纯体力+F10]
图片9.png

源码调试就是不一样,直接说明了FatFreeCCB的地方蓝屏.并且.堆栈很明显的指出.这是ObDereferenceObject(FileObject);引发的..
在这里.我走了不少弯路.那就是.分析FatFreeCCB为什么会蓝屏,跟着FastFat绕了好几圈.最后得出结论.蓝屏的时候的这个CCB值是无效的.
那这个CCB是从那来的.怎么就无效了呢..通过代码内查找引用.发现
[ TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); 从FileObject的FsContext2取出CCB然后传递给FatCommonClose释放的.]
FatFreeCCB就一句话.
  1. INLINE
  2. VOID
  3. FatFreeCcb (
  4.     IN PCCB Ccb
  5.     )
  6. {
  7. #if FAT_FILL_FREE
  8.     RtlFillMemoryUlong(Ccb, sizeof(CCB), FAT_FILL_FREE);
  9. #endif

  10.     ExFreePool( Ccb );
  11. }
复制代码

那么FileObject的CCB怎么就无端端的无效了呢.. 或者说FileObject->FsContext2.怎么就无效了.于是又跟了一圈.这次对FileObject的
FsContext2下硬断点.看看是怎么回事.最后得到如下堆栈.
图片11.png

看到这.和上边蓝屏的堆栈一结合.顿时明白了.内存重复释放了..而这个重复释放第一次释放是我们自己的代码.IrpClose内.发IRP_MJ_CLOSE.引发的.
第二次.是ObDereferenceObject(FileObject);引发的...
当时在这个时候.潜意识里一直在想.IrpCreateFile完了就应该IrpClose.是ObDereferenceObject(FileObject)引发了问题..直到我去根据蓝屏堆栈.在WRK找到内IopDeleteFile..彻底明白了.. ObDereferenceObject把对象减到0.自动触发对象删除例程.然后在这个例程内.做一些判断..然后就会调用IopCloseFile来发IRP_MJ_CLEANUP.后回到IopDeleteFile继续发IRP_MJ_CLOSE..这才是正常流程..
而我们自己发IRP_MJ_CLEANUP.和IRP_MJ_CLOSE. 让文件系统提前把相对应的信息释放了.等文件对象销毁的时候再给文件系统发IRP的时候.内存被重复释放.最终引发蓝屏... 脉络清楚之后.解决起来就非常简单了.
一句话.IrpCreateFile之后.不要调用IrpClose.直接一句ObDereferenceObject(FileObject); 搞定..系统自动把CLEANUP和CLOSE全发了.
修改之后,再次测试.Ntfs上也不再蓝屏.Bug解决.

备注:
再说三个BUG.但这三个BUG就不用再细说了.一来.简单.二来网上的IRP操作文件代码也已经解决了.
1.ObCreateObject时候FileObject大小.VISTA以前和以后是不一样的.不过这个不同版本DDK或者WDK的WDM.H头文件内有详细定义照抄即可.
2.创建出来的FileObject内的FileName的Buffer.最好是动态申请的.至于申请出来的Buffer需不需要自己释放.这个可以自由选择.但如果像代码过Verifer的话.
最好.在我上边说的ObDereferenceObject(FileObject);前主动释放掉.[如果不自己释放,IopDeleteFile内也会检测到来释放.]
3.黑月教主当年分析出结构大小需要添加ULONG Unknow[41].但随着操作系统版本升级.win8以后还是相对小了.仍然有几率蓝屏.. 最保险起见
ULONG Unknow[100].(当然了.我这里是偷懒了,准确的方法是沿着黑月教主当年的思路分析一下SeCreateAccessState.)


填完以上BUG之后.目前暂时未发现新的蓝屏点.但其中仍然有许多不足.
例如Read Write时候.IRP Flags的设置等.也需要参照WRK设置..(猜的.下一步用到再验证.但思路都差不多.)


补充:
游客,如果您要查看本帖隐藏内容请回复

评分

参与人数 2水晶币 +110 收起 理由
125096 + 10 很给力!
Tesla.Angela + 100 赞一个!

查看全部评分

854

主题

3481

帖子

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

Rank: 125Rank: 125Rank: 125Rank: 125Rank: 125

积分
36100
发表于 2017-1-17 12:39:33 | 显示全部楼层
我对LZ的填坑功力深表佩服!

0

主题

10

帖子

0

精华

铜牌会员

Rank: 2Rank: 2

积分
50
发表于 2017-1-17 12:42:08 | 显示全部楼层
不错!

1

主题

36

帖子

0

精华

铜牌会员

Rank: 2Rank: 2

积分
274
发表于 2017-1-17 12:50:29 | 显示全部楼层
很详细!非常感谢!

2

主题

45

帖子

0

精华

银牌会员

Rank: 3Rank: 3Rank: 3

积分
397
发表于 2017-1-17 13:03:04 | 显示全部楼层

我对LZ的填坑功力深表佩服!

3

主题

78

帖子

0

精华

初来乍到

Rank: 1

积分
440
发表于 2017-1-17 13:12:31 | 显示全部楼层
卧槽强帖留名,之前对这个IRP打开文件一直持敬畏精神,担心啥时候一不小心就蓝屏了

0

主题

55

帖子

0

精华

铜牌会员

Rank: 2Rank: 2

积分
177
发表于 2017-1-17 13:31:23 | 显示全部楼层
看下,还有些什么补充的。

0

主题

3

帖子

0

精华

初来乍到

Rank: 1

积分
13
发表于 2017-1-17 13:38:41 | 显示全部楼层
很详细!

76

主题

267

帖子

9

精华

贵宾会员

Rank: 2Rank: 2

积分
15599
发表于 2017-1-17 13:51:06 | 显示全部楼层
好!

0

主题

19

帖子

0

精华

铜牌会员

Rank: 2Rank: 2

积分
68
发表于 2017-2-5 10:40:03 | 显示全部楼层
楼主厉害了
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

手机版|Archiver|紫水晶工作室 ( 粤ICP备05020336号 )

GMT+8, 2024-4-19 16:41 , Processed in 0.037654 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表