【问题标题】:Can i execute code that resides in data segment (ELF binary)?我可以执行驻留在数据段(ELF 二进制文件)中的代码吗?
【发布时间】:2016-11-01 23:38:38
【问题描述】:

在理解二进制文件(虚拟内存布局、执行...等)的过程中,我编写了一个C 代码,该代码声明了一个包含可执行代码字节的全局字符串,然后我覆盖了从通过在main() 中声明一个指针(PTR),将main() 函数指向该可执行代码,这是一个在堆栈上保留的本地内存区域,距离main() 的返回地址2 个字远,所以我所做的就是将返回地址的地址分配给该指针(PTR=(int*)&PTR+2),然后用可执行代码的地址(静态字符串)覆盖该地址的内容。

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

使用 GDB,我确保该过程完美运行:返回地址更改为字符串的地址,但返回永远不会发生。

我所知道的是可执行代码已映射到虚拟内存中的页面标记为RW.data.bss 段),因此除非将代码注入到内存的executable 区域(标记为@987654335 的页面),否则可能无法执行这样的代码执行@)。这就是我对这个主题的理论,我邀请你提供更多细节。

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
}

【问题讨论】:

  • 您可能想调用 mprotect sycall 并添加 PROT_EXEC 标志...在许多架构(x86 也是)上的数据页上没有 x 权限,通过阅读 /proc/$ 检查 linux 中的内存映射应用程序运行时的 PID/maps 文件(在 gdb 中停止),其中 $PID 是目标进程的 pid。您将看到加载了 rw- 权限的 data/bss 段。
  • @osgx 这和我猜的一模一样,旧的 linux 内核(比如 2007 年之前)是否允许这种执行?
  • 你呢?您可以检查旧内核上的映射文件。有关于技术的 wiki 页面:en.wikipedia.org/wiki/Executable_space_protection 和“NX 位”/“XD 位”技术可能需要在 CPU 和内核中......将“可执行”位添加到硬件的页面级翻译(操作系统可能有 3 位 rwx权限;但硬件没有 x 位)。 PAE 也应该在 32 位 x86 模式下打开。 (详细信息在这里en.wikipedia.org/wiki/NX_bit
  • afr0ck,你真正的问题是什么?您需要更详细的链接吗?
  • Linux kernels > 2.3 支持带有 XD 位的完整 PAE,所以我真的需要一个非常旧的 Linux 内核来进行这样的尝试。顺便说一句,感谢您的帮助。 @osgx

标签: c memory segmentation-fault elf shellcode


【解决方案1】:

我收到分段错误。

这是数据执行预防的硬件控制 (https://en.wikipedia.org/wiki/Executable_space_protection#Linux) - 如果页表中没有设置“x”(执行)位,则不能直接跳转到数据页。所有位的内存映射在/proc/$pid/maps//proc/$pid/smaps 文件中列出,“rwx”表示可写代码,“rw-”表示未执行的数据,“r--”表示只读数据,“r-x”表示普通代码。

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

在 x86 世界中,这在 Pentium 4 (Prescott) 和更新版本(Core、Core2、Core i*、core m)/ Athlon 64 / Opteron 和更新版本中完全实现为"NX bit" / "XD bit" feature。如果操作系统在 32 位模式下工作,它必须打开 PAE 才能在页表中拥有该位。在 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 段寄存器的解决方案可以部分禁用部分内存空间的执行。

我可以在没有分段错误的情况下执行上面的程序吗?

你可以:

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

【讨论】:

  • PS:有人可以(但根据法律不应该)使用 spray 将自己的代码写入远程进程的可执行页面 (en.wikipedia.org/wiki/JIT_spraying)。不适用于 RISC 和 gogole NaCL(它们没有可变长度指令编码或跳转到指令中间)以及具有防喷功能的现代 JIT。
  • nx/xd 的 ubuntus 页面:wiki.ubuntu.com/Security/Features#nx "64 位和 32 位 -server 和 -generic-pae 内核是使用 PAE 寻址编译的。从 Ubuntu 9.10 开始,这种保护部分模拟了缺乏处理器NX 在 32 位内核上运行时......从 Ubuntu 11.04 开始,内核忽略 BIOS NX 设置。”和颜色矩阵。
  • 原来使用mprotect 非常简单,通过起始地址和长度给出一个区域。唯一需要注意的一点是起始地址必须是页面对齐的(addr & ~4095)。请注意,当进入 mprotect 调用时,GDB(至少 rr)会吓坏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-12
  • 2021-03-10
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 2011-09-27
  • 2019-08-29
相关资源
最近更新 更多