27、加密算法识别:常量搜索、密码学库识别(OpenSSL、Crypto++)、常见算法特征
加密算法识别,说白了就是跟二进制里的「密码锁」打交道。你拿到一个样本,里面可能有加密数据,也可能有加密通信。第一步不是去破解算法,而是先搞清楚——它到底用了什么加密?
我个人习惯,拿到一个待分析的二进制文件,先不急着上动态调试。先静态扫一遍,看看有没有熟悉的「味道」。这个味道,就是加密算法的特征。
常量搜索:最直接的指纹
加密算法在实现时,通常会用到一些固定的常量。这些常量就像算法的「DNA」。比如:
- AES:S盒(S-Box)是固定的 256 字节数组。0x63, 0x7c, 0x77... 这串值你只要在二进制里搜到,基本可以断定用了 AES。
- MD5:初始化常量 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476。这四个数太经典了。
- SHA-1:初始哈希值 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0。注意跟 MD5 的前四个一样,但多了一个。
- CRC32:多项式表,通常是 0xedb88320 相关的查找表。
实战技巧:用 IDA Pro 或 Ghidra 的「Search > Immediate value...」功能,直接搜这些常量。如果搜到了,十有八九就是对应的算法。我在项目中遇到过好几次,搜到 S 盒后,顺着交叉引用直接定位到加密函数,省了大量时间。
为什么会这样?因为加密算法的实现,尤其是标准算法,常量几乎不会变。开发者如果自己手写实现,必然会把常量硬编码进去。就算他用了混淆,常量也很难被完全隐藏。
避坑指南:我曾经遇到过一个样本,搜到了 MD5 的常量,但实际用的是 SHA-1。后来才发现,开发者把 SHA-1 的前四个常量改成了 MD5 的值,故意误导分析。所以,常量搜索只是线索,不能作为唯一证据。最好结合上下文和算法逻辑再确认。
密码学库识别:OpenSSL、Crypto++
很多开发者不会自己写加密,而是直接用现成的库。最常见的两个:OpenSSL 和 Crypto++。
识别库的好处是:一旦知道是哪个库,你就能直接找到对应的函数名、参数结构,甚至能预测代码的执行流程。
OpenSSL 特征
- 导出函数名:比如
EVP_EncryptInit_ex、AES_set_encrypt_key、MD5_Init。这些函数名在静态链接时会被保留(除非 strip 掉)。 - 字符串特征:OpenSSL 内部有很多错误字符串,比如
digital envelope routines、bad decrypt。搜这些字符串,基本能确定。 - 版本字符串:比如
OpenSSL 1.1.1k 25 Mar 2021。这个字符串通常藏在二进制里。
Crypto++ 特征
- 类名和命名空间:Crypto++ 是 C++ 库,编译后会有
CryptoPP::AES::Encryption这样的符号。如果没 strip,直接能看到。 - 静态常量:比如
CryptoPP::AES::Encryption::StaticAlgorithmName这种字符串。 - 异常字符串:Crypto++ 的异常信息,比如
StreamTransformationFilter: ciphertext length is not a multiple of block size。
我的做法:先用 strings 命令扫一遍二进制,把输出重定向到文件。然后 grep 关键词,比如 EVP_、AES_、CryptoPP。如果命中,基本可以确定库的类型。接下来,用 IDA 的 FLIRT 签名库自动识别,效率更高。
常见算法特征速查表
| 算法 | 关键常量/特征 | 典型函数名 |
|---|---|---|
| AES | S盒:0x63, 0x7c, 0x77...(256字节) | AES_set_encrypt_key, AES_encrypt |
| DES/3DES | IP置换表、S盒(8个6进4出) | DES_set_key, DES_ecb_encrypt |
| RSA | 大数运算、公钥指数 0x10001(65537) | RSA_public_encrypt, RSA_private_decrypt |
| MD5 | 初始值:0x67452301, 0xefcdab89... | MD5_Init, MD5_Update, MD5_Final |
| SHA-1 | 初始值:0x67452301, 0xefcdab89...(5个) | SHA1_Init, SHA1_Update |
| SHA-256 | 初始值:0x6a09e667, 0xbb67ae85... | SHA256_Init, SHA256_Update |
| CRC32 | 多项式表(0xedb88320 相关) | crc32, CRC32_Init |
注意:有些恶意软件会修改标准算法的常量,比如把 S 盒的值做 XOR 或加减混淆。这时候直接搜原始常量会搜不到。你需要先识别出「疑似加密代码段」,然后手动分析其逻辑,看是否与标准算法结构一致。
知识体系图:加密算法识别流程
实战中的一些心得
你想想看,识别加密算法其实就像侦探破案。常量是物证,库特征是目击证人的描述,而算法逻辑就是作案手法。三者结合起来,才能下定论。
我个人习惯,在 IDA 里用 View > Open subviews > Signatures 加载 FLIRT 签名库。如果签名匹配上了,函数名直接显示出来,连分析都省了。但要注意,有些样本会 strip 掉符号表,或者用静态链接但改过函数名。这时候就得靠常量搜索了。
嗯,这里还要提一句:不要只依赖一种方法。常量搜索 + 库特征 + 逻辑分析,三管齐下,准确率才高。我曾经遇到一个样本,常量搜到了 AES 的 S 盒,但函数名被混淆了。我顺着 S 盒的引用找到了加密函数,发现它调用了 EVP_EncryptInit_ex 的地址(通过动态获取),这才确认是 OpenSSL 的 AES。
一个小技巧:如果你怀疑是 OpenSSL,但函数名被 strip 了,可以搜字符串 EVP_CIPH_ 或 EVP_CTRL_。这些是 OpenSSL 内部定义的宏常量,通常不会被混淆。我在多个恶意软件样本里用这个方法成功定位了加密逻辑。
好了,加密算法识别这块,核心就是「找特征、对库、验逻辑」。多练几次,你看到二进制文件里的那串字节,就能闻出是什么加密算法的味道了。