试图理解C,这是否设置了一个等于char []的函数来执行char []?

时间:2010-09-19 17:23:29

标签: c

static char yes[80]; 

int main(int argc, char *argv[])
{
    void (*point)();
    // ... sets yes[] = to input
    point = (void*) yes;
    (*point)();
}

这样创建一个函数并执行yes []中的命令吗?怎么知道读取命令?我输入c,还是必须组装?

4 个答案:

答案 0 :(得分:7)

仅仅因为某些事情会被编译,并不意味着它们会产生有效的定义结果。

您正在创建一个字符数组(其中80个),然后您将其作为函数指针进行转换并尝试运行它。可能你的程序会崩溃,但结果是未定义的。

答案 1 :(得分:3)

如上所述,这不是一件有用的事情,但它与即时编译器一整天所做的事情或操作系统的可执行加载程序并没有那么遥远。

  • 正如Carl所说,您需要将机器指令放入缓冲区,而不是C或程序集。
    • 这意味着你可以自己完成所有遵守ABI的工作。
    • 这也意味着你根本没有可移植性。执行此类操作的代码必须写入N次 - 对于您关心的每个CPU + OS组合一次。即时编译器通常会为不支持的平台提供字节码解释器的回退。
  • 出于安全原因,您不能将机器代码转储到缓冲区并跳转到它;你必须告诉操作系统你在做什么。

碰巧我有一个例子。这仅适用于(x86或x86-64)/ Linux。如果你想让它做一些更有趣的事情,你需要用填充缓冲区的代码替换memset和机器代码,以便进行更有趣的操作。

不会在任何其他CPU上运行,因为它会对返回指令的x86机器编码进行硬编码。它可能不会在任何其他x86操作系统上工作,因为它忽略了mmapmprotect周围的可移植性雷区: - (

#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void __attribute__((noreturn))
perror_exit(const char *msg)
{
    perror(msg);
    exit(1);
}
int main(void)
{
    /* allocate one writable page */
    size_t pagesize = getpagesize();
    void *rgn = mmap(0, pagesize, PROT_READ|PROT_WRITE,
                     MAP_PRIVATE|MAP_ANON, -1, 0);
    if (rgn == MAP_FAILED)
        perror_exit("mmap");

    /* fill it with return instructions */
    memset(rgn, 0xC3, pagesize);

    /* now switch the page from writable to executable */
    if (mprotect((caddr_t)rgn, pagesize, PROT_READ|PROT_EXEC))
        perror_exit("mprotect");

    /* now we can call it */
    ((void (*)(void))rgn)();
    return 0;
}

答案 2 :(得分:2)

你可能可以按照你的意愿使这个代码工作,但它将取决于机器/编译器/系统。您放入yes的内容需要是机器指令,而不是C 程序集。我会尝试一个例子。

编辑:我的一些快速测试没有发现任何有用的东西。我猜想Mac OS X中的内存保护/安全性/安全性太高了。您的代码当然可以在受保护程度较低的环境中工作 - 嵌入式系统,BIOS等。

答案 3 :(得分:2)

在Linux上这不起作用。您必须mmap带有PROT_EXEC标志的内存段才能执行您想要的机器指令。

不要忘记代码指针和数据指针应该是不兼容的。