1. 背景
本文继续介绍当前磁盘分区下的文件遍历操作,详细介绍$Root元文件的A0H属性的Data Runs,并解析每个Data Run中的所有索引项,同时提供了基于元神操作系统的实现代码。
2. 方法
(1)Data Runs
A0H属性是非常驻属性,其属性体部分为Data Runs,即Data Run列表。其中的每个Data Run标识了一组存放数据的簇,第一个字节的高4位表示记录起始簇号的字节数,第一个字节的低4位表示记录簇数的字节数,第二个字节开始存放簇数,之后存放起始簇号,结合前文读取的$Root元文件数据,其中A0H属性的第一个Data Run数据为“31 02 53 03 2F”,根据第一个字节0x31可知,起始簇号占3个字节,簇数占1个字节,所以接下来的1个字节存放簇数,再之后的3个字节存放起始簇号,即簇53 03 2F(0x2F0353)开始的02个簇用于存放数据。解析完第一个Data Run之后,向后偏移3+1+1=5个字节,定位到下一个Data Run并重新解析,直到Data Run的第一个字节为00,表示Data Runs结束。
Data Runs所标识的每个簇都由一个标准索引头和若干个索引项构成。索引项的结构可以参考前文中对90H属性的介绍,标准索引头的结构为:偏移0x00-0x03总是“INDX”的ASCII码;偏移0x04-0x05表示更新序列号的偏移;偏移0x06-0x07表示更新序列号与更新数组的大小;偏移0x08-0x0F表示日志文件序列号;偏移0x10-0x17表示本索引缓存在索引分配中的VCN;偏移0x18-0x1B表示索引项的偏移;偏移0x1C-0x1F表示索引项的大小;偏移0x20-0x23表示索引项分配大小;偏移0x24处为子节点标志,值为1时表示还有子节点(即不是叶节点);偏移0x28开始为更新序列。
(2)定位A0H属性中的Data Runs
根据前文的描述,在$Root元文件的文件头的偏移0x14-0x15处获取第一个属性的偏移,并据此偏移到第一个属性位置;然后判断该属性是否是A0H属性,如果不是,则根据该属性的偏移0x04-0x07处的属性长度来定位和偏移到下一个属性位置,并重新判断;直至找到A0H属性,然后根据非常驻属性头的偏移0x20-0x21处的值来定位到Data Runs。代码如下所示:
movzx edx, word [fs:esi+0x14]
add esi, edx
.search_index_allocation:
cmp dword [fs:esi+0x00], 0xA0
je .index_allocation
add esi, dword [fs:esi+0x04]
jmp .search_index_allocation
.index_allocation:
movzx edx, word [fs:esi+0x20]
add esi, edx
(3)解析Data Run
根据上面的介绍,每个Data Run标识了一组簇,包括起始簇号和簇数,按照上面的介绍对其进行解析,代码如下所示:
movzx ecx, byte [fs:esi+0x00]
and ecx, 0x0F
add esi, ecx
xor eax, eax
.next_cluster_count:
shl eax, 8
mov al, byte [fs:esi]
dec esi
loop .next_cluster_count
movzx ecx, byte [fs:esi+0x00]