简体   繁体   English

如何让 bash 从标准输入执行 ELF 二进制文件?

[英]How can I make bash execute an ELF binary from stdin?

For some obscure reason I have written a bash script which generates some source code, then compiles it, using出于某种晦涩的原因,我编写了一个 bash 脚本,它生成一些源代码,然后编译它,使用

... whatever ... | gcc -x c -o /dev/stdout

Now, I want to execute the result on the compilation.现在,我想在编译时执行结果。 How can I make that happen?我怎样才能做到这一点? No use of files please.请不要使用文件。

As Charles Duffy said, to execute a binary, you'd have to tell your operating system (which seems to be a Unix variant) to load and execute something – and Unix systems only take files to execute them directly.正如 Charles Duffy 所说,要执行一个二进制文件,你必须告诉你的操作系统(它似乎是一个 Unix 变体)加载和执行某些东西——而 Unix 系统只接受文件来直接执行它们。

What you could do is have a process that prepares a memory region containing the ELF binary, fork and jump into that region - but even that is questionable, considering that there's CPU support to suppress exactly that operation (R^X).你可以做的是有一个进程来准备一个包含 ELF 二进制文件的内存区域,fork 并跳转到该区域 - 但即使这也是有问题的,考虑到有 CPU 支持来精确抑制该操作 (R^X)。 Basically, what you need is a runtime linker, and shells do not (and also: should not) include something like that.基本上,您需要的是一个运行时链接器,而 shell 不(并且:不应该)包含类似的东西。

Let's drop the Bash requirement (which really just sounds like you're trying to find an obvious hole in an application that is older than I am grumpy):让我们放弃 Bash 要求(这听起来就像你试图在比我脾气暴躁的更老的应用程序中找到一个明显的漏洞):

Generally, requiring ELF (which is a file format) and avoiding files at the same time is a tad complicated.通常,需要 ELF(这是一种文件格式)并同时避免文件有点复杂。 GCC generates machine code. GCC 生成机器码。 If you just want to execute known machine code, put it into some buffer, build a function pointer to that and call it.如果您只想执行已知的机器代码,请将其放入某个缓冲区,构建一个指向它的函数指针并调用它。 Simple as that.就这么简单。 However, you'd obviously don't have all the nice relocation and dynamic linking that the process of executing an ELF binary or loading a shared object ( dlopen ) would have.但是,您显然没有执行 ELF 二进制文件或加载共享对象 ( dlopen ) 的过程所具有的所有良好的重定位和动态链接。

If you want that, I'd look in the direction of things like LLVM – I know, for a fact, that there's people building "I compile C++ at runtime and execute it" with LLVM as executing instance, and clang as compiler.如果你想要,我会看看像 LLVM 这样的东西——我知道,事实上,有人在构建“我在运行时编译 C++ 并执行它”,将 LLVM 作为执行实例,将 clang 作为编译器。 In the end, what your gcc|something is is really just JIT – an old technology :)最后,你的gcc|something实际上只是 JIT——一种古老的技术:)

If your goal is to not write to the filesystem at all, then neither bash nor any other UNIX program will be able to help you execute an ELF from a pipe - execve only takes a path to a regular file as its filename and will fail (setting errno to EACCES ) if you pass it a special file (device or named pipe) or a directory.如果您的目标是根本不写入文件系统,那么bash或任何其他 UNIX 程序都无法帮助您从管道执行 ELF - execve仅将常规文件的路径作为其filename并且会失败(将errnoEACCES ),如果您向它传递一个特殊文件(设备或命名管道)或目录。

However, if your goal is to keep the executable entirely in RAM and not touch the hard disk (perhaps because the disk is read-only) you can do something with the same effect on your machine by using tmpfs , which comes with many UNIX-like systems (and is used in Linux to implement semaphores) and allows you to create a full-permissions filesystem that resides entirely in RAM:但是,如果您的目标是将可执行文件完全保存在 RAM 中并且不接触硬盘(可能是因为磁盘是只读的),您可以使用tmpfs在您的机器上做一些具有相同效果的事情,它随许多 UNIX-类似系统(并在 Linux 中用于实现信号量)并允许您创建一个完全驻留在 RAM 中的完全权限文件系统:

$ sudo mount -t tmpfs -o size=10M tmpfs /mnt/mytmpfs

You can then write your binary to that:然后,您可以将二进制文件写入:

... whatever ... | gcc -x c -o /mnt/mytmpfs/program.out
/mnt/mytmpfs/program.out

and bash will load it for you as if it was on disk. bash会为您加载它,就像它在磁盘上一样。

Note, however, that you do still need enough RAM onboard the device to store and execute the program - though due to the nature of most executable binaries, you would need that anyway.但是请注意,您仍然需要设备上有足够的 RAM 来存储和执行程序 - 尽管由于大多数可执行二进制文件的性质,您无论如何都需要它。

If you don't want to leave the program behind on your ramdisk (or normal disk, if that is acceptable) for others to find, you can also delete the file immediately after starting to execute it:如果您不想将程序留在您的 ramdisk(或普通磁盘,如果可以接受)上供其他人查找,您也可以在开始执行后立即删除该文件:

/mnt/mytmpfs/program.out &
rm /mnt/mytmpfs/program.out

The name will disappear immediately, but the process will internally hold a hard link to that file, then release that hard link when it terminates, allowing the file to be immediately deleted from disk.该名称将立即消失,但该进程将在内部保留指向该文件的硬链接,然后在终止时释放该硬链接,从而允许立即从磁盘中删除该文件。 (However, the storage won't actually be freed until the program exits, and the program will not be able to exec itself either). (但是,在程序退出之前,实际上不会释放存储空间,并且程序也无法exec自身)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM