Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Copy a function in memory and execute it

I would like to know how in C in can copy the content of a function into memory and the execute it?

I'm trying to do something like this:

typedef void(*FUN)(int *);
char * myNewFunc;

char *allocExecutablePages (int pages)
{
    template = (char *) valloc (getpagesize () * pages);
    if (mprotect (template, getpagesize (), 
          PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
        perror ("mprotect");
    } 
}

void f1 (int *v) {
    *v = 10;
}

// allocate enough spcae but how much ??
myNewFunc = allocExecutablePages(...)

/* Copy f1 somewere else
 * (how? assume that i know the size of f1 having done a (nm -S foo.o))
 */

((FUN)template)(&val);
printf("%i",val);

Thanks for your answers

like image 931
Elinghton Avatar asked Dec 28 '10 12:12

Elinghton


3 Answers

You seem to have figured out the part about protection flags. If you know the size of the function, now you can just do memcpy() and pass the address of f1 as the source address.

One big caveat is that, on many platforms, you will not be able to call any other functions from the one you're copying (f1), because relative addresses are hardcoded into the binary code of the function, and moving it into a different location it the memory can make those relative addresses turn bad.

like image 89
Eugene Smith Avatar answered Nov 03 '22 18:11

Eugene Smith


This happens to work because function1 and function2 are exactly the same size in memory. We need the length of function2 for our memcopy so what should be done is: int diff = (&main - &function2);

You'll notice you can edit function 2 to your liking and it keeps working just fine!

Btw neat trick. Unfurtunate the g++ compiler does spit out invalid conversion from void* to int... But indeed with gcc it compiles perfectly ;)

Modified sources:

//Hacky solution and simple proof of concept that works for me (and compiles without warning on Mac OS X/GCC 4.2.1):
//fixed the diff address to also work when function2 is variable size    
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){ 
   return x-5;
}   

int function2(int x){ 
  //printf("hello world");
  int k=32;
  int l=40;
  return x+5+k+l;
}   


int main(){
  int diff = (&main - &function2);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }   

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}   

Output:

Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ gcc memoryFun.c 
Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ ./a.out 
pagesize: 4096, diff: 35
native: 1
memory: 83
native: 1

Another to note is calling printf will segfault because printf is most likely not found due to relative address going wrong...

like image 45
Walter Schreppers Avatar answered Nov 03 '22 17:11

Walter Schreppers


Hacky solution and simple proof of concept that works for me (and compiles without warning on Mac OS X/GCC 4.2.1):

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){
   return x-5;
}

int function2(int x){
  return x+5;
}


int main(){
  int diff = (&function2 - &function1);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}
like image 32
Brian Avatar answered Nov 03 '22 17:11

Brian