NTFS 硬盘上 $I30 的无效 INDX 条目

逆向工程 视窗 十六进制
2021-06-15 00:25:35

在解析我的 NTFS 格式的硬盘时,我发现了一些无效的 INDX 条目,而 Windows 仍然能够列出所有根目录内容!

NTFS 3.1 中索引记录的结构很明确(NTFS doc):

Offset      Description
-------------------------------------
0x00        MFT Reference of the file
0x08        Size of the index entry
0x0A        Offset to the filename
...
0x52        Filename
...

但是,我发现一些条目的大小以及它们的 MFT 参考(这是一堆零)都有问题!

我附上一张屏幕截图,其中显示了 INDX 的一部分及其文本表示,其中每行的宽度为0x20我突出显示了错误的部分。

INDX 的无效条目

该图显示条目被合理解析,直到最后一个正确条目位于0x0628

  • MFT 参考(8 个字节): 66 30 00 00 00 00 01 00
  • 条目大小(2 字节):70 00 因此条目以0x0697.

此后,事情变得奇怪了!条目0x0698

  • MFT 参考(8 个字节):00 00 00 00 00 00 00 00似乎无效
  • 条目大小(2 字节):10 00当然无效,因为大小小于条目结构的最小大小,例如包含文件名的最小大小0x52

对我来说,“Buziol Games”似乎是硬盘根目录下的一个已删除文件夹,我不确定。无论如何,Windows 资源管理器在列出内容时不会遇到麻烦。

有人了解它是如何工作的吗?Windows 如何继续解析?

编辑:此外,请在pastebin上找到作为纯文本的十六进制转储

1个回答

INDEX_RECORD_ENTRY 应该在 INDEX_HEADER 前面加上魔术签名INDX

如屏幕截图所示,没有标头解密 INDEX_RECORD_ENTRIES 是困难的

以下观察结果基于您稍后编辑的 pastebin 转储

我使用bat文件将十六进制转换为二进制文件,因此

rem make a copy 
copy %1 %2
rem compare both
fc %1 %2
rem dump the first line for visualizing
head -1 %2
rem strip the address,colon and space 
rem this is to make it compatible with xxd input
sed s/.*:\x20//g %2 > %3
rem dump the ripped hex file first line 
head -1 %3
rem convert hex to binary 
xxd -r -p %3 > %4
rem check the size and compare with word count
rem both should be same 
ls -l %4
wc -w %3

在下载的 pastebin 转储上执行 bat 文件

C:\indx>converthextobin.bat indx_$i30_dump.txt indxhex.txt indxstripped.txt indxbin.bin

C:\indx>rem make a copy
C:\indx>copy indx_$i30_dump.txt indxhex.txt
        1 file(s) copied.

C:\indx>rem compare both
C:\indx>fc indx_$i30_dump.txt indxhex.txt
Comparing files indx_$i30_dump.txt and INDXHEX.TXT
FC: no differences encountered

C:\indx>rem dump the first line for visualizing
C:\indx>head -1 indxhex.txt
0000: 49 4E 44 58 28 00 09 00 D2 92 87 08 00 00 00 00

C:\indx>rem strip the address,colon and space
C:\indx>rem this is to make it compatible with xxd input
C:\indx>sed s/.*:\x20//g indxhex.txt  1>indxstripped.txt

C:\indx>rem dump the ripped hex file first line
C:\indx>head -1 indxstripped.txt
49 4E 44 58 28 00 09 00 D2 92 87 08 00 00 00 00

C:\indx>rem convert hex to binary
C:\indx>xxd -r -p indxstripped.txt  1>indxbin.bin

C:\indx>rem check the size and compare with word count
C:\indx>rem both should be same
C:\indx>ls -l indxbin.bin
-rw-rw-rw-  1 HP 0 6656 2017-07-22 15:20 indxbin.bin
C:\indx>wc -w indxstripped.txt
6656 indxstripped.txt

现在我们有了一个二进制形式,我们可以开始探索了

让我们转储 INDEX_HEADER 并验证

@echo off
xxd -s00 -g4 -l4 indxbin.bin &^
xxd -s04 -g2 -l2 indxbin.bin &^
xxd -s06 -g2 -l2 indxbin.bin &^
xxd -s08 -g8 -l8 indxbin.bin &^
xxd -s16 -g8 -l8 indxbin.bin &^
xxd -s24 -g4 -l4 indxbin.bin &^
xxd -s28 -g4 -l4 indxbin.bin &^
xxd -s32 -g4 -l4 indxbin.bin &^
xxd -s36 -g1 -l1 indxbin.bin &^
xxd -s37 -g3 -l3 indxbin.bin &^
xxd -s40 -g2 -l2 indxbin.bin

执行我们得到 INDEX_HEADER

C:\indx>dumpindxheader.bat
0000000: 494e4458                             INDX
0000004: 2800                                     (.
0000006: 0900                                     ..
0000000: 494e445828000900                   INDX(...
0000010: 0000000000000000                   ........
0000018: 40000000                             @...
000001c: 90060000                             ....
0000020: e80f0000                             ....
0000024: 00
0000025: 000000                                 ...
0000028: 1e02                                     ..

我们可以看到相对于 HEADER_OFFSET 的 INDEX_RECORD_ENTRY 是 0x40(我没有尝试控制 xxd 输出中的 Endiannes)

所以 INDEX_RECORD_ENTRY(术语可能不正确)从 0x40+0x18 = 0x58 开始,
它是一个大小可变的结构,适当地填充到边界

转储记录条目

@echo off
xxd -s88 -g8 -l8 indxbin.bin &^
xxd -s96 -g2 -l2 indxbin.bin &^
xxd -s98 -g2 -l2 indxbin.bin &^
xxd -s100 -g2 -l2 indxbin.bin &^
xxd -s102 -g2 -l2 indxbin.bin &^
xxd -c8 -s104 -g8 -l64 indxbin.bin &^
xxd -s168 -g1 -l1 indxbin.bin &^
xxd -s169 -g1 -l1 indxbin.bin &^
xxd -s170 -g1 -l22 indxbin.bin

执行bat文件

C:\indx>dumpindxrecordentry.bat
0000058: 0400000000000400                   ........
0000060: 6800                                     h.
0000062: 5200                                     R.
0000064: 0000                                     ..
0000066: 0000                                     ..
0000068: 0500000000000500  ........
0000070: d07fa49ac58cd201  ........
0000078: d07fa49ac58cd201  ........
0000080: d07fa49ac58cd201  ........
0000088: d07fa49ac58cd201  ........
0000090: 0090000000000000  ........
0000098: a08c000000000000  ........
00000a0: 0600000000000000  ........
00000a8: 08                                               .
00000a9: 03                                               .
00000aa: 24 00 41 00 74 00 74 00 72 00 44 00 65 00 66 00  $.A.t.t.r.D.e.f.
00000ba: 00 00 00 00 00 00                                ......

大小 68 是相对于 self 所以下一个条目将在 0x58+0x68 == 0xc0

文件名的偏移量是相对于自身的,因此文件名将在 0x58+0x52 = 0xaa 处作为转储

因此,您现在可以通过向 xxd 即 0xc0 或 0n192 提供适当的搜索地址来转储下一个条目

最后一个条目在 0x628 处,其大小为 0x70,因此它以 0x698 结束

最后一个条目的长度为 0x10 字节,mft 引用为 0

从原始帖子中链接的pdf中引用的
最后一个条目的大小为0x10(刚好足以容纳标志(并且mft ref为零)

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000690                          00 00 00 00 00 00 00 00          ........
000006A0  10 00 00 00 02 00 00 00                          ........