由于一些不明原因,我试图破坏一个生成一些源代码的bash脚本,而gcc使用
... whatever ... | gcc -x c -o /dev/stdout
现在,我想在编译时执行结果。我怎么能做到这一点?请不要使用文件。
答案 0 :(得分:2)
正如Charles Duffy所说,要执行二进制文件,您必须告诉您的操作系统(这似乎是Unix版本)加载和执行某些东西 - 而Unix系统只接受文件直接执行它们。
你可以做的是有一个进程准备一个包含ELF二进制文件的内存区域,分叉并跳转到该区域 - 但即使这样也是有问题的,考虑到有那些CPU支持来完全抑制 < / em>该操作(R ^ X)。基本上,你需要的是一个运行时链接器,而shell不会(也不应该)包含类似的内容。
让我们放弃Bash要求(这听起来真的只是你想要在比我脾气暴躁的应用程序中找到一个明显的漏洞):
通常,要求ELF(文件格式)并同时避免文件有点复杂。 GCC生成机器代码。如果您只想执行已知的机器代码,请将其放入某个缓冲区,构建一个指向该函数的函数指针并调用它。就那么简单。但是,您显然没有执行ELF二进制文件或加载共享对象(dlopen
)的过程所具有的所有良好的重定位和动态链接。
如果你想这样,我会看看像LLVM这样的方向 - 我知道,事实上,有人建立&#34;我在运行时编译C ++并执行它&# 34;将LLVM作为执行实例,并将其作为编译器。最后,你的gcc|something
实际上只是JIT - 一项旧技术:)
答案 1 :(得分:0)
如果您的目标是根本不写文件系统,那么bash
或任何其他UNIX程序都将无法帮助您从管道执行ELF-execve
仅采用路径如果将常规文件作为特殊文件(设备或命名管道)或目录传递给它,则会失败(将filename
设置为errno
)(将EACCES
设置为... whatever ... | gcc -x c -o ./temppath.out
temppath.out &
rm temppath.out
)。
但是,如果您的目标只是不留下任何永久性碎屑,那么您可以简单地创建文件,执行该文件,然后立即将其删除:
for _, s := range []string{
"test-project-233-TEST-ENDPOINT.test.as.ds.abcdefg.com",
"test-project-124-ENDPOINT.test.dd.ad.gf.abcdefg.com",
} {
fmt.Println(s[:16])
}
与Windows不同,UNIX不会阻止您在执行二进制文件时将其删除-进程将在内部保留指向该文件的硬链接,然后在终止时释放该硬链接,从而从磁盘中删除该文件。这实际上是UNIX程序中的一种相对常见的模式-程序有时会在其运行时目录中创建一个文件,将其打开,然后将其与文件系统断开链接,从而创建一个在程序生命周期内持续存在的临时文件(通常为一个内存映射区域)。
并且,实际上,大多数构建系统具有使此“事后删除”模式真正容易的工具-源代码控制系统通常会将一个或多个目录标记为已忽略,以防止意外提交,并且构建系统然后可以在其中存储其所有临时文件,包括临时二进制文件。然后,如果需要,“干净”命令可以擦除磁盘上的所有临时文件。