I tried to write a C program that would copy a function to other memory location, and then execute it as a function pointer. But I'm facing issues. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
extern uint64_t __start_myfnsection[];
extern uint64_t __stop_myfnsection[];
// I create a simple function, which will be placed in a separate binary section
__attribute__((noinline, section("myfnsection"))) void myfn() {
static int i;
i++;
printf("I love lemons!^^.\n");
printf("i=%d\n", i);
return;
}
int main () {
// Test the function.
myfn();
// Find out and print the size of my function.
uint64_t myfn_length = (__stop_myfnsection - __start_myfnsection);
printf("Length of myfn() function is: %lu\n", myfn_length);
// Allocate on-stack memory, and copy my function to it
void* memory = __builtin_alloca(myfn_length);
memcpy(memory, &myfn, myfn_length);
// Create a pointer to the copied function.
void (*myfn_copy)() = memory;
// Attempt to execute it.
myfn_copy();
return 0;
}
I compile with executable stack:
$ gcc -pie -z execstack -fno-stack-protector -g test.c
But the program crashes on start:
$ ./a.out
I love lemons!^^.
i=1
Length of myfn() function is: 9
Illegal instruction
With gdb:
# gdb ./a.out
GNU gdb (GDB) 14.2
Reading symbols from ./a.out...
(gdb) run
Starting program: /home/mika/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so".
I love lemons!^^.
i=1
Length of myfn() function is: 9
Program received signal SIGILL, Illegal instruction.
0x0000007ffffffb10 in ?? ()
(gdb)
(gdb) bt
#0 0x0000007ffffffb10 in ?? ()
#1 0x0000005555556748 in _start_main ()
#2 0x0000000000000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)
This system is arm64, if that's relevant.
What am I missing, or am trying to do something impossible? Thanks.
__builtin_allocaget the memory from? Will the memory be executable from? Did you look in the map file, where the section of your function is located? What are the involved addresses? While being undefined behaviour anyway, due to subtracting addresses of different memory object, I would assume__stop_myfnsection - __start_myfnsectionresults in the number ofuint64_telements, not in the size you need to copy. You probably should convert to intprt_t before you do the calculation.__start_myfnsectionandmyfn?uintptr_tthen subtract that to get the number of bytes.__stop_myfnsection[]and__start_myfnsection[]tochar.myfn_copy()at assembly instruction level and check if you get the same instructions than stepping intomyfn(). And maybe execution is not allowed in stack memory.