C函数指针:我可以跳转到堆内存汇编程序代码吗?

时间:2013-10-28 12:16:08

标签: c function-pointers

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

Target应该是常规的x86 Linux系统。

3 个答案:

答案 0 :(得分:17)

一般来说是的,但你需要进入系统特定的事情。我猜这并不奇怪,因为你要使用二进制汇编指令的事实非常清楚。

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

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

答案 1 :(得分:3)

此内存没有堆内存(请参阅下面的注释)。而且,我认为你不能改变堆内存的执行权限。

在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来获取可执行内存。

答案 2 :(得分:2)

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

如果你想这样做,你必须使用操作系统特定的功能,并且可能必须以“管理员”或“root”运行程序才能够执行它,尽管似乎没有必要。< / p>