将随机数据写入硬盘的随机扇区

将随机数据写入硬盘的随机扇区

我的硬盘坏了,在将它送去 RMA 之前,我想尽可能地清除硬盘上的数据。我尝试使用 Windows 实用程序,还对 /dev/random 执行了 dd。问题是我等不及这两种解决方案中的任何一种完成,因为 RMA 的原因是它的最大写入速度为 1 MB/秒。仅对 500GB 硬盘进行一次清理就需要 140 多个小时。

我一直在寻找一个实用程序(甚至是 Linux 上的 Bash 脚本),它可以随机选择扇区并向这些扇区写入随机数据(甚至是零)。我希望如果我运行这个程序 24 小时,它将擦除大约 80 GB 的数据。由于它是随机选择的,所有较大的文件将无法恢复,较小的文件要么被擦除,要么丢失块,要么可能可以恢复。不幸的是,这是目前对我来说的最佳解决方案。

解决方案

感谢“evildead”,我能够让驱动器上的大量数据随机地用 /dev/urandom 中的垃圾填充。如果有人需要,bash 脚本如下:

#!/bin/bash
while (true); do
    randnum=${RANDOM}${RANDOM}
    number=$((10#$randnum%976773168))
    echo -e $number >> progress.txt
    dd if=/dev/urandom of=/dev/sdx1 skip=$number count=1
done

您需要将 976773168 替换为驱动器上的块数。我最初尝试在 bash 中使用 $RANDOM,但它只是一个 16 位整数,因此只有 32k。由于我需要一个超过 9 亿的数字,因此我将两个 $RANDOM 值组合在一起,因此例如如果我的随机数是 22,861 和 11,111,我得到 2,286,111,111,然后将其拟合到我的块大小,我得到一个范围内的相当随机的值。它没有完美的熵,但话又说回来,计算机上真正随机的是什么?;) 10# 的存在是为了防止第一个随机数是 0,它会强制 bash 使用十进制,而不是八进制,如果它认为数字是八进制(前导零),它就会使用八进制。我还将随机数写入文件以供稍后分析,以查看传播情况。如果您不需要这个,您可以直接取出

echo -e $number >> progress.txt

它会运行良好。另外不要忘记替换sdx1与您要处理的实际驱动器或分区。我希望这对某些人有帮助,我知道这对我真的很有帮助。

答案1

您可以将 shellscript 与 dd 结合使用。

例如

 while (true); do
   number=$((($RANDOM * 32768 + $RANDOM)))
   dd if=/dev/urandom of=/dev/sdx1 seek=$number count=1
 done

您只需修改由 $RANDOM 生成的数字以适合您的块。

EDIT 2016:请注意,旧的解决方案是不正确的。因为我们想在输出流中的随机位置覆盖一个字节,所以我们必须使用 seek 而不是 skip,正如评论中提到的那样。

答案2

我的系统没有坏,写入速度/dev/random约为 650Kb/s。写入速度/dev/urandom为 7Kb/s。

我自己已经研究过这个问题,对于纯粹的 bash 解决方案,你必须对你的目标有现实的认识,因为除非你的目标是学习如何在 bash 中做到这一点,因为重点是在 bash 中完成所有操作,否则安全地擦除磁盘的目标最好通过其他方式来实现,尽管 bash 在解决方案中很有用。

evildead 的 bash 算法可以随机选择 dd 将写入驱动器的位置,但是,/dev/urandom 明显比 /dev/random 慢,并且我认为用大块的随机数据填充驱动器不太安全,并且我认为如果你快速进行两次写入 1 然后写入 0,从被擦除的驱动器中检索数据将更加困难。

我自己用以下命令将以下内容写入驱动器:

tr '\0' '\377' < /dev/zero | pv > /dev/sdz

然后我使用以下命令将零写入驱动器:

pv < /dev/zero > /dev/sdz

注意 pv 的使用。这是一个很棒的程序,尽管在大多数系统上你都必须安装它。很容易找到,似乎没有手册页,但网上有一个。它显示数据通过管道的进度,使用一些程序,你甚至可以将其设置为在传递一定量的数据后停止。

然后纯粹因为我对没有一个 bash 解决方案能够像上面任何一个写入那样快速地写入随机数感到恼火,我编写了一个名为 svrandom 的小型 C 程序来快速生成随机数,我从 bash 调用它如下:

while :; do ./svrandom; done  | pv > /dev/sdz

在我的系统上,用随机数填充驱动器 /dev/sdz 的速度与写入 /dev/zero 的速度一样快。用随机​​数擦除驱动器的目标已实现,解决方案中使用了 bash。

/* svrandom
a small program from shadowvision.com September 2015 to generate strings of random numbers.
the default setting of 10000000 gives about 453 megs, adjust as 
needed */ 

#include <stdio.h>
#include <stdlib.h>
int main()
{
int r,a,b;
 /* adjust following number as needed to suit your string length */
 for(a=0;a<10000000;a++)
 {
 for(b=0;b<5;b++)
 {
 r=rand();
 printf("%d",r);
 }

 }
 return(0);
}

在源代码中我提到你可以通过调整数字来控制随机数字符串的长度。如果你从while循环中调用它,你不需要这样做,尽管每个循环的末尾可能有一个回车符,但如果你想从程序中得到一个连续的字符串,你就必须更改数字。

剪断!四处寻找后,我找到了这个解决方案https://superuser.com/questions/19326/how-to-wipe-free-disk-space-in-linux

openssl enc -aes-256-ctr -pass pass:“$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)”-nosalt < /dev/zero |pv > /dev/sd{x}

就像那位朋友说的,我简直不敢相信速度这么快。它写入磁盘的速度比我想象的磁盘最大写入速度还要快。

在我看来,该命令正在使用 openssl 对 /dev/zero 中的一串零进行加密,使用 /dev/urandom 作为种子,但我不是 100% 确定。我使用 C 程序写入随机数的解决方案以 82mbps 的速度写入我的系统,而这个 openssl 解决方案的写入速度为 100mbps。哇!

答案3

一个 Python 3 脚本,包含:

  • 了解块设备的大小
  • 通过在边界写入字节来验证块设备的大小
  • 保证第一个字节和最后一个字节被销毁
  • 随机数据覆盖
  • 随机偏移
  • 随机批次大小

如果您需要 Python 2,那么使用“”format() 而不是 f”字符串应该很容易转换。

import subprocess
import random


REPS = 100
CRASH_ON_FIRST_FAILURE = True  # change to False if the device is not reliable

def run(*cmd, assert_returncode=None, print_stderr=False):
    completed = subprocess.run(cmd, capture_output=True)
    if assert_returncode:
        assert completed.returncode == assert_returncode, f"Unexpected return code (got={assert_returncode}, expected={assert_returncode})"
    if print_stderr:
        print(str(completed.stderr))
    return completed.stdout


def part_size(part):
    """
    Partition size in bytes
    """
    return int(run("blockdev", "--getsize64", part))


def destroy_block(part, bs, seek, assert_returncode=None, print_result=False):
    run(
        "dd", f"bs={bs}", "if=/dev/urandom", f"of={part}", f"seek={seek}", "count=1",
        assert_returncode=assert_returncode
    )
    if print_result:
        print(f"Destroyed bs={bs} of={part} seek={seek}")


def destory_random_block(part, part_size, bs):
    """
    bs=1 destroys bytes sized block
    bs=1024 destroys KB sized block
    etc.
    """
    seek_max = int(part_size / bs)
    seek = random.randint(0, seek_max)
    if CRASH_ON_FIRST_FAILURE:
        assert_returncode = 0
    else:
        assert_returncode = None
    destroy_block(part, bs=bs, seek=seek, assert_returncode=assert_returncode)


def destroy(part):
    """
    part - partition to be destroyed
    """
    s = part_size(part)
    destroy_block(part, bs=1, seek=s, assert_returncode=1)  # "test" destroying 1 byte at size boundary, should fail
    destroy_block(part, bs=1, seek=(s - 1), assert_returncode=0, print_result=True)  # "test" destroying 1 bytes before boundary, should pass
    destroy_block(part, bs=1, seek=0, assert_returncode=0, print_result=True)  # "test" destroying first 1 byte
    while True:
        print(f"Destroying {REPS} byte-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=1)
        print(f"Destroying {REPS} KB-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=1024)
        print(f"Destroying {REPS} MB-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=(1024 * 1024))
        rand_size = random.randint(1, 1024 * 1024)
        print(f"Destroying {REPS} {rand_size}-sized blocks")
        for _ in range(REPS):
            destory_random_block(part, part_size=s, bs=rand_size)
        print("\nRise and repeat\n\n")


destroy("/dev/sdb1")



示例输出:

# "test" destroying 1 byte at size boundary, should fail
# "test" destroying 1 bytes before boundary, should pass
Destroyed bs=1 of=/dev/sdb1 seek=10736369663
# "test" destroying first 1 byte
Destroyed bs=1 of=/dev/sdb1 seek=0

Destroying 100 byte-sized blocks
Destroying 100 KB-sized blocks
Destroying 100 MB-sized blocks
Destroying 100 875091-sized blocks

Rise and repeat


Destroying 100 byte-sized blocks
Destroying 100 KB-sized blocks
Destroying 100 MB-sized blocks
Destroying 100 1028370-sized blocks

Rise and repeat

跑步:

  1. 复制源代码,除了最后一行
  2. 在受害主机上登录
  3. 在受害主机上运行:python3
  4. 粘贴步骤 1 中的代码
  5. 键入destroy("/dev/XYZ")并回车键两次
  6. 几个小时后,按 Ctrl-c

注意:“/dev/XYZ”是将丢失数据的分区名称。

警告:小心“Fat-finger”错误。数据将永远消失,因此请仔细检查您正在输入的分区。

警告:如果您需要支付磁盘写入 IOP 费用,则在云服务中运行此脚本数天可能会产生费用。

答案4

实现此过程自动化的最佳软件是 Darik 的 Boot and Nuke(又名 DBAN)

它是一张具有全面驱动器擦除机制的启动 CD,其清除程度(以及擦除驱动器所需的时间)各不相同

可从http://www.dban.org/

相关内容