Скопируйте функцию в память и выполните ее - PullRequest
6 голосов
/ 28 декабря 2010

Я хотел бы знать, как в C in можно скопировать содержимое функции в memroy и выполнить ее?

Я пытаюсь сделать что-то вроде этого:

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);

Спасибо за ваши ответы

Ответы [ 5 ]

6 голосов
/ 28 декабря 2010

Вы, кажется, разобрались в части о флагах защиты. Если вы знаете размер функции, теперь вы можете просто выполнить memcpy () и передать адрес f1 в качестве адреса источника.

Одна большая оговорка заключается в том, что на многих платформах вы не сможете вызывать какие-либо другие функции из той, которую копируете (f1), потому что относительные адреса жестко закодированы в двоичный код функции и перемещены в нее. в другое место память может заставить эти относительные адреса испортиться.

3 голосов
/ 02 марта 2012

Это работает, потому что function1 и function2 имеют одинаковый размер в памяти.Нам нужна длина function2 для нашей memcopy, поэтому нужно сделать следующее: int diff = (& main - & function2);

Вы заметите, что можете редактировать функцию 2 по своему вкусу, и она продолжает работать просто отлично!

Кстати, хитрый трюк.Не отвлекайте внимание компилятор g ++ выдает неверное преобразование из void * в int ... Но, действительно, с gcc он отлично компилируется;)

Модифицированные источники:

//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;
}   

Вывод:

Walter-Schrepperss-MacBook-Pro: cppWork wschrep $ gcc memoryFun.c Walter-Schrepperss-MacBook-Pro: cppWork wschrep $ ./a.out размер страницы: 4096, разность: 35 "родной": 1 память: 83 "родной": 1

Следует также отметить, что вызов printf вызовет segfault, поскольку printf, скорее всего, не найден из-за неправильной адресации ...

1 голос
/ 10 января 2012

Хакерское решение и простое доказательство концепции, которое работает для меня (и компилируется без предупреждения в 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;
}
0 голосов
/ 12 сентября 2011

Это может быть решение для взлома здесь.Не могли бы вы создать фиктивную переменную или функцию сразу после функции (для копирования), получить адрес этой фиктивной переменной / функции и затем взять адрес функции, чтобы выполнить арифметику с суммой, используя адреса для получения размера функции?Это может быть возможно, поскольку память распределяется линейно и упорядоченно (а не случайно).Это также сохранит копирование функций в переносимой природе ANSI C, а не углубляется в системный код сборки.Я нахожу С достаточно гибким, просто нужно все обдумать.

0 голосов
/ 28 декабря 2010

Я пробовал эту проблему много раз в C и пришел к выводу, что это не может быть достигнуто с использованием только языка C.Моим главным занятием было определение длины копируемой функции.

Стандартный язык C не предоставляет никаких методов для получения длины функции.Тем не менее, можно использовать язык ассемблера и «разделы», чтобы найти длину.Как только длина найдена, ее легко скопировать и выполнить.

Самое простое решение - создать или определить сегмент компоновщика, который содержит функцию.Напишите модуль на ассемблере, чтобы вычислить и публично объявить длину этого сегмента.Используйте эту константу для размера функции.

Существуют и другие методы, которые включают настройку компоновщика, например, предопределенные области или фиксированные местоположения и копирование этих местоположений.

Во встроенных системах приземляются,большая часть кода, который копирует исполняемый материал в оперативную память, написана на ассемблере.

...