当我运行以下C程序(在Ubuntu中使用gcc编译)时,我遇到了分段错误。
#include <stdio.h>
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;
}
c.f:
f.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
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
- 我怎样才能让它起作用?
答案 0 :(得分:4)
有趣的是,链接器并未抱怨您尝试将char f[] = "...";
作为函数f()
链接到您的应用程序。您尝试调用函数f()
。有一个符号f
链接到可执行文件,但令人惊讶的是它根本不是函数,而是一些变量。因此它无法执行它。这可能是由于堆栈执行保护机制造成的。
为了避免这种情况,您只需将字符串输入到进程内存的文本段即可。如果将字符串声明为const char f[]
,则可以实现此目的。
来自Smashing The Stack For Fun And Profit, by Aleph One:
文本区域由程序修复,包含代码(说明) 和只读数据。该区域对应于文本部分 可执行文件。
由于const char[]
只读,编译器会将其与代码一起放入文本区域。从而避免了执行防止机制,并且机器能够在其中执行机器代码。
示例:
/* test.c */
#include <stdio.h>
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)
答案 1 :(得分:0)
如果我理解正确的话,你试图运行不在文本空间中的简单代码,而是在初始化的静态存储中?如果失败则只有三个原因:您的代码初始化不正确(在这种简单的情况下不太可能),您的数据空间已被踩(在这种简单的情况下看起来不像),或者您的系统是防止它作为一种安全措施(很可能因为你要做的事情非常不典型,主要用于缓冲区溢出利用)。