Fully static binary recompilation lifts legacy code across chip types

No Bit Left Behind: Using Brute-Force Lifting to Achieve Fully Static Binary Recompilation

Cryptography and Security

Summary

Old software often runs on computer chips it wasn't originally made for, and fixing security flaws in such old software is tricky. The authors present a way to convert whole programs directly from machine code into a form that other tools understand, without guesswork about where code and data are. Their method works by assuming every piece of the program might be needed and building a model that covers all possible ways the program could run. This means they can fully translate software from one type of chip to another without needing extra help when running the translated program.

What this means in practice

  • For software migration teams: Convert complex legacy x86-64 executables fully offline into AArch64-compatible code without runtime translations.
  • For security engineers: Automatically retrofit outdated executable binaries with security features by statically lifting them to standard intermediate code.

Authors

Tianjiao Huang, Po-An Chen, Nick Baron, Michael Franz

Abstract

Binary recompilation is a technique for operating directly on executable code. It promises to automate two important tasks: retrofitting security mitigations onto legacy binaries, and migrating binaries across instruction set architectures (ISAs). Yet today, there is no fully automated system that can reliably lift arbitrary binary executables to a compiler intermediate representation (IR) such as LLVM IR, or that can fully statically and reliably translate non-trivial binary executables from one ISA to another. The main underlying problem is that recovering a program's control flow graph (CFG) statically is impossible in general: computed branches can jump to targets that cannot be determined without actually running the program. Existing systems resort to runtime fallback mechanisms, requiring a significant portion of the binary translation machinery to accompany the translated program on the target machine. This article presents a fully static, whole-program binary lifting system requiring no runtime translation support on the target. Rather than attempting to distinguish code from data, we treat every byte offset as a potential branch target and lift the entire binary in a brute-force manner, constructing a superset CFG that conservatively contains all feasible control flows. Statically unresolvable computed branches are thereby reduced to lookups in a dispatch table that points to the corresponding translated control flow path. We have implemented this approach as a prototype binary recompiler from x86-64 binaries to LLVM IR, requiring no code/data heuristics. We validate it with a fully static cross-compilation to AArch64, achieved by reusing existing LLVM backends with no modification.