Files
Sec-Interview/_book/Chapter23/23-8.md
T
2025-11-08 21:00:06 +08:00

43 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### 如何比较两个 C 函数的相似度
**1. 二进制层面比较**
这是最直接但最不健壮的方法,通常只作为初步筛选
- **字符串哈希 (MD5/SHA-256)**:这是最简单的方法。将函数编译后的机器码提取出来,然后计算其哈希值。
- **优点**:速度快,可以快速识别完全相同的函数
- **缺点**:非常脆弱。任何微小的改动,比如插入一条 `NOP` 指令、改变局部变量的顺序,都会导致哈希值完全不同。因此,它无法检测代码克隆或相似的代码
- **模糊哈希 (Fuzzy Hashing)**:与传统的哈希算法不同,模糊哈希(如 **ssdeep****TLSH**)能够生成一个代表文件或代码块结构特征的哈希值。两个哈希值之间的距离可以用来衡量它们的相似度
- **优点**:能够容忍代码中的小改动,可以发现有细微变化的函数
- **缺点**:对于较大的代码重构(如改变控制流),效果不佳
**2. 结构层面比较**
这种方法比二进制比较更抽象,对编译器的影响和一些代码改动不敏感
- **控制流图 (Control Flow Graph, CFG) 比较**
- **方法**:将每个函数表示为一个控制流图,其中节点是基本块(一系列没有跳转的连续指令),边代表控制流。比较两个函数的相似度就变成了比较它们 CFG 的结构相似度。这通常通过图匹配算法来实现,比如子图同构或图编辑距离(graph edit distance
- **优点**:非常健壮。它对寄存器分配、指令顺序等改动不敏感。如果两个函数的逻辑结构相同,即使它们用不同的编译器编译,CFG 也会非常相似
- **缺点**:算法复杂,计算量大,尤其是在面对大型函数时
- **函数特征向量 (Function Feature Vectors)**
- **方法**:为每个函数提取一系列特征,并将其表示为一个向量。这些特征可以包括:
- 基本块数量
- 指令数量
- 算术指令、逻辑指令、跳转指令的比例
- 循环嵌套深度
- 函数调用的数量和类型
- **优点**:将函数简化为数值向量,可以使用简单的距离度量(如欧几里得距离或余弦相似度)进行快速比较,非常适合大规模数据集
- **缺点**:丢失了结构信息。两个结构完全不同的函数可能会有相似的特征向量,反之亦然
**3. 语义层面比较**
这是最强大但也是最困难的方法,旨在比较函数的行为和功能,而不是其形式
- **抽象语法树 (Abstract Syntax Tree, AST) 比较**
- **方法**:将源代码或反编译代码解析成抽象语法树。比较两个函数的相似度就变成了比较它们 AST 的结构。这通常通过树编辑距离(tree edit distance)算法来实现
- **优点**:高度抽象,对变量名、代码格式等变化完全免疫,能够准确反映代码的逻辑结构
- **缺点**:依赖于高质量的反编译器,并且 AST 比较算法同样非常耗时
- **污点分析 (Taint Analysis) 或数据流分析**
- **方法**:分析函数的输入如何影响其输出。如果两个函数在给定相同输入时产生相同的输出,并且内部数据流路径相似,它们就是相似的
- **优点**:能够发现功能上完全相同的代码,即使它们的实现方式天差地别
- **缺点**:非常复杂,很难自动化,且无法处理所有情况