Deterministic Fully-Static Whole-Binary Translation Without Heuristics
86 points by matt_d 3 hours ago | 14 comments

Panzerschrek 31 minutes ago
Can it handle self-modifying code?

Why only x86_64? It has more sense to convert 32-bit programs, like many old games.

reply
oinkt 27 minutes ago
Consider reading the linked article, where this is explicitly addressed:

> Self Modifying and JIT-Compiled Code. Elevator, like all fully static binary rewriters, does not support self modifying or just-in-time-compiled code.

reply
gobdovan 17 minutes ago
[dead]
reply
jonhohle 54 minutes ago
This is neat. I haven’t looked into it, but I would think relative offsets could still be an issue, but it seems there must be some translation layer/mmu since the codegen will be different sizes anyway. This would impact jump tables and internal branches, primarily.

I mostly work on stuff from the 90s, but disassemblers make a lot of assumptions about where code starts and ends, but occasionally a binary blob is not discoverable unless you have some prior knowledge (pointer at a fixed location to an entry point).

I would think after a few passes you could refine the binary into areas that are definitely code.

reply
fguerraz 15 minutes ago
Does it mean I can finally run Slack on Asahi?
reply
gobdovan 7 minutes ago
From the paper, Elevator currently supports only single-threaded binaries, does not support binaries using exception handling, has unsupported x64 extensions, and does not support self-modifying or JIT-compiled code. Slack is Electorn based, so t embeds Chromium and Node and depends on V8.

Maybe try an emulator? There's also this project I found: https://github.com/andirsun/Slacky

reply
dmitrygr 55 minutes ago
Cute, but Rice's theorem remains, and while they translated every byte as code, still no handling is possible for

   char buf[] = {0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3};
   return ((int (*)(void))buf)();
static translation is only possible when you assume no adversarial code AND mostly assume compiler-produced binaries. hand-rolled asm gets hard, and adversarial code is provably unsolvable in all cases.

still, pretty cool for cooperative binaries

reply
fsmv 40 minutes ago
I only read the abstract but I got the impression that their solution to this is they have both. They translate all the data as if it was code and if it gets called into they use the translation where if it gets read as memory they use the original.

Edit I found this in the paper

> Elevator sidesteps the code-versus-data determination altogether through an application of superset disassembly [6]: we simultaneously interpret every executable byte offset in the original binary as (i) data and (ii) the start of a potential instruction sequence beginning at that offset, and we build the superset control flow graph from every one of the resulting candidate decodes. Every potential target of indirect jumps, callbacks, or other runtime dispatch mechanisms that cannot be statically analyzed therefore has a corresponding landing point in the rewritten binary. These targets are resolved at runtime through a lookup table from original instruction addresses to translated code addresses that we embed in the final binary.

reply
tlb 51 minutes ago
But in fact no modern processor/OS executes this either. Pages are marked as executable or not, and static data is loaded as non-executable pages.
reply
dmitrygr 49 minutes ago
that is why it was not "static const char buf[]" ;) it was not an accident

executable stacks are still common (incl on windows with some settings), and sometimes they are required (eg for gcc nested functions)

reply
diamondlovesyou 37 minutes ago
That won't be located on the stack either. The underlying buffer will be a TU local - ie static and not rx
reply
lisper 15 minutes ago
Good grief, what a useless argument. Isn't it obvious that this could trivially be converted to a non-static array if that's really what was needed?
reply
userbinator 16 minutes ago
I read those bytes and immediately thought "mov eax, 42; ret".
reply
IshKebab 6 minutes ago
No based on the abstract it can handle that code. What it can't handle is runtime code generation.
reply
genxy 31 minutes ago
It looks like their system would just generate return 42;
reply