【问题标题】:C Program to Expand and Run PHP扩展和运行 PHP 的 C 程序
【发布时间】:2011-07-07 01:40:47
【问题描述】:

如何在 Linux 上制作 GCC C 程序:

  • 内部有一个 PHP 程序脚本,而不是单独的文件
  • 将自身扩展到 /tmp
  • shell 到 php CLI 命令行运行 PHP 脚本
  • 将 C 程序的命令行参数作为 PHP 程序的命令行参数传递
  • 如果系统上无法使用 php CLI,则会很好地显示错误消息

【问题讨论】:

  • 您在哪一步遇到了问题?我们不会为您编写程序...
  • 我可以从 C 调用 setenv() 和 system() 没问题。问题是在 C 文件之外扩展文件资源。

标签: c linux gcc expand php


【解决方案1】:

PHP程序脚本可以存储为全局char *,使用fopenfwrite函数打开并写入全局变量。然后使用popen 执行php 解释器(这几乎会执行您发送给它的任何命令)并指定一个您可以从中读取以获取输出的文件描述符。如果您不需要程序的输出(或者这不是您的意图),那么您可以利用 exec 套件执行命令并将 /tmp/filename 作为参数传递。

要从 C 程序中获取参数,您将在 int main(int argc, char *argv[]) 中使用 *argv[] 只需记住 argv[0] 是您的应用程序名称(我总是忘记这一点)。

exec 函数将返回 -1 并设置 errno。手册页应该回答每一个的实现。但以防万一你迷路了。

char *script = "here are your script contents";

char *php_application_name = "pear";

int main(int argc, char *argv[]) {
  FILE *fd;
  char *filename = create_random_filename("/tmp/");
  fd = fopen(filename, "rw");

  fwrite(script, sizeof(char), strlen(script), fd);

  fclose(fd);

  /* Assuming application executes like
     pear <script> <arguments>
   */
  char *script_args[argc];
  int i = 1;
  script_args[0] = php_application_name;
  script_args[1] = filename;
  for(i = 1; i < argc; i++) {
    script_args[i+1] = argv[i];
  }

  execvp(php_application_name, script_args);
}

【讨论】:

  • 我想补充一点,我通过使用以下技术在 C 程序中嵌入数据资源进行了调整:linuxjournal.com/content/…
  • 唯一的抱怨是您将自己绑定到 i386 elf 架构。通过将脚本作为嵌入的 char * 包含在内,您在其上编译的任何拱门都应该可以工作。
  • 好点。那么,C 是否有带有
  • 不,您可以使用 \` at the end of the each line to continue a char *` 字符串。请记住,添加 \` does NOT indicate continue to a new line in the string itself; you will still need a \n` 来表示换行符。
  • 请原谅上面的格式,显然SO不欣赏\'s
【解决方案2】:

我想为@Suroot 和这篇精彩的文章提供道具:http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967

但是,整个过程在Linux命令行下是这样的:

...首先,您需要在Linux上,需要启用命令行PHP(CLI),并且命令行中的PHP在执行“php -v”或通过测试时不应出现任何错误您知道通常可以在命令行中运行的脚本。

...其次,你需要安装 GCC 来编译 C 程序。

...创建一个工作目录并 'cd' 进入它。

...创建一个包含以下测试代码的文件 script.php:

<?php

$s1 = @ $argv[1];
$s2 = @ $argv[2];
$s3 = @ $argv[3];

for($i=0;$i<=10;$i++){
    echo "($s1) ($s2) ($s3)\n";
}

...注意,这只是我们的测试。证明测试有效后,您可以稍后将自己的 PHP 代码放入其中。

...请注意,“script.php”的命名至关重要,否则 main.c 在到达_binary_script_php_start 行时将无法工作。起初通过我进行了一个循环,因为我没有想到变量名被这个过程粘住了。

...创建一个包含以下代码的 C 代码文件 main.c:

#include <stdio.h>
#include <stdlib.h>

extern char _binary_script_php_start;
extern char _binary_script_php_end;

int main(int argc, char *argv[]) {
    // EXTRACT OUR RESOURCE OBJECT INTO /tmp/test.php
    char *p = &_binary_script_php_start;
    FILE *fp = fopen("/tmp/test.php","wb");
    while ( p != &_binary_script_php_end ) {
        fputc(*p++,fp);
    }
    fclose(fp);
    // NOW READ IN OUR STANDARD ARGUMENTS AND LAUNCH OUR COMMAND
    int i = 1;
    char *cmd = "php /tmp/test.php";
    char *s = NULL;
    asprintf(&s, "%s",cmd);
    for(i = 1; i < argc; i++) {
        asprintf(&s, "%s \"%s\"",s,argv[i]);
    }
    system(s);
    free(s);
    unlink("/tmp/test.php"); // comment me out for debugging if you want
}

...注意,我对 C 有点生疏(自 1980 年代以来就没有使用过),并且不建议使用 strcpy(),因为它不安全。所以,我read up on StackOverflow 我们应该在 GNU Linux 系统上使用 asprintf()。 显然 asprintf() 处理缓冲区溢出和 malloc 问题?我当然希望如此——我不想在这里误导你。请研究一下!

...现在魔法开始了!

...我们需要使用这个命令行命令将 script.php 嵌入到一个目标文件“data.o”中(因此从 $ 提示符开始):

$ objcopy -I binary -O elf32-i386 -B i386 script.php data.o

...现在我们构建命令“runme”,将“data.o”和“main.c”链接在一起:

$ gcc main.c data.o -o runme

...然后为我们编译了一个名为“runme”的 C 程序。然后我们可以执行它来测试它:

$ ./runme "test1" "test2 test3" "test4"

...您应该看到如下输出:

(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)
(test1) (test2 test3) (test4)

...如您所见,双引号实际上很重要——它们告诉 C 和 PHP,参数应该组合在一起。这就是为什么 test3 没有出现在最后一个括号中的原因。如果没有双引号,您将看到完全不同的结果。

此时,您将了解我们如何制作一个内置 PHP 脚本并在 Linux 上运行的 C 程序。 (Mac、Windows——您可能需要对这段代码进行一些调整。)C 程序将我们的 PHP 脚本扩展为 /tmp,执行它,并将我们可以读入和使用的参数传递给它。从这里开始,您可以根据需要修改 script.php,并且您可以了解如何使用唯一的文件名,这样您就不会破坏其他人的 /tmp/test.php 文件,以防万一。

【讨论】:

  • 你会有内存泄漏,你的 for 循环导致 asprintf 被调用,它每次都分配一个新的指针到 s 。但是你永远不会释放以前的 s。如果您担心缓冲区溢出;查看 snprintf() (但是您需要知道大小要求,您可以通过总结所有 argv 的 strlen 来做到这一点)。
  • @Suroot - 我现在将这个标记为答案,即使它有轻微的内存泄漏,因为它是完整的过程。但是,我将与您一起离线以消除内存泄漏并修改此答案。我只需要正确学习C字符串连接。
猜你喜欢
  • 2016-03-06
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
  • 2011-03-27
相关资源
最近更新 更多