软件编译中开启-O2
和-O3
的区别是什么?相信很多人都说不清楚细节,更不用说从二进制代码的层面来区分了。今天我们推荐一篇来自RAID '22、关于二进制代码编译工具链识别的研究论文BinProv: Binary Code Provenance Identification without Disassembly,由来自乔治梅森大学Sun Security Lab和清华大学的研究人员共同完成。
二进制代码编译工具链识别(Provenance Identification)指从二进制代码中恢复出程序编译工具链信息(包括编译选项,优化选项等),是二进制代码相似性检测以及相关下游应用的关键步骤之一。目前的检测方法(例如科恩实验室提出的BinaryAI)主要依赖于 IDA Pro 等反汇编器输出的汇编代码,并从中提取出汇编代码的特征,作为后续机器学习模型的输入。
然而,作者通过对真实软件(GitHub Top 100 的 C/C++ 项目,如上图所示)和编译优化选项的研究,发现上述方法存在三个方面的不足:
-
依赖于反汇编器的结果,对于经过混淆和 strip 的二进制代码不能做到精准反汇编;
-
依赖于某一 CPU 架构或某一编译器的特定知识来手动提取特征,难以将方法迁移到其他二进制代码;
-
对于编译优化的识别还不够精确,例如不能区分 O2 与 O3 级别的二进制代码,从而对于采用多种优化级别的项目识别效果欠佳。
为了解决上述问题,作者考虑直接研究编译工具链对二进制代码的影响:以上图中不同编译工具链生成的汇编代码和二进制代码为例,直接分析二进制代码的字节序列能够找出更多的不同特征。作者使用基于 BERT 的双向神经网络模型来学习这样的结构化语义特征,并提出了BinProv
这一端到端框架,如下图所示:
BinProv
的工作流程主要包含了四个阶段:
-
预处理阶段:从二进制文件的代码段中提取出定长的字节序列,并按照不同的指令集来制定字节序列的长度;
-
编码阶段:由相同的字节在不同的字节序列中可能代表不同的含义(这一点了解 ROP 的同学应该很容易理解),所以需要学习上下文相关的语义。作者使用 BERT 网络来学习特征向量。其网络图如下所示,将预处理得到的字节序列及各字节对应位置组成的序列作为输入,使用 Masked Language Model 来训练;
-
分类阶段:作者将分类任务分为了**编译器种类(Clang/GCC)和编译优化级别(O0/1/2/3)**两类,使用两层的全连接的网络来进行编译工具链的分类;
-
聚合推理阶段:由调研可知,同一个二进制文件中包含的二进制代码采用的优化级别大概率是相同的,从而可以采用投票机制(voting mechanism)来整合字节序列的分类结果,推理到函数乃至二进制级别;
作者选取了 BINKIT 作为 Benchmark,包含了 GNU 套件中的 51 个程序,并采用了不同的编译工具链组合生成了不同架构的二进制文件,如下图所示。随后作者选取了 Origin 和 O-glassesX 在编译工具链识别准确率和字节序列相似度上的结果作为 baseline,并使用与 BinRNN 和 O-glassesX* 进行了对比实验。
首先,作者在 x86_64 的二进制代码上验证了BinProv
的识别准确率。从表3中可以看出,仅仅粗粒度地评估编译器类型和编译优化程度的表现,BinProv
和之前的方法比优势不大。这是因为 O2/O3 相比于 O0/O1 多了很多非常明显的编译选项。但对比表4可以明显看出,BinProv
能够更细粒度地识别出优化级别,尤其是区分 O2 与 O3,这对于识别采用了混合优化级别的现实软件的意义是很大的。
此外,BinProv
对于 GCC 编译出的二进制代码的识别精度更高,一方面是因为GCC编译出的二进制产生了体积更大的二进制文件,为BinProv
提供了更多的输入;另一方面是Clang在编译过程中加入了大量不会受到编译优化的影响辅助函数,从而影响了BinProv
的判断。
为了验证BinProv
中聚合推理阶段的作用,作者还对比了在函数和二进制级别的识别准确性。可以看出相比于没有经过聚合处理的BinProv
,精度有提高。但作者也指出聚合处理的方法还有点草率,这样的结果不具有很高的置信度,有待改进…
由于BinProv
号称是架构无关的,作者也在将其进行调参后,应用到了其他指令集架构上,可以看出其对于定长指令集的识别效果更好;作者还使用了 OLLVM 的三种混淆方法来测试BinProv
的鲁棒性,可以看出基于 CFG 修改的 BCF 和 CLA 两种混淆方法处理后的二进制受影响不大,但破坏了原有字节序列的 SUB 方法则显著降低了BinProv
的精度。
作者还对于BinProv
中所使用到的模型组件进行了分析。例如,通过与 CNN/RNN 的对比,作者再次验证了使用 BERT 来学习二进制代码中稀疏的语义关系的有效性,如下图所示。此外,作者还对比分析了二进制文件大小,字节序列位置,固定长度的辅助函数对于分析结果的影响。
最后,作者对于编译器辅助函数的检测和二进制代码相似性两个应用进行了具体的 case study,快去戳原文看看吧~
论文地址:https://shuwang127.github.io/papers/raid22_BinProv.pdf
论文Artifact(暂未公开):https://github.com/Viewer-HX/BinProv
原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-09-09 BinProv
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论