Automatic Recovery of Fine-grained Compiler Artifacts at the Binary Level 论文阅读笔记

中文译名:二进制级细粒度编译器工件的自动恢复
作者:Yufei Du
单位:北卡罗来纳大学教堂山分校
国家: #美国
年份: #2022年
来源: #USENIX会议
关键字: #二进制 #编译
笔记建立时间: 2023-02-11 09:45

摘要

  • 识别二进制编译器配置使开发人员和分析人员能够定位由优化副作用引起的潜在安全问题,识别二进制克隆,并构建兼容的二进制补丁。
  • 现有的工作重点是使用语义特征和深度学习技术识别编译器家族、版本和优化级别。
  • 本文想要探索恢复二进制文件中每个函数的单独的、细粒度的优化传递。为此,我们开发了一种使用专门设计的功能以及直观和可理解的机器学习模型的方法。

引言

  • 编译器的优化可能带来安全方面的负面影响
    • 死代码消除优化可以删除使用敏感数据后擦除敏感数据的指令,导致敏感数据容易泄露
    • 用更高效的操作取代昂贵操作的强度降低优化可以打开侧通道
  • 避免这些陷阱的一种方法是让开发人员手动调整编译脚本
    • 具有挑战性和耗时的
    • 一些编译器还包含无法手动控制的隐藏优化
    • 现代编译器的代码库太大,用户无法查看和研究优化背后的逻辑
    • 安全关键项目 (如 OpenSSL 和 mbed TLS) 的开发人员采取了另一种方法,即在安全函数的源代码中实现工作区,以“迷惑”编译器,使其不会对安全代码应用优化
    • 但是不能一劳永逸,不适用于未来的编译器版本
  • 除了安全性验证外,编译器优化分类还会影响二进制代码克隆检测和二进制补丁。
    • 编译器配置会导致克隆检测技术性能的显著下降
    • 二进制补丁中,在存在某些编译器优化时,定位要修补的易受攻击函数变得更加困难
  • 当前技术侧重于识别编译器家族、主要编译器版本以及二进制文件的优化级别
    • 缺少更详细的信息,即可能已应用的传递
  • 当前方法依赖于语义特征(列如控制流图)或者采用深度学习的方法
  • 为了输出的可解释性,作者选择了使用具有特殊设计功能的浅层学习。
  • 作者的方法成为 passtell,可以识别影响单个函数安全的优化过程

总结:因为编译器的优化会产生一些意想不到的负面影响,包括安全问题、克隆检测技术性能下降和难以定位补丁函数。所以要有一种技术来检测编译器的优化?目前的技术侧重于识别识别编译器家族、主要编译器版本以及二进制文件的优化级别,缺少更详细的信息。作者提出的方法可以识别函数级的优化过程,提供更详细的优化信息。

背景

编译优化

  • 知道二进制文件的优化级别不足以确定应用于二进制文件的精确优化集。
    • 因为除了用户指定的优化级别外,在决定要运行的传递时,传递管理器还考虑多个因素,包括目标体系结构、目标处理器生成和源代码结构。

安全影响

  • 持久状态违反是指数据持续存在于其设计的可用范围之外。

    • D’silva et al.[3]列出了三种可能导致这种违规的优化: 死代码消除、函数内联和代码移动。
      • 在密码验证函数中,密码在验证期间临时存储在内存中,编译器可能会认为擦除本地内存的操作是死代码并将其删除,导致密码在使用后仍存在于内存中,直到最终被后面的函数覆盖。
      • 如果受信任的安全敏感函数内联在不受信任的函数中,则受信任函数的局部变量的生存期将扩展到不受信任函数返回时。
      • 代码移动可以切换指令的顺序,以避免不必要的计算或改善局部性。这种优化可能会导致程序在验证操作是否需要之前将敏感值写入内存。
  • 侧通道攻击:为了避免侧通道,开发人员可能会向函数中添加不必要或低效的操作,但优化可能会简化或删除这些操作,从而重新引入侧通道。

    • D’silva et al.[3]列出了三种可能引入侧通道的优化方法:
      • 公共子表达式消除,将多个指令合并为一条指令以避免重复计算;
      • 强度降低,用更有效的指令取代昂贵的指令,
      • 窥视孔优化,检查周围的指令,以寻找重新排序或替换指令的机会,以简化计算或更好的局部性。

本文的工作重点是识别上述两种优化。

相关工作

Rosenblum 等人在二进制文件的编译器识别领域做出了开创性的工作。他们的方法侧重于使用概率图形模型仅识别 IA-32 体系结构中代码片段的编译器家族。后来,Rosenblum et al.[17]扩展了这项工作,并提出了 Origin,这是一个工具,用于标识二进制文件中每个函数的编译器族、编译器版本和优化级别。Origin 使用线性支持向量机模型,其特征包括指令的习惯用法、控制流图的子图和函数的高级布局 (如起始地址)。然而,对于优化级别,Origin 只能执行粗粒度识别,有两个选项:-O0, -O1 为“low”,-O2, -O3 为“high”。
几年后,Rahimian 等人[16]提出了一种不同的编译器来源识别方法 (称为 BinComp)。BinComp 的重点是识别整个二进制文件的编译器族、编译器版本和优化级别。与 Origin 不同,BinComp 大量利用从编译器添加的实用函数中提取的特性来识别编译器版本和优化级别。这些实用程序函数包括程序初始化、启动代码和终止代码。虽然这些函数可以高度指示优化级别,但不可能对二进制文件中的每个函数执行识别。因此,BinComp 只能识别用于编译程序主例程的编译器配置。
最近在编译器来源识别方面的工作[2, 15, 20, 23]开始使用神经网络进行分类。Chen 等人[2]提出了 HIMALIA,这是一种使用递归神经网络来识别二进制的每个函数的优化水平的分类器。HIMALIA 使用分解指令的向量作为特征,并使用两个递归神经网络进行分类。一个网络将函数分为四类之一:-O0, -O1, -O2/O3 和- o; 另一个网络则区分-O2 和-O3。虽然 HIMALIA 的评估包括用不同版本的 LLVM Clang 编译器编译的二进制文件,但它只关注于确定每个函数的优化级别,而不区分应用于不同编译器版本的优化。Yang 等人[23]提出了 BinEye,这是一个使用卷积神经网络来识别 ARM 二进制文件中每个对象的优化级别的分类器。由于 ARM 架构中的每条指令都是 4 个字节,BinEye 使用每个对象的前 1024 条指令作为原始特征,并从中提取单词和位置嵌入。Tian 等人[20]提出了 NeuralCI,这是一种具有卷积神经网络或递归神经网络的分类器,用于识别二进制文件中每个函数的编译器族、编译器版本和优化级别。NeuralCI 使用 Word2Vec[14]嵌入允许可变大小的指令。与 BinEye 类似,NeuralCI 的评估将-O2 和-O3 合并为一个粗粒度的 OH 优化水平。
最近,Pizzolotto 和 Inoue 提出了一种方法,使用卷积神经网络或长短期内存网络来识别 7 种不同架构中 2KB 代码片段的编译器家族和优化级别。这种方法包括原始字节或操作码作为特征,但得出的结论是,当有大量可用的训练数据时,原始字节会导致更好的结果。与 HIMALIA 类似,这种方法的评估包括五个不同的优化级别:-O0, -O1, -O2, -O3 和-Os。由于 NeuralCI 进行了最深入和最现实的评估,并且它优于其他在函数级进行分类的方法,因此我们在本文后面选择它进行比较。

方法

PassTell,一种用于识别可能应用于二进制文件中的每个函数的优化传递集的方法。
image.png

数据生成

  • 首先,编写不同优化级别的程序,并记录应用于每个函数的优化列表
  • 然后,分解二进制来检索每个函数的指令
  • 最后,通过删除详细的内存地址、调用目标和直接值来净化指令

收集在编译期间修改函数的优化传递:因为 clang 可以列出编译期间应用于每个函数的优化,输出运行的所有传递,作者基于此进行修改以便于提取编译期间修改函数的优化通道
指令消毒:用 “mem”标签替换所有内存地址,用 “TARGET”替换所有调用目标,用“imm”替换所有即时值。我们做出这样的调整是因为详细的内存地址、即时值和调用目标在不同的程序中是高度可变的,在优化分类中没有用处。
总结:这部分对应 disassembler 操作,主要是将编译好的二进制文件分解成指令,然后对指令进行消毒,用于后面的特征提取。

动态特征生成

作为扩展,本文还提出了一种提取寄存器值变化 (通过仿真恢复) 的方法,并在分类器中使用这些动态特征。
目前,动态特性只包括寄存器增量。
加入这个动态特征的目的是为了探索它们提高分类精度的潜力。寄存器中的一些变化是隐式的,或许可以有助于分类器分类。

特征提取

image.png
默认情况下,我们使用七种类型的静态特性: 操作码、指令、寄存器、二元操作码、二元指令以及函数的第一条和最后一条指令。寄存器值 delta 是一个可选特性。

  • 特征选择:从指令、二元操作码、二元指令、寄存器值的变化这四种特征类型中每种选择 1000 个特征,用于每次优化
    • 策略:首先,我们过滤数据集,使其在优化过程中保持平衡 (即,经过优化的函数数量和未经过优化的函数数量是相同的); 其次,我们根据平衡数据集中至少出现一次该特征的函数的数量对特征进行排序; 最后,我们选择每种类型的 1000 个最常见的特征。
  • 对于其他特征类型,包括操作码、寄存器、第一条指令和最后一条指令,我们使用这些类型中的所有特征而不应用特征选择,因为这些类型中的特征较少。

所有特性都是二进制值。也就是说,我们检查函数是否具有这个特性。例如,在循环中执行算术运算的叶函数 (即不调用任何其他函数的函数) 对于操作码特征调用应该为 0,因为它不包括任何调用; 对于操作码特征测试,它可能为 1,因为它可能使用测试指令来确定循环的结束条件。?这段没看懂
总结:主要介绍了特征提取的策略

分类

在生成特征集之后,我们训练分类器进行优化分类。对于每个优化,我们训练一个二进制 LightGBM 分类器[9],它决定一个函数是否被这个单一优化修改。

  • LightGBM 是一种梯度增强决策树的实现。本文选择这个分类器而不是深度学习技术有两个原因。
    • 现代编译器包含大量的传递。每个传递都需要一个单独的二进制分类器,所以面对庞大的数据集,分类器应该足够轻量,在在训练时间和内存消耗方面都能很好地扩展。
    • 像支持向量机和神经网络这样的分类器不能轻易地证明特征的推理或重要性。另一方面,基于决策树的分类器可以更容易地显示特征的推理和重要性。(这里可以理解为基于决策树的分类器的结果可接受性更强?)

在训练阶段,生成所有优化传递的列表,并为每个优化传递创建模型。每个优化传递都对应这一个分类器,该分类器可以揭示函数是否应用了分类器对应的优化传递。

实施

  • 数据集生成
    • 用 Python 实现了数据集生成组件。采用源代码存储库,使用四个优化级别 (-O0、-O1、-O2 和-O3) 对其进行编译。
      • 编译时从编译器日志中提取每个函数的优化传递
      • 编译后用 objdump 分解二进制文件
      • 通过删除详细的内存地址、调用目标和立即值对指令进行消毒。
    • 在 LLVM 的遗留传递管理器的现有输出标志中添加了一个选项,以列出修改函数或函数内组件 (例如,循环) 的优化传递。
  • 动态特征生成
    • 使用 Zelos ,一个基于 python 的二进制仿真器平台,对二进制文件中的每个函数进行强制模拟,并在函数边界内的每条指令之后记录寄存器值的变化。
  • 特征提取和分类
    • 为了提高效率,本文将静态和动态特征的提取阶段和分类器结合到一个分类器组件中。
    • 我们使用 Python 和 LightGBM 库实现了我们的分类器。分类器遍历每个优化过程,选择并提取特征,然后创建一个 LGBMClassifier。在训练时,分类器首先过滤数据集,使数据集平衡,具有相同数量的正数据和负数据。然后,分类器选择第 4.3 节中描述的最流行的特征,提取静态和动态特征,并训练 LGBMClassifier。分类器在进行分类时,提取静态和动态特征,并使用 LGBMClassifier 来预测该函数是否在此优化过程中被修改。在分类器提取特征并对所有优化过程进行分类之后,它将结果合并在一起以生成最终结果,即应用于函数的优化列表。

评价

编译器配置识别

  • 对于编译器族、编译器版本和优化级别的识别,NeuralCI 实现了 76.6%的平均 F-1 评分,而我们的方法实现了 83.2%的平均 F-1 评分。我们对 NeuralCI 的重新实现产生了较低的结果,如他们的论文[20]所报道的那样。我们将这种变化归因于正确平衡的数据集。总的来说,结果表明我们的方法在识别编译器家族、主要编译器版本和优化级别方面比 NeuralCI 表现得更好。
  • 实验表明识别用 Clang 编译的二进制文件的优化级别和编译器版本更具挑战性。而对于对于 GCC 和 ICC 构建的函数,这两种方法在识别编译器族、编译器版本和优化级别方面都达到了很高的精度。

优化传递识别

  • 总的来说,我们的方法达到了平均 92.1%的 F-1 分数。
  • 研究结果进一步表明,与 Pizzolotto 和 Inoue[15]的说法相反,即使是看起来不太可能被检测到的传递,比如死代码消除,也可以被高精度地识别出来。

优化诱发漏洞案例研究

The Effects of the Dynamic Features

局限性

  • 没有研究应用于较大单元 (如模块和调用图) 的优化传递。
  • 我们的数据收集组件不支持在链接时提取应用的整个程序优化
  • 我们的方法只针对编译器直接生成的二进制文件。因此,它不能用于编译后修改二进制文件的情况,例如混淆的二进制文件或应用了二进制补丁的二进制文件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值