貌似关于NTFS文件系统的底层实现细节,网上资料很少. 这几天突然来了兴趣,于是挖掘了一下.
结合nt4src,IDA+ntfs.sys,windbg+VMWare,在XP SP2下,深入理解了一些NTFS文件系统相关知识.比如逆向搞到了VCB/FCB/LCB/SCB/BCB等结构体,文件打开/枚举/删除操作的流程,缓存管理器/虚拟内存/IO管理器
之间的交互.
KeyWord: VACB, XCB, NTFS, Cache
1.下面是我调试过程中总结的一张XCB之间的关系图 :
NTFS.sys在初始化时,填充分发例程:
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)NtfsFsdFileSystemControl;
IoCreateDevice将创建的设备对象和全局变量NtfsData关联起来,在设备扩展中包含卷控制块(VCB).
(1) IopMountVolume中会挂接相应的卷,填充IRP,发给NTFS.sys:
irpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
irpSp->MinorFunction = IRP_MN_MOUNT_VOLUME;
(2) NtfsFsdFileSystemControl --> NtfsCommonFileSystemControl --> NtfsMountVolume
主要在初始化该卷的VCB结构,通过NtfsOpenRootDirectory,创建了根目录的FCB,LCB,SCB.
2.[XP SP2] 在windbg中调试逆向得到XCB结构
bp Ntfs!NtfsCreateFcb
Ntfs!NtfsCreateFcb:
f974d91f 6a60 push 60h
kd> !thread
THREAD 8154b020 Cid 06c8.06d4 Teb: 7ffdf000 Win32Thread: e1c64e88 RUNNING on processor 0
Not impersonating
DeviceMap e1a57658
Owning Process 8154cd18 Image: explorer.exe
...
ChildEBP RetAddr Args to Child
f7db2520 f97580eb f7db2880 81788100 0000042d Ntfs!NtfsCreateFcb
[f7db2604] f97584ee f7db2880 814df008 814df150 Ntfs!NtfsOpenFile+0xf3
//
// 之前的大量代码已做了准备工作:1.要操作文件的父目录对应的FCB结构
// 2.该父目录的H/A0H属性对应的SCB结构3.在父目录的INDEX_ROOT中该文件
// 的INDEX_ENTRY(为了方便NtfsOpenFile在查找INDEX_ROOT中的巨多的小结构
// INDEX_ENTRY时,进行匹配),其中包含该文件的MFT号.
// 该函数要找到该文件,为其创建对应的FCB结构
//
f7db285c f9747e42 f7db2880 814df008 f7db29b0 Ntfs!NtfsCommonCreate+0x134a // 进入复杂而庞大的处理函数
f7db2a08 80578576 814df008 f7db2c00 81788020 Ntfs!NtfsNetworkOpenCreate+0x8a
//
// 进入Ntfs.sys的分发例程 NtfsFastIoDispatch.FastIoQueryOpen = NtfsNetworkOpenCreate;
//
f7db2af4 805b490a 817c69d0 00000000 8155e708 nt!IopParseDevice+0x916
//
// 熟悉的Object hook与其相关,常见的是干涉文件操作.eg:
// http://hi.baidu.com/sudami/blog/item/ec16d2dd81bd39325882dd51.html (重定向文件)
// http://hi.baidu.com/sudami/blog/item/852cc318de59b7bc4aedbc06.html (重定向注册表)
//
f7db2b7c 805b0deb 00000000 f7db2bbc 00000040 nt!ObpLookupObjectName+0x56a
f7db2bd0 8056c34d 00000000 00000000 00000001 nt!ObOpenObjectByName+0xeb
[f7db2d54] 8053da28 0007ec48 0007ec20 0007ec74 nt!NtQueryAttributesFile+0xf1 ;<--
f7db2d54 7c92eb94 0007ec48 0007ec20 0007ec74 nt!KiFastCallEntry+0xf8
0007ec00 7c92deec 7c80b7b3 0007ec48 0007ec20 ntdll!KiFastSystemCallRet
0007ec04 7c80b7b3 0007ec48 0007ec20 00008001 ntdll!NtQueryAttributesFile+0xc
0007ec74 77f47b2c 0013e6f0 0013e6f0 00000000 kernel32!GetFileAttributesW+0x79
0007ee98 77f47b60 0013e6f0 0013e718 00005021 SHLWAPI!GetFileAttributesWrapW+0x51
0007eeb0 77f5fc5c 0013e6f0 000eb108 00005021 SHLWAPI!PathFileExistsW+0x23
0007eed0 77f5fbfc 00000000 0007f170 00000050 SHLWAPI!_LoadDllString+0x89
0007f118 77429086 0007f170 0007f170 00000050 SHLWAPI!SHLoadIndirectString+0xcc
0007f140 773fedd2 00000001 0000004e 001262d8 SHELL32!CShellExecMenu::_GetMenuString+0x86
0007f214 773ff142 001262bc 001e0117 00000000 SHELL32!CShellExecMenu::QueryContextMenu+0x77
0007f3b0 773ff99e 000ef6c8 0012ec78 00000002 SHELL32!HDXA_AppendMenuItems2+0x2d0
0007f434 774861dd 00000000 001e0117 000eb250 SHELL32!CDefFolderMenu::QueryContextMenu+0x2e8
0007f5b0 77486310 00133e28 00000000 00000000 SHELL32!CDefView::_InvokeContextMenuVerb+0x13c
0007f5dc 77425ee1 00000000 00000000 04000000 SHELL32!CDefView::_InvokeContextMenuVerbOnSelection+0x9a
0007f85c 773d3660 0007fbd4 000d29b8 000d29b8 SHELL32!CDefView::_OnLVNotify+0x37a
0007f874 773d34e5 0007fbd4 00000000 000d29b8 SHELL32!CDefView::_OnNotify+0x7c
0007f9e8 773d3559 0001008e 0000004e 00000001 SHELL32!CDefView::WndProc+0x860
0007fa2c 77d18734 0001008e 0000004e 00000001 SHELL32!CDefView::s_WndProc+0x72
0007fa58 77d18816 773d3503 0001008e 0000004e USER32!InternalCallWinProc+0x28
0007fac0 77d1b89b 00094b80 773d3503 0001008e USER32!UserCallWinProcCheckWow+0x150
0007fafc 77d1b903 0058a4d0 0058a438 00000001 USER32!SendMessageWorker+0x4a5
0007fb1c 7719aff1 0001008e 0000004e 00000001 USER32!SendMessageW+0x7f
0007fbb4 771d0701 0009f078 ffffff8e 0007fbd4 comctl32!CCSendNotify+0xc20
0007fc30 771d0aa6 00010090 00000001 00000025 comctl32!ListView_HandleMouse+0x20e
0007fc50 771d14d9 0009f078 00000001 00000025 comctl32!ListView_OnButtonDown+0x1b
0007fdc0 77d18734 00010090 00000203 00000001 comctl32!ListView_WndProc+0x857
0007fdec 77d18816 771d0c82 00010090 00000203 USER32!InternalCallWinProc+0x28
0007fe54 77d189cd 00094b80 771d0c82 00010090 USER32!UserCallWinProcCheckWow+0x150
0007feb4 77d18a10 0007fed4 00000000 0007fef0 USER32!DispatchMessageWorker+0x306
0007fec4 7741973d 0007fed4 000c66c0 00010090 USER32!DispatchMessageW+0xf
0007fef0 774195d2 7c80929c 000c66c0 000c66c0 SHELL32!CDesktopBrowser::_PeekForAMessage+0x66
0007ff08 77412c57 00000000 0007ff5c 01016e95 SHELL32!CDesktopBrowser::_MessageLoop+0x14
打开C盘,即触发断点.在栈中找到nt!NtQueryAttributesFile 处的EBP,查看参数一,如下:
kd> dt nt!_OBJECT_ATTRIBUTES 0007ec48
+0x000 Length : 0x18
+0x004 RootDirectory : (null)
+0x008 ObjectName : 0x0007ec6c _UNICODE_STRING "\??\C:\WINDOWS\system32\mycomput.dll"
+0x00c Attributes : 0x40 // explorer.exe正准备查询mycomput.dll的属性
+0x010 SecurityDescriptor : (null)
+0x014 SecurityQualityOfService : (null)
通过Ntfs!NtfsOpenFile处的EBP,查看参数:
kd> dd f7db2604 参数
f7db2604 f7db285c f97584ee [f7db2880] 814df008
f7db2614 814df150 [e134cd20] [c17a60b0] 0078003c
-------- --------
参数:SCB 参数:IndexEntry
FullPathName.Buffer FinalName.Buffer
------- -------
f7db2624 [e1068c08] 00180018 [e1068c2c] 81780000
f7db2634 81788100 e1a00000 e1a00378 f7db272c
其中有几个较为重要的参数如下:
参数:IN PSCB ParentScb - 父目录的SCB结构,(为H 或A0H )
参数:IN PINDEX_ENTRY IndexEntry - This is the index entry from the disk for this file.
// 在INDEX_ROOT中有很多INDEX_ENTRY,每个代表一个子文件/文件夹.此函数表明要操作的子文件/文件夹对应的
// INDEX_ENTRY结构体,包含该文件/文件夹的MFT号,其偏移+0x052处为要操作文件的名字,不包含全路径
参数:IN UNICODE_STRING FullPathName - 要操作文件的全路径. eg. "\WINDOWS\system32\mycomput.dll"
参数:IN UNICODE_STRING FinalName - 要操作文件的短名字.eg."mycomput.dll";若名字长度为,则用文件MFT号打开文件
kd> db c17a60b0 // IndexEntry
c17a60b0 2d 04 00 00 00 00 01 00-78 00 5a 00 01 00 00 00 -.......x.Z..... // 参考ntfs3g对这段结构的描述
c17a60c0 1d 00 00 00 00 00 01 00-80 66 e3 86 f8 7c c4 01 .........f...|..
c17a60d0 80 66 e3 86 f8 7c c4 01-da 11 3d 1f a1 60 c8 01 .f...|....=..`..
c17a60e0 30 b3 3c a6 de a4 c8 01-00 60 01 00 00 00 00 00 0.<......`......
c17a60f0 00 60 01 00 00 00 00 00-20 00 00 00 00 00 00 00 .`...... .......
c17a6100 0c 03 6d 00 79 00 63 00-6f 00 6d 00 70 00 75 00 ..m.y.c.o.m.p.u. // 名字长x0C,命名空间为x03,
c17a6110 74 00 2e 00 64 00 6c 00-6c 00 5a 00 00 00 00 00 t...d.l.l.Z..... // 其后就是文件名
#define NTFS_NTC_DATA_HEADER ((NODE_TYPE_CODE)0x0700)
#define NTFS_NTC_VCB ((NODE_TYPE_CODE)0x0701)
#define NTFS_NTC_FCB ((NODE_TYPE_CODE)0x0702)
#define NTFS_NTC_SCB_INDEX ((NODE_TYPE_CODE)0x0703)
#define NTFS_NTC_SCB_ROOT_INDEX ((NODE_TYPE_CODE)0x0704)
#define NTFS_NTC_SCB_DATA ((NODE_TYPE_CODE)0x0705)
#define NTFS_NTC_SCB_MFT ((NODE_TYPE_CODE)0x0706)
#define NTFS_NTC_SCB_NONPAGED ((NODE_TYPE_CODE)0x0707)
#define NTFS_NTC_CCB_INDEX ((NODE_TYPE_CODE)0x0708)
#define NTFS_NTC_CCB_DATA ((NODE_TYPE_CODE)0x0709)
#define NTFS_NTC_IRP_CONTEXT ((NODE_TYPE_CODE)0x070A)
#define NTFS_NTC_LCB ((NODE_TYPE_CODE)0x070B)
#define NTFS_NTC_PREFIX_ENTRY ((NODE_TYPE_CODE)0x070C)
#define NTFS_NTC_QUOTA_CONTROL ((NODE_TYPE_CODE)0x070D)
//
// 重点关注SCB,以及其上的FCB,其下的CCB,LCB等内容
//
kd> dd e134cd20 l120 // 这是system32这个目录的H属性对应的SCB
e134cd20 01940703 00020040 817cd728 00000000
------ ------ -------------------> Resource & PagingIoResource
| |
| 4个UCHAR的合集,SCB->flag:0x40
|
0x703 表示是NTFS_NTC_SCB_INDEX,即该SCB是文件目录的H属性
0x194 该SCB结构的总大小
{}中为3个LARGE_INTEGER xxSize; 表示该文件分配的大小/实际大小/合法大小
e134cd30 { 00057000 00000000 00057000 00000000
e134cd40 00057000 0000000 } 81788fa0 e134cd4c // FastMutex 访问SCB结构的互斥体
--------
e134cd50 e134cd4c 00000000 e134ce30 00000000 ?上面这x40即是SCB结构标准头大小
└──────────────────────┘FSRTL_ADVANCED_FCB_HEADER
e134cd60 e134cc88 e134cc88 e134cc58 81788100
--------------- ------ ------
| | PVCB Vcb; 指向该卷的VCB结构,XCB里面很多都有此成员
| PFCB Fcb; ★Scb->Fcb,即指向该Scb属性对应的文件的FCB结构.该FCB就在本SCB的上方
| 大小为0xc8 = e134cc58 - e134cd20.★
|
LIST_ENTRY FcbLinks; 一个FCB可有多个被打开的属性,每个属性对应一个SCB,用双向连接连接
Flink == Blink,表明只有一个SCB,也就是说system32这个目录的MFT只有H属性被打开了.
e134cd70 100006a0 00000000 00000010 00000011 --> 打开这个属性的文件对象的数量
------ ------ ------ ------
| | |
| | 〓Scb->CleanupCount 该属性被打开的计数.强制删文件会用到,具体请跟踪
| | ZwClose函数〓
| |
| NonCachedCleanupCount 文件(就是某属性eg.90H)被打开后,有些被标记为非缓存句柄
| 即对该文件的操作不经过cache.在此记录此种类型的句柄数量.貌似一般情况下都为
|
ScbState 该SCB的状态位
typedef struct _SHARE_ACCESS { // size - 0x1C
ULONG OpenCount; // 和SCB.CleanupCount遥相呼应
ULONG Readers; //
ULONG Writers;
ULONG Deleters;
ULONG SharedRead;
ULONG SharedWrite;
ULONG SharedDelete;
} SHARE_ACCESS, *PSHARE_ACCESS;
e134cd80 { 00000010 00000010 00000000 00000000 // {}中为SHARE_ACCESS ShareAccess;
e134cd90 00000010 00000010 00000000 } 000000a0 --> AttributeTypeCode
|
若是H属性(数据属性),一般未命名,否则为流文件;若是A0H属性(索引位图属性),名字为"$I30"
UNICODE_STRING AttributeName; 根据AttributeTypeCode而确定.本次调试为:kd> du f973c9d8
--------------- f973c9d8 "$I30"
e134cda0 000a0008 f973c9d8 81785ed8 00000000
------
PFILE_OBJECT FileObject; 该SCB代表属性的MTF对应的文件的文件对象. 如下
kd> dt nt!_file_object 81785ed8
nt!_FILE_OBJECT
+0x000 Type : 5
+0x002 Size : 112
+0x004 DeviceObject : 0x817c69d0 _DEVICE_OBJECT
+0x008 Vpb : 0x817d83b8 _VPB
+0x00c FsContext : 0xe134cd20
+0x010 FsContext2 : (null)
+0x014 SectionObjectPointer : 0x81785d94 _SECTION_OBJECT_POINTERS
+0x018 PrivateCacheMap : 0x81797af8 // 瞧,system32目录的这个MFT
+0x030 FileName : _UNICODE_STRING "\$Directory" // 对应的文件对象,是目录嘛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
NonpagedScb; 理解不够深入,暂时不是很清楚 ? <这段区域属于MCB相关>
------
e134cdb0 00000000 81785d88 【e134cd20 00000001 // 【】中为结构体NTFS_MCB Mcb;
e134cdc0 00000001 00000001 e134cdd0 81788fa0】 // 最终指向该文件(MFT)的所有LCN
------ // 详细信息请参见MCB.h 文件
|
Mcb->NtfsMcbArray; +0x010 数组头的指针,看地址便知就在下面,紧随【】之后
e134cdd0 { 00000000 00000000 00000056 00000000 // {}中为结构体NTFS_MCB_ARRAY;
--------------- --------------- // 标记该文件的起始& 终止VCN
StartingVcn EndingVcn // 于是能计算出它占有的簇数量
NTFS_MCB_ARRAY.NtfsMcbEntry,是双向链表的表头,紧随{}其后
--------
e134cde0 e134cde8 00000000 } 【e13c4768 e134ca38 //【】中为结构体NTFS_MCB_ENTRY;
↑---------------
此处就是e134cde8地址. 双向链表,指向下个同样的结构
e134cdf0 e134cdb8 e134cdd0 817cd150 0000000f 运行时最大数量
--------------- ------ -------> LARGE_MCB.MaximumPairCount
| |
2个回指,指向之前的个结构体 访问该结构体的互斥体
当前的运行时数量LARGE_MCB.PairCount,这里为.就是一个运行时
------- ------> 指定运行时数组的起始地址Mapping
e134ce00 00000001 00000001 e134b828 00000000】
// ┎NextVcn = 0x057
// kd> dd e134b828 表明该MCB块有个运行时─╂Lcn = 0xbfaff
// e134b828 00000057 000bfaff 00000000 00000000 ┠该run data占用了x056个簇
// ┖该文件的逻辑扇区号= Lcn * 8
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
e134ce10 00000000 00000000 00000000 00000000 这段基本无意义,有信息的即是:
e134ce20 00000000 00000000 [00057000 00000000] LONGLONG TotalAllocated;
-----------------
e134ce30 e134ce30 e134ce30 e134cedc e16156b4 ScbSnapshot 保存一份SCB的快照,在
--------------- ------ -------> 系统遇到错误时,恢复用
| |
| PMOVE_FILE_DATA MoveData; R3可发送FSCTL_MOVE_FILE 移动文件
LIST_ENTRY EofListHead;
?从SCB开始到这条线为止,为固定不变
e134ce40 f7db28f8 00000000 的SCB头部,长度为x120.下面是种不同
类型的一种,这里为SCB_INDEX.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
00000000 00000000 ?<这段区域属于结构体SCB_INDEX> ┃
e134ce50 e134ce50 e134ce50 00000000 00000000 ┃
---------------
LIST_ENTRY LcbQueue; 指向该目录下所有打开的LCB,每个LCB指向一个子FCB,可以重复共有
e134ce60 00000000 00000000 00000000 00000000
e134ce70 00000000 00000000 00000000 00000000
e134ce80 e12bf428 e106eeb0 00000000 e1451290
---------------
2个PRTL_SPLAY_LINKS指针,不知道干么的
e134ce90 00220022 e13170e8 [fbf01991] 00000000 // 很奇怪fbf01991不可访问
----------------
kd> dt nt!_unicode_string e134ce90 // UNICODE_STRING NormalizedName;
"\WINDOWS\system32" // 该SCB对应MFT文件的路径
+0x000 Length : 0x22
+0x002 MaximumLength : 0x22
+0x004 Buffer : 0xe13170e8 "\WINDOWS\system32"
e134cea0 00000030 00000001 00001000 00000c01
------ ------ ------ -------
| | | 4个UCHAR的合集
| | BytesPerIndexBuffer
| CollationRule
AttributeBeingIndexed;
┃
e134ceb0 00000006 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
[00000000] 00700708 00002003 ?<这段区域属于结构体CCB>
------- ------ ------
这个当作SCB与CCB间的空隙 | ULONG Flags; 它的标志位算多的,eg:
| ┇
0x708 表示是NTFS_NTC_CCB_INDEX,每个文件对象有一个CCB, ┇
这个system32目录对象也不例外;0x070 该CCB结构的总大小 ┇
┇
#define CCB_FLAG_IGNORE_CASE (0x00000001) <-------------┚
#define CCB_FLAG_OPEN_AS_FILE (0x00000002)
#define CCB_FLAG_DENY_DELETE (0x00002000)
system32目录的CCB.Flags是上面三个的合集,即:
大小写敏感& 以文件的方式打开(非文件流) & 禁止删除
还有其他比较重要的标志位,eg:
#define CCB_FLAG_DELETE_FILE (0x00001000)
#define CCB_FLAG_CLEANUP (0x00008000)
#define CCB_FLAG_SYSTEM_HIVE (0x00010000)
// 发送FSCTL_MARK_AS_SYSTEM_HIVE,标记注册表hive文件windows\system32\config\system
#define CCB_FLAG_DELETE_ON_CLOSE (0x00040000) // 和NtfsCommonCleanup 相关
#define CCB_FLAG_DIR_NOTIFY (0x00800000)
e134cec0 00380022 e13bed70 00000012 00000000
----------------
kd> dt nt!_unicode_string e134cec0 // ●Ccb->FullFileName
"\WINDOWS\system32" // ●非常重要的参数,标记当前所代表的文件(夹)的路径
+0x000 Length : 0x22
+0x002 MaximumLength : 0x38
+0x004 Buffer : 0xe13bed70 "\WINDOWS\system32"
e134ced0 e13cc338 e134cf70 e134cf28 e13cc344
--------------- ------
| PLCB Lcb;指向下面的LCB结构体
LIST_ENTRY LcbLinks; 对应于Lcb->CcbQueue
e134cee0 e134ce38 00000003 00000000 00000000
------
UCHAR TypeOfOpen;该文件指定的打开方式= 0x03
typedef enum _TYPE_OF_OPEN
{
UnopenedFileObject = 1,
UserFileOpen, // 2; 打开的是文件
UserDirectoryOpen, // 3; 在这里为,因为是system32目录
UserVolumeOpen, // 4; 打开的是卷
StreamFileOpen, // 5; 打开的是文件流
} TYPE_OF_OPEN;
e134cef0 00000000 00000001 00000000 00000000
e134cf00 00000000 00000000 00000000 00000000 对这段结构很茫然,
e134cf10 00000000 00000000 00000000 00000000
e134cf20 00000000 00000000
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
0098070b 00000028 ?<这段区域属于结构体LCB> ┃
------ ------ ┃
| ULONG Flags;
|
0x70B 表示是NTFS_NTC_CCB_INDEX,每个文件对象有一个CCB,这个system32目录对象也不例外
0x098 该CCB结构的总大小
观察【】中这个重要变量,明显可以看出:LCB是一个桥梁.将\Windows目录和\system32目录
连接起来. 父亲永远是SCB所代表的(90H,A0H属性),儿子永远是FCB所代表的子文件/文件夹
━━━━━━━━
e134cf30 e13b0558 e134cad0 【e134c970 e134cc58】 ★LCB->Fcb★
--------------- ------- -------> PFCB Fcb;指向该system32目录对应的FCB
| |
| | // ●Lcb->ParantScb ;
| PSCB *ParantScb; // ●非常重要的参数,指向了system32目录
| // 的父目录WINDOWS 的A0H属性对应的SCB
LIST_ENTRY ScbLinks; 对应于Scb->LcbQueue // 结构体,所以可以这样逆着找到当前文件
// 文件的每层父节点●
e134cf40 e134cc80 e134cc80 00220010 e134cfdc
--------------- ---------------
| |
| kd> dt nt!_unicode_string e134cf48 // NAME_LINK.LinkName 大写名字
| +0x000 Length : 0x10
| +0x002 MaximumLength : 0x22
| +0x004 Buffer : 0xe134cfdc "SYSTEM32"
|
LIST_ENTRY FcbLinks; \Windows目录不仅打开了子目录\system32,还可能打开了其他子文件
/文件夹.这里的链表是对应于\Windows目录FCB结构的Fcb->LcbQueue; 通过它,可以将所有被
打开的\Windows目录下的子项目串联起来.
NAME_LINK.Links; 包含个指针,指向父节点,左子树,右子树
--------------------------
e134cf50 [e1637b68 e1640860 e14255f8] 00220010
e134cf60 e134cfba 00000000 00000000 00000000
------
kd> dt nt!_unicode_string e134cf5c // 小写名字Lcb.LittleName
+0x000 Length : 0x10
+0x002 MaximumLength : 0x22
+0x004 Buffer : 0xe134cfba "system32"
e134cf70 e134ced0 e16156a8 【c 00010000】// system32目录的父目录WINDOWS 的
--------------- // MFT号= 0x1C
LIST_ENTRY UnknownList1 ;
e134cf80 00000000 00000548 07443be3 00000000 这段很乱,成员不一定逆的正确,但偏移没问题
e134cf90 00000002 00000000 00000000 00000000 只关注父目录的MFT号& CleanupCount 即可
e134cfa0 1f1d2a75 00000010 e134cf78 00000000
━━━
〓CleanupCount 暴力删文件时会用到〓
↓FileName数组的第一个字节,也是FCB_INDEX.FileName的开始处
e134cfb0 00000000 00000000 00730308 00730079 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
e134cfc0 00650074 0033006d 00000032 00000000
e134cfd0 00000000 00000000 00000000 00590053 到e134cfe0处,整个大结构就结束了.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
kd> db e134cfb8
e134cfb8 08 03 73 00 79 00 73 00-74 00 65 00 6d 00 33 00 ..s.y.s.t.e.m.3.
e134cfc8 32 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 2...............
e134cfd8 00 00 00 00 53 00 59 00-53 00 54 00 45 00 4d 00 ....S.Y.S.T.E.M.
e134cfe8 33 00 32 00 00 00 00 00-00 00 00 00 00 00 00 00 3.2.............
//
// ★Scb->Fcb 和Lcb->Fcb都指向当前目录system32对应的FCB结构(见★),如下:
//
kd> dd e134cc58 l40
e134cc58 00c80702 00000c48 【d 00010000】// system32目录的MTF号和序列号
------ ------ // system32的MFT = 0x1d
| FcbState // Windows目录的MTF = 0x1c
0x702 表示是NTFS_NTC_FCB; 0xc8 该FCB结构的总大小
e134cc68 00000010 00000011 00000000 00000010
━━━
〓Scb->Fcb->CleanupCount 和Scb->CleanupCount 和Lcb->CleanupCount 相同,都为x10 〓
e134cc78 00000000 00000001 e134cf40 e134cf40
--------------
LIST_ENTRY LcbQueue;
LIST_ENTRY ScbQueue;
---------------
e134cc88 e134cd60 e134cd60 f7db28b0 f7db28b0
e134cc98 81788100 81788fa0 817cd728 00000000
------
Fcb->Vcb
e134cca8 dd9b2892 【c860dd e480f01c 01c912dd //【】中为结构体DUPLICATED_INFORMATION
e134ccb8 e480f01c 01c912dd cdae879c 01c9c7a9 // 一个再普通不过的结构了,里面包含一些时间
e134ccc8 00000000 00000000 00000000 00000000 // 和文件大小等信息,基本可忽略之
e134ccd8 10000000 00000000 20000000】00010001 // LinkCount 和TotalLinks,都为
-------
e134cce8 cfe33194 01c9c7ad e13c1770 00000000
e134ccf8 00000000 00000000 00000000 00000000
e134cd08 00000118 00000000 00000000 00000000
e134cd18 00000000 00000000 到此FCB结束,下面便是前面已经分析过的SCB
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
01940703 00020040
//////////////////////////////////////////////////////////////////////////
4. 跟踪系统打开文件的流程(仅仅跟踪到文件系统层面,下方的卷设备/disk/atapi/PCHIINDEX 暂不讨论)
NtfsCommonCreate在经过复杂的操作到达NtfsOpenFile后,必定是要打开已经存在的文件.否则会调用NtfsCreateNewFile创建新文件.可能没人引用过C:\WINDOWS\system32\mycomput.dll,那么系统的FcbTable就没有该文件对应的FCB,这时就需要NtfsOpenFile函数去创建该文件对应的Fcb,建立LCB和父目录的SCB的联系,然后加入到表中去:
5.嗯,原理了解了,来实践一下简单的NTFS文件系统底层文件劫持吧.
[xp sp2下函数的执行流程如下]
NtfsCommonCreate-->NtfsCreateNewFile-->NtfsCreateFcb-->ExAllocatePoolWithTag
NtfsCommonCreate-->NtfsOpenFile-->NtfsCreateFcb-->ExAllocatePoolWithTag
[未导出] [未导出] [未导出] [已导出]
系统会频繁查表,添加移除FCB.可瞬间挂勾此函数,栈回溯得到NtfsCreateFcb/ NtfsOpenFile /
NtfsCheckValidAttributeAccess 等函数的地址.卸掉钩子
Ntfs!NtfsCreateFcb:
f974da0f e87eb5fdff call Ntfs!NtfsAllocateEresource (f9728f92)
f974da14 894648 mov dword ptr [esi+48h],eax
f974da17 8945d8 mov dword ptr [ebp-28h],eax
f974da1a 684e744673 push 7346744Eh // 重要标记"ntfs"
f974da1f 6a20 push 20h // 进行特征匹配
f974da21 6a10 push 10h
f974da23 ff1514ae73f9 call dword ptr [Ntfs!_imp__ExAllocatePoolWithTag (f973ae14)]
// ExAllocatePoolWithTag((POOL_TYPE)16, 0x20u, 'sFtN');
我挂钩下面这个函数,保护c:\sudami.txt不被打开/写入/删除. 金山&360文件粉碎机/XueTr/IceSword均无法删除.
VOID fake_NtfsCheckValidAttributeAccess()
/*++
Author: sudami [sudami@163.com]
Time : 2009/04/30 [30:4:2009 - 12:45]
Routine Description:
[xp sp2]
有种情况会调用NtfsCheckValidAttributeAccess 函数
NtfsOpenFcbById // 这种情况太少了...
NtfsCommonCreate --> NtfsOpenExistingPrefixFcb // 若文件被打开过一次,就不走下面的函数,经过这里
NtfsCommonCreate --> NtfsOpenFile // 第一次打开这个文件
NtfsCommonCreate --> NtfsCreateNewFile // 创建新文件
--*/
仅一点儿调试心得,不对的地方敬请指正.
-----------------------------------------------------------------------
参考资料:
(1) 挂接缓存管理器CcMapData()实现文件XX
(2) NTFSI--the NT Cache Manager
(3) 基于IopXX的重定向文件)
(4)windbg, nt4src
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)