字节编码函数时出现分段故障?[重复]

问题描述 投票:2回答:2

当我运行下面的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 - 我怎么才能让它工作?

c security runtime-error
2个回答
4
投票

显然下面的建议在gcc中不再适用了,因为现在的数组数据被放置在一个单独的不可执行的只读ELF段中。

出于历史原因,我把它留在这里。


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

要规避这个问题,显然,你只需要把字符串的内容传递给 文段 的进程内存。你可以实现这一点,如果你把字符串声明为 const char f[].

砸堆的乐趣和收益,作者:阿莱夫一世。:

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

由于 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)


0
投票

如果我没有理解错的话,你是想运行不在文本空间,而是在初始化静态存储中的简单代码?如果失败了,那么只有三个原因:要么是你的代码初始化不正确(在这个简单的例子中不太可能),要么是你的数据空间被踩踏了(在这个简单的例子中看起来不像),要么是你的系统作为安全措施阻止了它(很有可能,因为你要做的是相当非典型的,主要用于缓冲区溢出利用)。

© www.soinside.com 2019 - 2024. All rights reserved.