字节编码function时的分段错误?

当我运行以下C程序(在Ubuntu中使用gcc编译)时,我遇到了分段错误。

#include  char f[] = "\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x89\x75\xf0\x48\x8b\x45\xf8\x8b\x10\x48\x8b\x45\xf0\x8b\x00\x89\xd1\x29\xc1\x89\xc8\xc9\xc3"; int main() { int (*func)(); func = (int (*)()) f; int x=3,y=5; printf("%d\n",(int)(*func)(&x,&y)); return 0; } 

字符串f包含以下函数的机器代码。

 int f(int*a, int*b) { return *a-*b; } 

CF:

 fo: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 : 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 48 89 7d f8 mov %rdi,-0x8(%rbp) 8: 48 89 75 f0 mov %rsi,-0x10(%rbp) c: 48 8b 45 f8 mov -0x8(%rbp),%rax 10: 8b 10 mov (%rax),%edx 12: 48 8b 45 f0 mov -0x10(%rbp),%rax 16: 8b 00 mov (%rax),%eax 18: 89 d1 mov %edx,%ecx 1a: 29 c1 sub %eax,%ecx 1c: 89 c8 mov %ecx,%eax 1e: c9 leaveq 1f: c3 retq 

这是使用以下编译的:

 gcc test.c -Wall -Werror ./a.out Segmentation fault 

预期的输出是-2 – 我怎样才能使它工作?

有趣的是,链接器并未抱怨您尝试链接char f[] = "..."; 作为函数f()到您的应用程序。 您尝试调用函数f() 。 有一个符号f链接到可执行文件,但令人惊讶的是它根本没有function,而是一些变量。 因此它无法执行它。 这可能是由于堆栈执行保护机制造成的。

为了避免这种情况,你需要将字符串放到进程内存的文本段中。 如果将字符串声明为const char f[] ,则可以实现此目的。

来自Aleph One的Smashing Stack for Fun and Profit :

文本区域由程序固定,包括代码(指令)和只读数据。 该区域对应于可执行文件的文本部分。

由于const char[] 只读的,因此编译器将其与代码一起放入文本区域。 从而避免了执行防止机制,并且机器能够在其中执行机器代码。


例:

 /* test.c */ #include  const char f[] = "\x55\x48\x89\xe5\x48\x89\x7d\xf8\x48\x89\x75\xf0\x48\x8b\x45\xf8\x8b\x10\x48\x8b\x45\xf0\x8b\x00\x89\xd1\x29\xc1\x89\xc8\xc9\xc3"; int main() { int (*func)(); func = (int (*)()) f; int x=3,y=5; printf("%d\n",(int)(*func)(&x,&y)); return 0; } 

收益率:

 $ gcc test.c -Wall && ./a.out -2 

(Fedora 16,gcc 4.6.3)

如果我理解你正确,你试图运行不在文本空间中的简单代码,而是在初始化的静态存储中? 如果失败则只有三个原因:要么你的代码被错误地初始化了(在这个简单的情况下不太可能),你的数据空间已被踩到(在这个简单的例子中看起来不像),或者你的系统是防止它作为一种安全措施(很可能因为你要做的事情是相当不典型的,主要用于缓冲区溢出利用)。