static char yes[80];
int main(int argc, char *argv[])
{
void (*point)();
// ... sets yes[] = to input
point = (void*) yes;
(*point)();
}
这样创建一个函数并执行yes []中的命令吗?怎么知道读取命令?我输入c,还是必须组装?
答案 0 :(得分:7)
仅仅因为某些事情会被编译,并不意味着它们会产生有效的定义结果。
您正在创建一个字符数组(其中80个),然后您将其作为函数指针进行转换并尝试运行它。可能你的程序会崩溃,但结果是未定义的。
答案 1 :(得分:3)
如上所述,这不是一件有用的事情,但它与即时编译器一整天所做的事情或操作系统的可执行加载程序并没有那么遥远。
碰巧我有一个例子。这仅适用于(x86或x86-64)/ Linux。如果你想让它做一些更有趣的事情,你需要用填充缓冲区的代码替换memset
和机器代码,以便进行更有趣的操作。
它不会在任何其他CPU上运行,因为它会对返回指令的x86机器编码进行硬编码。它可能不会在任何其他x86操作系统上工作,因为它忽略了mmap
和mprotect
周围的可移植性雷区: - (
#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
标志的内存段才能执行您想要的机器指令。
不要忘记代码指针和数据指针应该是不兼容的。