我想复制并调用一个函数,但是在调用缓冲区时,以下代码会出现段错误。我需要改变什么? (Linux,x86)
#include <string.h>
#include <malloc.h>
#include <stdio.h>
int foo () { return 12; }
void foo_end () {}
int main () {
int s = (unsigned long long) foo_end - (unsigned long long) foo;
int (*f) () = (int (*)()) malloc (s);
memcpy ((void*) f, (const void*) foo, s);
printf ("%d %d\n", f (), foo ());
}
编辑:工作解决方案:
#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
int foo () { return 12; }
void foo_end () {}
int main () {
int s = (unsigned long long) foo_end - (unsigned long long) foo;
int (*f) () = (int (*)()) malloc (s);
memcpy ((void*) f, (const void*) foo, s);
long ps = sysconf (_SC_PAGESIZE);
void *fp = (void*) ((unsigned long long) f & ~((unsigned long long) (ps-1)));
if (mprotect ((void*) fp, ps, PROT_READ | PROT_WRITE | PROT_EXEC)) return -1;
printf ("%d %d\n", f (), foo ());
}
答案 0 :(得分:9)
哇,那段代码有很多问题。
malloc()
返回的内存可以调入简而言之,不要这样做。
更新
在Linux中,我认为您可以使用mprotect()
来设置内存块的权限。我认为这需要root,但显然不是(只要你在自己的进程'内存中)。
答案 1 :(得分:3)
您可能正在使用不向数据段授予执行权限的操作系统。
某些环境会保护数据页面不被执行,以避免各种类型的安全问题(或利用它们)。
考虑调用mprotect()来启用该页面的执行并报告发生的情况。
答案 2 :(得分:0)
这是嵌入式系统民间的常见问题。这种技术通常用于从只读存储器复制到随机存取存储器(能够写和读)。使用标准C或C ++没有优雅的标准解决方案。
更简单的解决方案是使用链接器定义一些新的非标准段。使用非标准#pragma
指示编译器将函数放入新段中。使用非标准编译器指令访问该段的起始地址和结束地址。这将允许您获得函数的大小。
目标的更安全方法是创建具有可执行和写入属性的另一个段。将功能段中的数据复制到此可执行段中。设置一个指向该段开头的函数指针。通过指针执行该功能。
另一种解决方案是使用汇编语言执行此操作。通常,装配工给你更多的自由(射击你的脚)来操纵这样的记忆在较低的水平。
另外,请查看您的操作系统加载程序,内存属性和保护方案。某些操作系统可能会将此类行为限制为内核权限或更高权限。