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

标签 c memory segmentation-fault elf shellcode

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

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

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

我所知道的是可执行文件代码被映射到虚拟内存中的页面,这些页面被标记为 RW (.data & .bss 段) 所以也许没有办法做这样的事情代码执行,除非代码被注入(inject)内存的可执行区域(标记为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) - 如果页表中没有设置“x”(执行)位,您不能直接跳转到数据页。所有位的内存映射列在 /proc/$pid/maps//proc/$pid/smaps 文件中,作为可写代码的 'rwx','rw-'对于未执行的数据,'r--' 用于只读数据,'r-x' 用于普通代码。

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

在 x86 世界中,这完全实现为 "NX bit" / "XD bit" feature在 Pentium 4 (Prescott) 和更新版本(Core、Core2、Core i*、core m)/Athlon 64/Opteron 和更新版本中。如果 OS 工作在 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 的段寄存器的解决方案,以部分禁用部分内存空间的执行。

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

您可以:

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

关于我可以执行驻留在数据段(ELF 二进制文件)中的代码吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38113551/

相关文章:

c - 指针作为参数

计算给定边界框以及图像的宽度和高度的比例

image - 如何在 native win32 中将现有内存缓冲区包装为 DC?

python - 如何在 win7x64 上从 python 获取 PrivateUsage 内存值

c++ - 指向指针数组的指针导致段错误

c - 显示 ASCII 字符

c - 返回文件大小的函数?

c++ - 跨线程的内存分配和释放

当数据复制/扫描/读取到未初始化的指针时崩溃或 "segmentation fault"

c++ - 从文件中读取视频时 opencv 出现段错误