Skip to content

Algorithm — single-byte rolling key #1

Description

@ajsb85

这份文档描述了一种用于解密特定资源(通常为 Delphi 窗体文件 .dfm)的单字节滚动密钥算法。该算法通过一个初始密钥对数据进行异或解密,并在解密每个字节后动态更新密钥状态。

key = 0xD7
for each byte c of the form's class name (original case):  key ^= c
for i in 0 .. n-1:                       # n = resource size
    plain[i] = cipher[i] XOR key
    key = (key + ((n - i) & 0xFF)) & 0xFF # add remaining byte count
    key = ROL8(key, 1)                    # rotate-left 1 within a byte

算法流程详解

  1. 密钥初始化

算法的第一步是生成一个基于窗体类名的初始密钥。

  • 设定种子:将一个临时密钥变量初始化为固定值 0xD7。
  • 类名混淆:遍历窗体类名的每一个字节(区分大小写),并将临时密钥与该类名字节进行异或(XOR)运算。
  • 结果:经过上述运算后得到的临时密钥值,即为解密数据的初始密钥。
  1. 解密主循环

获取初始密钥后,算法将遍历资源的每一个字节(设资源总大小为 n),执行以下操作:

  1. 解密字节:将密文的当前字节与当前密钥进行异或运算,得到明文的对应字节。
  2. 更新密钥(加法):将当前密钥加上“剩余的未解密字节数”(即 n - 当前索引 i),并只保留结果的低 8 位(确保值在 0-255 之间)。
  3. 更新密钥(位旋转):将上一步计算出的新密钥值进行8位循环左移1位操作。

通过以上步骤循环往复,直至所有字节解密完成。

核心原理分析

为何无需类名即可解密

该算法虽然使用类名作为密钥种子的一部分,但在实际解密时,可以利用数据格式的特征直接反推初始密钥,而无需预先知道类名。

  • 已知明文特征:所有目标资源(DFM 文件)在明文状态下,其文件头的第一个字节必然是字母 T(这是文件内部特定标记的开头)。
  • 反推逻辑:
    • 解密公式为:明文[0] = 密文[0] XOR 初始密钥。
    • 由于 明文[0] 已知为 T,且 密文[0] 可以直接读取,因此可以直接计算出 初始密钥 = 密文[0] XOR 'T'。
  • 结论:既然初始密钥可以通过计算得出,那么解密过程就不再依赖于窗体类名。

关于旧版算法的说明

早期的同类资源(如旧版插件或工具涉及的资源)可能采用了不同的加密方式(例如基于 4 个 32 位状态字的流密码)。然而,当前所述的算法与旧版不同,它采用了更简洁的单字节滚动密钥机制,旧版的解密工具在此场景下将无法使用。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions