Relinking (syscall-free) ELF executable into Mach-O and PE executables

Hi,

Let's suppose we have an ELF executable that doesn't issue any syscall
(I mean, syscalls are issued from an external dynamic library, not
from the executable, and we can ignore such dynamic library because we
have the proper equivalent library with the proper syscalls in MacOS
and Windows).

So, the question: Is it "currently possible" (by "currently possible"
I mean that all the needed tools/code already exist) to somehow
"unlink" the code and data from the ELF executable, and relink it as
two new executables: one Mach-O and another PE?

Would this be possible with just LLVM tools, or would other
libraries/tools also be needed?

Thanks a lot!

ardi

Typically people do this kind of thing by writing a loader for the executable format you want to run, and they create libc stubs that either delegate or reimplement enough functionality to get the app in question to run. Wine, for example, uses this approach. It loads native PE executables, and implements enough of the win32 API to run some applications.

“Re-linking” would be tough because linking typically throws away static relocations that you would need.

Hi,

Would this be possible with just LLVM tools, or would other
libraries/tools also be needed?

I'd expect you'd run into the issues mentioned by Reid.

That being said, in terms of building blocks -- i.e., executables manipulation per se -- I'd recommend LIEF (Library to Instrument Executable Formats):
https://github.com/lief-project/LIEF

It supports multiple formats (including ELF, PE, and Mach-O). What's relevant here in particular is that you can extract code and data from an existing executable -- as well as build another one from scratch (with a given code and data):
https://lief.quarkslab.com/doc/latest/tutorials/01_play_with_formats.html
https://lief.quarkslab.com/doc/latest/tutorials/02_pe_from_scratch.html

One of the challenges you may also run into is (mentioned in https://lief.quarkslab.com/doc/latest/tutorials/08_elf_bin2lib.html -- admittedly a somewhat different context):
"For non-PIE executables such transformation would be very difficult because it requires to transform first the executable into a relocatable executable. It means creating relocations, patching absolute jump, …"

In terms of existing work, you may also want to take a look at:
- Exodus (a tool to relocate Linux ELF binaries from one system to another): https://github.com/Intoli/exodus
- loadlibrary (a library that allows native Linux programs to load and call functions from a Windows DLL): https://github.com/taviso/loadlibrary
- wine-binfmt: https://reposcope.com/package/wine-binfmt

More executables resources which may be of help:
https://github.com/MattPD/cpplinks/blob/master/executables.md

Best,
Matt

Couldn’t you write the relocations to the ELF executable? I don’t know if current linkers have support for this, but it seems possible in theory to make a relinkable executable. If you want to do this with an already linked executable though, then yea this won’t be possible.

As Reid mentioned, using a loader is the straightforward option, but I
have some concern that some "app stores" (ie: Apple, Google, or any
other) might reject apps if they see a "loader that loads some
binary". So, before opting for a loader, I want to discard other
possibilities.

Looking at the LIEF tutorials, I saw one for transforming an ELF
executable into a dynamic library:
https://lief.quarkslab.com/doc/latest/tutorials/08_elf_bin2lib.html

Maybe that path could be used. If I can find some way for turning an
ELF DSO into either a PE static library, or a Mach-O static library,
then the process would be
ELF_exec->ELF_dso->Target_static->Target_exec (where Target is either
PE or Mach-O).

Another possibility perhaps, would be to map the ELF executable, do a
binary dump of the mapping, and then embed such mapping into an
executable, but I guess that the mapping depends on the address being
given by the OS for the process, so maybe this path wouldn't be
possible (also, I guess those "app stores" would also see a big
suspecting binary area if they "nm" the executable).

Is there any other alternative before opting for a loader?

@Zachary: As probably can be deduced from my comments, I'm not an
expert in low-level executable formats, so I'm not really sure about
you are implying to do, nor if it would be feasible for my scenario.

Thanks!

ardi

You can do a "ld --relocatable" to create an elf file that can be used
as further input to the linker (so relocations will be preserved,
etc.). However, that file will not be a fully functional executable
until you do a final non-relocatable link on it.

I was actually proposing something like where you write a fully working executable (identical to what the linker writes today), but you additionally write an extra section that contained information about the type and location of all applied relocations. This way you could re-write relocations on a subsequent link where the executable was used as an input. I don’t know if any linkers currently have a mode where you can do this though, and it sounds like OP might want to use only functionality that is currently available in an existing linker today.