Deterministic Fully-Static Whole-Binary Translation Without Heuristics
摘要
本文介绍了 Elevator,一种新型二进制翻译器。它能够将完整的 x86-64 二进制文件确定性且完全静态地翻译为 AArch64 架构,无需使用启发式方法或运行时回退机制。Elevator 实现了与 QEMU 相当的性能,同时支持对翻译后的代码进行部署前验证和认证。
查看缓存全文
缓存时间: 2026/05/13 06:36
# 无启发式确定性全静态全二进制翻译 来源:https://arxiv.org/html/2605.08419 ,James McGowan <[email protected]> (https://arxiv.org/html/2605.08419v1/mailto:[email protected]) 加州大学尔湾分校,加州,尔湾,美国 和 Michael Franz <[email protected]> (https://arxiv.org/html/2605.08419v1/mailto:[email protected]) 加州大学尔湾分校,加州,尔湾,美国 ###### 摘要 我们提出了 **Elevator**,这是第一个能够将整个 x86-64 二进制可执行文件静态翻译为 AArch64 的二进制翻译器,且无需使用调试信息、源代码或对原始二进制文件中代码模式或布局的任何假设。与现有的二进制翻译系统不同,后者依赖启发式方法或运行时回退机制来从错误的代码与数据解码决策中恢复,**Elevator** 考虑原始可执行文件中每个字节的所有可能解释,并提前为每种可行的解释创建单独的翻译。例如,任何字节都可以被解释为数据、操作码的一部分,或者作为操作码参数的部分。我们为所有这些解释生成了单独的控制流路径,仅剪除那些导致异常程序终止的路径。对于每条此类控制流路径,通过组合从源指令集架构(ISA)中单个指令的高级语言描述自动推导出的代码“瓦片(tiles)”来生成翻译。这带来了一个灵活的二进制翻译框架。我们的方法是确定性的,并生成完整、自包含的输出二进制文件。与之前的解决方案不同,它不需要在可信代码库中包含任何运行时组件。**Elevator** 提供了与以往不同的成本/收益特征,主要成本是代码体积显著膨胀。作为回报,主要好处是 **Elevator** 的输出就是实际将要运行的代码,因此可以在部署前进行测试、验证、认证和/或加密签名,与模拟器或即时(JIT)编译器相比降低了风险。我们在包括整个 SPECint 2006 套件在内的多样化真实世界二进制文件语料库上展示了 **Elevator** 的有效性,表明静态全程序二进制翻译可以既可靠又实用。我们的方法实现了与带有 JIT 加速的 QEMU 用户模式模拟相当或更优的性能。 全程序静态二进制翻译,带有交叉编译的二进制提升,二进制到二进制的跨 ISA 翻译,全规模实现的实用评估。 ††ccs:软件及其工程 翻译器编写系统和编译器生成器 ††ccs:软件及其工程 软件逆向工程 ††ccs:软件及其工程 维护软件 ††ccs:软件及其工程 软件演化 ††ccs:软件及其工程 软件维护工具 ††ccs:软件及其工程 编译器 ††copyright:none ## 1. 引言 硬件从一种指令集架构(ISA)过渡到另一种时,往往需要将遗留软件带到新平台上。通常,这种遗留软件过渡无法完全通过“简单地重新编译”现存的源代码以机械方式实现。为了进一步使问题复杂化,当遗留代码经过验证或认证时,通常被认证的并不是源代码,而是一个经过充分测试的特定“权威二进制可执行文件”。日后从源代码逐位重建这个确切的“权威二进制文件”通常是不可行的。即使有存活的源代码,并且我们设法使其编译和构建,要重建完全相同的代码,很可能需要与创建原始二进制文件时使用的完全相同版本的编译器、链接器,以及可能还包括构建系统的其他部分。因此,从旧源代码重建遗留程序可能存在风险,因为我们无法确定是否忠实地复制了“权威二进制文件”的功能。相反,任何存活的归档源代码可能指的是一个微妙不同的版本。此外,还有报告案例,例如 (Kolsek, 2017),制造商通过手动且熟练地直接对二进制文件应用“补丁”来修复软件错误,完全绕过了源代码。因此,使用归档的源代码版本可能会重新引入已在当前运行的二进制文件中修复的未知编程错误。除了穷举测试外,通常没有简单的方法来确定日后从源代码重建的任何软件是否实际上是预期的软件版本。 作为替代方案,一种不依赖源代码的方法直接从现有二进制文件开始。正如我们在下文相关工作部分所扩展阐述的,先前处理二进制代码的解决方案采用了模拟、静态和动态翻译的组合。所有这些先前解决方案的共同点是,它们并不完全静态地将整个二进制程序从一种 ISA 翻译到另一种 ISA,而是都需要额外的系统级组件与翻译后的程序一起执行。因此,这些额外的运行时组件必须是可信代码库的一部分,并隐含地包含在所有测试中。由于此类系统的动态行为可能导致基于特定测试或输入顺序的不同结果,因此确定整体可靠性变得更加困难。 相比之下,**Elevator** 做出了以下关键贡献: - **一个完全静态、确定性、无启发式的跨 ISA 二进制到二进制翻译器。** **Elevator** 据我们所知,是第一个从 x86-64<sup>1</sup> 到 AArch64 的跨 ISA 二进制到二进制翻译器,它是完全静态的、完全确定性的且无启发式的。它对输入的代码布局或生成它的工具链不做任何假设。将同一个输入二进制文件两次通过 **Elevator** 运行会产生完全相同的输出比特序列。一旦翻译完成,生成的 AArch64 二进制文件就是一个独立的可执行文件,不需要运行时翻译支持,并且可以独立进行测试和认证。 - **一个轻量级的、基于 LLVM 的代码生成器。** 我们的 AArch64 代码生成器基于一种轻量级机制,利用 LLVM 成熟的编译器基础设施自动生成跨 ISA 翻译,而不是针对每条指令手写。这大大降低了引入新后端所需的工程工作量,并且相同的方法可以直接扩展到其他目标架构。 我们已经构建了一个全规模实现原型,并在综合测试语料库上展示了其有效性。我们的评估包括整个 SPECint 2006 基准测试套件(作为真实世界遗留二进制文件的代理)和少量手工制作的二进制文件(如清单 1 和清单 2 所示),旨在揭示现有全静态方法的局限性。我们认为,我们的方法创造了一种真正不同且与现有方法互补的新能力。在某些情况下,我们的技术可能优于现有解决方案,例如当某些处理器型号因政治原因或供应链问题突然不可用时。在这种情况下,使用现有二进制的静态翻译可以提供快速的临时“过渡”跨 ISA 可移植性,同时保留在部署前对生成的输出代码进行穷举测试的能力。这比使用模拟器或即时编译器风险更低。我们对这项研究没有商业利益,并承诺在研究项目结束时开源所有内容。 <sup>1</sup> 我们已为 x86-64 输入二进制文件实现了我们的系统,但为了便于阅读,我们在全文中主要将其缩写为“x64”。 ## 2. 背景和相关工作 长期以来,人们一直对在没有源代码访问权限的情况下修改现有二进制文件感兴趣。这种最一般的形式称为*二进制重写*,旨在允许将各种程序转换应用于程序的二进制形式。此类转换的最终目标可能是插桩、安全加固、优化或去混淆 (Wenzl et al., 2019)。特别是在过去几年中,人们对二进制重写产生了 renewed interest( renewed interest 指重新兴起的兴趣),其下游应用范围广泛,包括安全 (Kolsek and Team, 2017)、优化 (Panchenko et al., 2019) 和代码去膨胀 (Qian et al., 2019; Agadakos et al., 2019)。 术语*二进制重新编译*现在经常用于描述以下整程序重写技术:首先将程序“提升”到中间表示,然后将其“降低”回机器可执行形式。本文描述的系统执行从一种 ISA 到另一种 ISA 的二进制*交叉(重新)编译*。 *静态重写器*在不执行二进制文件的情况下对其进行操作。静态技术范围从*直接*到*最小侵入性* (Duck et al., 2020) 再到*全翻译* (Wenzl et al., 2019)。直接和最小侵入性方案针对特定任务,如转移控制流、插入跳板或执行指令级修改。另一方面,全翻译技术通常将程序翻译为专用中间表示(IRs),并最终*重新汇编*新的二进制文件。此类重写器使用的 IRs 旨在忠实表示原始程序语义。示例包括 VEX IR (Valgrind Project, 2024)、Binary Analysis Platform (BAP) 的 IL (Brumley et al., 2011) 和 REIL (Dullien and Porst, 2009)。关键在于,全翻译技术利用这些强大 IRs 的表现力来恢复更高级别的结构,如控制流、基本块和函数,从而使它们能够应用复杂的程序级分析和转换。 *动态重写器*在程序执行*期间*转换程序。这是通过使用插桩引擎(如 PIN (Luk et al., 2005) 或 DynamoRIO (Bruening et al., 2003))在原生执行期间插入细粒度钩子,或在虚拟环境(如 QEMU (Bellard, 2005) 或 Valgrind (Nethercote and Seward, 2007))中运行二进制文件来实现的。与静态重写器相比,动态方法可以在运行时观察控制流和程序状态,从而执行更精确和细粒度的修改。然而,此类重写器执行的修改仅在当前执行运行期间持续。 直到最近,现有的静态二进制重新编译器在其能力方面出奇地有限;大多数已发表的重新编译框架甚至无法重新编译一些最基本的标准基准测试套件(如 SPECint 2006)中的组成部分程序。这根本原因在于“提升”是一个难题:Horspool 和 Marovac (1980) 早在 1980 年就表明,二进制可执行文件的“去翻译”(反编译/反汇编)的一般问题需要能够确切地区分代码和数据,这对于大多数计算机架构而言等同于停机问题 (Turing, 1937),因此在一般情况下是不可解的。我们的方法通过分别翻译可执行文件每个字节在所有可能解释下的情况,从而克服这一问题,因此根本不需要做出这种决定。 以前的静态二进制提升器 (Anand et al., 2013; Dinaburg and Ruef, 2014; Yadavalli and Smith, 2019; Di Federico et al., 2017; Williams-King et al., 2020; Panchenko et al., 2019; Dinesh et al., 2020) 试图使用不精确的启发式方法来近似区分代码和数据,这在尝试预测间接控制流转移目标时尤其成为问题 (Pan et al., 2020)。例如,LLBT (Shen et al., 2012, 2014) 通过将 ARM 指令提升为 LLVM IR 并重新编译到目标架构来对 ARM 二进制文件进行静态翻译。然而,像许多静态二进制重写器一样,LLBT 依赖启发式方法来检测潜在的间接分支目标,使其在处理混淆或手工制作的间接分支代码时容易出错。此外,LLBT 在代码识别过程中对输入二进制文件做出了其他几项假设,这有助于缩小其地址映射表的大小,并使输出二进制文件适合二进制大小是严重问题的嵌入式设备。使用此类不精确的启发式方法是所有基于静态二进制提升的现有重新编译器难以处理甚至相对简单的基准程序的主要原因:即使是一个好的启发式方法也会在某些输入上失败,而正确提升整个二进制文件要求启发式方法在每一个代码与数据的决策上都正确无误。因此,二进制文件越大,至少有一个基于启发式的决定在某处出错的可能性就越高。 相反,动态方法遵循指令在实际执行时的流程 (Altinay et al., 2020)。因此,它们能够处理不仅精确的指令恢复,而且按设计也能处理间接控制流;毕竟,处理器也必须能够跟踪并正确解码指令流。然而,动态方法只能提升程序具体执行期间到达的指令。因此,严格的动态提升器可能对二进制程序中包含的控制流图具有不完整的视图,并且对应于“未见”部分的二进制部分将从提升的代码中省略。结果是,任何从提升代码生成的输出二进制文件都必须能够处理动态计算的分支突然跳转到“未知之地”的情况,即提升期间未覆盖的以前未见过的代码片段(并且可能已被误认为是“数据”)。静态提升器在处理仅通过计算分支可达的控制流目标时也面临这个问题,其中一些可能规避常规的静态控制流分析。 使问题更加复杂的是,像 x64 这样具有变长指令的 ISA 使得指令序列可以在彼此之间嵌套。终止于多字指令中间的分支将...
相似文章
弥合LLM代码翻译中功能正确性与运行时效率的差距
本文介绍了SwiftTrans框架,该框架解决了LLM代码翻译中被忽视的运行时效率问题,在多个基准测试中同时提升了正确性和效率。
Theseus,一个静态的Windows模拟器
Theseus是一个新型的静态Windows/x86模拟器,它在编译时翻译程序,而不是在运行时解释或即时编译,代表了一种不同于传统模拟架构的方法。
字节码虚拟机在意外场景中的应用 (2024)
本文探讨了字节码虚拟机的出人意料的应用,特别是Linux内核中的eBPF以及编译后二进制文件中用于调试信息的DWARF表达式。
schrodingers-toctou: The binary you run is not the program you wrote
This research describes compiler-invented loads, where compiler optimizations create additional memory reads not present in source code, turning seemingly secure code into vulnerable binaries with TOCTOU races. It includes audits across kernels, hypervisors, enclaves, and firmware.
伦理超速(EHV):一种可证明确定性的、基于治理的即时编译器架构,用于自主系统
本文介绍了一种名为“伦理超速”(EHV)的架构框架,该框架结合了无冲突复制数据类型和可信执行环境,能够在自主系统中实现亚毫秒级的形式化验证,将治理延迟从天级降至常数时间。