Я хотел бы знать, как в 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);
Спасибо за ваши ответы
Вы, кажется, разобрались в части флагов защиты. Если вы знаете размер функции, теперь вы можете просто выполнить memcpy () и передать адрес f1 в качестве исходного адреса.
Одно большое предостережение заключается в том, что на многих платформах вы не сможете вызывать любые другие функции из того, который вы копируете (f1), поскольку относительные адреса жестко закодированы в двоичный код функции и перемещают его в другую местоположение, которое память может сделать, эти относительные адреса ухудшаются.
Это происходит, потому что функции 1 и function2 имеют одинаковый размер в памяти. Нам нужна длина функции2 для нашей memcopy, так что нужно сделать: int diff = (& main – & function2);
Вы заметите, что можете редактировать функцию 2 по своему вкусу, и она отлично работает!
Btw опрятный трюк. Unstallunate компилятор 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 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 pagesize: 4096, diff: 35 native: 1 memory: 83 native: 1
Еще одно замечание – вызов printf будет segfault, потому что printf, скорее всего, не найден из-за неправильного адреса адреса …
Я много раз пробовал эту проблему в C и пришел к выводу, что ее невозможно выполнить, используя только язык C. Моим основным терном было найти длину функции для копирования.
Стандартный язык C не предоставляет никаких методов для получения длины функции. Однако для определения длины можно использовать язык ассемблера и «разделы». Как только длина будет найдена, копирование и выполнение легко.
Самое простое решение – создать или определить сегмент компоновщика, содержащий эту функцию. Напишите модуль языка ассемблера для расчета и публичного объявления длины этого сегмента. Используйте эту константу для размера функции.
Существуют и другие методы, которые include настройку компоновщика, например, предопределенные области или фиксированные местоположения и копирование этих местоположений.
Во встроенных системах земли большая часть кода, который копирует исполняемый файл в ОЗУ, записывается в сборку.
Это может быть решение для взлома. Не могли бы вы сделать фиктивную переменную или функцию непосредственно после функции (для копирования), получить адрес / функцию фиктивной переменной и затем выполнить адрес функции, чтобы сделать сумму арифметики с использованием адресов, чтобы получить размер функции? Это возможно, поскольку память распределяется линейно и упорядоченно (а не случайным образом). Это также сохранит функцию копирования в переносном режиме ANSI C, а не вникает в системный код сборки. Я считаю, что C является довольно гибким, нужно просто подумать.
Решение Hacky и простое доказательство концепции, которая работает для меня (и компилируется без предупреждения в Mac OS X / GCC 4.2.1):
#include "stdio.h" #include "stdlib.h" #include "string.h" #include 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; }