首页
论坛
课程
招聘
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝

[原创]简单说点对文件系统、分层驱动、文件读写的理解

2009-4-3 22:30 14691

[原创]简单说点对文件系统、分层驱动、文件读写的理解

2009-4-3 22:30
14691
write by http://hi.baidu.com/weolar/blog/item/34a8ff19be316572dbb4bd4f.html
今天看到sudami同学学习起这些东西,好久没搞了,很生疏,所以重新学习了一下,有点小小心得(仅仅是心得,有不少错误,希望大家斧正 ):
在我的理解中,设备对象(drevobj)相当于驱动对象(drvobj)创建的子对象,用来形成设备链,从而接受、处理数据的。设备对象挂到设备链中,接受到了被设备管理器派遣的IRP时(记得某本书上好像说,没有真正所谓的设备管理器,只是一组派遣例程,如IopfCallDriver就是将IRP派遣的。通过hook这个函数能得到很多我们想要的东西),这时设备对象的母对象--驱动对象组建的IRP派遣函数,(即DriverObject->MajorFunction[IRP_MJ_CREATE]         = DispatchCreate;形式的函数)将会接受IRP并处理。而设备堆栈则是每次IRP下发时辅助IRP找到相应派遣函数并存储一些可重用参数的地方。
    废话说了这么多,那么我们平时访问、删除文件是怎么回事呢?比如我们删除一个文件,那么系统的流程就是:

(应用层)DeleteFileA -->
DeleteFileW -->
ntdll.ZwSetInformationFil->
(驱动层)NtSetInformationFile->
SrSetInformationFile->
NtfsNtSetInformationFile->
NtfsCommonSetInformationFile->
NtfsSetDispositionInfo ->
MmFlushImageSection ->
MiCleanSection

到了驱动层,windows就是通过IRP来传递了。上面的流程中,nt!NtSetInformationFile->SrSetInformationFile->NtfsNtSetInformationFile->NtfsCommonSetInformationFile 几个此时虽然也有IRP的传送,但都还是直接调用,不是IopfCallDriver的形式。而IRP起到传递参数的作用。它体内保持着将要下发的设备对象。现在来看接下来某个IRP(并非删除文件)在设备链中的传递:

nt!NtFlushBuffersFile->

nt!IopSynchronousServiceTail->

sr!SrPassThrough->

Ntfs!NtfsFsdFlushBuffers->

Ntfs!LfsFlushToLsn->

Ntfs!LfsFlushToLsnPriv->

Ntfs!LfsFlushLbcb->

Ntfs!LfsFlushLfcb->

sr!SrWrite->

Ntfs!NtfsCommonWrite->

Ntfs!NtfsNonCachedIo->

Ntfs!NtfsSingleAsync->

VolSnap!VolSnapWrite->

ftdisk!FtDiskReadWrite->

CLASSPNP!ClassReadWrite->

CLASSPNP!ServiceTransferRequest->

CLASSPNP!SubmitTransferPacket->

atapi!IdePortDispatch(\Driver\atapi \ IdeDeviceP0T0L0-3)->

atapi!IdePortInsertByKeyDeviceQueue->

atapi!StartIo Packet->

HAL->

Io 端口……
也就是说:IRP是从Ntfs ->ftdisk (卷设备) -> class(classpnp )-> atapi -> hal -> IO的流向的。

那么\\.\Physical Drive%d 啊,\Device\Harddisk%d\Partition0啊~ 是表示什么呢?通过DeviceTree和winobj可以得知,
\\.\PhysicalDrive 只是Device\Harddisk%d\Partition0的符号连接,

而Device\Harddisk0\Partition0是\Device\Harddisk0\DR0的符号链接。

Device\Harddisk0\Partition1、2……则是Device\HarddiskVolume1、2的符号连接。

那么设备堆栈是怎么回事呢,原来从上到下是这样:

FS DRIVER--->>

Volsnap--->>>

ftdisk(Device\HarddiskVolume1)--->>

partmgr(Ipartmgr )--->>

disk(Device\Harddisk%d\Partition0\ DR0)--->>

acpi--->>>

atapi( IdeDeviceP0T0L0-3)


每层都是attached到上一层,所以形成设备链的。括号内表示驱动对象创建的设备对象,用来形成设备堆栈并接受IRP的。
(所以过滤驱动挂载到任意一层时遍能拦截到数据,这也是微软提倡的“HOOK”方式)

这也就对应了微软的说法,IRP是从文件系统->卷驱动 -> 磁盘驱动-> 类驱动-> 端口驱动-> 微端口驱动的流程的。

而Device\Harddisk%d\Partition0\ DR0则是disk驱动对象创建用来处理ClassReadWrite等IRP的设备对象了。我看了disk的IRP_MJ_READ确实是CLASSPNP!ClassReadWrite,这就可以接受为什么IRP到了disk这层反而到了classpnp中去处理IRP了。

另外,MJ前辈还说过:
1.文件系统设备站和storage设备站使用同一个irp,到了atapi,这个MINIPORT,就换成pkt中的另一个Irp,
2.如果中间没有人重新转发IRP(例如DISKF)的话,从FSD到ATAPI都是用的同一个IRP。IdePortDispatch 没有源代码,而classpnp是开源的(wdk就有),可参考classpnp中的ServiceTransferRequest和SetupReadWriteTransferPacket。

IRP再往下会到哪呢?原来通过在ATAPI中通过IdePortInsertByKeyDeviceQueue将IRP入队列,再往下就是ATAPI的StartIo 了。StartIo 再往下就没有IRP的概念了,便到达HAL(硬件抽象)层,再往下就是端口IO了!

下面是大米同学的图,画的很好,先引用一下^_^:
IRP |     
        |         
        |           attach dev               attach dev
        |               |                       |
   ntfs/fat32.sys  --> dev --> dev --> ... --> dev
        |               |                       |
        |           attach dev               attach dev
        |               |
        |              ...   
        |
        |
        |   
        |              ...
        |               |
      partmgr.sys  --> dev --> dev --> ... --> dev
        |               |                        
        |              ...
        |
        |
        |                                     dev ( \driver\partmgr)
        |              |                       |
       disk.sys   --> dev --> dev --> ... --> dev (DR0)
        |              |
                       
        |
        |                                   dev ( \driver\partmgr)
        |                                      |
        |                                    dev (DR0)   (\driver\disk)                     
        |              |                       |
       atapi.sys  ->  dev --> dev --> ... --> dev
        |
        |
       ...
另外AZY前辈也说过:

读写IRP->IdePortDispatch->IoStartPacket->IdePortStartIo,到这里分两支
有DMA能力的走: BmSetup->BmReceiveScatterGatherList->IdePortAllocateAccessToken->xxx
无DMA能力的走:IdePortAllocateAccessToken->CallIdeStartIoSynchronized->IdeStartIoSynchronized->AtapiStartIo->IO端口xxx

[公告]看雪论坛2020激励机制上线了!多多参与讨论可以获得积分快速升级?

最新回复 (18)
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2009-4-3 22:41
2
0
沙发自己做,哈哈~
雪    币: 461
活跃值: 活跃值 (64)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2009-4-3 22:45
3
0
IdePortDispatch 有源的,在nt4src里面. 它内部调用了IoStartPacket.而 IoStartPacket函数又会调用该dev对应的driver的DriverStartIo例程. eg:

ntdll!_DRIVER_OBJECT
   +0x000 Type             : 4
   +0x002 Size             : 168
   +0x004 DeviceObject     : 0x817dab58 _DEVICE_OBJECT
   +0x008 Flags            : 0x12
   +0x00c DriverStart      : 0xf97ff000
   +0x010 DriverSize       : 0x17480
   +0x014 DriverSection    : 0x817f1c28
   +0x018 DriverExtension  : 0x817c7dc8 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING "\Driver\atapi"
   +0x024 HardwareDatabase : 0x8066f9d8 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
   +0x028 FastIoDispatch   : (null)
   +0x02c DriverInit       : 0xf98145f7     long  atapi!GsDriverEntry+0
   +0x030 DriverStartIo    : 0xf98067c6     void  atapi!IdePortStartIo+0

IdePortStartIo内部跟进去,会调用PCIINDEX内部函数,再往里走就进入HAL.DLL模块了,然后就是IO 操作了. 比如:

kd> kv
ChildEBP RetAddr  Args to Child              
f9dff348 f9c1cddb 817e8190 817e1508 f9dffac8 hal!HalGetScatterGatherList (FPO: [Non-Fpo])
f9dff37c f98068b1 817e15c0 00000000 00000200 PCIIDEX!BmSetup+0x5f (FPO: [Non-Fpo])
f9dff3b4 804efe19 81786030 815ce528 817c75a0 atapi!IdePortStartIo+0xeb (FPO: [Non-Fpo])
f9dff3d4 f9c9703e 81786030 815ce528 00000000 nt!IoStartPacket+0x7d (FPO: [Non-Fpo])
f9dff3f8 f9805c9a 81786030 815ce528 00000000 Main!fake_IoStartPacket+0xbe (FPO: [Non-Fpo]) (CONV: stdcall) [d:\program\r0\coding\逆向sysnap_注册表还原\code\main\patchmodule.c @ 307]
f9dff424 804eedf9 81786030 005ce528 815ce6c0 atapi!IdePortDispatch+0x4e6 (FPO: [Non-Fpo])
f9dff434 f99dd061 00000000 815b7af0 815ce6c0 nt!IopfCallDriver+0x31 (FPO: [0,0,0])
f9dff448 f99dcd58 815ce6c0 81783588 815b7ba8 CLASSPNP!SubmitTransferPacket+0x82 (FPO: [Non-Fpo])
f9dff478 f99dce49 00004000 00004000 815b7af0 CLASSPNP!ServiceTransferRequest+0xe4 (FPO: [Non-Fpo])
f9dff49c 804eedf9 817834d0 00000000 81778208 CLASSPNP!ClassReadWrite+0xff (FPO: [Non-Fpo])
f9dff4ac f9c2436c 817d90e8 815b7bcc f9dff4e8 nt!IopfCallDriver+0x31 (FPO: [0,0,0])
f9dff4bc 804eedf9 817832a8 815b7af0 815b7bf0 PartMgr!PmReadWrite+0x93 (FPO: [Non-Fpo])
f9dff4cc f983e1c6 815b7c0c 817e0b78 815b7af0 nt!IopfCallDriver+0x31 (FPO: [0,0,0])
f9dff4e8 804eedf9 817d9030 815b7af0 815b7c30 ftdisk!FtDiskReadWrite+0x194 (FPO: [Non-Fpo])
f9dff4f8 f99bcaa7 815b7a00 81723100 817c7030 nt!IopfCallDriver+0x31 (FPO: [0,0,0])
f9dff50c 804eedf9 817d9750 815b7af0 815b7af0 VolSnap!VolSnapWrite+0xbb (FPO: [Non-Fpo])
f9dff51c f9725243 f9dff918 815b7af0 f9dff70c nt!IopfCallDriver+0x31 (FPO: [0,0,0])
f9dff52c f9724da6 f9dff918 817d9698 493d4000 Ntfs!NtfsSingleAsync+0x6d (FPO: [Non-Fpo])
f9dff70c f9725ae9 f9dff918 815b7af0 e1480990 Ntfs!NtfsNonCachedIo+0x2f8 (FPO: [Non-Fpo])
f9dff908 f9725c97 f9dff918 815b7af0 0110070a Ntfs!NtfsCommonWrite+0x1949 (FPO: [Non-Fpo])

呵呵,算是大致明白了. weolar同学钻研的很细致~,赞一个!
雪    币: 461
活跃值: 活跃值 (64)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2009-4-3 22:47
4
0
其中 过滤层Volsnap , ftdisk, PartMgr等基本只是稍微处理下IRP包,然后向下转发.
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2009-4-3 22:52
5
0
哈,是啊!还有几个地方不是很懂,呆会再调试调试~
IdePortDispatch  的在哪个文件????
雪    币: 1675
活跃值: 活跃值 (11)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
cntrump 活跃值 13 2009-4-3 22:56
6
0
还是想诱惑大咪出来。。。。。
雪    币: 461
活跃值: 活跃值 (64)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2009-4-3 23:03
7
0
- -
在nt4src的 _nt4_src\private\ntos\dd\scsiport\internal.cScsiPortDispatch
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sosoab 活跃值 2009-4-3 23:14
8
0
那必须得顶阿
雪    币: 292
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
dplayer 活跃值 1 2009-4-3 23:17
9
0

    非顶下盟主不可 ,顺带学习下 -.-
雪    币: 166
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
小塞 活跃值 2009-4-3 23:28
10
0
呵呵,Main!fake_IoStartPacket....原来挂了这个阿
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
alexwe 活跃值 2009-4-3 23:36
11
0
呵呵,写的很详细,好文章!
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
只是学习 活跃值 2009-4-4 00:00
12
0
深入解析里描述的windows存储栈很详细
雪    币: 2512
活跃值: 活跃值 (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
option 活跃值 2009-4-4 09:56
13
0
以我的水平,只有学习,无法模仿!
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
znsoft 活跃值 2009-4-4 14:25
14
0
找本NT文件系统内幕一看就清楚了
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2009-4-4 16:28
15
0
我已经买了~~写的确实很详细
雪    币: 326
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
快雪时晴 活跃值 4 2009-4-4 18:19
16
0
无法学习,只能赞叹
雪    币: 558
活跃值: 活跃值 (10)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
dge 活跃值 6 2009-4-4 23:38
17
0
好文,支持加精。
雪    币: 250
活跃值: 活跃值 (20)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2009-4-25 17:19
18
0
再补充一句,我觉得IoCopyCurrentIrpStackLocationToNext和IoSkipCurrentIrpStackLocation两个函数最大的区别其实只是一个用来设置完成例程,一个不可设置
雪    币: 240
活跃值: 活跃值 (10)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
三根火柴 活跃值 4 2009-4-25 19:03
19
0
楼主所说的书是哪本书
游客
登录 | 注册 方可回帖
返回