文件隐写术:直接将数据隐藏在扇区中

小前言

如果有人不记得的话,隐写术正在将信息隐藏在某些容器中。 例如,在图片中(讨论过 这里 и 这里)。 您还可以隐藏文件系统的服务表中的数据(这是关于 这里), 乃至 TCP协议服务报文中。 不幸的是,所有这些方法都有一个缺点:为了在不知不觉中将信息“插入”到容器中,您需要巧妙的算法来考虑容器内部结构的特殊性。 容器的抗操作性会出现问题:例如,如果稍微编辑图片,隐藏的信息就会丢失。

是否有可能以某种方式不需要狡猾的算法和微妙的数据操作,并且仍然确保容器的功能和隐藏数据的可接受的安全级别? 展望未来,我会说——是的,你可以! 我什至会提供一个实用程序。

该方法的血腥细节

基本思想就像敲打额头一样简单:磁盘上有一些区域操作系统永远不会写入(或在极少数情况下写入)。 为了避免使用狡猾的算法搜索这些区域,我们将使用冗余 - 也就是说,我们将在磁盘的所有扇区中多次复制隐藏信息。 然后,在所有这些辉煌之上,您可以创建必要的分区,格式化文件系统,写入文件并安装操作系统 - 尽管如此,部分秘密数据将被保存并可以检索,并且重复复制将帮助我们将原来的整体从碎片中拼凑起来。

这种方法的优点是显而易见的:我们不依赖于文件格式,甚至不依赖于所使用的文件系统的类型。

我认为缺点也很明显:

  • 秘密数据只能通过完全重写整个磁盘来更改,然后重新创建用户可见的内容。 但是,您不能使用从映像重新创建磁盘的软件:它还会重新创建以前的秘密数据。
  • 秘密数据量越大,丢失某些信息的可能性就越大。
  • 从磁盘检索数据可能需要很长时间。 从几分钟到几天(现代磁盘很大)。

现在让我们继续讨论具体细节。

很明显,如果你简单地将秘密数据涂抹在整个磁盘上,它只会被肉眼隐藏。 如果你的目光配备了磁盘编辑器,那么数据就会展现在你眼前。 因此,最好对数据进行加密,使其不被泄露。 我们将进行简单但有品味的加密:使用 aes256-cbc 算法。 我们将询问用户加密密钥并让他想出一个好的密码。

下一个问题是我们如何区分“好”数据和坏数据。 这里校验和会帮助我们,但不是简单的校验和,而是 SHA1。 还有什么? 它对于 git 来说已经足够好了,所以它也适合我们。 决定:我们为每条存储的信息提供一个校验和,如果解密后匹配,则说明解密成功。

您还需要秘密数据的片段编号和总长度。 碎片编号是为了记录哪些碎片我们已经破译,哪些碎片还剩下。 总长度对我们处理最后一个片段时会有用,以免写入不必要的数据(即填充)。 好吧,由于我们仍然有一个标头,因此我们将在其中添加秘密文件的名称。 解密后会有用,免得猜测如何打开。

在实践中测试该方法

为了进行检查,我们采用最常见的介质 - 闪存驱动器。 我找到了一个旧的,容量为1GB,非常适合实验。 如果您像我一样提出了不使用物理介质,而是在文件(磁盘映像)上测试它的想法,那么我会立即说:它行不通。 当格式化这样的“磁盘”时,Linux 会再次创建该文件,并且所有未使用的扇区都将用零填充。

作为一台Linux机器,不幸的是,我不得不在阳台上的Raspberry Pi 3上使用气象站,那里没有太多内存,所以我们不会隐藏大文件。 我们将最大大小限制为 10 MB。 隐藏太小的文件也是没有意义的:该实用程序以 4 KB 簇的形式将数据写入磁盘。 因此,下面我们将限制文件大小为 3 kb - 它适合这样一个簇。

我们将分阶段模拟闪存驱动器,在每个阶段后检查隐藏信息是否可读:

  1. 快速格式化为 FAT16 格式,簇大小为 16 KB。 这就是 Windows 7 为没有文件系统的闪存驱动器提供的功能。
  2. 将闪存驱动器中的各种垃圾填满50%。
  3. 将闪存驱动器中的各种垃圾填满100%。
  4. FAT16 格式的“长”格式化(覆盖所有内容)。

正如预期的那样,前两次测试以完全胜利告终:该实用程序能够成功地从闪存驱动器中提取 10 兆字节的秘密数据。 但是当闪存驱动器装满文件后,出现故障:

Total clusters read: 250752, decrypted: 158
ERROR: cannot write incomplete secretFile

正如您所看到的,只有 158 个簇被成功解密(632 KB 的原始数据,这提供了 636424 字节的有效负载)。 很明显,这里无法获得 10 兆字节,但这些集群之间显然存在重复。 你甚至无法通过这种方式恢复 1 MB。 但我们可以保证,即使在闪存驱动器被格式化并写入容量之后,我们也能从闪存驱动器中恢复 3 KB 的秘密数据。 然而,实验表明,从这样的闪存驱动器中提取 120 KB 长的文件是很有可能的。

不幸的是,最后一次测试表明整个闪存驱动器被覆盖:

$ sudo ./steganodisk -p password /dev/sda
Device size: 250752 clusters
250700 99%
Total clusters read: 250752, decrypted: 0
ERROR: cannot write incomplete secretFile

没有一个集群幸存下来......悲伤,但不是悲剧! 在格式化之前,我们尝试在闪存驱动器上创建一个分区,并在其中创建一个文件系统。 顺便说一句,它从工厂来时就具有这种格式,因此我们不会做任何可疑的事情。
闪存驱动器上的可用空间略有减少是预料之中的。

完全满的磁盘上不可能隐藏 10 兆字节,这也是意料之中的事。 但现在成功解密的集群数量已经增加了一倍多!

Total clusters read: 250752, decrypted: 405

不幸的是,不可能将碎片拼凑成一兆字节,但两百千字节却很容易。

好吧,关于最后第四次检查的消息,这次是令人高兴的:完全格式化这样的闪存驱动器并没有导致所有信息被破坏! 4 KB 的秘密数据完全适合未使用的空间。

测试汇总表:

文件隐写术:直接将数据隐藏在扇区中

一些理论分析:关于可用空间和未使用的扇区

如果您曾经将硬盘驱动器划分为多个分区,您可能已经注意到并不总是可以分配磁盘上的所有可用空间。 第一部分总是以一些缩进开始(通常为 1 兆字节,或 2048 个扇区)。 在最后一部分的后面,还碰巧还存在一小部分未使用的扇区“尾巴”。 有时章节之间会存在间隙,尽管这种情况很少见。

换句话说,磁盘上有一些扇区在磁盘正常工作时无法访问,但可以向这些扇区写入数据! 这也意味着阅读它。 调整后,还有分区表和引导加载程序代码,它们位于磁盘开头的空白区域。

可以这么说,让我们暂时离开这些部分,从鸟瞰的角度看一下磁盘。 这里我们的磁盘上有一个空分区。 让我们在其中创建一个文件系统。 我们可以说磁盘上的某些扇区仍未被删除吗?

E-e-e-鼓声响起! 答案几乎总是肯定的! 事实上,在大多数情况下,创建文件系统归结为仅将几块服务信息写入磁盘,否则分区的内容不会改变。

而且——纯粹凭经验——我们可以假设文件系统不能总是占据分配给它的所有空间,直到最后一个扇区。 例如,簇大小为16KB的FAT64文件系统显然无法完全占用大小不是64KB倍数的分区。 在这样一个部分的末尾,必须有几个扇区的“尾部”,无法存储用户数据。 然而,这一假设无法通过实验得到证实。

因此,为了最大化隐写图的可用空间,您需要使用具有更大簇大小的文件系统。 您还可以创建分区,即使这不是必需的(例如在闪存驱动器上)。 无需创建空白部分或留下未分配的区域 - 这将吸引感兴趣的公民的注意。

实验实用程序

您可以触摸该实用程序的源代码 这里

要构建,您需要 Qt 5.0 或更高版本以及 OpenSSL。 如果某些功能不起作用,您可能需要编辑 steganodisk.pro 文件。

您可以将簇大小从 4 KB 更改为 512 字节(在 Secretfile.h 中)。 同时,服务信息的成本也会增加:标头和校验和占用固定的68字节。

当然,您需要以 root 用户权限运行该实用程序,并且要小心。 在覆盖指定文件或设备之前不会提出任何问题!

享受。

来源: habr.com

添加评论