【问题标题】:C function pointer: Can I jump to heap memory assembler code?C 函数指针:我可以跳转到堆内存汇编代码吗?
【发布时间】:2013-11-07 05:06:42
【问题描述】:

是否可以通过分配动态内存来创建一个动态函数,向它写入一些汇编器操作码(例如 0x90 0xC2 for NOP RET ),创建一个指向该动态内存的函数指针,并像在 C 程序中的常规函数​​一样执行它?

目标应该是常规的 x86 Linux 系统。

【问题讨论】:

  • 类似,但不是一回事——int main=0xc290; 编译运行成功。
  • @ugoren 仅在某些情况下。
  • @glglgl,在问题描述的情况下。

标签: c function-pointers


【解决方案1】:

一般来说是的,但是您需要进入特定于系统的事情才能做到这一点。我想这并不奇怪,因为您将使用二进制汇编指令这一事实已经很清楚了。

您需要注意,您不能假设现代操作系统上的堆内存是可执行的,因此您可能需要跳过一些环节才能做到这一点。您不能只调用malloc() 并假设返回的指针指向您可以执行代码的内存。

在 Linux 中,您可以使用 mmap() 请求内核为您映射一些内存,并通过在调用中指定 PROT_EXEC 标志您可以请求它使内存也可执行。

【讨论】:

  • Windows下可以使用VirtualProtect
  • 我想说你甚至不能假设堆内存是可执行的。但是你不需要这个内存是堆的;看我的回答。
【解决方案2】:

此内存不是堆内存(请参阅下面的注释)。此外,我认为您无法更改堆内存的执行权限。

在 Linux 上,您可以使用以下内容:

#include <sys/mman.h>
size_t size = 0x1000; // 1 page
// this will be mapped somewhere between /lib/x86_64-linux-gnu/ld-2.15.so
// and stack (see note and memory map below)
void *code = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
// use `code` to write your instructions
// then store location at which you want to jump to in `fp`
void *fp = ...;
mprotect(code, size, PROT_READ | PROT_EXEC);
// use some inline assembly to jump to fp

注意:在 Linux 上,用户映射的内存位于单独的区域(类似于从 400000000000 到 x86 Linux 上的堆栈,在 x64 上可能是 7f0000000000)。堆位于程序的 ELF 段之后和区域之前,可用于mmap。堆本身可以使用brk 系统调用直接分配(现在被malloc 取代)。看这个例子(在我的 Ubuntu 12.10 x64 上):

➜  ~ ps
  PID TTY          TIME CMD
 9429 pts/3    00:00:07 zsh
20069 pts/3    00:00:00 git-credential-
22626 pts/3    00:00:00 ps
➜  ~ cat /proc/9429/maps 
00400000-004a2000 r-xp 00000000 08:01 6291468                            /bin/zsh5
006a1000-006a2000 r--p 000a1000 08:01 6291468                            /bin/zsh5
006a2000-006a8000 rw-p 000a2000 08:01 6291468                            /bin/zsh5
006a8000-006bc000 rw-p 00000000 00:00 0 
01a51000-01fd8000 rw-p 00000000 00:00 0                                  [heap]
...
7f6529d61000-7f6529d91000 rw-p 00000000 00:00 0 
...
7f652d0d3000-7f652d0d5000 rw-p 00023000 08:01 44833271                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffd7c7f000-7fffd7cae000 rw-p 00000000 00:00 0                          [stack]
7fffd7dff000-7fffd7e00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

如您所见,heap 不可执行(确实如此),因此您不能使用 malloc 获取可执行内存。

【讨论】:

    【解决方案3】:

    很长一段时间以来,许多系统在虚拟内存页面上都有标志,以告知它们是否可以包含可执行代码。为堆分配的内存很可能不会设置此“可执行”标志。所以不,你不能直接这样做。

    如果你想这样做,你必须使用操作系统特定的功能,并且可能必须以“管理员”或“root”身份运行程序才能做到这一点,尽管这似乎没有必要。

    【讨论】:

    • 我不认为你需要是 root,分配可执行内存并不是什么危及系统的事情,并且有它的用途(几乎所有当前的浏览器都在 JavaScript 引擎中这样做)。
    猜你喜欢
    • 2015-04-08
    • 2011-06-19
    • 2019-10-07
    • 2023-03-07
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 2014-11-30
    相关资源
    最近更新 更多