我们提供安全,免费的手游软件下载!

安卓手机游戏下载_安卓手机软件下载_安卓手机应用免费下载-先锋下载

当前位置: 主页 > 软件教程 > 软件教程

Linux中内存中执行脚本和程序的原理

来源:网络 更新时间:2024-05-14 11:30:36

在Linux中,可以通过将数据映射到内存中,而无需在文件系统上实际存在脚本或二进制程序的文件,就能够执行这些脚本和程序。

具体原理很简单,Linux系统可以将某块内存映射成文件描述符。对于每一个文件描述符,Linux会在 /proc/self/fd/<文件描述符> 路径上创建一个对应描述符的实体。这个路径可以像普通文件一样使用,能够正常读取其中的数据。只要具有可执行权限,就可以加载并执行其中的内容。

实现这一原理的第一步是通过 memfd_create 系统调用创建内存到文件描述符的映射。该系统调用会返回一个文件描述符,关联到一块内存上。默认情况下,这块内存的大小为0。大多数适用于普通文件描述符的操作也同样适用于这个描述符,比如read、write、ftruncate和close。当向其中写入数据时,系统会自动分配合适长度的内存。当所有引用这块内存的文件描述符被关闭后,这块内存会被自动释放。

总之, memfd_create 提供了像操作文件一样操作内存的能力,是一切皆文件理念的体现之一。

此外, memfd_create 创建的页面默认具有可执行权限,在proc底下的对应的描述符文件也有可执行权限。

因此,只需将脚本或二进制程序的数据写入 memfd_create 返回的描述符,前两步就已经完成。对于脚本,有一些要求,需要带有Shebang(类似 #!/usr/bin/env python3 )。

需要注意的是,虽然 /proc/self/fd/<文件描述符> 有描述符文件存在,但实际上这只是一个软链接,我们的数据全在内存中。

写入成功后,可以利用execve执行proc下的描述符文件,也可以通过 fexecve 系统调用直接调用文件描述符。由于golang没有提供fexecve,因此示例中使用了 exec.Cmd

以下是一个示例:

package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	"golang.org/x/sys/unix"
)

func main() {
    // 名字其实无所谓,传空字符传也许,名字只是方便debug没有其他影响
	fd, err := unix.MemfdCreate("memexec", unix.MFD_CLOEXEC)
	if err != nil {
		panic(err)
	}
	file := os.NewFile(uintptr(fd), "memexec")
	defer func() {
		if err := file.Close(); err != nil {
			panic(err)
		}
	}()
	_, err = file.Write([]byte("#!/usr/bin/env python\nimport math\nprint('Hello, world!')\n"))
	if err != nil {
		panic(err)
	}
	_, err = file.Write([]byte("print(f'{math.sqrt(2)=}')\n"))
	if err != nil {
		panic(err)
	}
    // 因为设置了CLOEXEC,子进程里execve之后看不到这个描述符,会导致调用失败
    // 所以只能用父进程的
	cmd := exec.Command(fmt.Sprintf("/proc/%d/fd/%d", os.Getpid(), fd))
	data, err := cmd.Output()
	fmt.Println("output:", string(data))
	if err != nil {
		panic(err)
	}
}

对于golang,可以配合embed将二进制程序的数据提前嵌入程序内,这样写入的时候会更加方便。

安全性方面:memfd_create创建的东西默认具有可执行权限,同时默认也是可写的,很可能会被恶意程序利用。因此,目前内核也在推进解决这个问题,并已经添加了flag可以让不添加可执行权限。建议遵守权限最小化的原则。

memfd原本的用途:用来在内存中创建文件(比如不想在存储器上创建文件时可以用这个),并可以在父子进程间传递(最好配合file sealing api使用,防止数据被意外修改);或者干脆当匿名共享内存用。执行内存中的程序是附带效果。

参考资料

https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html