为什么execstack需要在堆上执行代码?

mer*_*011 6 c gcc

我编写了下面的代码来测试/tmp/passwd安全类中的赋值的shellcode(用于取消链接).

当我编译时gcc -o test -g test.c,我得到了跳转到shellcode的段错误.

当我使用后处理二进制文件时execstack -s test,我不再获得段错误并且shellcode正确执行,删除/tmp/passwd.

我运行gcc 4.7.2.为了使堆可执行,似乎要求堆栈是可执行的似乎是个坏主意,因为后者比前者有更多合法的用例.

这是预期的行为吗?如果是这样,理由是什么?

#include <stdio.h>                                     
#include <stdlib.h>                                    


char* shellcode;                                       


int main(){                                            
    shellcode = malloc(67);                            
    FILE* code = fopen("shellcode.bin", "rb");      
    fread(shellcode, 1, 67, code);                     

    int (*fp)(void) = (int (*) (void)) shellcode;      
    fp();                                              
}    
Run Code Online (Sandbox Code Playgroud)

这是输出xxd shellcode.bin:

0000000: eb28 5e89 760c 31c0 8846 0bfe c0fe c0fe  .(^.v.1..F......           
0000010: c0fe c0fe c0fe c0fe c0fe c0fe c0fe c089  ................           
0000020: f3cd 8031 db89 d840 cd80 e8d3 ffff ff2f  ...1...@......./           
0000030: 746d 702f 7061 7373 7764                 tmp/passwd                 
Run Code Online (Sandbox Code Playgroud)

the*_*ejh 5

这是预期的行为吗?

查看 Linux 内核代码,我认为该标志的内核内部名称是“read 意味着 exec”。所以是的,我认为这是意料之中的。

似乎要求堆栈可执行以使堆可执行似乎是个坏主意,因为后者的合法用例比前者要多得多。

为什么需要完整的堆才能执行?如果您确实需要动态生成机器代码并运行它,您可以使用mmap系统调用显式分配可执行内存。

理由是什么?

我认为这个想法是这个标志可以用于期望所有可读的东西也是可执行的遗留程序。这些程序可能会尝试在堆栈上运行内容,也可能会尝试在堆上运行内容,所以这都是允许的。


Chr*_*odd 5

真正的“意外”行为是,设置标志会使以及堆栈都可执行。该标志旨在用于生成基于堆栈的thunk(例如,当您使用嵌套函数的地址时为gcc)的可执行文件,并且不会真正影响堆。但是Linux通过全局使所有可读页面可执行来实现此目的。

如果您希望获得更细粒度的控制,则可以使用mprotect系统调用以每页为基础控制可执行权限-添加类似以下代码:

uintptr_t pagesize = sysconf(_SC_PAGE_SIZE);
#define PAGE_START(P) ((uintptr_t)(P) & ~(pagesize-1))
#define PAGE_END(P)   (((uintptr_t)(P) + pagesize - 1) & ~(pagesize-1))
mprotect((void *)PAGE_START(shellcode), PAGE_END(shellcode+67) - PAGE_START(shellcode),
         PROT_READ|PROT_WRITE|PROT_EXEC);
Run Code Online (Sandbox Code Playgroud)