百趣云 百趣云的博客

AES 识别实战:从特征常量到模式判断

为什么要先识别再还原

逆向加密代码时,第一步永远是识别算法家族——是标准算法(AES/RSA/SHA)还是自定义算法?标准算法意味着你只需要找密钥,自定义算法才需要还原逻辑。识别靠的不是读代码,是特征常量:密码学算法内部都有固定的数学常量,它们在二进制里像指纹一样独特。

AES 的特征常量

AES 的核心是 S 盒(SubBytes 替换表),256 字节的固定表:

63 7c 77 7b f2 6b 6f c5 30 01 67 2b fe d7 ab 76
ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0
...

IDA 里搜前几个字节 63 7C 77 7B F2 6B 6F C5,命中即 AES。这是逆向圈识别 AES 的百年老店级手法。

另一个特征:AES 的轮密钥生成用 Rcon 表(01 02 04 08 10 20 40 80 1B 36),搜这个也能命中。

模式判断:ECB 还是 CBC

确认是 AES 后,判断工作模式(决定要不要找 IV):

ECB 模式特征

  • 代码里没有 IV 参数(或 IV 传 null/全 0)
  • 相同明文分组加密结果相同——用已知明文对拍验证:输入 32 字节全 0,输出若前 16 字节和后 16 字节相同,是 ECB

CBC 模式特征

  • 有 16 字节 IV 参数
  • 相同明文不同 IV 结果不同

Java 层判断最简单——Cipher.getInstance("AES/CBC/PKCS5Padding") 的字符串直接写明。SO 层看参数个数和 IV 的使用痕迹。

密钥长度判断

AES-128/192/256 的区别在密钥长度和轮数(10/12/14 轮):

  • 数循环轮数:IDA 里看主循环次数
  • 看密钥拷贝长度:memcpy(key_buf, input, 16) = AES-128

对拍验证:识别的终审

识别结论必须用对拍验证:

from Crypto.Cipher import AES

# 用 hook 拿到的 key/iv,对已知明文加密,和 App 输出对比
cipher = AES.new(key, AES.MODE_CBC, iv)
result = cipher.encrypt(pad(known_plaintext))
assert result == app_ciphertext  # 一致 = 算法、模式、密钥全对

对拍不一致的排查顺序:模式错(ECB/CBC 搞反)→ 填充错(PKCS7 vs NoPadding)→ 密钥错(密钥可能经过了 KDF 派生,不是原始字符串)。

精髓:密钥不一定是你看到的字符串

hook 拿到的"密钥"经常不是最终密钥,而是经过了派生:

  • 直接当 key"1234567890abcdef" 就是 16 字节密钥
  • MD5 派生md5("salt" + input)[:16] 才是密钥
  • PBKDF2/多次哈希:金融 App 常见

判断方法:hook 到的密钥直接用于对拍,失败就往上追密钥的来源代码——密钥的"出生点"(是硬编码、是计算得出、还是网络下发)决定还原策略。

总结

  1. AES 识别靠 S 盒常量 63 7C 77 7B,Rcon 表是辅助证据
  2. 模式判断:ECB 无 IV 且同明文同密文,CBC 有 IV
  3. 密钥长度看轮数或 memcpy 长度
  4. 对拍是终审,失败按模式→填充→密钥派生排查

交流微信:run1255

By 百趣云 阅读量:23 On