对函数进行字节编码时出现分段错误? [复制]

Posted

技术标签:

【中文标题】对函数进行字节编码时出现分段错误? [复制]【英文标题】:Segmentation fault when byte coding a function? [duplicate] 【发布时间】:2012-09-16 12:45:19 【问题描述】:

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

【问题讨论】:

f 函数的代码在哪里? 运行这样的代码,你甚至都不知道它对 root 权限(sudo 等)做了什么是不负责任的。你应该让你自己的程序吃掉你的硬盘。 【参考方案1】:

显然下面的建议不再适用于 gcc,因为现在的数组数据位于单独的不可执行只读 ELF 段中。

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


有趣的是,链接器并没有抱怨您尝试将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)

【讨论】:

我翻译的书有错误,我把所有的都放在了 test.c 并且错误是 f is not a function 我更新了 Wall 中没有错误的问题,但继续分段错误 f[] 不在堆栈上,而是全局(和公共)。我不认为 .data 部分是可执行的。 @wildplasser 将数组转换为 const 对我有用。虽然我并不完全有信心知道为什么会这样。 现在这是反直觉的。 “const 被认为是有害的” ;-)【参考方案2】:

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

【讨论】:

我运行 sudo ./a.out 也遇到同样的错误 代码没有溢出,如何绕过安全措施 以 root 身份运行不会让您绕过缓冲区溢出保护——事实上,它是您最需要它的地方。至于强制绕过——我不确定哪些系统调用可以让你修改 MMU 保护位。

以上是关于对函数进行字节编码时出现分段错误? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中创建大型数组时出现分段错误

使用 fread() 函数时出现分段错误

指针数组的分段错误

处理二维数组时出现分段错误[关闭]

运行我的代码时出现分段错误(核心转储)问题

在 C++ 中使用向量时出现分段错误