J'aimerais savoir comment en C dans peut copier le contenu d'une fonction en mémoire et l'exécuter?
J'essaie de faire quelque chose comme ceci: P>
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 Réponses :
Vous semblez avoir compris la partie sur les drapeaux de protection. Si vous connaissez la taille de la fonction, vous pouvez désormais passer memcpy () et transmettre l'adresse de F1 comme adresse source. p>
Une grande mise en garde est que, sur de nombreuses plateformes, vous ne pourrez pas appeler d'autres fonctions de celui que vous copiez (F1), car les adresses relatives sont calculées dans le code binaire de la fonction et le déplaçant dans un endroit différent, la mémoire peut rendre ces adresses relatives à tourner mal. P>
Pourrait toujours exécuter les relocalisations à partir du fichier code>. Amusez-vous à écrire votre propre lien. :-)
L'adresse de départ d'une fonction est facilement obtenue, en utilisant le nom de la fonction. La longueur i> d'une fonction est une question différente.
J'ai essayé ce problème plusieurs fois en C et est venu à la conclusion qu'il ne peut être accompli en utilisant uniquement le langage C. Ma principale Thorn trouvait la longueur de la fonction à copier. p>
Le langage C standard ne fournit aucune méthode pour obtenir la longueur d'une fonction. Cependant, on peut utiliser la langue d'assemblage et les «sections» pour trouver la longueur. Une fois la longueur trouvée, la copie et l'exécution sont faciles. p>
La solution la plus simple consiste à créer ou à définir un segment de liaison contenant la fonction. Écrivez un module de langage de montage pour calculer et déclarer publiquement la longueur de ce segment. Utilisez cette constante pour la taille de la fonction. P>
Il existe d'autres méthodes qui impliquent la mise en place de la liaison, telles que des zones prédéfinies ou des emplacements fixes et copier ces emplacements. P>
Dans les systèmes de systèmes intégrés, la majeure partie du code qui copie des éléments exécutables dans la RAM est écrit en montage. p>
Vous n'avez pas besoin Assembly i> pour comprendre la longueur d'une fonction - vous pouvez faire cette pièce avec un script de liaison.
Cela pourrait être une solution de hack ici. Pourriez-vous faire une variable mannequin ou une fonction directement après la fonction (à copier), obtenez cette adresse / la fonction de la fonction de variable factice, puis prenez l'adresse de fonctions pour faire une sorte d'arithmétique à l'aide d'adresses pour obtenir la taille de la fonction? Cela pourrait être possible car la mémoire est allouée linéairement et ordonnée (plutôt que de manière aléatoire). Cela maintiendrait également la copie de la fonction dans une nature portable ANSI C plutôt que de préciser le code de montage spécifique du système. Je trouve C plutôt flexible, il suffit de penser à des choses. P>
Solution hacky et simple preuve de concept qui fonctionne pour moi (et compile sans avertissement sur 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; }
Bonne réponse! Problème mineur: MALLOC (4096) CODE> n'est pas garanti de renvoyer la mémoire alignée sur 4096 octets (bien que je pense que cela va généralement avec la plupart des allocateurs), mais
mprotect () code> habituellement Nécessite que son premier argument soit aligné sur une page. Pour être sûr, vous voudrez peut-être utiliser
aligné_alloc () code> (disponible depuis C11) et utiliser
getpagesize () code> au lieu de la constante 4096. EN.CPPREFERFERFECK.fr/w/c/Memory/aligned_alloc
Ceci arrive à fonctionner car la fonction1 et la fonction2 sont exactement la même taille en mémoire. Nous avons besoin de la longueur de la fonction2 pour notre membopie, donc ce qui devrait être fait est: INT DIFF = (& Main - & Fonction2);
Vous remarquerez que vous pouvez modifier la fonction 2 à votre goût et cela continue de fonctionner simplement! P>
BTT NEAT Trick. Profinate du compilateur G ++ sort de la conversion invalide de Void * vers INT ... mais en effet avec GCC, il compile parfaitement;) p>
Sources modifiées: P>
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
Bonne réponse! Problème mineur: MALLOC (4096) CODE> n'est pas garanti de renvoyer la mémoire alignée sur 4096 octets (bien que je pense que cela va généralement avec la plupart des allocateurs), mais
mprotect () code> habituellement Nécessite que son premier argument soit aligné sur une page. Pour être sûr, vous voudrez peut-être utiliser
aligné_alloc () code> (disponible depuis C11) et utiliser
getpagesize () code> au lieu de la constante 4096. EN.CPPREFERFERFECK.fr/w/c/Memory/aligned_alloc
Vous avez déjà posé déjà posé cette question une fois ici, Stackoverflow.com/questions/4541419/... - Pourquoi demandez-vous encore?
Recherchez sur le Web pour "Copie Embedded Cool C RAM" pour plus d'informations.