如何将char缓冲区作为可执行代码传入exec系列函数调用?
可行实现方案
以下方案均针对你硬编码的ELF格式二进制适用:
方案1:内存临时文件执行(最通用,完全匹配exec语义)
这是安全性最高、实现成本最低的方案,全程无磁盘文件落盘,不会产生残留风险:
- 利用Linux系统的
memfd_create系统调用,直接在内存中创建匿名文件描述符,不需要挂载特殊文件系统 - 操作流程:
- 调用
memfd_create("tmp_exec_bin", MFD_CLOEXEC)创建内存文件描述符 - 将硬编码的
code数组完整写入该文件描述符 - 直接调用
fexecve传入该文件描述符、argv参数数组、环境变量数组即可完成执行,完全符合你要的类exec调用效果 - 若运行环境glibc版本较低不支持
fexecve,可以拼接路径/proc/self/fd/[你的fd编号],将该路径传给普通的execve函数即可
- 调用
- 参考实现代码:
#include <linux/memfd.h> #include <sys/syscall.h> #include <unistd.h> #include <stdio.h> // 你的硬编码二进制数组和长度 extern const unsigned char code[]; extern const size_t code_len; int exec_hardcode_bin(char *const argv[], char *const envp[]) { int fd = syscall(SYS_memfd_create, "exec_bin", MFD_CLOEXEC); if (fd < 0) { perror("memfd_create 调用失败"); return -1; } if (write(fd, code, code_len) != code_len) { perror("二进制写入内存文件失败"); close(fd); return -1; } // 优先用fexecve直接执行 int ret = fexecve(fd, argv, envp); // 失败兜底用proc路径执行 if (ret < 0) { char proc_path[64]; snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd); ret = execve(proc_path, argv, envp); } close(fd); return ret; }
- 优势:完全遵循exec的原生语义,执行后原进程映像会被完全替换,不需要手动处理ELF加载、段映射等底层逻辑,安全性满足要求。
方案2:手动ELF加载执行(适配特殊无memfd环境)
如果运行环境不支持memfd_create和proc文件系统,可以自己实现轻量ELF加载器:
- 手动解析硬编码的ELF头、程序头,将可执行段、数据段映射到进程虚拟地址的对应位置
- 手动构造栈结构,写入
argc、argv、环境变量、辅助向量等执行必要信息 - 最后跳转至ELF入口地址执行
- 注意:该方案不会自动替换原进程的完整映像,原进程打开的文件描述符、信号处理规则等资源会被保留,如果需要完全等价exec的语义需要手动清理这些资源,实现复杂度较高。
注意事项
- 如果硬编码的是静态链接ELF,上述两种方案都可以正常运行;如果是动态链接ELF,需要运行环境存在对应的动态链接器和依赖库才能正常执行
- 硬编码的二进制数组要注意字节对齐,数组长度必须和实际二进制大小完全一致,避免写入内容不完整导致执行崩溃
内容的提问来源于stack exchange,提问作者psionic12
相关产品推荐
相关产品推荐

