为什么这个秘密如此惊人?

system() 函数:最简单的方式

原理:直接调用操作系统的Shell(如Linux的/bin/sh或Windows的cmd.exe)执行命令。
示例

int main() {
    // Linux/MacOS
    system("ls -l");  // 列出当前目录文件
    // Windows
    system("dir");    // 等效命令
    return 0;
}

特点

  • ✅ 优点:简单易用,直接返回命令退出状态。
  • ❌ 缺点:
    • 安全性低:若命令字符串来自用户输入,可能引发命令注入攻击(如; rm -rf /)。
    • 效率低:每次调用需启动新Shell进程,资源开销大。

popen() 函数:捕获命令输出

原理:建立管道连接,读取命令的标准输出(或写入输入)。
示例(读取命令结果):

#include <stdio.h>
int main() {
    FILE *fp;
    char buffer[1024];
    // 执行命令并读取输出
    fp = popen("ls -l", "r"); 
    if (fp == NULL) {
        perror("popen失败");
        exit(1);
    }
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);  // 逐行打印输出
    }
    pclose(fp);  // 关闭管道
    return 0;
}

特点

  • ✅ 优点:可获取命令的实时输出,适用于需要处理结果的场景(如日志分析)。
  • ❌ 缺点:
    • 只能单向通信(读 写)。
    • 仍需启动Shell进程。

exec() 族函数:直接替换进程

原理:用新进程替换当前进程,不创建新进程(常与fork()配合使用)。
示例(结合fork()):

#include <unistd.h>
#include <sys/wait.h>
int main() {
    pid_t pid = fork();  // 创建子进程
    if (pid == 0) {      // 子进程
        execlp("ls", "ls", "-l", NULL);  // 替换为ls命令
        perror("execlp失败");            // 仅当出错时执行
        exit(1);
    } else {             // 父进程
        wait(NULL);      // 等待子进程结束
    }
    return 0;
}

特点

  • ✅ 优点:无Shell开销,效率高,安全性好(无命令注入风险)。
  • ❌ 缺点:
    • 语法复杂(需管理进程)。
    • 原进程会被替换(通常先fork()exec())。

Windows API:CreateProcess()

原理:Windows原生API,提供更精细的进程控制。
示例

#include <windows.h>
int main() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    // 执行命令(例如启动记事本)
    if (!CreateProcess(
        NULL,                   // 不指定可执行文件
        "notepad.exe",          // 命令
        NULL, NULL, FALSE, 0, NULL, NULL,
        &si, &pi)) {
        fprintf(stderr, "CreateProcess失败 (%lu)\n", GetLastError());
        return 1;
    }
    WaitForSingleObject(pi.hProcess, INFINITE);  // 等待结束
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return 0;
}

安全实践:避免命令注入

  1. 绝不直接拼接用户输入
    // 危险示例!
    char user_input[100];
    scanf("%s", user_input);
    system(strcat("ls ", user_input));  // 若输入"; rm -rf *" 将导致灾难
  2. 解决方案
    • 使用exec()族函数分离参数:
      execlp("ls", "ls", user_input, NULL);  // 安全:参数由系统直接传递
    • 白名单校验用户输入(如只允许字母数字)。

方法选择建议

场景 推荐方法
快速执行简单命令 system()
需捕获命令输出 popen()
高性能/安全关键场景 exec() + fork()
Windows精细控制 CreateProcess()

引用说明

  1. Linux system()手册页:[man7.org]
  2. POSIX popen()标准:[pubs.opengroup.org]
  3. exec函数族详解:[GNU Libc Manual]
  4. Windows进程API文档:[Microsoft Learn]

通过合理选择方法并遵循安全规范,可高效安全地在C程序中集成系统命令。

原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/7154.html

(0)
酷番叔酷番叔
上一篇 2025年7月13日 02:03
下一篇 2025年7月13日 02:19

相关推荐

  • linux管道命令键盘怎么打

    Linux 中,管道命令使用 | 符号,可通过键盘上的 Shift + \

    2025年8月15日
    8800
  • 如何安全关闭IIS服务?

    IIS(Internet Information Services) 是 Windows 系统自带的 Web 服务器软件,当您需要执行服务器维护、更新配置或排查故障时,可能需要停止 IIS 服务,以下是四种经过验证的方法,适用于 Windows 10/11 及 Windows Server 系统,操作前请务必备……

    2025年7月29日
    9800
  • 安全帽训练数据集如何构建以适配多场景并提升检测精度与鲁棒性?

    安全帽训练数据集是计算机视觉领域中用于工业安全场景的专用数据集,核心目标是通过标注图像或视频数据,训练人工智能模型实现对“是否佩戴安全帽”的自动识别与检测,该数据集在建筑、矿山、工厂等高风险工业场景中具有重要应用价值,能够帮助企业实时监控工人安全规范执行情况,降低安全事故发生率,从数据构成来看,安全帽训练数据集……

    2025年10月19日
    9400
  • 命令行怎么退出vi编辑模式

    vi编辑模式中,按Esc键退出编辑模式,然后输入:q保存并退出或`:q!

    2025年8月17日
    7800
  • CAD X命令怎么用?详细操作步骤与实用技巧解析

    在CAD软件中,X命令是“EXPLODE”(分解)命令的快捷键,主要用于将复合对象分解为多个独立的单一对象,这一命令在绘图过程中非常实用,尤其当需要对组合对象(如块、多段线、尺寸标注等)进行局部编辑时,通过分解可快速拆解其构成元素,提升绘图效率,以下从功能原理、操作步骤、应用场景及注意事项等方面详细说明X命令的……

    2025年8月30日
    10100

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN

关注微信