Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C function pointer: Can I jump to heap memory assembler code?

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.

like image 400
muffel Avatar asked Oct 28 '13 12:10

muffel


People also ask

Are function pointers faster?

So in a worst case scenario, a function pointer call is arbitrarily slower than a direct function call, but this is misleading. It turns out that if foo_ptr had been const , then call_foo() and call_foo_ptr() would have generated the same code.

Are function pointers bad practice in C?

No, they're not evil. They're absolute necessary in order to implement various features such as callback functions in C. Without function pointers, you could not implement: qsort(3)

What is the point of function pointers?

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer that points to a function. As opposed to referencing a data value, a function pointer points to executable code within memory.

Why function pointer is used in C?

In C, we can use function pointers to avoid code redundancy. For example a simple qsort() function can be used to sort arrays in ascending order or descending or by any other order in case of array of structures. Not only this, with function pointers and void pointers, it is possible to use qsort for any data type.


2 Answers

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.

like image 158
unwind Avatar answered Oct 22 '22 07:10

unwind


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.

like image 39
Michael Pankov Avatar answered Oct 22 '22 06:10

Michael Pankov