有谁知道在文件中某个特定偏移量处强制取值的方法吗?这是需要强制取的 4 个连续字节。我知道损坏文件的正确 SHA-1。因此,我想要做的是每次更改字节值时比较完整文件的 SHA-1。
我知道确切的 4 个字节被更改了,因为该文件是数据恢复专家给我的,作为恢复挑战。对于那些有兴趣了解的人来说,rar 文件中有 4 个字节是故意更改的。我被告知了更改的 4 个字节和原始 SHA-1 的偏移量。那个人说,一旦更改了 4 个字节,就不可能恢复存档中的确切文件。即使只有几个字节,而且您确切知道损坏的位置。因为它没有恢复记录。我正在尝试看看是否有办法正确填写这 4 个特定的字节,以便文件可以无错误地解压缩。文件大小约为 5mb。
例子:
我上传了照片,这样可以更清楚地说明我到底想做什么。我相信有人可以在这里发布这些照片,让我获得更多的关注。
我关注的示例偏移量是0x78
第一张图片显示的值,因为CA
我希望脚本将值增加 1,使其变为CB
第二张图片所示。我希望它继续增加值1
,然后每次比较整个文件的 SHA-1。仅对指定偏移量的那 4 个字节进行更改。
它会尝试CAC5C58A
比较 SHA-1。如果不匹配,它会尝试CBC5C58A
。然后一旦第一个值达到,FF
它就会转到00C6C58A
等等。基本上,我希望它能够从那里开始00000000-FFFFFFFF
,但也可以选择你想要它从哪里开始和结束。我知道这可能需要一些时间,但我仍然想尝试一下。请记住,我知道损坏的字节的确切偏移量。我只需要正确的值。
如果您在 Google 上搜索:“如何通过强力修复损坏的文件”,有人编写了一个 Linux 程序。但是,它只针对程序中包含的文件起作用。我正在寻找某种方法对我的文件使用相同的过程。
答案1
这是一个小型 Python 程序,它可以完成您描述的操作。
#!/usr/bin/env python3
from hashlib import sha1
with open('binaryfile', 'rb') as bin:
binary = bin.read()
base = 0x0078
# ... is not valid Python; add more sequences, or take it out (or see below)
for seq in [[0xCA, 0xC5, 0xC5, 0x8A], [0xCB, 0xC5, 0xC5, 0x8A], ...]:
copy = binary[0:base]
copy += bytes(seq)
copy += binary[base+len(seq):]
if sha1(copy).hexdigest() == '9968733ce3ff0893bbb0a19e75faaf2fb0000e19':
print('success with bytes {0}'.format(seq))
break
else:
print('no success')
联合国仅短暂已测试;如果发现错别字,请通知我。
指定base
尝试应用这四个字节的位置,长字符串'996873
... 是预期 SHA1 的十六进制表示。行for seq in
... 定义要尝试的字节;当然,将其替换'binaryfile'
为您要尝试挽救的文件的路径。
您可以用某些东西替换文字列表[[0xCA, 0xC5,
...]]
来实际循环遍历所有可能的值,但它基本上只是一个更有用的东西的占位符,因为我不太确定您到底想要什么。
类似于for seq in itertools.product(range(256), repeat=4)):
将循环遍历从 0 到 2 32 -1 的所有可能值。(然后您需要import itertools
在顶部附近添加。)或者您可以简单地添加一个偏移量;更新脚本以将当前脚本替换for seq in
为以下内容(再次需要import
在主程序之前进行);
import struct
for n in range(2**32):
val=(n+0x8AC5C5CA) % 2**32 # notice reverse order
seq=list(reversed(struct.pack(">I", val)))
copy = ...
我反转了字节的顺序,这样它自然地从 0x8AC5C5CA 递增到 0x8AC5C5CB,但下一个增量将是 0x8AC5C5CC 等。魔术struct
是将其转换为字节序列(必须从中查找https://stackoverflow.com/a/26920983/874188)。它将从 0x8AC5C5CA 开始,到 0xFFFFFFFF,然后绕回到 0x00000000 并爬回到 0x8AC5C5C9。
如果你有多个候选范围,你想按特定顺序检查,也许像
for rge in [(0x8AC5C5CA, 0x8AFFFFFF), (0x00C6C58A, 0x00FFFFFF),
(0x00000000, 0x00C6C589), (0x01000000, 0x8AC5C5C9)]:
for val in range(*rge):
seq=list(reversed(struct.pack(">I", val)))
copy = ...
但你需要确保自己(开始,结束)如果你真的想检查所有空间,那么 中的对将覆盖rge
0x00000000 和 0xFFFFFFFF 之间的所有空间。(再次注意,范围增加了最后的字节并seq
根据您所规定的要求反向应用值的字节。)
如果您想使用两个不同的base
地址,那么您很快就会遇到一生中用蛮力所能及的极限;但是,例如,您可以将 4 字节数字拆分为两个 2 字节部分,并将它们应用于不同的偏移量。
base1 = 0x1234
base2 = 0x2345
for seq in range(whatever):
copy = binary[0:base1]
copy += bytes(seq[0:1])
copy += binary[base1+2:base1+base2]
copy += bytes(seq[2:3])
copy += binary[base2+2:]
答案2
不,不,不,再说一遍不!
你得到的答案很少会不符合你的预期。
向您提问一些问题:
- 有可能专家不知道是否可以强行破解一串字节并迭代尝试 SHA-1 直到它收敛?不
- 他有可能忘记了吗?不
- 您是否无法对 rar 文件执行此操作?不
- 是另一个答案错了吗?绝对错了不
所以呢?... 时间。
关键在于您只需改变很少的字节...仅 4 个!
这是什么意思?256 4即 256x256x256x256 种可能性,一个非常非常大的数字。
如果你的计算机能够处理每秒 1 次操作(在文件 + sha1 中替换)...
你应该等136年以上,或者如果您愿意,可以超过 49710 天。
你很幸运,在旧电脑上,一个 5MB 的预缓存文件(已加载到内存和缓存中)只需要大约 0.03 秒(最少 0.025 秒)。这将你的预期时间缩短到 1242-1492 天(超过 3 年)。
确实如此,顺便说一句,从统计学上来说,一半的时间你应该会得到肯定的答案。尽管如此,您还是应该等到尝试了所有可能性之后再确定只有 1 个替换会给您相同的 SHA-1 校验和...
现在不可能的听起来“不可能值得多少时间”。
如何进行
对您的技术问题更恰当的回答是:当您谈到蛮力时,它不一定是盲目的蛮力。
另一个答案的评论中只是指出,您不需要计算损坏前部分的 sha1 校验和。您只需第一次计算,就可以节省每次迭代的时间(可能是 2 倍,具体取决于位置)。
可以改变努力毫无价值的事情是写一篇并行代码将在 GPU 上运行。如果您有一块好的显卡,您可能有大约 1000 个核心可以为您并行计算(甚至更多,但它们的频率低于 CPU,但仍然很多)。如果您能够将时间从 1400 天缩短到 1.4 天,也许您甚至可以做到。
A不同的方法可以让你更快地找到解决方案。
你说这是一个 rar 文件。rar 文件结构被分成块。如果你计算一下,你就能知道损坏发生在何处。如果它在数据部分,在标题部分,或者两者都有。那么你可以采取相应的行动。为了简单起见,我们假设它是在数据上:
你可以对偏移量进行强力攻击,检查该块的每个正 CRC,如果它是正的,则检查整个文件的 SHA1。同样,你可以执行并行代码。
最后说明
如果它们是 6 个字节而不是 4 个字节,那么使用现有技术你就已经出局了。