Windows回收站信息文件的二进制格式

4
在Windows中以编程方式将文件移至回收站是一个微不足道的操作。
简而言之:只需将文件移至C:\$Recycle.Bin\SID\$R{name} * (对于C驱动器),并创建一个相关的二进制文件($I{name}),其中包含有关“已删除”文件/文件夹的元信息。
* 其中SID是您的操作系统安装标识符,看起来像:S-1-5-21-1234567890-1234567890-1234567890-1001
但是在研究后我有两个问题:
  • 删除日期转换为64位值的算法是什么?
  • 垃圾箱中的文件名是否是随机生成的还是有一些逻辑?

信息文件结构如下(根据我的研究):
const buffer = new Uint8Array([
    0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Header
    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Size                // 65535 (bytes)
    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xd7, 0x01,  // Deletion date (64-bit value)
    0x0b, 0x00, 0x00, 0x00,                          // Path string length  // `11`
                            0x43, 0x00, 0x3a, 0x00,  // File path + \0      // `C:\1\1.txt`  // `C:\\1\\1.txt\0`
    0x5c, 0x00, 0x31, 0x00, 0x5c, 0x00, 0x31, 0x00,
    0x2e, 0x00, 0x74, 0x00, 0x78, 0x00, 0x74, 0x00,
    0x00, 0x00
]);

文件头(始终相同),以字节为单位的文件大小(仅在文件资源管理器中可见),64位删除日期值,路径字符串长度和UTF-16编码的以null结尾的路径字符串。

唯一有问题的部分是日期。它是如何编码的?

例如:

00 00 00 00 00 29 d7 01代表2021年4月4日03:10

00 00 00 00 01 29 d7 01代表2021年4月4日03:17

00 00 00 00 00 30 d7 01代表2021年4月13日00:57

(前四个十六进制数只是为了方便而写的00。)

例如:00 00 00 00 00 29 d7 01字节表示为132619794007457792,但是new Date(132619794007457792/100000)表示的是2012.01.10 12:19:00

我需要将00 00 00 00 00 29 d7 01字节转换为2021.04.04 03:10


C:\$Recycle.Bin\SID\中的“已删除”文件名称以$R + [A-Z0-9]{7} + 可选的.{扩展名}开头。 例如:$RL6JQMF.txt。 以及相关的元数据文件:$IL6JQMF.txt,它只以$I开头。

这个命名有逻辑还是随机生成的?

实际上,例如,它可以同时使用$R___ + $I___$R123456789 abc + $I123456789 abc。因此,我认为它只是随机生成的。

只需要$R/$I。扩展名仅用于在文件资源管理器中显示相应的图标。


1
这种方法的一个缺点是,直到刷新回收站之前,回收站状态不会改变。因此,如果您将文件移动到“空”回收站中,即使文件已经显示在文件资源管理器中,其图标也不会更改。 - KeyKi
请注意,在Windows 7/8.1上,“header”以0x01开头,并且该结构体没有路径长度字段。 - AntonK
这是一个自Windows 95 beta版以来所有回收站格式的文档:https://github.com/danielmarschall/recyclebinunit/blob/master/FORMAT.md。此外,在该存储库中还有一个Delphi库和已编译的EXE文件,可以读取回收站信息。 - Daniel Marschall
2个回答

4

好的,我知道了。

虽然00 00 00 00 00 00 00 00代表的是1899.12.30 00:00

但是00 00 00 00 00 00 01 00代表的是1601.11.22 18:44

因此这个时间戳是自1601年1月1日以来的100纳秒间隔数。

例如,对于00 00 00 00 00 29 d7 01132619794007457792),我得到正确的日期(2021.04.04 03:10),就像在文件资源管理器中显示的那样:

new Date(132619794007457792 / 10000 + Number(new Date("1601.01.01 Z")))

无论如何,我认为这个主题对人们非常有用。

奇怪的是,在2021年我没有找到任何关于Windows回收站工作原理的信息。


4
难道不就是 FILETIME 吗? - PeterT
1
是的,看起来是这样。已修复。 - KeyKi
1
为什么你不直接使用Windows API将文件发送到回收站呢? - Simon Mourier
2
我对Win-API、C++以及如何在Node.js应用程序中使用它们没有经验。对信息文件结构的了解可以让您以非常普遍的方式进行各种操作:读取、删除、恢复文件等,还可以自定义删除日期和显示大小。 - KeyKi

3
我已经对此进行了广泛的研究,因为令人惊讶的是,在网上关于回收站如何实现的信息非常少。
一切都不难理解。当您在回收站中删除文件时,它实际上并没有移动到回收站中。
首先,让我们看一下 $Recycle.Bin 的子文件夹:
  • C:\$Recycle.Bin\S-1-5-18 是内置的SYSTEM帐户的文件夹
  • C:\$Recycle.Bin\S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-1XXX\,从1000开始是非内置用户文件夹。您应该首先通过在命令提示符中键入 whoami /all 来获取您的SID或 wmic useraccount get name,sid 来获取所有本地帐户的SID,然后选择与SID匹配的文件夹。
如果您将安全权限授予所有这些文件夹的帐户,资源管理器可能会在每个文件夹中显示您已删除的文件,但实际上这只是资源管理器的错误。如果您导航到例如C:\$Recycle.Bin\S-1-5-18文件夹并键入dir /a,您将看到它实际上是空的,只有与您的SID匹配的文件夹包含您已删除的文件。
请注意,即使您是PC上唯一的用户,您仍然可能拥有C:\$Recycle.Bin\S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-1000\文件夹,最有可能为空。那么您的实际文件夹将是...-1001\。用户“1000”似乎是由Windows在安装或某些更新时自动创建然后删除的用户的悬挂文件夹。但Recycle.Bin文件夹没有被销毁,而只是留在那里。我认为删除此悬挂文件夹是安全的。对于C:\$Recycle.Bin\S-1-5-18,我不是很确定,但我相当确定它也是安全的,因为OS系统帐户无需使用Bin。
因此,这里是删除算法:
系统在C:\$Recycle.Bin\S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-1XXX\文件夹中创建已删除文件的硬链接,命名为$RXXXXXX.<file_ext>,其中XXXXXX是基于文件内容计算的6个符号哈希值。同时,在同一文件夹中创建元数据文件,命名为$IXXXXXX.<file_ext>。原始文件被删除,但由于在$Recycle.Bin中有额外的硬链接,实际文件数据仍然保留在驱动器上相同的位置,就像文件从未被触及一样。它没有被移动到其他任何地方。这就是为什么每个逻辑卷必须有自己的$Recycle.Bin文件夹,因为硬链接只能在同一卷内工作。
恢复算法如下:
  1. 读取元数据文件,并根据原始文件位置中 $IXXXXXX.<file_ext> 的信息创建硬链接 $RXXXXXX.<file_ext>,使用原始文件名。
  2. $Recycle.Bin 中删除元数据和备份文件。

相当简单,不是吗?

现在,最有趣的部分是元数据文件:

0000  02 00 00 00 00 00 00 00  <-- File header (QW)
0008  00 7C 0A 00 00 00 00 00  <-- File size (QW)
0010  90 83 72 44 28 9C D8 01  <-- File deletion date (QW)
0018  18 00 00 00|43 00 3A 00  <-- File path string length (DW)
0020  5C 00 24 00 52 00 65 00  
0028  63 00 79 00 63 00 6C 00
0030  65 00 2E 00 42 00 69 00
0038  6E 00 5C 00 66 00 73 00
0040  73 00 2E 00 65 00 78 00
0048  65 00 00 00|             <-- |Null-terminated path string| (wchar_t)

所有的数值都采用小端字节序格式。
文件头是固定的,对于所有文件都是相同的。请注意,一些$I$文件可能会在文件头之前出现一些垃圾字节FF FE。我不知道这是什么,所以您应该在继续阅读之前检查完整的文件头。
删除日期采用FILETIME格式,并且可以通过FileTimeToSystemTime转换为常规SYSTEMTIME。它表示自1601年1月1日(协调世界时)以来的100纳秒间隔。
因此,这不是超级复杂的文件格式,但设计相当有趣。
我计划使用这些信息,创建一个自定义的“垃圾回收器”用于Windows,并将其添加到任务计划程序中以定期启动和扫描\删除24小时前已删除的文件等。我知道Windows 10有内置选项,但它不够灵活和可靠(有时会留下元数据文件,而只删除$R文件)。此外,我认为之前的Windows版本根本没有这个功能。
我鼓励您也进行尝试!例如,您的程序可能会将所有删除的文件的元数据信息保存在某个数据库中,这样您就可以完整地记录您曾经删除的所有文件的历史!

这是我程序原型的样例输出 - ScienceDiscoverer
2
既然Fat32和Win95都没有硬链接,那么我认为它会移动文件。 - Anders
嘿,由于该社区不允许我编辑答案。这些“垃圾字节”似乎是小端序的字节顺序标记(BOM)。 - Marcel
另一个有趣的观察是,通过资源管理器恢复文件时,元数据文件实际上是被保留下来的。我对他们为什么这样做感到困惑。顺便说一下,我使用的是Windows 11操作系统。 - Marcel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接