恶意样本给出函数家族的 md5,如何进行分类
1. 样本预处理
首先,我们需要拿到恶意样本文件。为了确保分析的安全性,这些样本通常在沙箱环境或隔离的虚拟机中运行和处理
2. 静态分析与函数提取
这是最关键的一步。我们需要使用专业的反汇编或反编译工具(如 IDA Pro、Ghidra、Binary Ninja 等)对样本进行静态分析,提取其中的所有函数
在提取过程中,我们要确保做到以下几点:
- 识别所有函数: 准确地识别出样本中所有的函数入口点和函数体
- 清理和标准化: 许多编译器会在函数中插入一些无用的代码(如栈帧设置、调试信息等)。为了确保哈希的一致性,我们需要清理这些与核心逻辑无关的代码。例如,可以使用工具去除 NOP(空操作)指令、对齐填充等
- 标准化函数代码: 即使是相同的逻辑,不同的编译器或编译选项也会产生略有差异的机器码。为了让哈希值保持一致,我们需要对函数进行标准化。这通常涉及将函数体转化为一种更抽象、更稳定的表示形式,比如:
- 代码归一化(Code Normalization): 替换寄存器名称、删除地址无关的指令,使得哈希值不受编译地址的影响
- 指令序列哈希: 只对核心的指令序列进行哈希,忽略一些可变的部分
3. 计算函数哈希
在函数代码被标准化和清理后,我们就可以计算它们的 MD5 哈希值了。这里通常采用两种策略:
- MD5 哈希: 直接对标准化后的函数二进制代码或其序列进行 MD5 计算。这是最简单也最直接的方法
- 模糊哈希(Fuzzy Hashing): 对于一些变种较大的函数,使用 MD5 可能会失效。这时,我们可以使用模糊哈希算法,如 ssdeep 或 TLSH。这些算法能够计算出相似度分数,而不是一个绝对的哈希值,从而可以匹配那些有细微改动的函数
4. 构建哈希数据库
在提取并计算出哈希值后,我们需要将这些信息存储到一个哈希数据库中。这个数据库通常包含以下信息:
- 函数 MD5 哈希值
- 该函数所属的样本文件名或哈希
- 该函数的家族分类信息(如果已知)
- 该函数的功能描述(如果分析过)
通过不断地分析新的样本并填充这个数据库,我们就能建立一个庞大的恶意软件函数指纹库
5. 家族分类
现在我们有了函数哈希和数据库,就可以开始进行分类了
- 第一步: 拿到一个新的未知样本
- 第二步: 按照上述步骤,提取该样本中的所有函数,并计算它们的 MD5 哈希值
- 第三步: 将这些新计算出来的函数哈希值与我们的哈希数据库进行比对
- 第四步: 如果一个或多个函数哈希在数据库中找到了匹配项,并且这些匹配项都指向同一个恶意软件家族(例如,都匹配到“Emotet”家族中的多个样本),那么我们就可以初步判断这个新样本也属于这个家族
- 第五步: 如果匹配到了多个不同的家族,我们需要进行进一步的分析,比如:
- 函数数量匹配: 看看哪个家族匹配到的函数数量最多
- 核心功能函数匹配: 某些函数(如加密、持久化)比其他函数(如日志记录)更能代表一个家族的特征。如果核心功能函数匹配上了,分类的准确度会更高