[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis

概述

In-Memory Fuzzing for Binary Code Similarity Analysis [ASE 2017]

Shuai Wang and Dinghao Wu The Pennsylvania State University

检测二进制可执行文件中的相似函数是许多代码分析和重利用任务的基础, 但是目前(2017年)识别二进制代码中的相似组件依然是一个具有挑战性的问题. 现有的方法通过静态或者动态方法来捕捉程序中的语法和语义层面的特征来做相似度比较. 但是这些方法有局限性, 包括高开销, 低准确率, 规模小, 难以实际应用等.
在本文中, 我们提出一种全新的方法: 利用在内存中fuzzing来做代码相似度分析. 我们的原型机 IMF-sim 使用In-memory Fuzzing面向每一个函数和收集的不同程序行为的路径信息做相似度分析. 相似度分数由两个程序行为的路径的最长公共子序列来衡量. 对于两个函数, 特征向量由其行为的路径级别的相似度分数组成. 我们基于打好标签的特征向量数据集训练了一个模型, 然后用模型给需要衡量相似度的两个函数进行打分, 我们在不同编译器, 不同优化选项, 不同混淆方法, 总共上千个二进制可执行文件上测试了 IMF-sim 模型. 结果显示 IMF-sim 的准确率显著超过当前所有已存在的方法或者工具.

一句话: 利用内存fuzzing得到不同程序行为的路径信息做代码相似度分析

导论

确定两个二进制代码组件之间的相似性的研究可以应用于
(1) 二进制代码克隆检测通过分析两个二进制组件[57]、[50]的相似性来识别潜在的代码复制或剽窃
(2) 基于补丁的利用比较了前补丁和后补丁的二进制文件,揭示了补丁[11]修复的隐藏漏洞
(3) 恶意软件研究分析不同恶意软件样本之间的相似性,以揭示恶意软件集群或血统关系[8],[36]

现有工作和缺陷
工业标准工具BINDIFF主要通过图同构比较[20]、[23]来标识类似的函数, 该算法通过比较控制流和调用图来检测相似的功能。
还有一些工作结合程序语义来揭示隐藏相似性[50], [21], [56], [15].

但是现有研究的存在一些弱点。例如,基于动态分析的方法通常有覆盖问题。典型的静态方法虽然可以测试任何程序组件,但可能会受到现实世界中具有挑战性的问题的影响,例如编译器优化或程序混淆。

In-memory fuzzing
模糊测试技术的一种, 可以针对程序中特定目标函数进行模糊测试, 其中一种实现方式就是修改程序中的目标函数的函数链, 在子例程中插入无限循环执行流, 将目标函数从整个程序中隔离出来, 对目标函数进行模糊测试
[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第1张图片

参考
https://crossbowerbt.github.io/in_memory_fuzzing.html

Motivation
(1) 现有动态分析的一个明显问题是测试目标(例如,函数)的低覆盖率。从理论上讲,生成程序输入以保证每个代码组件的可达性是一个不可判定的问题。这意味着,现有的动态工具一般无法分析二进制可执行文件中的所有函数,极大地限制了它的应用范围。
(2) 静态分析对于实际程序的应用效果有限,例如复杂的控制流、库或系统调用。此外,基于符号执行的约束求解的相似性分析可能会有明显的性能损失。而且不能应对程序混淆的情况等.
(3) 因为二进制相似度分析的一个主要应用是做恶意软件研究, 因此现实中常常要面临代码混淆的情况, 而动态模糊测试技术可以帮助克服这个难题, 还可以解决函数的覆盖率问题, 所以论文提出基于内存模糊测试的相似度分析方法

Contributions
(1) 提出 IMF-sim, 一种基于内存模糊测试技术的函数级二进制代码相似度分析方法
(2) 克服相似度分析任务应用fuzzing技术的一些独特挑战, 并揭示fuzzing技术的优势
(3) IMF-SIM能够有效地应对来自不同编译器、优化甚至常用程序混淆的挑战。测试效果很好, SOTA (2017)

方法

method

为了比较两个二进制可执行文件中的两个函数,我们首先启动内存模糊处理(in-memory fuzzing)来执行函数的迭代,并记录多种行为轨迹. 这一步的核心挑战是缺乏数据类型信息。例如,我们事先不知道函数形参是值类型还是指针类型,并且误用非指针数据作为指针会导致内存访问(指针解引用)错误。
为了解决这个问题,每当这个指针发生解引用错误时, 使用向后污点分析来恢复指针数据流的“根”。然后重新执行该函数,并使用有效的指针值恢复数据流的根.
然后,我们连接相同类型的行为轨迹(例如,表示堆内存访问的行为轨迹)来构建最终的行为轨迹
为了比较两个函数,使用同类的两个行为轨迹来计算Jaccard引用率; 收集所有行为轨迹的Jaccard索引率,为两个函数形成一个数值向量, 然后是基于groud truth给数据打标签形成数据集, 最后训练模型

[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第2张图片

IMF-SIM由四个模块组成,分别是模糊处理模块、污点分析模块、相似度分析模块和机器学习模块。

输出结果:
对于二进制bin1中的给定函数f1, 用户需要提供起始和结束地址,为了找到它在bin2中的匹配函数,我们将f1与bin2中的每个函数进行比较,并将排序后的最上面的函数作为最终结果。

IMF-SIM捕捉各种运行时行为。IMF-SIM的一个重要设计理念是将目标函数视为一个黑箱。这意味着,我们只捕获被监视函数及其运行时环境之间的交互。所捕获的特征包括

  1. Value read from or write to the program heap (f1, f2).
  2. Memory address offsets for reading the .plt.got section (f3).
  3. Memory address offsets for reading the .rodata section
    (f4) .
  4. Memory address offsets for reading (f5) or writing (f6)
    the .data section.
  5. Memory address offsets for reading (f7) or writing (f8)
    the .bss section.
  6. System calls made during execution (f9).
  7. Memory address offsets for accessing v mem1 (f10) or
    v mem2 (f11).
  8. Function return value (f12).

这些信息用来作为后向污点分析的输入, 以恢复指针类型数据流的root

Backword Taint Analysis

图2a为编译函数生成的汇编代码;这个函数包含一个循环来访问数组的每个元素。数组的基址通过函数的第一个参数传入(即寄存器rdi),并存储在堆栈中(第1行)。随后,内存地址流到rax(第5行)。在循环中,数组的基址递增(第5-7行)以访问每个内存单元格(第8行)。假设函数参数rdi被错误地赋值为值类型的数据。当内存访问出错时 (第8行),“in-place”方法只会更新rax,以便于第8行的当前内存访问。但是这个更新方法会继续遇到内存错误.

[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第3张图片

所以论文提出使用后向污点分析进行指针数据更新. 给定指针解引用错误,我们污染指针并向后传播污染,直到到达根(例如,函数输入参数)。然后从头开始重新执行函数,当遇到根函数时,用有效的指针更新它。

[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第4张图片

表 I 总结了6种污染规则, 比如第一种规则, 是赋值操作, 当左值为污染右值未被污染时, 则将污染传播给右值(可以是寄存器或者内存单元), 然后把污染从左值去除.

Longest Common Subsequence

利用最长公共子序列(LCS)算法来计算两条轨迹之间的相似度。最长公共子序列问题是指出现在所有序列中的最长子序列。我们注意到,由于LCS允许跳过不匹配的元素,它自然地容忍由于程序优化甚至混淆而导致的行为跟踪上的不同或噪音
衡量两个序列的相似程度, 使用Jaccard Index:
[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第5张图片

model training

选择训练一个基于树的模型(Extra-Trees)用于预测相似度
相比于神经网络模型和基于核的SVM模型, 基于树的模型更利于人类理解
在基于树的模型中, 随机森林存在过拟合问题, 所以作者最终选择Extra-Trees模型

数据集的lable通过函数名相同的groud truth来标记, 作者假设两个函数只有在名称相同的情况下才相似

实验

数据集
采用一个广泛使用的程序集 - GNU coreutils - 作为研究的数据集。总共由106个二进制文件组成,提供不同的功能,如文本处理和系统管理。排除了具有破坏性语义的二进制文件(例如rm),这将剩下94个程序.

混淆器
使用一个广泛应用的混淆器: obfusator - llvm (OLLVM)
OLLVM是一组在llvm编译器套件中实现的混淆传递,它提供了三种混淆方法,即
(1 指令替换 sub
(2 伪造控制流 bcf
(3 控制流扁平化 fla

Compiler. We use GNU gcc 4.7.2, Intel icc 14.0.1 and llvm 3.6 to compile programs.
Optimization Level. We test three commonly-used compiler optimization settings, i.e., -O0, -O2 and -O3.
Obfuscation Methods. we test program binaries obfuscated by three commonly-used methods, which are provided by Obfuscator-LLVM (version 3.6.1).

Groud Truth
尽管我们的技术本身并不依赖于二进制可执行文件中的调试和符号信息,但是我们使用调试符号来编译测试程序以获得函数信息。特别地,我们使用反汇编器(objdump[1])反汇编二进制代码,然后从反汇编输出中读取函数名和范围信息。我们工作中的基本事实是通过比较函数名来获得的。两个函数只有在名称相同时才被认为是匹配的。此外,每个函数的范围(起始和结束内存地址)作为IMF-SIM的输入。

特征重要性实验

评估捕获的每个特征的重要性。即每个特征对IMF-SIM的整体有效性有多大贡献。 f 1 f_1 f1 f 12 f_{12} f12见上边的 方法 - method
[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第6张图片

其中有4个功能的重要性超过10%,11个功能的重要性超过5%。唯一的异常值(f6)是内存写入全局数据段,其重要性为1.5%。总的来说,我们的评估表明,大多数特征具有明显的重要性.

准确率实验

采用标准方法,即十倍交叉验证,来测试IMF-SIM的性能。这种验证将整个数据集分为10个子集,并使用其余9个子集训练的模型对每个子集进行测试. 在这一步中,使用了由9个编译设置产生的二进制代码。Table III 为三个等级的评价结果。准确率是10次测试的平均值。平均而言,IMF-SIM的rank- 1相似度超过83%,rank- 5匹配的准确率超过90%。评估数据显示,编译器优化确实会影响性能。另一方面,我们观察到排名第三和排名第五的表现明显提高。
[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第7张图片

利用第一次评估中使用的所有六组数据来训练一个模型, 然后在最具挑战性的设置下比较二进制代码,即比较未优化的(-O0)二进制代码和高度优化的(-O3)代码。Table IV 显示 gcc/icc 和 llvm 之间的比较显示了相似的结果,特别是llvm -O0和gcc/icc -O3。BinDiff在交叉编译实验中表现很拉胯.

横向比较

BinGo: 通过符号执行和I/O采样获取语音信息
Blanket Execution (BLEX): 强制执行目标程序, 不修复指针引用错误
BinDiff: 利用CFG图同构分析相似度

[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第8张图片

总的来说,可以认为这四种工具都显示了类似的结果,繁重的编译器优化带来了相似度分析挑战,即-O2和-O3之间的比较产生的结果比-O0和-O3更好。而且 IMF-sim 达到了SOTA.

混淆代码分析实验

利用了OLLVM提供的所有混淆方法来混淆经过-O3优化的二进制代码(OLLVM使用编译器llvm来编译代码)。给定三组模糊代码,然后将每组代码与三组正常代码进行比较。
[论文笔记] In-Memory Fuzzing for Binary Code Similarity Analysis_第9张图片

bcf: 虚假控制流
fla: 控制流扁平化
sub: 指令替换

可以看到 IMF-sim 相比 BinDiff有更强的对混淆弹性, sub类型的混淆对准确率影响较小, fla和bcf因为改动了控制流, 也会对fuzzer造成影响, 所以准确率下降较多.

Processing Time

在我们的评估中,我们测试了21组比较,每组由94对程序组成。我们测量特征生成的总时间,从开始执行第一个测试二进制文件直到生成最后一个比较的特征向量。我们报告说,IMFSIM处理所有比较需要1027.1个CPU小时 (94对* 21组)。平均而言,它需要0.52左右比较两个二进制文件的CPU小时。

ExtraTrees模型的训练需要609.8 CPU秒。上述所有实验的预测时间是15389.6 CPU秒, 21组, 每组94对比较, 平均 7.8s 比较一对二进制文件.

总结

Related Works

[8] U. Bayer, P. M. Comparetti, C. Hlauschek, C. Kruegel, and E. Kirda, “Scalable, behavior-based malware clustering,” in Proceedings of the 2009 Network and Distributed System Security Symposium, ser. NDSS ’09. Internet Society, 2009.
[11] D. Brumley, P. Poosankam, D. Song, and J. Zheng, “Automatic patchbased exploit generation is possible: Techniques and implications,” in Proceedings of the 2008 IEEE Symposium on Security and Privacy, ser. S&P ’08, 2008, pp. 143–157.
[15] M. Chandramohan, Y. Xue, Z. Xu, Y. Liu, C. Y. Cho, and H. B. K. Tan, “BinGo: Cross-architecture cross-OS binary search,” in Proceedings of the 2016 24th ACM SIGSOFT International Symposium on Foundations of Software Engineering, ser. FSE 2016. ACM, 2016, pp. 678–689.
[20] T. Dullien and R. Rolles, “Graph-based comparison of executable objects,” SSTIC, vol. 5, pp. 1–3, 2005.
[21] M. Egele, M. Woo, P. Chapman, and D. Brumley, “Blanket execution: Dynamic similarity testing for program binaries and components,” in Proceedings of the 23rd USENIX Security Symposium. USENIX Association, Aug. 2014, pp. 303–317.
[23] H. Flake, “Structural comparison of executable objects,” in Proceedings of the First International Conference on Detection of Intrusions and Malware & Vulnerability Assessment, ser. DIMVA’04. Springer-Verlag, 2004, pp. 161–173.
[36] J. Jang, M. Woo, and D. Brumley, “Towards automatic software lineage inference,” in Proceedings of the 22nd USENIX Conference on Security, ser. USENIX Security’13. USENIX Association, 2013, pp. 81–96.
[50] “Semantics-based obfuscation-resilient binary code similarity comparison with applications to software plagiarism detection,” in Proceedings of the 22nd ACM SIGSOFT International Symposium on Foundations of Software Engineering, ser. FSE 2014. ACM, 2014, pp. 389–400.
[56] J. Pewny, B. Garmany, R. Gawlik, C. Rossow, and T. Holz, “Crossarchitecture bug search in binary executables,” in Proceedings of the 2015 IEEE Symposium on Security and Privacy, ser. S&P ’15. IEEE Computer Society, 2015, pp. 709–724.
[57] A. Sæbjørnsen, J. Willcock, T. Panas, D. Quinlan, and Z. Su, “Detecting code clones in binary executables,” in Proceedings of the Eighteenth International Symposium on Software Testing and Analysis, ser. ISSTA ’09. ACM, 2009, pp. 117–128.

Insights

(1) 程序功能分析可以结合fuzzing进行
(2) 结合污点分析确定数据类型
(3) In-memory fuzzing可以分析代码主干, 粒度比函数级更细
(4) 通过相同函数名来构建测试集
(5) 评估优化等级对分析效果的影响, 用不同优化等级之间的函数相似度准确率来衡量

你可能感兴趣的:(软件安全,论文阅读,人工智能,软件安全)