问题
Is it possible to create a dynamic function by allocating dynamic memory, writing some assembler opcodes to it (like 0x90 0xC2 for NOP RET), creating a function pointer which points to that dynamic memory and execute it like a regular function from within a C program?
Target should be a regular x86 Linux system.
回答1:
This memory doesn't have be heap memory (see note below). Moreover, I'd think that you can't change execution permission of heap memory.
On Linux, You can use the following:
#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
Note: On Linux, memory mapped by user is located in separate region (something like from 400000000000
and up to stack on x86 Linux, and probably 7f0000000000
on x64 one). Heap is located after ELF segments of the program and before region, available for mmap
. Heap itself can be allocated directly using brk
system call (superseded by malloc
by now). See this example (got on my 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]
As you can see, heap
is not executable (and is rightly so), so you can't use malloc
to get executable memory.
回答2:
In general yes, but you need to go into system-specific things to do so. That's not very surprising I guess, since the fact that you're going to use binary assembly instructions is making it pretty clear.
You need to be aware that you can't assume that heap memory on modern operating systems is executable, so you might need to jump through some hoops to make it so. You can't just call malloc()
and assume the returned pointer points to memory where you can execute code.
In Linux, you can use mmap() to ask the kernel to map you some memory, and by specifying the PROT_EXEC
flag in the call you can ask it to make the memory executable too.
回答3:
Many systems have for a long time had flags on virtual memory pages that tells if they can contain executable code or not. Memory allocated of the heap most likely won't have this "executable" flag set. So no you can not directly do that.
If you want to do that you have to use OS specific functions, and may have to run the program as "administrator" or "root" to be able to do it, though it doesn't seem to be necessary.
来源:https://stackoverflow.com/questions/19634587/c-function-pointer-can-i-jump-to-heap-memory-assembler-code