简体   繁体   English

在另一个进程中从内存执行进程?

[英]Execute a process from memory within another process?

I would like to have a small "application loader" program that receives other binary application files over TCP from an external server and runs them. 我想有一个小的“应用程序加载器”程序,它通过TCP从外部服务器接收其他二进制应用程序文件并运行它们。

I could do this by saving the transmitted file to the hard disk and using the system() call to run it. 我可以通过将传输的文件保存到硬盘并使用system()调用来运行它来完成此操作。 However, I am wondering if it would be possible to launch the new application from memory without it ever touching the hard drive. 但是,我想知道是否有可能从内存中启动新应用程序而不会触及硬盘驱动器。

The state of the loader application does not matter after loading a new application. 加载新应用程序后,加载程序应用程序的状态无关紧要。 I prefer to stick to C, but C++ solutions are welcome as well. 我更喜欢坚持C,但也欢迎C ++解决方案。 I would also like to stick to standard Linux C functions and not use any external libraries, if possible. 我还想坚持使用标准的Linux C函数,如果可能的话,不要使用任何外部库。

Short answer: no. 简答:不。

Long answer: It's possible but rather tricky to do this without writing it out to disk. 答案很长:如果不将其写入磁盘,这样做可能相当棘手。 You can theoretically write your own elf loader that reads the binary, maps some memory, handles the dynamic linking as required, and then transfers control but that's an awful lot of work, that's hardly ever going to be worth the effort. 理论上你可以编写自己的elf加载器来读取二进制文件,映射一些内存,根据需要处理动态链接,然后转移控制,但这是一项非常多的工作,这几乎不值得付出努力。

The next best solution is to write it to disk and call unlink ASAP. 下一个最佳解决方案是将其写入磁盘并尽快调用unlink。 The disk doesn't even have to be "real" disk, it can be tmpfs or similar. 磁盘甚至不必是“真正的”磁盘,它可以是tmpfs或类似的。

The alternative I've been using recently is to not pass complete compiled binaries around, but to pass LLVM bytecode instead, which can then be JIT'd/interpreted/saved as fit. 我最近使用的替代方法是不传递完整的编译二进制文件,而是传递LLVM字节码,然后可以JIT /解释/保存为合适。 This also has the advantage of making your application work in heterogeneous environments. 这还具有使您的应用程序在异构环境中工作的优势。

It may be tempting to try a combination of fmemopen , fileno and fexecve , but this won't work for two reasons: 尝试fmemopenfilenofexecve的组合可能很诱人,但这不会有两个原因:

  1. From fexecve() manpage: 来自fexecve()页:

    "The file descriptor fd must be opened read-only, and the caller must have permission to execute the file that it refers to " “文件描述符fd必须以只读方式打开,并且调用者必须具有执行其引用的文件的权限”

    Ie it needs to be a fd that refers to a file. 即它需要是一个引用文件的fd。

  2. From fmemopen() manpage: fmemopen()页:

    "There is no file descriptor associated with the file stream returned by these functions (ie, fileno(3) will return an error if called on the returned stream)" “没有与这些函数返回的文件流相关联的文件描述符(即,如果在返回的流上调用,则fileno(3)将返回错误)”

Much easier than doing it is C would just to set up a tmpfs file system. 比做它容易多了就是设置一个tmpfs文件系统。 You'd have all the advantages of the interface of a harddisk, from your program / server / whatever you could just do an exec . 你可以拥有硬盘接口的所有优点,从你的程序/服务器/你只能做一个exec These types of virtual filesystems are quite efficient nowadays, there would be really just one copy of the executable in the page cache. 这些类型的虚拟文件系统现在非常高效,页面缓存中实际上只有一个可执行文件的副本。

As Andy points out, for such scheme to be efficient you'd have to ensure that you don't use buffered writes to the file but that you "write" (in a broader sense) directly in place. 正如Andy指出的那样,为了使这种方案更有效率,你必须确保不对文件使用缓冲写入,而是直接在适当位置“写入”(在更广泛的意义上)。

  • you'd have to know how large your executable will be 你必须知道你的可执行文件有多大
  • create a file on your tmpfs 在你的tmpfs上创建一个文件
  • scale it to that size with ftruncate 使用ftruncate将其缩放到该大小
  • "map" that file into memory with mmap to obtain the addr of a buffer 使用mmap将该文件“映射”到内存中以获取缓冲区的addr
  • pass that address directly to the recv call to write the data in place 将该地址直接传递给recv调用以将数据写入到位
  • munmap the file munmap文件
  • call exec with the file 用文件调用exec
  • rm the file. rm文件。 can be done even when the executable is still running 即使可执行文件仍在运行,也可以完成

您可能希望查看并重UPX ,它将可执行文件解压缩到内存,然后将控制权转移到ld-linux以启动它。

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

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