今天是个好日子,和北京奥运会开幕式一样,日期里面只有0、2和8!在这样一个日子里,我们推荐一篇来自2022年IEEE S&P、关于binary code lifting(怎么翻译呢?二进制代码提升?抬举?都很怪,还是直接用英文吧)的 SoK 论文 Demystifying Binary Lifters Through the Lens of Downstream Applications
不同于之前在我们的IEEE S&P 2022参会小记中的简要介绍,今天的论文推荐将更加深入地解读五类 binary code lifters 的实验表现和对比。首先,作者指出现有针对 lifter 的研究和 lifter 的开发者大多都在关注 lifting 出来的 IR 的正确性,而并没有考虑到 IR 作为程序分析的基础架构,对于下游安全研究应用的支持程度。事实上,已经有很多应用在安全研究中的 IR,比如 Ghidra 中的 P-Code,angr 中的 VEX IR 以及 Rizin 中的 EZIL/RZIL,但考虑到 IR 使用的广泛程度和背后编译基础架构的支持,作者最终选取了基于 LLVM IR 的三个 lifter 和一项 EuroSys '20 的研究工作 BinRec 作为分析对象。
如下图所示,一般的 lifter 的工作流程是先将指令语义拆分到 LLVM IR 中,再使用 LLVM Passes 对指令不断优化,恢复出高级语义。在针对这些工具的前期研究中,作者发现,尽管他们都是基于 LLVM IR,但实际上提取出的代码还是在语义层次上有区分。借助 LLVM IR 对于寄存器和内存的抽象模型,像 McSema 这样的 lifter 可以实现 Emulation-style 的提升(本文称为 EIR ),而 RetDec 则是借助各种 LLVM Passes,能够将 EIR 提升到更高语义层次的 HIR (本文称为 HIR),这也增强了诸如反编译等应用的效果。
但无论如何,编译本质上是一个损失信息的过程,从上图的 case 中也可以看出,lifter 产生的 IR 相比于通过源代码产生的 IR (本文称为 CIR )显得还是不那么抽象。后续的对比实验也将在这三类 IR 中展开。
为了评估 lifter 对于安全研究的影响,作者选取了三类较为基础的分析技术/工具进行实验,分别是:
-
严格的指针分析,以 SVF 作为工具,并以在 SVF 附带的测试程序上进行变异生成程序作为数据集
-
差异性分析,以NeurIPS '18的 ncc 作为工具,并以 POJ-104 作为数据集
-
C 代码反编译,以llvmir2hll 作为工具,并以 SPEC INT 2006 作为数据集。测试集的规模如下:
此外,为了保证测试的公平性,作者还做了很多 manual effort(不得不说 SoK 的背后真是有很多看不见的努力)。比如为了适配 mctoll 和 McSema 产生的 10 个特殊的 IR 指令,作者对 llvmir2hll 进行了 patch。经过处理之后的 lifter 如下图所示:
做了这么多准备工作,终于要开始进行实验了~首先,我们来看看这些 lifter 的基本表现,毕竟成功产生 lifted IR 是后续分析的基础。将数据集通过 clang 不带优化地编译后生成二进制文件,可以看到除了少部分产生 broken IR 或者运行时异常的情况,可以看出大部分二进制都能被成功地提升到 LLVM IR。其中Microsoft mctoll 因为对 C++ 的不支持从而表现较差,BinRec 则因为其符号执行引擎而导致了超时。
随后,我们来看几乎“全军覆没”的指针分析:只有 RetDec 凭借其强大的 Pass 对于 IR 的优化,能够部分识别出的 NoAlias 的情况。而观察分析的中间结果,即表中有关 SVFG 的数据也可以看出,其他的 lifter 产生的 IR 都复杂了很多。进一步对 RetDec 的结果进行分析,作者手动修复了16个不正确的结果,发现阻碍 IR 进行严格分析的并不是变量恢复,而是(局部变量和参数的)类型推断。基于这一点观察,作者建议 lifter 利用好 IDA-Pro 前端产生的结果(比如函数原型),并结合其他的工作中已有的推断技术(比如CCS '18的Debin)。
在差异性分析中,不同的工具因为其对 IR 的优化程度/方式不同,而导致了结果的区别。比如不带后期优化的 McSema 版本的效果就非常差,而 BinRec 使用 wrapper function 的优化方式也破坏了原有的程序结构。而 RetDec 的表现仍然很好,甚至在某些程序中表现出了比 CIR 更好的结果,作者也建议其他的 lifter 多多学习 RetDec 自带的优化,在差异性分析中追求更高语义层次的 HIR 。当然,考虑到 ncc 是一个 DNN 模型,其结果也可能存在 Bias。
在反编译的分析中,作者选取了#goto(指令的数量)和 LoC(产生的IR行数)作为评价的指标,这也反映了广大逆向工程师的心声。这一次,所有的 lifter 都表现得不错,但和差异性分析类似,作者仍然对 lifter 提出了代码优化和局部变量识别两点改进方向。
最后,尽管不是本文的重点,作者还是对提升后的 IR 程序行为正确性进行了验证,可以看到提升到 EIR 的 lifter 因为其更低的抽象层次,反而更容易维护程序的功能,方便进行很多二进制级别的分析(例如sanitization)。
结束了常规的分析后,考虑到 IR 平台无关的特性,作者进行了 cross-platform 的分析。作者重新编译出了 ARM64 的二进制文件,并重新进行了上述分析(可以看到 mctoll 因为其较差的效果已经被排除了)。可以看出,lifter 的表现和 x64 平台上类似,只有 McSema 的效果变差了,这也引导作者发现了一个 bug,并报给了 lifter 的开发者。
而为了验证分析结果的鲁棒性,作者还进行了cross -compiler/optimization 的交叉分析。可以看出,RetDec 对于优化后/破坏程序结构的汇编代码的鲁棒性更好,但仍然不免产生更多的#goto 和 LoC;所有的 lifter 都对于 clang 更为友好,而在 gcc 上产生的 IR 更加复杂。
最后,作者还对比了在 IR 层面分析相比于直接二进制分析的效果。也是采用相同的思路,作者分别在 sanitization,binary diffing 和 decompilation 三个应用各选取了代表性的工具进行分析,发现 IR 在很多地方能达到相近的效果,但在反汇编效果上还是比不上通用的工具 IDA-Pro 和 Ghidra。
论文Artifact:https://github.com/monkbai/ir_lifting_data
论文链接:https://www.computer.org/csdl/proceedings-article/sp/2022/131600a453/1wKCev3wlbO
原文始发于微信公众号(安全研究GoSSIP):G.O.S.S.I.P 阅读推荐 2022-08-08 Demystifying Binary Lifters
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论