我可以执行驻留在数据段(ELF 二进制文件)中的代码吗?

Can i execute code that resides in data segment (ELF binary)?

为了理解二进制文件(虚拟内存布局、执行...等),我编写了一个 C 代码,它声明了一个包含可执行代码字节的全局字符串,然后我覆盖了通过在 main() 中声明一个指针 (PTR),从 main() 函数到该可执行代码的 return 地址是保留在stack 2 WORDS far away from the return address from the main(),所以我所做的就是将return地址的地址分配给那个指针(PTR=(int*)&PTR+2),然后覆盖内容该地址与可执行代码(静态字符串)的地址。

现在的困境是,每当我编译和执行时,我都会收到一个 分段错误。 可执行代码没有内存 input/output(它只是一堆 NOPs)。

我使用 GDB 确保该过程完美运行:return 地址更改为字符串的地址,但 return 从未发生。

我所知道的是可执行代码被映射到虚拟内存中被标记为 RW.data.bss 段)的页面,所以也许没有办法这样做代码执行,除非代码被注入 executable 内存区域(标记为 RE 的页面)。这就是我对这个主题的理论,我邀请你提供更多细节。

char code[]="\x90\x90\x90\x90\x90\x90\x90\x90"; //a static string contains executable code

int main()
{
int *return_address; //Pointer to the return address - uninitialized
return_address = (int *)&return_address + 2; //Initializing the return address - according to stack layout
(*return_address) = (int)code; //Overwriting the return address with the code's address
}

i receive a segmentation fault.

它是数据执行预防的硬件控制(https://en.wikipedia.org/wiki/Executable_space_protection#Linux) - 如果页面[=80=中没有设置'x'(执行)位,你不能直接跳转到数据页]s。 /proc/$pid/maps / /proc/$pid/smaps 文件中列出了所有位的内存映射,如 'rwx' 用于 writable 代码,'rw-' 用于未执行的数据,'r--'对于只读数据,'r-x' 对于普通代码。

如果你想执行数据,你应该调用 mprotect 带有 PROT_EXEC 标志的系统调用在你想要成为代码的数据部分。

在 x86 世界中,这在 Pentium 4 (Prescott) 和更新版本(Core、Core2、Core i*、core m)/ Athlon 64 / Opteron 和更新版本中完全实现为 "NX bit" / "XD bit" feature。如果 OS 在 32 位模式下工作,则必须打开 PAE 才能在页面 table 中拥有此位。在 x86_64 模式(64 位)中,始终支持 NX/XD 位。

2004 年左右,linux 添加了第一个支持变体:http://linuxgazette.net/107/pramode.html

在 2007 年,您可能拥有过时的硬件、旧内核或没有 PAE 的 32 位模式内核。

关于 NX/XD 位的信息:https://en.wikipedia.org/wiki/NX_bit

有时'rwx'模式可能被禁止,检查https://en.wikipedia.org/wiki/W^X

对于 NX 之前的系统,存在基于 x86 的段寄存器的解决方案,以部分禁用部分内存 space 的执行。

can i execute the program above without having an segmentation fault ?

您可以:

  • 通过使用 PROT_READ|PROT_EXEC
  • 调用 mprotect 使数据页 executable
  • 将 elf 文件的数据段标记为 executable(需要深入 ld 脚本内部 - 默认为 ld --verbose
  • 使所有页面包括.data和堆执行table(不仅仅是堆栈)
    使用 ld 或 gcc -z execstack
  • 移动 shellcode 到 elf 文件的文本数据
  • 尝试禁用内核中的 nx/xd 位(很难;可能需要重新编译)
  • 使用未启用 PAE 选项(构建时选项)的 32 位 OS(内核)。
  • 使用旧的 cpu 没有 NX/XD