关键是获得大量样本,以便分析有依据。如果您可以将样本保存在可以交互查询的数据库表或字典中,例如从某种脚本外壳中查询,那真的很有帮助。Python 应该可以很好地工作,但我对它没有太多经验,因为在过去的二十年里,我一直在使用 Visual FoxPro 进行交互式探索。
一旦您准备好要查询的样本,您就可以测试各种简单的假设并通过找到反例来反驳它们。例如,以下示例似乎表明第四个字节的差异导致校验和的四倍差异:
00h 5Ch A2h 00h 00h 01h 7Fh
00h 5Ch A2h 01h 00h 01h 63h
00h 5Ch A2h 02h 00h 01h 67h
00h 5Ch A2h 03h 00h 01h 6Bh
00h 5Ch A2h 04h 00h 01h 6Fh
关键是找到仅在当前“工作”列和校验和中不同的样本,以研究工作列中的更改对校验和的影响。例如,给定上面的输入,我们可以记4 * b[3]
下第四个字节的初步术语,然后在示例数据库中查询反例,如果这不起作用。也就是说,您选择仅在第四个字节和校验和上不同的样本对,并计算成功和失败的次数
delta(checksum) mod 256 == 4 * delta(byte[3]) mod 256.
反正就是这个想法。是什么样的事情delta(checksum) mod 256
实际上看起来像取决于你的脚本外壳,效果显着。使用 VFP 将是
mod(256 + asc(substr(right, 7, 1)) - asc(substr(left, 7, 1)), 256)
上面测试的完整表达式会很长,因此您通常会编写很少的辅助函数。使用名为的助手将byte_delta()
其结果规范化到 [0, 255] 范围内,您可能有
select le.sample as left, ri.sample as right ;
from all_samples le, all_samples ri ;
where stuff(left(ri.sample, 6), 4, 1, "") == stuff(left(le.sample, 6), 4, 1, "") ;
and le.sample <> ri.sample ;
into cursor byte_3_pairs
select byte_delta(right, left, 7) == mod(4 * byte_delta(right, left, 4), 256) as ok, count(*) ;
from byte_3_pairs ;
group by 1
在考虑的情况下,您将获得此查询的混合图片(请参阅上面第一个和第二个示例之间的区别,即 E4 而不是 4)。通常你会先做一些选择差异,只是为了感受一下。“差异”可以是算术差异,按位异或,等等。
这就是为什么你需要一个像 Python 或 VFP 这样的交互式 shell;对于编译语言的编辑-编译-运行循环,这将是相当麻烦的。我已经给出了 VFP 示例,因为具有数据库支持的脚本语言可以使这里的事情变得容易得多。
对于像 ISBN 之类的东西中通常的“人类可计算”校验和这样的简单加权和,这可以提供相当快的结果。我已经使用这种方法从不同数量的样本中确定了德国健康保险号码中使用的所有校验位方案——这些方案大多没有记录(或者至少在当时没有记录)。当然,在那种情况下,我的优势在于方案的基本类型 - 加权数字总和 - 是已知的,并且样本已经驻留在数据库表中......
正在讨论的案例比较困难,因为基本方案尚不清楚。这就是为什么查看位模式以了解事物很重要的原因。例如,冒泡进位表示加法函数。这在主题反转简单消息 + 校验和对(32 字节)中有更详细的解释,其中还显示了一些更改模式示例。
PS:除了尝试梳理特定位或字节变化的校验和差异之外,当样本被填充到某种可查询的表/字典/映射中时,还有很多其他的事情可以做。第一件事通常是使用现有的标准函数运行一系列测试,如直接字节和、直接字节异或、各种 CRC 等,以观察校验和的差异(算术和异或)。将结果显示为位模式 - 如链接文章中所示 - 通常有助于辨别在十六进制或十进制格式中不太明显的规律。
更新目前样本太相似(前三个字节没有差异),而且样本太少,无法快速丢弃假设。换句话说,适合现有数据的潜在函数太多了……
例如,以下简单的 Fox 函数正确预测了原始少数样本的校验和,除了少数情况下它偏离了 0x20:
function f (s)
local x, i
x = 0
for i = 1 to len(m.s) - 1
x = bitand(bitlshift(m.x, 1) + asc(substr(m.s, m.i, 1)), 0xFF)
next i
return bitand(m.x + 0x8E, 0xFF)
这可能是因为它是旋转而不是移位,或者涉及一些异或,或者与每个字节的位数重叠以在第四个字节和校验和之间创建两位距离的其他移位(相对于 8 为素数)。轮换 5 将做到这一点。然而,还有很多其他的可能性……这就是我们需要更多样本的原因。;-)
分析PasteBin 上的样本表明,校验和之前最后一个字节位置的差异始终等于校验和的差异。这意味着可以从样本库中删除最后一个字节及其对校验和的影响。这增加了仅在一个字节位置上不同的样本数量,这意味着有更多容易实现的分析结果......
例如样品
00 5C A0 00 00 00 00 00 06 00:69
00 5C A0 00 00 00 00 00 06 01:6A
...
00 5C A0 00 00 00 00 00 06 FF:68
all 映射到新样本(点表示已删除的字节,这里只是为了说明):
00 5C A0 00 00 00 00 00 06 . 69
缩短的样本库立即显示了“二的幂”规则不起作用的情况(这里的最后一个字节最初是倒数第二个):
00 5C A0 00 00 00 00 00 00 . 7D
00 5C A0 00 00 00 00 00 01 . 7F
00 5C A0 00 00 00 00 00 02 . 61 <- difference -0x20 to predicted delta 2
00 5C A0 00 00 00 00 00 03 . 63
00 5C A0 00 00 00 00 00 04 . 65
...
00 5C A0 00 00 00 07 00 00 . B5
00 5C A0 00 00 00 08 00 00 . BD
00 5C A0 00 00 00 09 00 00 . A5 <- difference -0x20 to predicted delta 8
00 5C A0 00 00 00 0A 00 00 . AD
00 5C A0 00 00 00 0B 00 00 . D5 <- back on track with the earlier sequence