字节编码功能时的分段错误?

时间:2012-09-16 12:45:19

标签: c security runtime-error

当我运行以下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 - 我怎样才能让它起作用?

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)

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