我将在这里发布我学到的东西以供后代使用。我已经找到了做我想做的事的方法,尽管我怀疑我是否拥有完成任务的系统能力。
我尝试的第一件事是我猜测的所有可能组合。首先,我编写了一个 Ruby 脚本来生成它。
#!/usr/bin/env ruby
JOINERS = ['', '-', '_', ' ']
PREFIX = %w[words for prefix]
CONJUNCTION = ['and', nil]
OPTIONAL = %w[words for optional]
SUFFIX = %w[.tar.gz .tgz .tar.gz.aes .tgz.aes]
def permute collection, length = nil
(1..(length || collection.length)).
flat_map {|qty| collection.permutation(qty).to_a }
end
def prefixer
permute(PREFIX, 3).each do |prf|
yield prf
end
end
def optionaler(pfx, j, s, cap = false)
permute(OPTIONAL, 3).each do |opt|
opt = opt.map(&:capitalize) if cap
CONJUNCTION.each do |cj|
puts [pfx.join(j), cj, opt.join(j)].compact.join(j) + s
end
end
end
SUFFIX.each do |s|
JOINERS.each do |j|
prefixer do |prf|
puts prf.join(j) + s
optionaler(prf, j, s)
prf = prf.map(&:capitalize)
puts prf.join(j) + s
optionaler(prf, j, s, true)
end
end
end
我运行了这个脚本,输出给了我将近 500,000 个条目。然后,我使用我的 FishShell 遍历其中的每一个并尝试输入密码。
for password in (ruby script.rb)
aescrypt -d -p $password encrypted_file.aes 2>/dev/null
end
这些都不起作用,所以我不得不改用蛮力……这意味着我可能永远不会打开它。
所以我学会了如何按照 Matthew 的建议使用crunch,并结合 xargs 非常棒!
由于我每次都运行一个 shell 命令来尝试解密文件,我认为磁盘驱动器 IO 可能是性能考虑因素,所以我创建了一个tmpfs文件系统文件夹来放入文件并在 RAM 中操作所有内容。
mkdir tmpfs
sudo mount -t tmpfs -o size=800M,mode=0755 tmpfs tmpfs/
cp encrypted_file.aes tmpfs/
cd tmpfs
这是我制定的第一个命令。
crunch 3 26 abcdefhilmnoprstuvwyz0123456789\ -_. -d 1@ --stdout | \
xargs -r -P 4 -I PASSWORD bash -c \
"! aescrypt -d -p 'PASSWORD' encrypted_file.aes 2>/dev/null"
这是零件。 crunch生成以下参数的所有可能性。第一个数字是最小字符数,第二个是最大字符数。之后是用于每次尝试的字符列表。我已经排除了我确定不在其中的字符,因此字符列表更短,并且该过程将更快地完成。接下来我有-d 1@,它告诉 crunch 没有两个相同的字符会彼此相邻。
然后我将它通过管道传递给xargs,这是一个很好的工具,通常用于将流式输入数据作为参数传递给以下命令/参数。但在这种情况下,我们使用-I选项将其传送到特定位置,该选项确定要替换的文本。该-r选项表示不会与空的输入运行。该-P 4,告诉它运行在通过四个不同的参数并行4个实例(这需要我的系统上利用所有4个核心)。使用 4 个内核而不是 1 个内核可以节省大约 60% 的时间成本。
接下来,我通过 bash 命令bash -c执行aescrypt ,并用传入的每个单独输入替换PASSWORD区域。我以 bang ( ! ) 开头的原因是因为当aescrypt没有成功解密它写入 STDERR 的文件时并给出一个失败的退出状态,这将立即停止整个命令。爆炸会翻转结果,以便在每次失败时它都会继续运行,但是当文件最终被解密时,它将否定积极响应并退出循环,因为我们的工作已经完成。
笔记
我意识到这不是最有效的方法,但我正在努力尝试。我将提供一些我见过的额外的性能观察。
使用xargs并行参数时,无论您走多高,您仍将获得与您拥有的核心数量相同的性能。但是,如果您使用xargs运行多个 shell,每个 shell 都要求比您拥有的内核更多,那么您将减慢所有 shell 的性能,就好像您只有 1 个内核一样。
由于我最好的猜测之一是密码以结尾,因此.tar.gz我通过将上面的命令更改为使用两个核心并将第二个命令的字符列表缩短为不包括gz或任何数字(因为如果扩展名存在数字)将任务分成两半此密码不存在)并且我已替换'PASSWORD'为'PASSWORD.tar.gz'. 第二个命令我还给出了 2 个并行进程。
因为我瞎了眼,我想知道进展如何,我研究了如何阅读管道中的内容。首先,您可以使用pidof crunch获取每个 crunch 实例的 PID 。一旦你有了它,你可以通过以下方式观看通过每个单独的 PID 的流式传输:
sudo strace -pPID_NUM_HERE -s99999 -e write
从这里我可以写下进度,停止一个 crunch 过程,然后通过添加一个-s选项作为起点来重新启动我停止的 crunch 命令。
迈向更好的表现
在两个字符的密码下,我每秒尝试大约 35 个密码,在 3 个字符的密码下,我每秒尝试大约 12 个密码。通过放在time -v --output=somefile上面的命令之前进行测试。它并不快。
我意识到使用管道、xargs 和 bash 来运行这些命令每个都有自己的成本,而且我用 Rust 编写一个实现来完成上面所做的事情会更方便。我需要获取AES Crypt的源代码并将库链接到 Rust 以直接调用 C 代码。要么对crunch做同样的事情,要么只是手动实现我需要的部分(后者可能更好)。
如果我去掉所有的中间件外壳,只运行纯 Rust,它肯定会更高效。哎呀,如果我可以利用我的 GPU,那会很酷。但是我要到达那里有一点学习曲线。
我希望这些信息对其他人有用。随意分享和这个一样有启发性的答案。谢谢!
更新
Ori 问我是否测试过一条快乐的道路是否能按预期工作。事实证明,在这两种情况下我都没有考虑到这一点。我在这里有一个更新版本的 FishShell 脚本,它适用于快乐的路径。
for password in (ruby script.rb)
if test -s the_file
break
else
aescrypt -d -p $password the_file.aes 2>/dev/null
end
end
测试test -s文件the_file是否为空白。 将在同一目录中写入一个没有扩展aescrypt名的相同文件名的空文件。.aes它也使用相同的名称来成功解密。在所有情况下都应考虑到这一点。
好的,新更新的crunch和xargs代码将起作用:
crunch 3 26 abcdefhilmnoprstuvwyz0123456789\ -_. -d 1@ --stdout | \
xargs -r -P 4 -I PASSWORD bash -c \
"! aescrypt -d -p 'PASSWORD' -o 'PASSWORD' encrypted_file.aes \
2>/dev/null; if [[ -s \"PASSWORD\" ]]; then exit 255; fi"
无论当前密码是什么,这都会命名输出文件,如果文件不为空,则退出成功。我已经用一个例子对此进行了测试,它可以工作!
希望我现在可以解密我的文件。
2017 年 9 月 22 日更新:编写程序
我编写了一个名为abrute的多线程 AES 文件强力解密软件。您需要在系统可执行路径中有aescrypt才能正常工作。